宇岚 发表于 2025-7-16 10:50

物联网,启动!基于OneNET平台实现物联网功能

本帖最后由 宇岚 于 2025-7-17 14:51 编辑

#申请原创# #技术资源#

背景
随着时代的发展,“智慧生活”一词逐渐被频繁提及;智慧生活平台是依托云计算技术的存储,在家庭场景功能融合、增值服务挖掘的指导思想下,采用主流的互联网通信渠道,配合丰富的智能家居产品终端,构建享受智能家居控制系统带来的新的生活方式,简单来讲,就是利用物联网实现嵌入式设备自动化;简介物联网(Internet of Things,简称 IoT),是通过传感器、通信技术、计算设备等将物理世界中的物体连接到互联网,实现物与物、物与人之间的数据交互和智能控制的系统。而OneNET是由中国移动打造的PaaS物联网开放平台。平台能够帮助开发者轻松实现设备接入与设备连接,实现方法简单,功能多样,最重要的是,基础功能免费!实现原理IoT平台主要通信方式为MQTT协议,MQTT协议中主要参与者有三位,发布者(Publisher)、服务器(Broker)以及订阅者(Subscriber),消息结构则是分为主体(Topic)和负载(Payload)两部分;MQTT协议运行工作,简单来讲,就是发布者凭借服务器在平台发布作品,订阅者在平台订阅作品;协议结构MQTT协议中主要参与者有三位,发布者(Publisher)、服务器(Broker)以及订阅者(Subscriber),消息结构则是分为主体(Topic)和负载(Payload)两部分;Broker(代理服务器):MQTT 系统中负责接收和分发消息的服务器,是 MQTT 系统的核心组件。Publisher(发布者):向 Broker 发布消息的客户端,可以选择一个或多个主题进行消息发布。Subscriber(订阅者):订阅感兴趣的主题,并接收相关消息的客户端。Topic(主题):用来标识消息的分类和结构。Publisher 将消息发布到特定的主题上,Subscriber 订阅特定的主题以接收相关消息。Payload(负载):消息订阅者所具体接收的内容。
协议通信过程MQTT协议通信过程如下:
[*]客户端连接:Publisher 或 Subscriber 通过 TCP/IP 连接到 Broker。
[*]客户端注册:客户端发送 CONNECT 报文到 Broker,包含客户端的身份认证信息、协议版本号等。
[*]会话建立:Broker 接收到 CONNECT 报文后,根据客户端的身份认证信息进行验证,并为客户端创建对应的会话。
[*]主题订阅:Subscriber 发送 SUBSCRIBE 报文到 Broker,指定订阅的主题。
[*]订阅确认:Broker 收到 SUBSCRIBE 报文后,在订阅列表中将 Subscriber 加入,并返回 SUBACK 报文给 Subscriber。
[*]消息发布:Publisher 发送 PUBLISH 报文到 Broker,包含消息的主题和内容。
[*]消息分发:Broker 收到 PUBLISH 报文后,根据主题将消息分发给订阅了该主题的所有 Subscriber。
[*]消息传递:Subscriber 收到经过分发的消息后,进行相应的处理。
[*]客户端断开:客户端发送 DISCONNECT 报文到 Broker,表明断开连接。

其中,MQTT定义了三种消息质量等级,用于确保消息的可靠传递:
第一种消息格式为:最多一次(At Most Once):消息发布后,不进行任何确认和重传机制,消息可能会丢失或重复;
第二种消息格式为:至少一次(At Least Once):消息发布后,接收者必须返回一个确认消息(PUBACK)给发布者,如果发布者没有收到确认消息,则会重传消息,确保至少一次的消息传递;
第三种消息格式为:只有一次(Exactly Once):消息发布和传递过程中进行了多次握手和确认,确保消息只被传递一次。
最后我们来讨论一下MQTT协议通信的数据报文格式:
固定报头(Fixed header),第一个字节高4位是MQTT控制报文的类型 + 第一个字节低4位用于指定控制报文类型的标志位(只在PUBLISH发布消息时用到) + 剩余长度1~4个字节(剩余长度字段最大4个字节)可变报头(Variable header),可变报头的内容根据报文类型的不同而不同;有效载体(Payload),某些 MQTT 控制报文在报文的最后部分包含一个有效载荷;
实现步骤
OneNet平台建设
①搜索OneNet,进入网站,登录并进入开发者中心;
https://cdn.nlark.com/yuque/0/2025/png/53372109/1742868739608-07af1341-0919-499c-b326-4b6aef03836c.png②创建产品,点击“产品开发”,创建你的产品,并填写产品信息;

