ZYB ARTICLES REPOS

用go语言实现在中移动OneNet的MQTT交互

发送方

代码中的设备密钥产品ID设备ID都可以在后台管理系统里查询到

package main

import (
	"crypto/tls"
	"fmt"
	MQTT "github.com/eclipse/paho.mqtt.golang"
	"math/rand"
	"time"
)

const qos = 0
const server = "tcp://183.230.40.39:6002"

const topic = "sample/data"

const password = "设备密钥"
const username = "产品ID"
const clientid = "设备ID"

func main() {

	connOpts := MQTT.NewClientOptions().AddBroker(server).SetClientID(clientid).SetCleanSession(true)
	connOpts.SetUsername(username)
	connOpts.SetPassword(password)

	tlsConfig := &tls.Config{InsecureSkipVerify: true, ClientAuth: tls.NoClientCert}
	connOpts.SetTLSConfig(tlsConfig)

	client := MQTT.NewClient(connOpts)
	if token := client.Connect(); token.Wait() && token.Error() != nil {
		fmt.Println(token.Error())
		return
	}
	fmt.Printf("Connected to %s\n", server)

	for {
		message := fmt.Sprintf("{\"data\":\"%v\", \"time\":\"%v\"}", rand.Intn(10000), time.Now().Format("2006-01-02 15:04:05"))
		fmt.Printf("MQTT SENDER: %s\n", message)
		client.Publish(topic, byte(qos), false, message)
		time.Sleep(5 * time.Second)
	}
}

接收方

package main

import (
	"crypto/tls"
	MQTT "github.com/eclipse/paho.mqtt.golang"
	"log"
	"os"
	"os/signal"
	"syscall"
)

const qos = 0
const server = "tcp://183.230.40.39:6002"

const password = "设备密钥"
const username = "产品ID"
const clientid = "设备ID"

var onMessageReceived MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
	log.Printf("MQTT RECEIVER: topic: %s  Message: %s\n", msg.Topic(), msg.Payload())
}

func main() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)

	sub_topics := []string{
		"sample/data",
	}

	connOpts := MQTT.NewClientOptions().AddBroker(server).SetClientID(clientid).SetCleanSession(true)
	connOpts.SetUsername(username)
	connOpts.SetPassword(password)

	tlsConfig := &tls.Config{InsecureSkipVerify: true, ClientAuth: tls.NoClientCert}
	connOpts.SetTLSConfig(tlsConfig)
	connOpts.SetDefaultPublishHandler(onMessageReceived)

	client := MQTT.NewClient(connOpts)
	if token := client.Connect(); token.Wait() && token.Error() != nil {
		log.Println(token.Error())
		return
	}
	log.Printf("Connected to %s\n", server)

	for _, topic := range sub_topics {
		if token := client.Subscribe(topic, byte(qos), nil); token.Wait() && token.Error() != nil {
			log.Println(token.Error())
			return
		}
	}

	<-c
}

API的Token算法

算法针对的是多协议接入方案

其中productIDaccessKey可以在产品管理页面查到,expiry是过期时间戳

func getAPIToken(productID int, accessKey string, expiry int64) string {

    const method = "sha256"
    const version = "2018-10-31"

    res := fmt.Sprintf("products/%v", productID)
    et := fmt.Sprintf("%v", expiry)

    signature := et + "\n" + method + "\n" + res + "\n" + version

    key, _ := base64.StdEncoding.DecodeString(accessKey)

    mac := hmac.New(sha256.New, key)
    mac.Write([]byte(signature))
    sign := base64.StdEncoding.EncodeToString(mac.Sum(nil))

    res = url.QueryEscape(res)
    sign = url.QueryEscape(sign)

    s := fmt.Sprintf("version=%v&res=%v&et=%v&method=%v&sign=%v",
        version, res, et, method, sign)

    return s
}