通讯协议
Topic规则:每个设备的Topic按设备ID进行区分
指令接收:smart/device/in/devId,通过订阅该Topic接收来自APP和云端的控制指令
上报数据:smart/device/out/devId,通过该Topic发送上报数据
MQTT消息格式
协议版本号 (3位/16进制) |
签名CRC32 (4位/16进制) |
序号:递增,防重复 (4位/16进制) |
来源 :1 (4位/16进制) |
协议数据(AES加密) (16进制) |
---|---|---|---|---|
2.2 | 63580128 | 消息数递增,防重复 | 00000001 | |
协议数据加密
设备通过MQTT向云端发送(Publish)的协议数据为:
payload = {
'protocol': 协议号4/5/6/7,
't': 时间戳,
'data': {
'devId': '设备ID',
'dps': {'101': True}
}
}
例如下面例子,设备向云端发送的数据
payload = {
'protocol': 4,
't': 1632205107,
'data': {
'devId': '6c1a2a1c62ece803eelaqb',
'dps': {'101': True}
}
}
将JSON的’’转成””,并按照字符串排列,参考json.dumps()
#!/usr/bin/python
# Write Python 3 code in this online editor and run it.
# 将JSON的''转成"",并按照字符串排列,参考json.dumps()
import json
payload = {
'protocol': 4,
't': 1632205107,
'data': {
'devId': '6c1a2a1c62ece803eelaqb',
'dps': {'101': True}
}
}
print(json.dumps(payload).encode('utf-8'));
输出为:
{“protocol”: 4, “t”: 1632205107, “data”: {“devId”: “6c1a2a1c62ece803eelaqb”, “dps”: {“101”: true}}}
对上面输出的数据进行AES加密,加密的秘钥Key为:’localKey’: ‘c70bc07421fed338’
防篡改签名:crc32
(从序号部分开始到协议数据结束,序号 + 来源 + 协议数据,三部分进行crc32计算得到的值),列如:
序号:00000004
来源:00000001
数据:e3ad33371db44b72b04bb48230c367d8fe00c519c3340234db4ea40788dd3cdd5f55dcc30194fbd623c580bde4a9d6e1646c4f3d95525227b7cf414707dbd62740213b309af92b4f55ecdebe4682d6132d803b8fe07adba08cf754790a6a51d4e3846627198da1904fc1d3dc0f4581f9
使用以下数据进行CRC32计算
0000000400000001e3ad33371db44b72b04bb48230c367d8fe00c519c3340234db4ea40788dd3cdd5f55dcc30194fbd623c580bde4a9d6e1646c4f3d95525227b7cf414707dbd62740213b309af92b4f55ecdebe4682d6132d803b8fe07adba08cf754790a6a51d4e3846627198da1904fc1d3dc0f4581f9
协议号:322e32
CRC32签名:48c429ce(CRC32计算后在这里)
消息序号:00000004
来源:00000001
实际数据:e3ad33371db44b72b04bb48230c367d8fe00c519c3340234db4ea40788dd3cdd5f55dcc30194fbd623c580bde4a9d6e1646c4f3d95525227b7cf414707dbd62740213b309af92b4f55ecdebe4682d6132d803b8fe07adba08cf754790a6a51d4e3846627198da1904fc1d3dc0f4581f9
设备最终通过MQTT发送给云端的数据为:协议号+CRC32签名+消息序号+来源+实际数据
322e32
48c429ce
00000004
00000001
e3ad33371db44b72b04bb48230c367d8fe00c519c3340234db4ea40788dd3cdd5f55dcc30194fbd623c580bde4a9d6e1646c4f3d95525227b7cf414707dbd62740213b309af92b4f55ecdebe4682d6132d803b8fe07adba08cf754790a6a51d4e3846627198da1904fc1d3dc0f4581f9
mqtt数据点下发上报新格式:https://wiki.tuya-inc.com:7799/page/7733297#924354
pv=2.1消息加密及签名算法:
假设 002dr00118fe34d9a124 的localKey 为 8bb486f35dbc57dd
1、数据加密:aes(算法调整:二进制转为字符串时由原来的“转为十六进制”改为转为“base64编码”)
将需要加密的数据使用密钥进行aes。加密的内容为:protocol、t、dps、devId。结构见加密内容
样例:
encryptData=aes(“{\”protocol\”: 5, \”t\”: 1459168450, \”data\”:{\”devId\”: \”002dr00118fe34d9a124\”, \”dps\”:{\”1\”: \”true\”}}}”)
结果为:YzE/13Vp6p84PA1dV/1rACuvQlqIDsHDjpzZF5hqvPLdWu0bd7SKADwzK893HfHKMl4rdHb5Qc1qPOqfSFVc1ceQGhvwDO7pqCLmArcUpYDSEiSjFCfRKh1hnsbZrXEj
2、防篡改:md5(算法调整:将生成的32位字符串,转为16位字符串,算法:取32位中的中间16位,即8-24位)
将每个参数格式化为”key=val”,进行组装(使用key升序),组装后的字符串格式如:k1=v1||k2=v2,然后加上密钥如:k1=v1||k2=v2…kn=vn||key,进行整串字符串的MD5。
参数包括:data、pv 及密钥
样例:
md5前的数据串str:data=YzE/13Vp6p84PA1dV/1rACuvQlqIDsHDjpzZF5hqvPLdWu0bd7SKADwzK893HfHKMl4rdHb5Qc1qPOqfSFVc1ceQGhvwDO7pqCLmArcUpYDSEiSjFCfRKh1hnsbZrXEj||pv=2.1||8bb486f35dbc57dd
将上面的直接进行MD5
sign:md5(str) 结果为:326053f1f965e98d6db781a6010def3b
326053f1 f965e98d6db781a6 010def3b
取32位中的中间16位,即8-24位,结果为 f965e98d6db781a6
3、整体为字符串,分为三部分。格式如下:
协议版本pv(3位) | md5签名串sign(16位) | aes(长度不定) |
---|---|---|
2.1 | f965e98d6db781a6 | YzE/13Vp6p84PA1dV/1rACuvQlqIDsHDjpzZF5hqvPLdWu0bd7SKADwzK893HfHKMl4rdHb5Qc1qPOqfSFVc1ceQGhvwDO7pqCLmArcUpYDSEiSjFCfRKh1hnsbZrXEj |
最终传输的字符串为:2.1f965e98d6db781a6YzE/13Vp6p84PA1dV/1rACuvQlqIDsHDjpzZF5hqvPLdWu0bd7SKADwzK893HfHKMl4rdHb5Qc1qPOqfSFVc1ceQGhvwDO7pqCLmArcUpYDSEiSjFCfRKh1hnsbZrXEj