https://cdn.nlark.com/yuque/0/2025/png/53372109/1742869208858-7a381375-5a2b-4604-8f9f-6244062913d6.png说明:所属地区随意,不会影响使用,节点类型根须自身需求选择,接入协议选择MQTT;连接方式可以选择蜂窝或者WiFi,相对简单;开发方案选择自定义方案;③创建设备,选择谁被接入管理,点击设备管理,为产品添加设备,填写设备信息;

https://cdn.nlark.com/yuque/0/2025/png/53372109/1748423588023-8801f69b-bd91-4df5-9005-b92d2b7742b1.png④收集三元组,分别为产品ID、access_key以及设备名称,这三个重要数据要写入代码中,需准确无误;https://cdn.nlark.com/yuque/0/2025/png/53372109/1748423203329-1ef57e43-ece0-491e-a733-cc0fcd151094.png⑤添加产品属性,添加数据流,注意:数据流名称必须与上传的名称相同;也可以添加任何数据流,上传数据时,平台会自动创建同名数据流;https://cdn.nlark.com/yuque/0/2025/png/53372109/1742870981075-55038248-7699-448e-9a9a-709ad37eaec6.pnghttps://cdn.nlark.com/yuque/0/2025/png/53372109/1742871034242-33c0d2f7-f678-4ae1-a8ab-a012a19aa835.png至此,代理(Breaker)建设完毕,等待发布者或订阅者传输信息;
OneNet平台连接前准备
平台建设步骤中,准备收集好的三元组,在连接平台之前需要登陆密钥,这个密钥需要通过token算法得到,不过不用担心,官方已经准备好了计算工具下载连接;
工具中需要输入以下内容:res : products/产品ID/devices/设备名称et : 时间戳,可直接网站搜索获取,注意:此时填写的必须比当前时间晚,即填写“未来”的某个时间key:三元组中获取的access_key;③进入OneNET文档中心,查找服务器接入地址与端口,这个地址与端口会在连接时用上;https://cdn.nlark.com/yuque/0/2025/png/53372109/1748393891624-32fdc6da-5165-4f4d-bc29-e89011bcfbe6.png



一切准备好后,开始着手准备连接OneNET平台;
OneNet平台连接调试

MQTT.fx是一款基于Eclipse Paho,使用Java语言编写的MQTT协议客户端工具。支持通过Topic订阅和发布消息,用来前期和物理云平台调试非常方便;①下载MQTT.fx软件,推荐使用1.7.1版本,免费切资源丰富;下载好之后打开,进入设置界面;

②进入设置界面,填入Broker Address,Broken Point,修改通信版本
③修改用户信息,第二、三步非常重要,请多次核实确保填入信息无误;④设置好之后保存,点击“Connect”进行连接,状态灯显示绿色则连接正确;
此时,进入OneNET工作台,想要连接的设备已经处于在线状态;

⑤调试订阅消息功能,指令格式:$sys/产品ID/设备名称/dp/post/json/+

⑥调试发布消息功能,指令格式:$sys/产品ID/设备名称/dp/post/json ;并且发布消息内容根据一下格式进行修改;

成功收到消息后,能看到此时来自平台的消息;

根据以上格式,改变数据内容,多发送几次;⑦进入平台操作界面,进入设备详情;点击数据流,即可看到刚才上传的数据名称以及其数据,别忘了打开实时刷新;


点击数据,还能根据数据变化绘制曲线图;以上则是MQTT.fx与OneNET平台连接的全过程;



MCU与OneNet平台连接
硬件分析首先来说说项目使用的硬件,主控选型上采用极海半导体推出的工业级基础拓展型MCU:APM32e030R8T6,这款MCU集成搭载 Arm® Cortex®-M0 + 内核,工作主频 72MHz;而本人则是有幸能拿到极海家最新出品的MicroE030开发板;

其次Wifi模块是不可或缺的部分;通过WIFI连接互联网,以实现基于OneNet平台的物联网功能;本次项目采用ESP8266作为WIFI模块;


ESP8266模块拥有一套完整的AT指令集,不需要你懂Wifi的知识,只需要利用串口进行相关的数据收发即可;常用的基础AT指令:

指令说明返回结果
AT测试AT是否OKOK
AT+RST复位指令OK
AT+CWMODE = 1设置模块WIFI模式,设置为Station模式OK
AT+CWDHCP=1设置DHCP模式,设置为开启CWDHCPOK
AT+CWJAP=\"账号,\"密码\"设置模块的AP信息,连接WIFIGOT IP
AT+CIPSTART="ip","网关","子网掩码"设置 Station 的 IP 地址OK
AT+CIPSEND=xxx通过WIFI向IP发送数据SEND OK
此模块引出了8个引脚,其解释和连线如下:

