用go语言实现在腾讯云iothub的MQTT交互
发送方
每隔5秒推送一次数据
package main
import (
"crypto/tls"
"fmt"
MQTT "github.com/eclipse/paho.mqtt.golang"
"math/rand"
"time"
)
const qos = 0
const productID = "这里填产品ID"
const deviceName = "Sender" // 设备名称
var topic = productID + "/" + deviceName + "/event"
var clientid = productID + deviceName
var username = "需要按算法生成,参见下文"
var password = "需要按算法生成,参见下文"
var server = "tcp://" + productID + ".iotcloud.tencentdevices.com:1883"
func main() {
fmt.Println(topic)
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 {
tmstr := time.Now().Format("2006-01-02 15:04:05")
var message string
// 如果要用数据模板,可参考数据模板协议:
// https://cloud.tencent.com/document/product/1081/34916
message = fmt.Sprintf(`
{
"clientToken": "Server",
"method": "report",
"params": {
"data": "%v",
"time": "%v"
}
}
`, rand.Intn(10000), tmstr)
// 或者直接自定义数据
message = fmt.Sprintf("{\"data\":\"%v\", \"time\":\"%v\"}", rand.Intn(10000), tmstr)
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 productID = "这里填产品ID"
const deviceName = "Receiver" // 设备名称
var topic = productID + "/" + deviceName + "/data"
var clientid = productID + deviceName
var username = "需要按算法生成,参见下文"
var password = "需要按算法生成,参见下文"
var server = "tcp://" + productID + ".iotcloud.tencentdevices.com:1883"
func main() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
sub_topics := []string{
topic,
}
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
}
var onMessageReceived MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
log.Printf("MQTT RECEIVER: topic: %s Message: %s\n", msg.Topic(), msg.Payload())
}
建立数据转发规则
要使发送方的数据能正常到达接收方,还需要在腾讯云iothub
平台的规则引擎里添加并启用一条规则,就是:
把Sender发往topic为xxx/Sender/event的数据转发到Receiver能接收的topic: xxx/Receiver/data
生成认证信息的方法
上文代码中的username
和password
的生成算法
// TencentIotHubMQTTAuthInfo 腾讯云 Iot Hub MQTT 认证信息
type TencentIotHubMQTTAuthInfo struct {
ClientID string `json:"clientid"`
UserName string `json:"username"`
Password string `json:"password"`
}
// GenerateTencentIotMQTTAuthInfo 生成腾讯云iot的mqtt密码
// https://cloud.tencent.com/document/product/634/32546
// productID 产品号
// deviceName 设备名
// psk 设备对称密钥
func GenerateTencentIotMQTTAuthInfo(productID, deviceName, psk string) (TencentIotHubMQTTAuthInfo, error) {
var ai TencentIotHubMQTTAuthInfo
var err error
// 1. 生成 connid 为一个随机字符串,方便后台定位问题
connid := randConnID(5)
// 2. 生成过期时间,表示签名的过期时间,从纪元1970年1月1日 00:00:00 UTC 时间至今秒数的 UTF8 字符串
expiry := time.Now().Add(365 * 24 * time.Hour).Unix()
// 3. 生成 MQTT 的 clientid 部分, 格式为 ${productid}${devicename}
ai.ClientID = productID + deviceName
// 4. 生成 MQTT 的 username 部分, 格式为 ${clientid};${sdkappid};${connid};${expiry}
ai.UserName = fmt.Sprintf("%v;%v;%v;%v", ai.ClientID, 12010126, connid, expiry)
// 5. 对 username 进行签名,生成token
key, err := base64.StdEncoding.DecodeString(psk)
if err != nil {
return ai, err
}
mac := hmac.New(sha256.New, key)
mac.Write([]byte(ai.UserName))
token := hex.EncodeToString(mac.Sum(nil))
// 6. 根据物联网通信平台规则生成 password 字段
ai.Password = token + ";hmacsha256"
return ai, err
}
// ToJSONString 将TencentIotHubMQTTAuthInfo转换为json string
func (ai TencentIotHubMQTTAuthInfo) ToJSONString() string {
data, _ := json.Marshal(ai)
return string(data)
}
// randConnID 随机产生一个长度为n的connid
func randConnID(n int) string {
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
s := make([]byte, n)
for i := range s {
s[i] = letters[rand.Intn(len(letters))]
}
return string(s)
}