Skip to main content

Go - MQTT Hello World

Guangzhou, China

Go Paho MQTT Client

I already wrote a Go MQTT client before. I will try to expand this a little bit:

go mod init go/go-mqtt
go get github.com/eclipse/paho.mqtt.golang@latest

Connect to the MQTT broker

  • Broker IP: 192.168.2.115
  • MQTT Service Port: 1883
  • Broker Login: admin/instar

Go - MQTT Hello World

./main.go

package main

import (
"fmt"
"time"

mqtt "github.com/eclipse/paho.mqtt.golang"
)

var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
fmt.Printf("Topic: %s | %s\n", msg.Topic(), msg.Payload())
}

var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) {
fmt.Println("Connected")
}

var connectLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
fmt.Printf("Connect lost: %+v", err)
}

func main() {
var broker = "192.168.2.115"
var port = 1883
opts := mqtt.NewClientOptions()
opts.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
opts.SetClientID("go_mqtt_client")
opts.SetUsername("admin")
opts.SetPassword("instar")
opts.SetDefaultPublishHandler(messagePubHandler)
opts.OnConnect = connectHandler
opts.OnConnectionLost = connectLostHandler
client := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}

sub(client)
publish(client)

client.Disconnect(250)
}

func publish(client mqtt.Client) {
// Turn privacy mask 1 on and off again after 15s
nums := []int{1, 0}
for _, num := range nums {
value := fmt.Sprintf("%d", num)
token := client.Publish("cameras/115/multimedia/privacy/region1/enable/raw", 0, false, value)
token.Wait()
time.Sleep(15 * time.Second)
}
}

func sub(client mqtt.Client) {
// Subscribe to the LWT connection status
topic := "cameras/115/status/testament"
token := client.Subscribe(topic, 1, nil)
token.Wait()
fmt.Println("Subscribed to LWT", topic)
}

Running the Program

go run .\main.go
Connected
Subscribed to LWT cameras/115/status/testament
Topic: cameras/115/status/testament | {"val":"alive"}

The program connects to my camera broker, subscribes to the last-will topic and publishes updates to the privacy mask to turn it on and off again after 15s. The client disconnects after 250ms after that.

To get a binary file out I can run the build command:

go build ./main.go -o mqtt

And run the binary with ./mqtt.

Cross Compiling with Go

Go supports a variety of platforms and operating systems, including:

  • Android
  • Darwin
  • Linux
  • Windows

The file created requires a 64bit x86-64 system to be executed:

file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, Go BuildID=GkWKfp1sGIj5CJ0LesYM/P1txXPn8ar3YIQEGRF3P/hbjIOYuyC5-d1UMZN32q/CGL0UrtrAC1goylMkfFl, with debug_info, not stripped

So how do I get a file that I can use on my IP camera that uses an ARM7 processor?

uname -m
armv7l

So how do I find out what systems are supported?

go tool dist list

android/386
android/amd64
android/arm
android/arm64
ios/amd64
ios/arm64
js/wasm
linux/386
linux/amd64
linux/arm
linux/arm64
linux/loong64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64
linux/ppc64le
linux/riscv64
linux/s390x
windows/386
windows/amd64
windows/arm
windows/arm64

...

I can add the information as a environment variable when running the build:

env GOOS=linux GOARCH=arm go build -o mqtt_arm

Now I got a binary that can be executed on a 32bit ARM system:

file mqtt_arm
mqtt_arm: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, Go BuildID=msMp-jFIWHH3UaYAwNkh/TSOtDFvNMz_m1j_2VuU-/jOS7whdSr12-3_dBf4qC/xOLKo5WJnx4cluesUzqW, with debug_info, not stripped

And this worked - just copying the binary onto my IP Camera and executing it and I got the broker connection. Very nice <3