RT-Thread物联网实战 --- MQTT + cJSON + OneNET云平台
前言
设备联网之后,如何将数据上传到云平台并实现远程监控?本文将串联MQTT协议、Paho MQTT库、cJSON数据解析以及OneNET云平台,构建完整的物联网数据链路:传感器 → MCU → ESP8266 → MQTT → OneNET云平台。
一、MQTT 协议
1.1 什么是MQTT?
MQTT(Message Queuing Telemetry Transport)是一种发布/订阅模式的轻量级消息传输协议,专为低带宽、不稳定网络和低功耗场景设计,是物联网通信的首选协议。
1.2 核心角色
| 角色 | 说明 | 比喻 |
|---|---|---|
| 发布者(Publisher) | 发送数据的设备 | 投稿人 |
| 订阅者(Subscriber) | 接收数据的设备 | 读者 |
| 代理(Broker) | 消息路由中心 | 报社编辑部 |
| 主题(Topic) | 消息分类标签 | 报纸栏目 |
发布者和订阅者不直接通信,而是通过Broker中转,实现松耦合。
1.3 工作流程
- 设备连接Broker:通过TCP长连接,使用唯一的客户端ID注册。
- 发布者发布消息 :指定主题发送数据,如
/home/livingroom/temperature→25°C。 - Broker转发消息:找到所有订阅该主题的客户端,逐一推送。
- 订阅者接收消息:处理接收到的数据。
1.4 主题通配符
- 单层通配符
+:/home/+/temperature匹配所有房间的温度 - 多层通配符
#:/home/#匹配家中所有传感器数据
1.5 QoS 消息质量
| QoS级别 | 保证 | 适用场景 |
|---|---|---|
| QoS 0 | 至多一次,可能丢失 | 温度数据等非关键信息 |
| QoS 1 | 至少一次,可能重复 | 开关控制指令 |
| QoS 2 | 恰好一次,不丢不重 | 报警状态等关键信息 |
1.6 保留消息与遗嘱消息
- 保留消息:Broker保存主题的最新消息,新订阅者加入时立即推送,适合状态同步。
- 遗嘱消息:客户端连接时预设,意外断开时Broker自动发布,适合故障通知。
二、Paho MQTT 库
Paho MQTT 是RT-Thread中常用的MQTT客户端库,提供完整的连接、订阅、发布功能。
2.1 订阅列表配置
c
MQTTClient client;
client.messageHandlers[0].topicFilter = "/device/data";
client.messageHandlers[0].callback = mqtt_sub_callback;
client.messageHandlers[0].qos = QOS1;
2.2 回调函数
| 回调 | 触发时机 |
|---|---|
connect_callback |
MQTT连接成功 |
online_callback |
客户端上线 |
offline_callback |
客户端掉线 |
defaultMessageHandler |
默认消息接收 |
messageHandlers[x].callback |
指定主题消息接收 |
2.3 URI 格式
tcp://iot.eclipse.org:1883 // 域名
tcp://192.168.10.1:1883 // IPv4
ssl://192.168.10.1:1884 // SSL加密
tcp://[fe80::20c:29ff:...]:1883 // IPv6
2.4 核心API
| API | 说明 |
|---|---|
paho_mqtt_start(client) |
启动MQTT客户端 |
paho_mqtt_stop(client) |
停止MQTT客户端 |
paho_mqtt_subscribe(client, qos, topic, cb) |
订阅主题 |
paho_mqtt_unsubscribe(client, topic) |
取消订阅 |
paho_mqtt_publish(client, qos, topic, msg) |
发布消息 |
paho_mqtt_control(client, cmd, arg) |
控制客户端参数 |
控制命令:
| 命令 | 功能 |
|---|---|
MQTT_CTRL_SET_CONN_TIMEO |
设置连接超时时间 |
MQTT_CTRL_SET_RECONN_INTERVAL |
设置重连间隔 |
MQTT_CTRL_SET_KEEPALIVE_INTERVAL |
设置心跳间隔 |
MQTT_CTRL_PUBLISH_BLOCK |
设置发布阻塞/非阻塞模式 |
三、cJSON 库
cJSON是轻量级JSON解析/生成库,物联网中用于构建上传数据和解析下发命令。
3.1 核心数据结构
c
typedef struct cJSON {
struct cJSON *next, *prev; // 链表指针
struct cJSON *child; // 子节点(对象/数组)
int type; // 节点类型
char *valuestring; // 字符串值
int valueint; // 整数值
double valuedouble; // 浮点值
char *string; // 键名
} cJSON;
支持的类型:cJSON_False、cJSON_True、cJSON_NULL、cJSON_Number、cJSON_String、cJSON_Array、cJSON_Object
3.2 解析 JSON
c
/* 解析JSON字符串 */
const char *json_str = "{\"temperature\":25,\"humidity\":60}";
cJSON *root = cJSON_Parse(json_str);
/* 获取字段值 */
cJSON *temp = cJSON_GetObjectItem(root, "temperature");
if (cJSON_IsNumber(temp))
{
rt_kprintf("温度: %d\n", temp->valueint);
}
/* 释放内存 */
cJSON_Delete(root);
3.3 构建 JSON
c
/* 创建JSON对象 */
cJSON *root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "temperature", 25);
cJSON_AddStringToObject(root, "status", "normal");
/* 转为字符串 */
char *json_str = cJSON_PrintUnformatted(root);
rt_kprintf("JSON: %s\n", json_str); // {"temperature":25,"status":"normal"}
/* 释放 */
cJSON_free(json_str);
cJSON_Delete(root);
3.4 常用API速查
| 操作 | API |
|---|---|
| 解析JSON | cJSON_Parse(str) |
| 创建对象 | cJSON_CreateObject() |
| 创建数组 | cJSON_CreateArray() |
| 添加数字 | cJSON_AddNumberToObject(obj, key, num) |
| 添加字符串 | cJSON_AddStringToObject(obj, key, str) |
| 添加子对象 | cJSON_AddItemToObject(obj, key, item) |
| 获取字段 | cJSON_GetObjectItem(obj, key) |
| 获取数组元素 | cJSON_GetArrayItem(arr, index) |
| 转为字符串 | cJSON_Print(obj) / cJSON_PrintUnformatted(obj) |
| 释放对象 | cJSON_Delete(obj) |
| 类型检查 | cJSON_IsNumber() / cJSON_IsString() 等 |
3.5 RT-Thread 内存适配
c
cJSON_Hooks hooks;
hooks.malloc_fn = rt_malloc;
hooks.free_fn = rt_free;
cJSON_InitHooks(&hooks);
四、OneNET 云平台
OneNET是中国移动推出的物联网开放平台,支持设备接入、数据存储、可视化展示和远程控制。
4.1 工作原理
OneNET软件包基于MQTT和HTTP Client实现:
-
数据上传:通过MQTT向特定topic发布消息
-
命令下发:Broker将服务器命令推送给设备
-
数据查询:通过HTTP GET/POST请求获取历史数据
┌─────────┐ MQTT ┌──────────┐ HTTP ┌──────────┐
│ 设备 │ ─────────→ │ OneNET │ ←─────────→ │ 网页/APP │
│ (MCU) │ ←───────── │ Broker │ │ (用户) │
└─────────┘ 命令下发 └──────────┘ 数据查询 └──────────┘
4.2 依赖库
| 库 | 用途 |
|---|---|
| cJSON | 构建/解析JSON数据 |
| Paho MQTT | MQTT连接、发布、订阅 |
| HTTP Client | 数据查询、设备注册 |
4.3 初始化
c
int onenet_mqtt_init(void);
内部流程:
- 设置MQTT参数(URI、设备ID、用户名、密码)
- 注册回调函数(连接/上线/掉线/消息接收)
- 启动MQTT客户端
c
/* 核心初始化逻辑 */
mq_client.uri = "tcp://183.230.40.96:1883";
mq_client.condata.clientID.cstring = device_id;
mq_client.condata.username.cstring = product_id;
mq_client.condata.password.cstring = auth_info;
mq_client.defaultMessageHandler = mqtt_callback;
paho_mqtt_start(&mq_client);
4.4 数据上传API
上传数字数据
c
rt_err_t onenet_mqtt_upload_digit(const char *ds_name, const double digit);
c
/* 上传温度数据到 "temperature" 数据流 */
onenet_mqtt_upload_digit("temperature", 25.5);
上传字符串数据
c
rt_err_t onenet_mqtt_upload_string(const char *ds_name, const char *str);
c
/* 上传设备状态 */
onenet_mqtt_upload_string("status", "running");
上传二进制数据
c
rt_err_t onenet_mqtt_upload_bin(const char *ds_name, const uint8_t *bin, size_t len);
从文件路径上传
c
rt_err_t onenet_mqtt_upload_bin_by_path(const char *ds_name, const char *bin_path);
向指定主题发布
c
rt_err_t onenet_mqtt_publish(const char *topic, const uint8_t *msg, size_t len);
4.5 命令接收与响应
设置命令响应回调,当云端下发命令时自动调用:
c
void cmd_response(uint8_t *recv_data, size_t recv_size,
uint8_t **resp_data, size_t *resp_size)
{
rt_kprintf("收到命令: %.*s\n", recv_size, recv_data);
/* 构建响应 */
*resp_data = (uint8_t *)"OK";
*resp_size = 2;
}
/* 注册回调 */
onenet_set_cmd_rsp_cb(cmd_response);
4.6 数据查询API(HTTP)
| API | 说明 |
|---|---|
onenet_http_get_datastream(name, info) |
获取数据流信息 |
onenet_get_dp_by_limit(name, n) |
获取最近N个数据点 |
onenet_get_dp_by_start_end(name, start, end, n) |
获取指定时间段数据点 |
4.7 设备管理API
| API | 说明 |
|---|---|
onenet_http_register_device(name, auth) |
注册新设备 |
onenet_port_save_device_info(id, key) |
保存设备信息(需用户实现) |
onenet_port_get_register_info(name, auth) |
获取注册信息(需用户实现) |
onenet_port_get_device_info(id, key, auth) |
获取设备信息(需用户实现) |
onenet_port_is_registed() |
查询设备是否已注册 |
五、完整物联网数据链路
将前面所有知识串联起来,一个完整的物联网项目数据流如下:
┌─────────┐ GPIO ┌──────────┐ UART+AT ┌──────────┐
│ DHT11 │ ──────────→ │ STM32 │ ──────────→ │ ESP8266 │
│ 传感器 │ 温湿度数据 │ RT-Thread│ AT命令控制 │ WiFi模块 │
└─────────┘ └──────────┘ └──────────┘
│ │
cJSON构建数据 MQTT发布
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ OneNET │ ←────────── │ MQTT │
│ 云平台 │ 数据入库 │ Broker │
└──────────┘ └──────────┘
│
网页/APP展示
关键技术栈对应:
| 环节 | 技术 | RT-Thread组件 |
|---|---|---|
| 数据采集 | GPIO/传感器框架 | PIN设备、传感器框架 |
| 设备联网 | AT命令 + WiFi | AT组件、ESP8266库 |
| 数据格式化 | JSON | cJSON库 |
| 数据传输 | MQTT协议 | Paho MQTT库 |
| 云端对接 | OneNET API | OneNET软件包 |
总结
| 要点 | 内容 |
|---|---|
| MQTT协议 | 发布/订阅模式,轻量高效,支持QoS |
| Paho MQTT | RT-Thread的MQTT客户端库 |
| cJSON | 轻量级JSON解析/生成,物联网数据格式标准 |
| OneNET | 中国移动物联网平台,支持MQTT+HTTP |
| 数据链路 | 传感器 → MCU → WiFi → MQTT → 云平台 → 用户 |