W5500io-M模组MQTT协议连接OneNet平台 (微信小程序控制方案) _w5500 mqtt
目录
1 前言
2 项目环境
2.1 硬件环境
2.2 软件环境
3.硬件连接和方案
3.1 方案图示
3.2 W5500硬件连接
4 注册OneNet的账号以及建立物模型
4.1 创建产品
4.2 创建物模型
4.3 获取基本信息
4.4 token密钥生成
4.5 物模型Topic
5 修改代码
6 数据上报
7 命令下发
8 上位机
8.1 获取属性最新数据
8.2 下发指令设置
8.3 小程序控制演示
1 前言
MQTT是一种轻量级通信协议,基于TCP/IP,采用发布-订阅模式,广泛应用于物联网领域。
MQTT的工作原理围绕着三个核心部分:发布者(Publishers)、代理(Broker,也称服务器)和订阅者(Subscribers)。发布者负责发送消息到特定的主题(Topic),代理则接收这些消息并将其转发给所有订阅了该主题的订阅者。这种模式允许设备间异步通信,且设备不需要直接了解彼此的存在,从而降低了系统的复杂性。
W5500io-M 是炜世推出的高性能SPI转以太网模块,具有以下特点:
- 极简设计:集成MAC、PHY、32KB缓存及RJ45网口,通过4线SPI接口直连主控,3.3V供电,紧凑尺寸适配嵌入式场景 。
- 简单易用:用户无需再移植复杂的TCP/IP协议栈到MCU中,可直接基于应用层数据做开发。
- 资料丰富:提供丰富的MCU应用例程和硬件参考设计,可直接参考使用,大大缩短研发时间,硬件兼容W5100sIO-M模组,方便方案开发与迭代。
- 应用广泛:在工业控制、智能电网、充电桩、安防消防、新能源、储能等地方都有广泛应用。
产品链接:商品详情
2 项目环境
2.1 硬件环境
- W5500io-M
- STM32F103VCT6 EVB
- 网络连接线
- 杜邦线若干
- 交换机或路由器
2.2 软件环境
- OneNET物联网开放平台。
- 微信开发者平台
- 飞思创串口助手
- 例程链接:w5500.com/w5500.html
3.硬件连接和方案
3.1 方案图示
3.2 W5500硬件连接
//W5500_SCS--->STM32_GPIOD7/*W5500的片选引脚*/ //W5500_SCLK--->STM32_GPIOB13/*W5500的时钟引脚*/ //W5500_MISO--->STM32_GPIOB14/*W5500的MISO引脚*/ //W5500_MOSI--->STM32_GPIOB15/*W5500的MOSI引脚*/ //W5500_RESET--->STM32_GPIOD8/*W5500的RESET引脚*/ //W5500_INT--->STM32_GPIOD9/*W5500的INT引脚*/
4 注册OneNet的账号以及建立物模型
注册账号在这里不进行赘述,下面我们看如何建立物模型
4.1 创建产品
4.2 创建物模型
物模型的建立根据自己的需要建立
4.3 获取基本信息
注册账号以及建立物模型在此不在赘述,下面查看项目和设备的基本信息参数
获得产品ID设备名称以及密钥
1.产品ID:iP20B5FpF6
2.设备名称:d2
3.设备密钥:TFU3bT***********************=
4.4 token密钥生成
在设备与 OneNet 平台进行通信时,token 作为设备或应用程序的身份凭证。只有拥有有效 token 的设备或应用,才能被平台识别和认证,从而建立起安全的连接,确保只有授权的设备和应用可以访问平台资源。token密钥生成需要token工具,可以通过链接跳转下载OneNET - 中国移动物联网开放平台。
1.res字段:products/{产品id}/devices/{设备名},key为设备级key。将{产品id}替换成自己产品的id,{设备名}替换成自己的设备名。
2.et字段:填写访问过期的时间。可以在此网站获取时间戳(Unix timestamp)转换工具 - 在线工具。
3.key字段:填写自己的设备的密钥。
4.填写完成后点击generate即可得到token密钥
4.5 物模型Topic
1.设置直连设备属性: $sys/iP20B5FpF6/d2/thing/property/set
2.直连设备属性设置响应: $sys/iP20B5FpF6/d2/thing/property/set_reply
3.直连设备上报属性 : $sys/iP20B5FpF6/d2/thing/property/post
4.直连设备上报属性响应 :$sys/iP20B5FpF6/d2/thing/property/post/reply
5 修改代码
找到do-mqtt.c文件,把上述中的产数更换为自己OneNet的参数,这些参数我们在上面都有讲到,可以自行替换。
// 定义MQTT连接参数结构体并初始化mqttconn mqtt_params = { .mqttHostUrl = \"mqtts.heclouds.com\", // MQTT服务器的URL地址 .server_ip = {0,}, // 服务器IP地址(此处未使用,保留默认值) .port = 1883, // 连接端口号,1883为MQTT默认非加密端口 .clientid = \"d2\", // MQTT客户端ID,需保持唯一性 .username = \"iP20B5FpF6\", // MQTT用户名,通常为产品ID .passwd = \"vers=md5&sign=YT2N73HSjmyy%2BbQEFMDjMw%3D%3D\", // 用户密码,包含签名认证信息 .pubtopic = \"$sys/iP20B5FpF6/d2/thing/property/post\", // 发布属性数据的主题 .pubtopic_reply = \"$sys/iP20B5FpF6/d2/thing/property/post/reply\", // 属性数据发布响应主题 .subtopic = \"$sys/iP20B5FpF6/d2/thing/property/set\", // 订阅属性设置的主题 .subtopic_reply = \"$sys/iP20B5FpF6/d2/thing/property/set_reply\", // 属性设置响应主题 .pubQoS = QOS0, // 发布消息的服务质量等级(0:最多一次) .willtopic = \"/wizchip/will\", // 遗嘱消息主题,客户端异常断开时发布 .willQoS = QOS0, // 遗嘱消息的服务质量等级 .willmsg = \"wizchip offline!\", // 遗嘱消息内容 .subQoS = QOS0, // 订阅消息的服务质量等级};
下方代码第6行为上报到服务器物模型的数据以及标识符,标识符要与服务器物模型相同,数值为本地传感器采集到的数据,由单片机进行处理,然后把数值填写到value的后面,然后就可以把本地数据上传到服务器
case PUB_MESSAGE:{ // 准备发布的MQTT消息 pubmessage.qos = QOS0; // 设置服务质量等级为QoS0(最多一次) // 构建JSON格式的负载数据,包含温度值26 pubmessage.payload = \"{\\\"id\\\":\\\"123\\\",\\\"version\\\":\\\"1.0\\\",\\\"params\\\":{\\\"temp\\\":{\\\"value\\\":26}}}\"; pubmessage.payloadlen = strlen(pubmessage.payload); // 计算负载长度 // 发布消息到指定主题 ret = MQTTPublish(&c, (char *)&(mqtt_params.pubtopic), &pubmessage); // 检查发布结果 if (ret != SUCCESSS) { run_status = ERR; // 发布失败,设置错误状态 } else { // 发布成功,打印主题和消息内容 printf(\"publish:%s,%s\\r\\n\\r\\n\", mqtt_params.pubtopic, (char *)pubmessage.payload); run_status = KEEPALIVE; // 设置为保持连接状态 } break;}
6 数据上报
此时把代码下载进入单片机。串口显示如下,此时显示MQTT连接成功,数据上报成功,然后我们查看OneNet服务器端
服务器端显示本地上传的数据,此时本地数据就可正常上报到服务器了
7 命令下发
如果想在远端控制本地的设备需要怎么办,我们可以在单片机中加入解析json数据的代码,然后在服务器下发指令,达到相应的效果。此段代码为解析服务器解析下发的指令,可以根据服务器下发指令是开灯还是关灯来操作本地的LED,如果想在服务器操作其他本地器件,则可根据上述代码进行添加。
void json_decode(char *msg){ int ret; char replymsg[128] = {0}; // 存储响应消息的缓冲区 cJSON *id = NULL; // 消息ID节点 cJSON *jsondata = NULL; // 根JSON对象 cJSON *params = NULL; // 参数节点 cJSON *LED = NULL; // LED控制节点 // 解析JSON消息 jsondata = cJSON_Parse(msg); if (jsondata == NULL) { printf(\"json parse fail.\\r\\n\"); // 解析失败处理 return; } // 提取关键数据节点 id = cJSON_GetObjectItem(jsondata, \"id\"); // 提取消息ID params = cJSON_GetObjectItem(jsondata, \"params\"); // 提取参数部分 // 处理LED控制命令 LED = cJSON_GetObjectItem(params, \"led\"); if (LED->valueint) // 判断LED控制值(1表示关闭) { printf(\"LED OFF\\r\\n\"); // TODO: 实际硬件控制代码 - 关闭LED } else // 0表示开启 { printf(\"LED ON\\r\\n\"); // TODO: 实际硬件控制代码 - 开启LED } // 构建响应消息 pubmessage.qos = QOS0;// 设置QoS等级为0 sprintf(replymsg, \"{\\\"id\\\":\\\"%s\\\",\\\"code\\\":200,\\\"msg\\\":\\\"success\\\"}\", id->valuestring); // 构建成功响应 printf(\"reply:%s\\r\\n\", replymsg); // 打印响应内容 // 发布响应消息 pubmessage.payload = replymsg; pubmessage.payloadlen = strlen(replymsg); ret = MQTTPublish(&c, mqtt_params.subtopic_reply, &pubmessage); // 发布响应到指定主题 // 处理发布结果 if (ret != SUCCESSS) { run_status = ERR; // 发布失败设置错误状态 } else { printf(\"publish:%s,%s\\r\\n\\r\\n\", mqtt_params.subtopic_reply, (char *)pubmessage.payload); // 打印发布信息 } // 释放JSON解析资源 cJSON_Delete(jsondata);}
由此可以看到,在服务器下发指令可以被正确解析并执行,此时说明数据下发与是正确的。
8 上位机
使用服务器进行查看和下发指令可能不太方便,我们可以使用微信小程序作为上位机更加直观的观看和控制,如图所示
小程序进行获取信息和下发指令是通过微信小程序的 wx.request 方法向 OneNet 提供的 HTTP API 发送请求,获取目标设备的最新属性数据(模拟值),再通过解析收到的数据将他们渲染到页面中。我的小程序源码链接提取码:2oqz ,可导入微信开发者平台,根据代码后面的标注提示进行更改,自己也可以根据需求进行更改。
8.1 获取属性最新数据
接口功能:根据产品id和设备名,查询设备最新属性功能点数据
接口地址:https://iot-api.heclouds.com/thingmodel/query-device-property
API说明:
请求方式:GET
http query 请求参数:
参数
类型
是否必选
描述
product_id
string
是
产品 ID,平台生成唯一 ID
device_name
string
是
设备名称
返回数据:
参数名称
类型
描述
code
int
调用成功或失败时,返回的 code 码
msg
string
调用成功或失败时,返回的 msg 信息
request_id
string
调用 API 生成的请求标识
data
-
调用成功时,返回的业务数据
data.list
array
设备属性数据集合
微微信小程序向OneNET云平台发送”设备属性最新数据查询“请求。
OneNET云平台返回查询结果给微信小程序。
可以看到图中读取到led和温度的数值
8.2 下发指令设置
接口功能:根据产品ID和设备名,设置该设备的属性期望值,当设备在线后将下发该期望值到设备。
接口地址:https://iot-api.heclouds.com/thingmodel/set-device-desired-property
API说明:
请求方式:POST
http body 请求参数:
参数
类型
是否必选
描述
product_id
string
是
产品 ID,平台生成唯一 ID
device_name
string
是
设备名称
params
object
是
设置的属性期望值,数据格式为 json 对象,形式为 key-value,key 为属性功能点标识,value 为属性值,取值符合物模型定义的数据类型和取值范围,例如 {\"switch\": true}
返回数据:
参数名称
类型
描述
code
int
调用成功或失败时,返回的 code 码
msg
string
调用成功或失败时,返回的 msg 信息
request_id
string
调用 API 生成的请求标识
data
-
调用成功时,返回的业务数据
图中可以看到指令设置成功
8.3 小程序控制演示
当点击开灯时,通过下发指令的过程,单片机会执行开灯的操作,并在串口打印出来。
当点击关灯时,通过下发指令,单片机会执行关灯的操作,并在串口打印出来。
我们再看一下信息获取展示。我进行手动修改温度来表示温度变化,在第6行value后进行修改
case PUB_MESSAGE:{ // 准备发布的MQTT消息 pubmessage.qos = QOS0; // 设置服务质量等级为QoS0(最多一次) // 构建JSON格式的负载数据,包含温度值26 pubmessage.payload = \"{\\\"id\\\":\\\"123\\\",\\\"version\\\":\\\"1.0\\\",\\\"params\\\":{\\\"temp\\\":{\\\"value\\\":30}}}\"; pubmessage.payloadlen = strlen(pubmessage.payload); // 计算负载长度 // 发布消息到指定主题 ret = MQTTPublish(&c, (char *)&(mqtt_params.pubtopic), &pubmessage); // 检查发布结果 if (ret != SUCCESSS) { run_status = ERR; // 发布失败,设置错误状态 } else { // 发布成功,打印主题和消息内容 printf(\"publish:%s,%s\\r\\n\\r\\n\", mqtt_params.pubtopic, (char *)pubmessage.payload); run_status = KEEPALIVE; // 设置为保持连接状态 } break;}
此时我们查看小程序上面的温度也发生了变化,功能完好
感谢您的观看,如您对本文有不清楚的地方或想了解更多产品信息的,欢迎私信或在评论区留言,我们会及时回复您!