package main import ( "fmt" "log" "time" "strings" mqtt "github.com/eclipse/paho.mqtt.golang" ) const ( QOS = byte(1) RETAINED = true MQTT_CONNECT_TIMEOUT = 1 * time.Second MQTT_SUBSCRIBE_TIMEOUT = 1 * time.Second MQTT_DISCONNECT_TIMEOUT_US = 500 MQTT_KEEPALIVE_PERIOD = 2 * time.Second ) var ( mqttServerHealthTopic string ) type MQTTMessage struct { Topic string Payload []byte } func (m MQTTMessage) String() string { return fmt.Sprintf("topic='%s' message='%s'", m.Topic, string(m.Payload)) } func MQTTRun(config MQTTConfig, rx chan MQTTMessage, tx chan MQTTMessage) { mqttServerHealthTopic = fmt.Sprintf("%s/server/health", config.TopicPrefix) opts := mqtt.NewClientOptions() opts.AddBroker(config.Broker) opts.SetClientID(config.ClientID) opts.SetCleanSession(true) opts.SetOnConnectHandler(func(c mqtt.Client) { log.Printf("Connected to MQTT broker.") c.Publish(mqttServerHealthTopic, QOS, true, []byte(`good`)) topic := fmt.Sprintf("%s/cover/+/movement", config.TopicPrefix) token := c.Subscribe(topic, byte(2), func(c mqtt.Client, msg mqtt.Message) { message := MQTTMessage{ Topic: strings.TrimPrefix(msg.Topic(), config.TopicPrefix + "/"), Payload: msg.Payload(), } rx <- message }) success := token.WaitTimeout(MQTT_SUBSCRIBE_TIMEOUT) if !success { log.Fatal("Initial topic subscription failed.") } }) opts.SetConnectionLostHandler(MQTTConnectionLostHandler) opts.SetAutoReconnect(true) opts.SetConnectRetry(true) opts.SetConnectTimeout(MQTT_CONNECT_TIMEOUT) opts.SetKeepAlive(MQTT_KEEPALIVE_PERIOD) opts.SetWill(mqttServerHealthTopic, `bad`, QOS, true) client := mqtt.NewClient(opts) token := client.Connect() success := token.WaitTimeout(MQTT_CONNECT_TIMEOUT) if !success { log.Fatal("Initial connection to MQTT broker failed.") } defer client.Disconnect(MQTT_DISCONNECT_TIMEOUT_US) for message := range tx { topic := fmt.Sprintf("%s/%s", config.TopicPrefix, message.Topic) client.Publish(topic, QOS, RETAINED, message.Payload) } } func MQTTConnectionLostHandler(c mqtt.Client, err error) { log.Printf("Connection to MQTT broker lost: %v", err) }