(七)RT-Thread物联网实战--MQTT-cJSON-OneNET

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 工作流程

  1. 设备连接Broker:通过TCP长连接,使用唯一的客户端ID注册。
  2. 发布者发布消息 :指定主题发送数据,如 /home/livingroom/temperature25°C
  3. Broker转发消息:找到所有订阅该主题的客户端,逐一推送。
  4. 订阅者接收消息:处理接收到的数据。

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_FalsecJSON_TruecJSON_NULLcJSON_NumbercJSON_StringcJSON_ArraycJSON_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);

内部流程:

  1. 设置MQTT参数(URI、设备ID、用户名、密码)
  2. 注册回调函数(连接/上线/掉线/消息接收)
  3. 启动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 → 云平台 → 用户
相关推荐
2501_943695332 小时前
2026高职物联网专业发展前景好吗?
物联网
爱编码的小八嘎2 小时前
C语言完美演绎3-9
c语言
普中科技2 小时前
【普中STM32F1xx开发攻略--标准库版】-- 第 34 章 RTC 实时时钟实验
stm32·单片机·嵌入式硬件·开发板·rtc·实时时钟·普中科技
weixin_649555672 小时前
C语言程序设计第四版(何钦铭、颜晖)第七章之利用数组求矩阵各行元素之和并输出
c语言·算法·矩阵
智者知已应修善业2 小时前
【输入矩阵将其按副对角线交换后输出】2024-11-27
c语言·c++·经验分享·笔记·线性代数·算法·矩阵
我在人间贩卖青春2 小时前
NVIC相关寄存器
单片机·嵌入式硬件·中断·nvic
Silicore_Emma2 小时前
芯谷科技—79MXX系列三端负电压稳压器
单片机·运算放大器·线性稳压器·消费电子·芯谷科技·通讯设备系统·便携式车载音响
玩转单片机与嵌入式2 小时前
Keil 最反人类的设计是什么?答:加文件!(附一键添加工具)
单片机
易水寒陈2 小时前
单片机的工厂模式
单片机