Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
MQTT
国民技术_N32G45x
【N32G457】基于RT-Thread和N32G457的智能家居demo
发布于 2022-03-16 11:16:13 浏览:1642
订阅该版
文章目录 [toc] ----------- # 1 摘要 本文使用 N32G457 开发板,移植 RT-Thread 操作系统,增加 ESP8266 WIFI 模块模拟了一个小型的智能家居项目,通过 WIFI 模块将数据上云,然后使用腾讯连连小程序做用户层的开发,显示开发板上传的数据,同时可以通过腾讯连连小程序反向控制开发板上的硬件。 用到的主要技术又:RTT操作系统;AT组件;ESP8266 WIFI模块;MQTT移植;cJSON;腾讯连连 项目的代码地址为:[https://gitee.com/robot266/n32g457_esp8266](https://gitee.com/robot266/n32g457_esp8266) 该项目的整体架构如下图所示。 ![N32架构.png](https://oss-club.rt-thread.org/uploads/20220316/554de9da3f3fca3d1fcc267b540c20bc.png) # 2 硬件介绍 项目使用的 WIIFI 模块为 ESP8266,实物如下图所示。 ![image.png](https://oss-club.rt-thread.org/uploads/20220316/5da236d4cc3a99a78a7c87fecfe63afe.png.webp) ESP8266 和 N32G457 开发板通过串口2 (UART2_TX <-> PA2; UART2_RX <-> PA3) 进行通讯,硬件连接如下图所示(电源为3.3V)。 ![image.png](https://oss-club.rt-thread.org/uploads/20220316/7ddbb5f5f2e95273b00f2cdf6d352e76.png.webp) # 3 软件开发过程 本次开发使用 RT-Thread Studio 仅从代码的开发和调试,代码的整体架构如下图所示,其中 applications 目录下为用户编写的代码,将不同模块的驱动代码分成不同的源文件和头文件进行编写。 ![代码.png](https://oss-club.rt-thread.org/uploads/20220316/e1f9fdfd5c0109804e34d300946220b3.png) ## 3.1 基础工程的创建 基础工程的创建参考 RTT 论坛中的文章进行创建 [【N32G457】使用rtt studio开发n32g45x](https://club.rt-thread.org/ask/article/3274.html) 。基础工程包含了下载功能,调试功能,串口日志输出功能(115200 8n1) 和 LED闪烁功能。 ## 3.2 软件包的添加 本项目中用到了 AT组件,MQTT组件和 cJSON 组件,软件包的添加过程如下。 ### 3.2.1 AT组件 使用 ENV 配置工具添加组件,配置选项如下 ``` → RT-Thread online packages → IoT - internet of things →AT DEVICE: RT-Thread AT component porting or samples for different device → Espressif ESP8266 ``` ![image.png](https://oss-club.rt-thread.org/uploads/20220316/78ca0ec7afe819d991d78d9f4c5cfd5f.png) ### 3.2.2 MQTT组件 本次使用的是 Paho MQTT 组件,组件的添加步骤为 ``` → RT-Thread online packages → IoT - internet of things → Paho MQTT: Eclipse Paho MQTT C/C++ client for Embedded platforms ``` ![image.png](https://oss-club.rt-thread.org/uploads/20220316/4d86d814a2ad60d35c63eb5f5aa245c5.png) ### 3.2.3 cJSON 组件 在解析 MQTT 腾讯云服务器的下发消息时需要解析 json 数据,本次项目添加的 cJSON 组件如下所示。 ``` → RT-Thread online packages → IoT - internet of things → cJSON: Ultralightweight JSON parser in ANSI C ``` ![image.png](https://oss-club.rt-thread.org/uploads/20220316/8937df76c8fd64855da7e2a9f8dd8ecd.png) ## 3.3 代码展示 作为本项目的核心,在此只展示 mqtt 部分的相关代码,mqtt 部分创建了一个线程来进行 mqtt 的初始化和连接,以及定时的额发布消息功能,具体代码如下所示。 ```c #include
#include
#include
#include
#include "rtdevice.h" #define DBG_TAG "mqtt_task.c" #define DBG_LVL DBG_LOG #include
#include "paho_mqtt.h" #include "n32_esp8266.h" #include "json_parse.h" #include "led.h" #include "cJSON.h" #include "cJSON_util.h" /** * MQTT URI farmat: * domain mode * tcp://iot.eclipse.org:1883 * * ipv4 mode * tcp://192.168.10.1:1883 * ssl://192.168.10.1:1884 * * ipv6 mode * tcp://[fe80::20c:29ff:fe9a:a07e]:1883 * ssl://[fe80::20c:29ff:fe9a:a07e]:1884 */ #define MQTT_URI "tcp://T0FR66L94D.iotcloud.tencentdevices.com:1883" #define MQTT_CLIENT_ID "T0FR66L94Dn32_esp8266" #define MQTT_USERNAME "T0FR66L94Dn32_esp8266;12010126;AVBVT;1647450202" #define MQTT_PASSWORD "68dab4c81b227f841ef86b6223711975106a4a4cfe6556f77504b606430eeae0;hmacsha256" #define MQTT_SUBTOPIC "$thing/down/property/T0FR66L94D/n32_esp8266" #define MQTT_PUBTOPIC "$thing/up/property/T0FR66L94D/n32_esp8266" #define MQTT_WILLMSG "Goodbye!" /* define MQTT client context */ static MQTTClient client; static int is_started = 0; /** * @brief MQTT 订阅回调函数 * @param c 客户端标识 * @param msg_data 收到的数据 * @return 无 */ static void n32_mqtt_sub_callback(MQTTClient *c, MessageData *msg_data) { *((char *) msg_data->message->payload + msg_data->message->payloadlen) = '\0'; LOG_D("mqtt sub callback: %.*s", //msg_data->topicName->lenstring.len, //msg_data->topicName->lenstring.data, msg_data->message->payloadlen, (char * )msg_data->message->payload); parse_msg(msg_data->message->payloadlen, (char *) msg_data->message->payload); // 解析收到的数据 } /** * @brief MQTT 默认的订阅回调函数 * @param c 客户端标识 * @param msg_data 收到的数据 * @return 无 */ static void n32_mqtt_sub_default_callback(MQTTClient *c, MessageData *msg_data) { *((char *) msg_data->message->payload + msg_data->message->payloadlen) = '\0'; LOG_D("mqtt sub default callback: %.*s %.*s", msg_data->topicName->lenstring.len, msg_data->topicName->lenstring.data, msg_data->message->payloadlen, (char * )msg_data->message->payload); } /** * @brief MQTT 连接的回调函数 * @param c 客户端标识 * @return 无 */ static void n32_mqtt_connect_callback(MQTTClient *c) { LOG_D("enter mqtt_connect_callback!"); } /** * @brief MQTT 上线的回调函数 * @param c 客户端标识 * @return 无 */ static void n32_mqtt_online_callback(MQTTClient *c) { LOG_D("enter mqtt_online_callback!"); } /** * @brief MQTT 掉线的回调函数 * @param c 客户端标识 * @return 无 */ static void n32_mqtt_offline_callback(MQTTClient *c) { LOG_D("enter mqtt_offline_callback!"); } /** * @brief MQTT 启动 * @param 无 * @return 成功返回0,失败返回-1 */ int n32_mqtt_start(void) { /* init condata param by using MQTTPacket_connectData_initializer */ MQTTPacket_connectData condata = MQTTPacket_connectData_initializer; static char cid[20] = { 0 }; if (is_started) { LOG_E("mqtt client is already connected."); return -1; } /* config MQTT context param */ { client.isconnected = 0; client.uri = MQTT_URI; /* generate the random client ID */ rt_snprintf(cid, sizeof(cid), "rtthread%d", rt_tick_get()); /* config connect param */ memcpy(&client.condata, &condata, sizeof(condata)); client.condata.clientID.cstring = MQTT_CLIENT_ID; client.condata.keepAliveInterval = 30; client.condata.cleansession = 1; client.condata.username.cstring = MQTT_USERNAME; client.condata.password.cstring = MQTT_PASSWORD; /* config MQTT will param. */ client.condata.willFlag = 1; client.condata.will.qos = 1; client.condata.will.retained = 0; client.condata.will.topicName.cstring = MQTT_PUBTOPIC; client.condata.will.message.cstring = MQTT_WILLMSG; /* malloc buffer. */ client.buf_size = client.readbuf_size = 1024; client.buf = rt_calloc(1, client.buf_size); client.readbuf = rt_calloc(1, client.readbuf_size); if (!(client.buf && client.readbuf)) { LOG_E("no memory for MQTT client buffer!"); return -1; } /* set event callback function */ client.connect_callback = n32_mqtt_connect_callback; client.online_callback = n32_mqtt_online_callback; client.offline_callback = n32_mqtt_offline_callback; /* set subscribe table and event callback */ client.messageHandlers[0].topicFilter = rt_strdup(MQTT_SUBTOPIC); client.messageHandlers[0].callback = n32_mqtt_sub_callback; client.messageHandlers[0].qos = QOS1; /* set default subscribe event callback */ client.defaultMessageHandler = n32_mqtt_sub_default_callback; } /* run mqtt client */ paho_mqtt_start(&client); is_started = 1; return 0; } /** * @brief MQTT 停止 * @param 无 * @return 成功返回0,失败返回-1 */ int n32_mqtt_stop(void) { if (is_started == 1) { is_started = 0; return paho_mqtt_stop(&client); } } /** * @brief MQTT 发布消息 * @param send_buff 要发布的消息的内容 * @return 成功返回0,失败返回-1 */ int n32_mqtt_publish(char *send_buff) { if (is_started == 0) { LOG_E("mqtt client is not connected."); return -1; } paho_mqtt_publish(&client, QOS1, MQTT_PUBTOPIC, send_buff); return 0; } /** * @brief MQTT 新订阅的回调函数 * @param client 客户端标识 * @param msg_data 收到的数据 * @return 无 */ void n32_mqtt_new_sub_callback(MQTTClient *client, MessageData *msg_data) { *((char *) msg_data->message->payload + msg_data->message->payloadlen) = '\0'; LOG_D("mqtt new subscribe callback: %.*s %.*s", msg_data->topicName->lenstring.len, msg_data->topicName->lenstring.data, msg_data->message->payloadlen, (char * )msg_data->message->payload); } /** * @brief MQTT 订阅 * @param topic 要订阅的主题的名字 * @return 成功返回0,失败返回-1 */ int n32_mqtt_subscribe(char *topic) { if (is_started == 0) { LOG_E("mqtt client is not connected."); return -1; } return paho_mqtt_subscribe(&client, QOS1, topic, n32_mqtt_new_sub_callback); } /** * @brief MQTT 取消订阅 * @param topic 要取消订阅的主题的名字 * @return 成功返回0,失败返回-1 */ int n32_mqtt_unsubscribe(char *topic) { if (is_started == 0) { LOG_E("mqtt client is not connected."); return -1; } return paho_mqtt_unsubscribe(&client, topic); } /* * json数据格式 * { * "method":"report", // report 表示设备属性上报 * "clientToken":"123", // 用于上下行消息配对标识 * "timestamp":1628646783, // 属性上报的时间,格式为 UNIX 系统时间戳,不填写该字段表示默认为当前系统时间。单位为毫秒 * "params":{ // JSON 结构内为设备上报的属性值 * "led":1, * "led2":1, * "temp":23, * "humi",34 * } * } */ /** * @brief MQTT 处理线程 * @param parameter 线程的入参 * @return 无 */ void mqtt_thread_entry(void *parameter) { while (1) { if (get_esp8266_link_status() == 0) // 等到 ESP8266 连接成功后才能连接腾讯云 { break; } else { rt_thread_mdelay(1000); } } n32_mqtt_start(); // 启动mqtt,连接服务器 cJSON *root = NULL; cJSON *params = NULL; char *send_str = NULL; while (1) { rt_thread_mdelay(5000); // publish 间隔 root = cJSON_CreateObject(); /* 创建一个cJSON对象,要用 cJSON_Delete 释放内存 */ if (root != NULL) { cJSON_AddStringToObject(root, "method", "report"); cJSON_AddStringToObject(root, "clientToken", "123"); params = cJSON_CreateObject(); /* 创建子对象 */ if (params != NULL) { cJSON_AddItemToObject(root, "params", params); cJSON_AddNumberToObject(params, "led1", get_led1_status()); // 添加 LED1 状态 cJSON_AddNumberToObject(params, "led2", get_led2_status()); cJSON_AddNumberToObject(params, "temp", rand() % 40); // 模拟传感器数据 cJSON_AddNumberToObject(params, "humi", rand() % 70); send_str = cJSON_Print(root); if (send_str != NULL) { LOG_D("send msg: %s\n", send_str); n32_mqtt_publish(send_str); } } } if (send_str != NULL) // 释放空间 { cJSON_free(send_str); send_str = NULL; } if (root != NULL) { cJSON_Delete(root); // 防止内存泄露,会把下面所有的子节点都释放 } } } /** * @brief 启动 MQTT 处理线程 * @param 无 * @return 无 */ int start_mqtt_thread(void) { /* 创建 MTQTT 处理线程 */ rt_thread_t thread = rt_thread_create("mqtt_thread", mqtt_thread_entry, RT_NULL, 2048, 10, 20); if (thread != RT_NULL) { rt_thread_startup(thread); // 创建成功则启动线程 } else { LOG_E("create mqtt thread failed"); return (-RT_ERROR); } return RT_EOK; } ``` # 4 腾讯云物联网开发平台的使用 ## 4.1 腾讯云物联网开发平台的使用 腾讯云物联网开发平台作为本项目的云平台进行数据的转发。MQTT 三元组信息以及服务器的IP参数的构建参考腾讯云文章 [MQTT.fx 快速接入指引](https://cloud.tencent.com/document/product/1081/46507 "MQTT.fx 快速接入指引") 和 [智能灯接入指引](https://cloud.tencent.com/document/product/1081/41155)。订阅和发布消息的数据帧格式参考腾讯云文章 [物模型协议](https://cloud.tencent.com/document/product/1081/34916)。创建好的设备和物模型页面如下图所示。 ![腾讯云1.png](https://oss-club.rt-thread.org/uploads/20220316/04f36f399a4bf9cc8344ebf24f5acd24.png) ## 4.2 腾讯连连的使用 腾讯连连的无代码开发参考腾讯云文章 [交互开发](https://cloud.tencent.com/document/product/1081/40457)。创建好的腾讯连连小程序页面如下图所示。 ![腾讯云2.png](https://oss-club.rt-thread.org/uploads/20220316/0b526f82a2acc5176f8067709975fb56.png.webp) # 5 实验结果 ## 5.1 消息发布实验结果 查看开发板上电后的日志输出,日志如下图所示,可以看到首先显示 ESP8266 连接 WIFI 成功,然后连接 MQTT 服务器,最后发布了一条消息。 ![image.png](https://oss-club.rt-thread.org/uploads/20220316/d29aa3cb05f13cd3c9e93f1eded5ecef.png.webp) 发布消息成功后,查看腾讯连连小程序界面,可以看到小程序界面的数值已经更新,如下图所示。 ![image.png](https://oss-club.rt-thread.org/uploads/20220316/a85e00407bc29cc162a62d4936d85b04.png.webp) ## 5.2 消息订阅实验结果 在腾讯连连界面不断的调整 LED灯 的按钮,可以看到开发板收到了服务器转发的 MQTT 消息,并且板子上的灯随着小程序的额开关也执行相应的动作,日志如下图所示,证明了小程序控制消息下发并解析成功。 ![image.png](https://oss-club.rt-thread.org/uploads/20220316/b7591f8fecaee280211fdb6e9ad208b2.png.webp) # 6 开发中遇到的问题 开发中遇到 ESP8266 固件比较老旧的问题,错误提示如下。参考 [ESP8266-01S不支持AT+CIPDNS_CUR?](https://club.rt-thread.org/ask/question/430058.html) 和 [ESP8266 固件升级办法](https://www.icode9.com/content-4-633075.html) 得以解决。 ``` [E/at.clnt] execute command (AT+CIPDNS_CUR?) failed! [W/at.dev.esp] please check and update esp0 device firmware to support the "AT+CIPDNS_CUR?" cmd. ``` # 7 开发感想 本项目基于 RT-Thread 和 N32G457 开发板开发了一个智能家居的小 demo,完成了感知层,传输层和显示层等多维度的开发,作为一个物联网和 DIY 的小项目,虽然项目小巧,但是也能体现出物联网开发的整个步骤,在后期的开发中将更多的优化腾讯连连小程序的显示界面,增加更多传感器数据的获取和上报,完成更加智能的物联网设备。 在此非常感谢 RT-Thread 官方和国民技术对本次大赛的支持❤️❤️❤️,让大家能够免费获取开发板并得以开发,在开发过程中受益于 RT-Thread 强大的组件的支持,省去了很多的组件的移植时间,非常感谢 RT-Thread 操作系统的开源和 RT-Thread 论坛对开发者的支持❤️❤️❤️。 本项目仍有一些待完善的地方,欢迎各位开发者和 DIY 爱好者下载本项目的源码进行实验,欢迎大家一起讨论使用过程中遇到的问题,一起学习交流💪。
5
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
crystal266
嵌入式
文章
14
回答
547
被采纳
161
关注TA
发私信
相关文章
1
umqtt 软件包使用后,连接上emqx服务器,过一会儿就掉线了
2
使用正点原子的 潘多拉 开发板 的例程19_iot_mqtt
3
mqtt软件包,不支持直接关闭?
4
kawaii_mqtt 申请内存崩溃
5
_signal_entry() 函数中dbg_enter在哪里定义呢?
6
start to connect mqtt server 失败
7
MQTT 在“ read 0:1, break “后断开重连
8
paho_mqtt线程相关疑问
9
RT thread studio kawaii mqtt 无法连接EMQ
10
调试bc26 ,断言错误failed at rt_thread_timeout
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
MicroPython
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
15
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
RTT_逍遥
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部