前言
由于阿里云物联网套件关于设备认证的文档不够详细,笔者差不多摸索了几天才连接上MQTT。下面是使用Python模拟设备接入阿里云的MQTT。
概述
阿里云物联网套件提供两种接入方式:
- MQTT客户端域名直连(资源受限设备推荐)
- 先HTTPS发送授权后再连接MQTT(一些特殊增值服务,比如设备级别的引流)
本文主要介绍第一种接入方式,TCP直连,并提供Python代码示例。
主要参数
连接域名
<ProductKey>.iot-as-mqtt.cn-shanghai.aliyuncs.com:1883
MQTT Connect报文参数
1、mqttClientId
mqttClientId = "<ClientId>"+"|securemode=3,signmethod=hmacsha1,timestamp=132323232|"
2、mqttUsername
使用&
拼接<DeviceName>
和<ProductKey>
。
mqttUsername = "<DeviceName>&<ProductKey>"
3、mqttPassword
把以下参数按字典键名排序,再把键名都拼接起来(没有分隔符)生成content,然后以DeviceSecret为盐,对content进行hma_sha1加密,最后二进制转为十六进制字符串表示。
- clientId
- deviceName
- productKey
- timestamp
mqttPassword = hmac_sha1(DeviceSecret, content).toHexString();
示例
假设
- clientId = 12345
- deviceName = device
- productKey = pk
- timestamp = 789
- signmethod = hmacsha1
content拼接结果:clientId12345deviceNamedeviceproductKeypktimestamp789
注意:不用拼接signmethod参数。
对content以DeviceSecret为盐进行hmacsha1加签后,再转为十六进制字符串,最后结果:FAFD82A3D602B37FB0FA8B7892F24A477F851A14
注意:不需要base64。
最后总结一下生成的参数:
- mqttHost =
"pk.iot-as-mqtt.cn-shanghai.aliyuncs.com"
- mqttPort =
1883
- mqttClientId =
"12345|securemode=3,signmethod=hmacsha1,timestamp=789|"
- mqttUsername =
"device&pk"
- mqttPassword =
"FAFD82A3D602B37FB0FA8B7892F24A477F851A14"
参数说明
参数 | 描述 |
---|---|
ProductKey | 产品Key。从iot套件控制台获取 |
DeviceName | 设备名称。从iot套件控制台获取 |
DeviceSecret | 设备密码,从iot套件控制台获取 |
signmethod | 算法类型,hmacmd5 或hmacsha1 |
clientId | 客户端自表示id,建议mac或sn |
timestamp | 当前时间毫秒值,可选 |
securemode | 目前安全模式,可选值有2(TLS直连模式)、3(TCP直连模式) |
示例代码
填写自己的ProductKey
、ClientId
、DeviceName
、DeviceSecret
。
#!/usr/bin/python3
# coding=utf-8
import datetime
import time
import hmac
import hashlib
import math
# 测试加密开关,=1表示不进行连接
TEST = 0
ProductKey = ""
ClientId = "12345" # 自定义clientId
DeviceName = ""
DeviceSecret = ""
# signmethod
signmethod = "hmacsha1"
# signmethod = "hmacmd5"
# 当前时间毫秒值
us = math.modf(time.time())[0]
ms = int(round(us * 1000))
timestamp = str(ms)
data = "".join(("clientId", ClientId, "deviceName", DeviceName,
"productKey", ProductKey, "timestamp", timestamp
))
# print(round((time.time() * 1000)))
print("data:", data)
if "hmacsha1" == signmethod:
ret = hmac.new(bytes(DeviceSecret, encoding="utf-8"),
bytes(data, encoding="utf-8"),
hashlib.sha1).hexdigest()
elif "hmacmd5" == signmethod:
ret = hmac.new(bytes(DeviceSecret, encoding="utf-8"),
bytes(data, encoding="utf-8"),
hashlib.md5).hexdigest()
else:
raise ValueError
sign = ret
print("sign:", sign)
# ======================================================
strBroker = ProductKey + ".iot-as-mqtt.cn-shanghai.aliyuncs.com"
port = 1883
client_id = "".join((ClientId,
"|securemode=3",
",signmethod=", signmethod,
",timestamp=", timestamp,
"|"))
username = "".join((DeviceName, "&", ProductKey))
password = sign
print("="*30)
print("client_id:", client_id)
print("username:", username)
print("password:", password)
print("="*30)
def secret_test():
DeviceSecret = "secret"
data = "clientId12345deviceNamedeviceproductKeypktimestamp789"
ret = hmac.new(bytes(DeviceSecret, encoding="utf-8"),
bytes(data, encoding="utf-8"),
hashlib.sha1).hexdigest()
print("test:", ret)
# ======================================================
# MQTT Initialize.--------------------------------------
try:
import paho.mqtt.client as mqtt
except ImportError:
print("MQTT client not find. Please install as follow:")
print("pip install paho-mqtt")
# ======================================================
def on_connect(mqttc, obj, flags, rc):
print("OnConnetc, rc: " + str(rc))
mqttc.subscribe("test", 0)
def on_publish(mqttc, obj, mid):
print("OnPublish, mid: " + str(mid))
def on_subscribe(mqttc, obj, mid, granted_qos):
print("Subscribed: " + str(mid) + " " + str(granted_qos))
def on_log(mqttc, obj, level, string):
print("Log:" + string)
def on_message(mqttc, obj, msg):
curtime = datetime.datetime.now()
strcurtime = curtime.strftime("%Y-%m-%d %H:%M:%S")
print(strcurtime + ": " + msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
on_exec(str(msg.payload))
def on_exec(strcmd):
print("Exec:", strcmd)
strExec = strcmd
# =====================================================
if __name__ == '__main__':
if TEST:
secret_test()
exit(0)
mqttc = mqtt.Client(client_id)
mqttc.username_pw_set(username, password)
mqttc.on_message = on_message
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.on_subscribe = on_subscribe
mqttc.on_log = on_log
mqttc.connect(strBroker, port, 120)
mqttc.loop_forever()
参考资料
终于知道之前为什么总是连接不上了!!!是因为之前官方文档对password加密的字段多了「signmethodhmacsha1」字符串!