Aiming for Jarvis, Creating D.A.N.I.

Tutorial 24: MQTT and IoT (or, Talking to the things that talk back)

If you've made it to the networking tutorial, you're already comfortable with the raw, chaotic nature of TCP. But let’s be honest: in the world of IoT (Internet of Things), TCP is a bit like driving a semi-truck to buy a gallon of milk. It’s heavy, it’s complex, and it’s overkill for a temperature sensor that just needs to say "it's 22 degrees."

For that, we use MQTT—the "Hello World" of messaging protocols. It’s lightweight, it’s publish/subscribe, and it’s the heartbeat of every smart home project I’ve ever built that didn't end in a small electrical fire.

Initialising the client

In Skink, we use std/mqtt. It’s built on top of the classic C mosquitto library, so it’s rock-solid, provided you remember to clean up after yourself.

module main

import "std/mqtt"

fn main() -> int {
    // Connect to a public broker. Don't build a business on this one!
    client, err := mqtt.NewClient("skink_client", "test.mosquitto.org", 1883)
    if err.message != "" {
        print("create failed: {err.message}")
        return 1
    }

    err = client.Connect()
    if err.message != "" {
        print("connect failed: {err.message}")
        client.Close()
        return 1
    }

    // Publish a message to a topic
    err = client.Publish("home/livingroom/temperature", "22.5", 0)
    if err.message != "" {
        print("publish failed: {err.message}")
    } else {
        print("published")
    }

    client.Disconnect()
    client.Close()
    mqtt.Cleanup()
    return 0
}

Subscribing to a topic

MQTT is all about the "fire and forget" publish/subscribe model. You subscribe to a topic, and when someone else publishes to it, you get the update.

err := client.Subscribe("home/+/temperature", 0)
if err.message != "" {
    print("subscribe failed: {err.message}")
    return 1
}

// MQTT needs a "Loop" to keep the connection alive and process incoming packets
for i := 0; i < 10; i = i + 1 {
    client.Loop(100) // Process messages for 100ms
    time.SleepMs(100)
}

Receiving messages

A word of warning: std/mqtt is currently a thin wrapper. We don't have fancy event-driven callbacks quite yet. If you're planning on building a serious IoT hub, I suggest wrapping the low-level C mosquitto calls in your own struct to handle the incoming buffer properly. It’s a bit of extra work, but it’s the difference between a prototype and a real service.

Exercises

Don't just read about the smart home—go out and build a part of it:

  1. The Sensor Stream: Write a script that publishes a changing value (like a random number) to a topic once every second.
  2. The Listener: Write a client that subscribes to that topic and prints the value every time it arrives. It’s incredibly satisfying when the two programs start "talking" to each other.
  3. The Intelligent Home: Combine std/mqtt with our ruleset from Tutorial 14. Make it so that if the temperature goes above 25.0, your code prints a "Warning: Melting point reached" message.

Next

When you're ready to start presenting your data with a bit more style, we'll talk about Web templates and static files.