通讯协议


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)的协议数据为:

  1. payload = {
  2. 'protocol': 协议号4/5/6/7,
  3. 't': 时间戳,
  4. 'data': {
  5. 'devId': '设备ID',
  6. 'dps': {'101': True}
  7. }
  8. }

例如下面例子,设备向云端发送的数据

  1. payload = {
  2. 'protocol': 4,
  3. 't': 1632205107,
  4. 'data': {
  5. 'devId': '6c1a2a1c62ece803eelaqb',
  6. 'dps': {'101': True}
  7. }
  8. }

将JSON的’’转成””,并按照字符串排列,参考json.dumps()

  1. #!/usr/bin/python
  2. # Write Python 3 code in this online editor and run it.
  3. # JSON''转成"",并按照字符串排列,参考json.dumps()
  4. import json
  5. payload = {
  6. 'protocol': 4,
  7. 't': 1632205107,
  8. 'data': {
  9. 'devId': '6c1a2a1c62ece803eelaqb',
  10. 'dps': {'101': True}
  11. }
  12. }
  13. print(json.dumps(payload).encode('utf-8'));

输出为:
{“protocol”: 4, “t”: 1632205107, “data”: {“devId”: “6c1a2a1c62ece803eelaqb”, “dps”: {“101”: true}}}

对上面输出的数据进行AES加密,加密的秘钥Key为:’localKey’: ‘c70bc07421fed338’

image.png

防篡改签名:crc32

(从序号部分开始到协议数据结束,序号 + 来源 + 协议数据,三部分进行crc32计算得到的值),列如:
序号:00000004
来源:00000001
数据:e3ad33371db44b72b04bb48230c367d8fe00c519c3340234db4ea40788dd3cdd5f55dcc30194fbd623c580bde4a9d6e1646c4f3d95525227b7cf414707dbd62740213b309af92b4f55ecdebe4682d6132d803b8fe07adba08cf754790a6a51d4e3846627198da1904fc1d3dc0f4581f9

使用以下数据进行CRC32计算
0000000400000001e3ad33371db44b72b04bb48230c367d8fe00c519c3340234db4ea40788dd3cdd5f55dcc30194fbd623c580bde4a9d6e1646c4f3d95525227b7cf414707dbd62740213b309af92b4f55ecdebe4682d6132d803b8fe07adba08cf754790a6a51d4e3846627198da1904fc1d3dc0f4581f9

image.png
协议号: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
image.png

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

image.png