Appearance
MQTT 设备接入指南
本文档以 MQTT 调试工具 为例介绍如何通过 MQTT 协议 将设备安全接入到Xlink物联网平台,实现数据上报、命令下发等功能。MQTT(Message Queuing Telemetry Transport)是一种轻量级的发布/订阅消息传输协议,适用于低带宽、不稳定网络环境下的设备通信。MQTT 调试工具是由 云智易 开发的开源项目,提供功能完善的在线 MQTT 调试与测试能力,支持消息发布、订阅、连接验证等多种操作。您可以访问 https://mqtt-client.app/ 开始使用。
接入准备
创建产品,在云智易物联网平台中创建一个 产品(Product)。

定义物模型,创建产品后,您需要进入到产品管理页面定义物模型。平台提供了海量的设备物模型,您可以直接使用,或自定义物模型。

注册设备,选择MQTT直连接入方式,注册设备并获取设备凭证。

设备凭证是系统自动生成的,可以直接复制使用。
连接信息
| 参数 | 说明 | 示例 |
|---|---|---|
| Broker 地址 | MQTT 服务器地址(MQTT/MQTTS 协议与WebSocket 版本ws/wss 协议均支持) | mqtt.xlink.cn |
| ClientID | 设备认证标识,全平台通用 | X:DEVICE;A:13;V:5; |
| Username | {ProductId}#{DeviceMac} | 161ff6d801#ZNCJD001 |
| Password | Sha-256({ProductID} + {Mac} + {ProductKey}) | 690DC71B0A620948E... |
| QoS 支持 | 0 / 1 | 0 |
| KeepAlive | 心跳间隔时间(秒) | 60 |
接入配置
配置连接信息,获取MQTT服务器的连接信息,并在MQTT 调试工具中填充。


连接服务,创建连接后,点击连接,若连接信息都无误,调试工具即可连接服务器。


设备调试
- 调试配置,连接上服务后,就可以开始调试属性上报。平台默认提供
设备属性上报、设备事件上报、设备服务下发、设备服务下发响应四个Topic。 平台提供了自动生成Topic和payload功能,只需简单操作即可生成。
主题规范(Topic)
设备与平台通过 Topic 进行通信。常见的主题规范如下:
| 方向 | Topic 格式 | 说明 |
|---|---|---|
| 设备 → 平台 | $xlink/device/{product_id}/{mac}/thing/ | 设备属性上报 |
| 设备 → 平台 | $xlink/device/{product_id}/{mac}/thing/ | 设备事件上报 |
| 设备 → 平台 | $xlink/device/{product_id}/{mac}/thing/ | 设备服务下发响应 |
| 平台 → 设备 | $xlink/device/{product_id}/{mac}/thing/ | 设备服务下发 |
- 设备调试,在调试工具填入Topic和payload,点击“发布消息”按钮。若上报成功,平台调试页面能看到属性变化。


以上就是按照平台标准物模型接入设备的操作介绍,若不希望使用平台物模型,平台提供了自动以Topic和数据解析的方法以满足这种需求。
自定义Topic
当平台提供的物模型属性与您的设备不匹配,且不想自定义属性,则可以通过使用自定义Topic+数据解析功能的方式实现设备数据的上报和下发。
创建自定义Topic,平台支持创建发布、订阅、发布和订阅三种设备操作权限的自定义Topic,您可以根据自己产品的Topic规范定义个性化的Topic。

数据解析脚本,支持添加JS解析脚本,将设备自定义Topic数据转换为平台标准物模型数据,或将平台标准物模型主题数据转为设备自定义主题。