引脚名称描述
VCC供给电压5V
RSTPA4
ENPA5
TXD(RX)PA3
RXD(TX)PA2
IO0悬空
IO2悬空
GND地线

按照连线,硬件准备完毕

软件分析
模块硬件初始化:配置PA4复位引脚和PA5使能引脚,并且初始化USART模块;

<span style="color: rgb(38, 38, 38); font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif, &quot;Segoe UI&quot;; background-color: rgb(248, 248, 248); font-size: 14px; font-variant-ligatures: none; text-wrap-mode: nowrap;">void ESP8266_GPIO_Init(void)</span>模块初始化:
1.硬件模块复位,需将RST引脚拉低200ms以上,再拉高并保持高电平;2.发送指令”AT“,保证模块通信无误;3.发送指令”AT+CWMODE“,配置WIFI为Station模式;//wifi模式4.发送指令”AT+CWDHCP ”,配置WIFI开启DHCP;5.发送指令“AT+CWJAP   ”,配置WIFI模块连接服务器的账号和密码;#define ESP8266_WIFI_INFO "AT+CWJAP=\"Maxxx Pro\",\"12345678\"\r\n" //WIFI名称与密码

其中,Wifi发送函数与接收含函数如下:
<blockquote>_Bool ESP8266_SendCmd(char *cmd, char *res,short timeout)//发送函数在Wifi连接成功之后,就需要连接OneNet平台,回应Success,则表示连接成功,此时OneNet平台设备状态应该为绿色在线;
<blockquote>#define PROID<span style="white-space:pre">                        </span>"rPt76ojBtN"<span style="white-space:pre">                                        </span><span style="white-space:pre">                                                      </span>//产品ID数据发送前,需要将数据打包为OneNet平台可识别格式;
unsigned char OneNet_FillBuf1(char *buf)
{
      
      char text= " " ;
      memset(text, 0, sizeof(text));

      strcpy(buf, "{\"id\":123,\"dp\":{");
      
      memset(text, 0, sizeof(text));
      sprintf(text, "\"Temperature\":[{\"v\":%1f}],", Temperature);
      strcat(buf, text);
      
      memset(text, 0, sizeof(text));
      sprintf(text, "\"Heart_Rate\":[{\"v\":%d}],", hrAvg);      //心率
      strcat(buf, text);
      
      memset(text, 0, sizeof(text));
      sprintf(text, "\"Blood_Oxygen\":[{\"v\":%d}],", spo2Avg);          //心率
      strcat(buf, text);
//
      memset(text, 0, sizeof(text));
      sprintf(text, "\"Longitude\":[{\"v\":%5f}],", longitude_sum);      //经度
      strcat(buf, text);
      memset(text, 0, sizeof(text));
      sprintf(text, "\"Latitude\":[{\"v\":%5f}]",latitude_sum);//纬度
      strcat(buf, text);
      strcat(buf, "}}");
      return strlen(buf);

}然后,数据需要符合MQTT报文结构,即可利用Wifi模块发送;
//==========================================================
//      函数名称:      MQTT_PacketSubscribe
//
//      函数功能:      Subscribe消息组包
//
//      入口参数:      pkt_id:pkt_id
//                              qos:消息重发次数
//                              topics:订阅的消息
//                              topics_cnt:订阅的消息个数
//                              mqttPacket:包指针
//
//      返回参数:      0-成功                其他-失败
//
//      说明:               
//==========================================================
uint8 MQTT_PacketSubscribe(uint16 pkt_id, enum MqttQosLevel qos, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket)
{
      
      uint32 topic_len = 0, remain_len = 0;
      int16 len = 0;
      uint8 i = 0;
      
      if(pkt_id == 0)
                return 1;
      
      //计算topic长度-------------------------------------------------------------------------
      for(; i < topics_cnt; i++)
      {
                if(topics == NULL)
                        return 2;
               
                topic_len += strlen(topics);
      }
      
      //2 bytes packet id + topic filter(2 bytes topic + topic length + 1 byte reserve)------
      remain_len = 2 + 3 * topics_cnt + topic_len;
      
      //分配内存------------------------------------------------------------------------------
      MQTT_NewBuffer(mqttPacket, remain_len + 5);
      if(mqttPacket->_data == NULL)
                return 3;
      
/*************************************固定头部***********************************************/
      
      //固定头部----------------------头部消息-------------------------------------------------
      mqttPacket->_data = MQTT_PKT_SUBSCRIBE << 4 | 0x02;
      
      //固定头部----------------------剩余长度值-----------------------------------------------
      len = MQTT_DumpLength(remain_len, mqttPacket->_data + mqttPacket->_len);
      if(len < 0)
      {
                MQTT_DeleteBuffer(mqttPacket);
                return 4;
      }
      else
                mqttPacket->_len += len;
      
/*************************************payload***********************************************/
      
      //payload----------------------pkt_id---------------------------------------------------
      mqttPacket->_data = MOSQ_MSB(pkt_id);
      mqttPacket->_data = MOSQ_LSB(pkt_id);
      
      //payload----------------------topic_name-----------------------------------------------
      for(i = 0; i < topics_cnt; i++)
      {
                topic_len = strlen(topics);
                mqttPacket->_data = MOSQ_MSB(topic_len);
                mqttPacket->_data = MOSQ_LSB(topic_len);
               
                strncat((int8 *)mqttPacket->_data + mqttPacket->_len, topics, topic_len);
                mqttPacket->_len += topic_len;
               
                mqttPacket->_data = qos & 0xFF;
      }

      return 0;

}最后即可通过函数实现MQTT订阅和发布
//==========================================================
//      函数名称:      OneNET_Publish
//
//      函数功能:      发布消息
//
//      入口参数:      topic:发布的主题
//                              msg:消息内容
//
//      返回参数:      无
//
//      说明:               
//==========================================================
void OneNET_Publish(const char *topic, const char *msg)
{

      MQTT_PACKET_STRUCTURE mqtt_packet = {NULL, 0, 0, 0};                                                //协议包
      
//      UsartPrintf(USART_DEBUG, "Publish Topic: %s, Msg: %s\r\n", topic, msg);
      
      if(MQTT_PacketPublish(MQTT_PUBLISH_ID, topic, msg, strlen(msg), MQTT_QOS_LEVEL0, 0, 1, &mqtt_packet) == 0)
      {
                ESP8266_SendData(mqtt_packet._data, mqtt_packet._len);                                        //向平台发送订阅请求
               
                MQTT_DeleteBuffer(&mqtt_packet);                                                                              //删包
      }

}

//==========================================================
//      函数名称:      OneNET_Subscribe
//
//      函数功能:      订阅
//
//      入口参数:      无
//
//      返回参数:      无
//
//      说明:               
//==========================================================
void OneNET_Subscribe(void)
{
      
      MQTT_PACKET_STRUCTURE mqtt_packet = {NULL, 0, 0, 0};                                                //协议包
      
      char topic_buf;
      const char *topic = topic_buf;
      
      snprintf(topic_buf, sizeof(topic_buf), "$sys/%s/%s/cmd/#", PROID, DEVICE_NAME);
      
//      UsartPrintf(USART_DEBUG, "Subscribe Topic: %s\r\n", topic_buf);
      
      if(MQTT_PacketSubscribe(MQTT_SUBSCRIBE_ID, MQTT_QOS_LEVEL0, &topic, 1, &mqtt_packet) == 0)
      {
                ESP8266_SendData(mqtt_packet._data, mqtt_packet._len);                                        //向平台发送订阅请求
               
                MQTT_DeleteBuffer(&mqtt_packet);                                                                              //删包
      }

}
至此,MCU即可实现利用传感器获取数据,通过WIFI模块上传OneNet平台,根据获取数据进行其他操作;

总结
本篇文章讨论了如何使用OneNet作为物联网平台,并给出详细搭建和调试步骤,并使用APME030R8T6作为主控MCU实现IoT数据交互功能;

资料文章涉及内容较为浅显,若读者对相关知识有兴趣,可跳转至下方资料深入学习MQTT学习资料:
MQTT协议https://blog.csdn.net/weixin_44788542/article/details/129690265?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522f90e144d7df6261ab98db9b525c062d7%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=f90e144d7df6261ab98db9b525c062d7&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-129690265-null-null.142^v102^pc_search_result_base6&utm_term=MQTT&spm=1018.2226.3001.4187OneNet物联网文档中心
https://open.iot.10086.cn/doc/aiot/fuse/search?kw=token&path=new_platform

密钥计算助手token
https://open.iot.10086.cn/college/video/onenet-portal/2024-04-19/17134946071850.exe


Gfan 发表于 2025-8-6 09:52

不得不说干货满满,从 MQTT 讲到 OneNET 平台,再到用APM32E030的 上手实操,一条龙全给整明白了
高亮加精华 安排

DawnFervor 发表于 2025-8-6 19:22

学习了。
这是把MQTT的协议跑在了E030上面了吧!
如果把其安排在ESP8266 可以吗?
页: [1]
查看完整版本: 物联网,启动!基于OneNET平台实现物联网功能