示例:JS 解析代码
javascript
// 仅自定义Topic支持数据解析
// 解析脚本生效后,物模型Topic将不可用
// 以下为脚本模版,您可以基于以下模版进行脚本编写
/**
* 将设备自定义topic数据转换为平台标准物模型数据,设备发布主题时调用,注:设备发布的自定义主题必须是设备可发布权限。
* 入参:topic string 上报消息的原始topic
* 入参:topicParams Object 主题包含的变量,如定义了主题为device/${id},那么这里会将${id}作为变量提取。
* 入参:payload byte[]数组的HEX字符串,
* 出参:返回设备协议主题数据
*/
function transformFrom(topic, topicParams, payload) {
//发布示例: { "temp": 18, "hum": 15}
//自定义解码
var payloadJson = hexToJson(payload);
var temp = payloadJson.temp;
var hum = payloadJson.hum;
return {
"topics": [{
"topic": "$xlink/device/16a8dcd14848000116a8dcd14848e201/17244517454545/thing/attribute/report", // 平台标准的设备协议主题
"payload": {
"attribute": {
"v": "2",
"extra": {
"temperature": temp,
"humidity": hum
}
}
}
}]
}
}
/**
* 将平台标准物模型主题数据转为设备自定义主题,平台控制下发时调用,注:转出的设备自定义主题必须是设备可订阅权限。
* 入参:topic string 下发报消息的原始topic
* 入参:topicParams Object 主题包含的变量,一般是平台标准物模型主题定义的变量,如${product_id},${mac}等
* 入参:payload byte[]数组的HEX字符串,
*/
function transformTo(topic, topicParams, payload) {
//自定义解码
//
var payloadJson = hexToJson(payload);
var msgId = payloadJson.msg_id;
var serviceName = topicParams.service_name;
var productId = topicParams.product_id;
var mac = topicParams.mac;
return {
"topics": [{
"topic": "down",
"format": "TEXT",
"payload": {
"mac": mac,
"serverName": serviceName,
"msgId": msgId,
"productId": productId
}
}]
}
}
function hexToJson(hexString) {
jsonString = '';
for (i = 0; i < hexString.length; i += 2) {
hex = hexString.substr(i, 2);
jsonString += String.fromCharCode(parseInt(hex, 16));
}
return JSON.parse(jsonString);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
示例中只是简单地把设备属性转为平台属性,您还可以通过解析脚本对数据进行各种运算后再转换。
批量注册设备
除上述单个设备接入的方法,平台还提供了批量注册设备的方法,通过导入设备列表csv文件实现设备的批量注册。 
使用平台激活凭证
若使用平台激活凭证激活设备,可以按照设备激活凭证生成方法,给批量生成激活凭证,并配置到设备上。
txt
// 设备激活凭证生成方法
ClientID: 客户端ID,全平台统一,`X:DEVICE;A:13;V:5;`
Username: 用户名,`{ProductId}#{DeviceMac}`
Password: 密码,`Sha-256({ProductID} + {Mac} + {ProductKey})`1
2
3
4
2
3
4
使用自定义激活凭证
若使用自定义的激活凭证激活设备,可以通过在设备列表文件中补全设备激活凭证字段即可通过自定义的激活凭证激活设备。 
设备列表文件字段解析
| 参数 | 说明 |
|---|---|
| MAC | 设备MAC地址,用作平台的设备唯一标识 |
| SN | 设备序列号,全球唯一的识别编号 |
| NAME | 设备名称,用作平台显示的设备名称 |
| MQTT_CLIENT_ID | 客户端ID,用于设备激活 |
| MQTT_USERNAME | 用户名,用于设备激活 |
| MQTT_PASSWORD | 密码,用于设备激活 |
网关代理接入
若设备无法直接接入平台,可以采用网关代理的方式接入平台。网关代理接入方式允许通过网关设备,批量上报子设备的属性和事件;网关可以是物理网关或逻辑网关,这里以第三方平台作为逻辑网关接入平台为例,一步步介绍如何接入。
创建产品
需要在物联网平台创建至少两个产品:- 一个网关类型产品,用于第三方平台作为网关设备接入,并接入第三方平台上报的数据、下发数据和解析数据;
- 其他产品用于第三方平台上报的设备数据解析到对应产品(根据设备类型数量创建对应数量的产品)
例如:
网关产品:「示例平台」,(产品ID:162428d3084303e9162428d308430001)
其他产品:「温湿度传感器」和「智能温湿度传感器」,
(产品ID:161ff6d0c69e03e9161ff6d0c69ef801/162422d305f203e9162422d305f2b201)
创建证书
创建产品后,需要创建产品证书,用于关联我们上面创建的三个产品。

创建网关设备
在网关产品「示例平台」下使用 MQTT 直连接入方式创建设备,用于接收第三方平台上报的数据。示例:
- 设备 MAC:
gw_device_001 - 设备名称:示例平台001

- 设备 MAC:
创建自定义 Topic
在网关产品「示例平台」下创建自定义 Topic,用于接收第三方平台上报的数据和下发数据。示例:
- 上报数据 Topic:
/device/up - 下发数据 Topic:
/device/down

- 上报数据 Topic:
添加解析脚本
通过解析脚本,可以把平台上报的数据解析到对应的产品下,实现平台数据的同步。这里以一个简单的第三方平台 MQTT 协议为例。
第三方平台协议示例
第三方平台上报数据 payload
javascript
{
"timestamp": 1770185731129,
"devices": [
{
"deviceId": "DEV001",
"deviceType": "TH_Sensor01",
"eventType": "attribute",
"data": {
"humidity": 40,
"temperature": 35.1
}
},
{
"deviceId": "DEV002",
"deviceType": "TH_Sensor02",
"eventType": "attribute",
"data": {
"humidity": 60,
"temperature": 23
}
},
{
"deviceId": "DEV002",
"deviceType": "TH_Sensor02",
"eventType": "event",
"data": {
"humidity_alarm": {
"value": 60,
"status": "active",
"time": 1770185721138
}
}
},
{
"deviceId": "DEV003",
"deviceType": "TH_Sensor01",
"eventType": "attribute",
"data": {
"humidity": 10,
"temperature": 25.1
}
}
]
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
第三方平台接收数据 payload
javascript
{
"timestamp": 1700000000000,
"data":
{
"deviceId": "DEV001",
"deviceType": "TH_Sensor",
"eventType": "attribute",
"data": {
"humidity": 40,
"temperature": 35.1
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
示例协议参数说明
| 项目 | 示例值 | 说明 |
|---|---|---|
| deviceId | DEV001 | 第三方平台上报的设备ID |
| deviceType | TH_Sensor01 | 第三方平台上报的设备类型 |
| eventType | attribute/event | 第三方平台上报的数据类型,包括属性上报和事件上报 |
| data | { "humidity": 40, "temperature": 35.1 } | 第三方平台上报的数据 |
示例产品数据说明
| 项目 | 示例值 | 说明 |
|---|---|---|
| 平台网关产品 ID | 162428d3084303e9162428d308430001 | 第三方平台在本平台中对应的网关产品ID |
| 网关设备 MAC | gw_device_001 | 网关设备在平台中的唯一设备标识 |
| 子产品 ID(TH_Sensor01) | 161ff6d0c69e03e9161ff6d0c69ef801 | 温湿度传感器类型 01 的产品模型 |
| 子产品 ID(TH_Sensor02) | 162422d305f203e9162422d305f2b201 | 温湿度传感器类型 02 的产品模型 |
数据上报Topic
| 项目 | 示例值 | 说明 |
|---|---|---|
| 网关设备上报Topic | /device/up | 第三方平台上报数据Topic |
| 子设备属性批量上报Topic | $xlink/gateway/{gateway_product_id}/{gateway_mac}/thing/attribute/report | 属性批量上报数据Topic |
| 子设备事件批量上报Topic | $xlink/gateway/{gateway_product_id}/{gateway_mac}/thing/event/report | 事件批量上报数据Topic |
| gateway_product_id | 162428d3084303e9162428d308430001 | 网关产品 ID |
| gateway_mac | gw_device_001 | 网关设备 Mac |
解析脚本实现
根据上面的示例数据,解析脚本如下:
javascript
/*************************************************
* 固定配置
*************************************************/
// 网关产品 & 设备
var GW_PRODUCT_ID = "162428d3084303e9162428d308430001";
var GW_DEVICE_MAC = "gw_device_001";
// 子设备产品映射
var DEVICE_TYPE_PRODUCT_MAP = {
"TH_Sensor01": "161ff6d0c69e03e9161ff6d0c69ef801",
"TH_Sensor02": "162422d305f203e9162422d305f2b201"
};
// 第三方平台 Topic
var THIRD_PARTY_UP_TOPIC = "/device/up";
var THIRD_PARTY_DOWN_TOPIC = "/device/down";
/*************************************************
* 上行解析
*************************************************/
function transformFrom(topic, topicParams, payload) {
var topics = [];
if (topic !== THIRD_PARTY_UP_TOPIC) {
return { topics: topics };
}
var msg = JSON.parse(hexToString(payload));
var timestamp = msg.timestamp;
var devices = msg.devices || [];
/******** 1. 网关自身上报(保留时间戳) ********/
topics.push({
topic: "$xlink/device/" + GW_PRODUCT_ID + "/" + GW_DEVICE_MAC + "/thing/attribute/report",
payload: {
attribute: {
v: "2",
extra: {
time: timestamp
}
}
}
});
/******** 2. 子设备拆分 ********/
for (var i = 0; i < devices.length; i++) {
var dev = devices[i];
var productId = DEVICE_TYPE_PRODUCT_MAP[dev.deviceType];
if (!productId || !dev.deviceId) {
continue;
}
// 属性
if (dev.eventType === "attribute") {
topics.push({
topic: "$xlink/device/" + productId + "/" + dev.deviceId + "/thing/attribute/report",
payload: {
state: 1, // ✅ 与 attribute 同级
attribute: {
v: "2",
extra: dev.data || {}
}
}
});
}
// 事件
if (dev.eventType === "event") {
for (var eventName in dev.data) {
topics.push({
topic: "$xlink/device/" + productId + "/" + dev.deviceId + "/thing/event/report",
payload: {
event: {
v: "2",
name: eventName,
extra: dev.data[eventName]
}
}
});
}
}
}
return { topics: topics };
}
/*************************************************
* 下行解析
*************************************************/
function transformTo(topic, topicParams, payload) {
var service = payload.service || {};
var input = service.input || {};
var deviceId = topicParams.mac;
var productId = topicParams.product_id;
var downPayload = {
timestamp: new Date().getTime(),
data: {
deviceId: deviceId,
deviceType: productId,
eventType: "attribute",
data: input
}
};
return {
topics: [
{
topic: THIRD_PARTY_DOWN_TOPIC,
format: "TEXT",
payload: downPayload
}
]
};
}
/*************************************************
* HEX → String
*************************************************/
function hexToString(hex) {
var str = '';
for (var i = 0; i < hex.length; i += 2) {
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
}
return str;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
- 测试验证
使用 MQTT 测试工具,按照上面的示例数据配置,发布的数据经过解析脚本后,最终输出到平台的数据结构如下:
javascript
{
"topics": [
/* 1️⃣ 网关属性上报 */
{
"topic": "$xlink/device/162422d305cc03e9162422d305cc8601/gw_device_001/thing/attribute/report",
"payload": {
"attribute": {
"v": "2",
"extra": {
"time": "2026-02-05 09:35:31"
}
}
}
},
/* 2️⃣ 子设备批量上线(去重) */
{
"topic": "$xlink/gateway/162422d305cc03e9162422d305cc8601/gw_device_001/thing/online",
"payload": {
"msg_id": 1,
"devices": [
{
"product_id": "161ff6d0c69e03e9161ff6d0c69ef801",
"mac": "DEV001",
"time": 1770185731129
},
{
"product_id": "162422d305f203e9162422d305f2b201",
"mac": "DEV002",
"time": 1770185731129
},
{
"product_id": "161ff6d0c69e03e9161ff6d0c69ef801",
"mac": "DEV003",
"time": 1770185731129
}
]
}
},
/* 3️⃣ DEV001 属性 */
{
"topic": "$xlink/device/161ff6d0c69e03e9161ff6d0c69ef801/DEV001/thing/attribute/report",
"payload": {
"attribute": {
"v": "2",
"extra": {
"humidity": 40,
"temperature": 35.1
}
}
}
},
/* 4️⃣ DEV002 属性 */
{
"topic": "$xlink/device/162422d305f203e9162422d305f2b201/DEV002/thing/attribute/report",
"payload": {
"attribute": {
"v": "2",
"extra": {
"humidity": 60,
"temperature": 23
}
}
}
},
/* 5️⃣ DEV002 事件(时间已转换) */
{
"topic": "$xlink/device/162422d305f203e9162422d305f2b201/DEV002/thing/event/report",
"payload": {
"event": {
"v": "2",
"name": "humidity_alarm",
"extra": {
"value": 60,
"status": "active",
"time": "2026-02-05 09:35:21"
}
}
}
},
/* 6️⃣ DEV003 属性 */
{
"topic": "$xlink/device/161ff6d0c69e03e9161ff6d0c69ef801/DEV003/thing/attribute/report",
"payload": {
"attribute": {
"v": "2",
"extra": {
"humidity": 10,
"temperature": 25.1
}
}
}
}
]
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
测试结果说明:
使用 MQTT 测试工具,连接网关设备,模拟平台发送数据。
注:用户名和密码需要按照下面表格说明生成
| 参数 | 值/生成规则 | 说明 |
|---|---|---|
| ClientID | X:DEVICE;A:14;V:5; | 客户端标识,全平台统一使用此固定值 |
| Username | {CertificateID} + # + {ProductID} + # + {Mac} | 用户名,由证书ID、产品ID和设备MAC拼接而成 |
| Password | Sha-256({CertificateID} + {ProductID} + {Mac} + 证书密钥(CertificateKey)) | 密码,使用SHA-256算法加密生成 |
| CertificateID | 69831f46e3f16c00261f1fbc | 证书ID,从平台创建的产品证书中获取(替换为实际证书ID) |
| CertificateKey | 368efa81-d595-4d3b-b2cd-9fe4eafbbc38 | 证书密钥,从平台创建的产品证书中获取(替换为实际证书密钥) |
| ProductID | 162428d3084303e9162428d308430001 | 网关产品ID,网关产品的唯一标识(替换为实际网关产品ID) |
| Mac | gw_device_001 | 网关设备MAC地址,网关设备的唯一标识(替换为实际网关设备MAC) |
按照输入内容,最终平台将:
- 更新「示例平台」产品的
time属性 - 在「温湿度传感器」和「智能温湿度传感器」产品下分别注册
DEV001、DEV002、DEV003三个设备
常见问题 FAQ
Q1:连接失败(return code 5)是什么原因? A1:一般是用户名或签名错误,请确认 username、password、clientId 输入无误。
Q2:设备掉线频繁? A2:请确保设备定期发送心跳包,或增大 keepalive 时间。

