搜索
bottom↓
回复: 5

OneNET连接流程

[复制链接]

出0入234汤圆

发表于 2022-4-23 18:35:37 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2022-4-25 11:02 编辑

以下文章来源于:公众号:开源电子网,读取更多技术文章,请扫码关注
开源电子网,扫码2222222.png



前言


         OneNET-中国移动物联网开放平台是由中国移动打造的PaaS物联网开放平台。平台能够帮助开发者轻松实现设备接入与设备连接,提供综合性的物联网解决方案,实现物联网设备的数据获取,数据存储,数据展现。本文就介绍如何将传统的设备连接到OneNET。



       采用MQTT+JSON格式对接OneNET平台上传温度度的数据,当然我们也可以在平台下发消息来控制设备。





01操作和实战

        注册OneNET:https://open.iot.10086.cn/,注册OneNET账号。注册过程比较简单这里就不再累述。登录之后。打开产品服务à MQTT物联网套件à 点击立刻使用,如下图所示:


1.png



      进入MQTT物联网套件,在该页面点击添加产品,如下图所示:



2.png


       从上图中,技术参数根据自己的硬件选择,如果我们的联网硬件为无线产品,则选择wifi;如果我们的联网硬件为有线产品,则选择移动蜂窝网络。协议为MQTTS,操作系统为无,而网络运营商可以全选,最后点击完成就可以创建产品,如下图所示:


3.png



         点击上图的产品,进入相关界面,然后点击设备列表创建设备,如下图所示:


4.png



        添加完成之后,我们得到一个设备,,如下图所示:


5.png



       点击上图中的数据流,这些数据流是由用户添加的,例如显示温湿度等等,如下图所示:


6.png



      最后我们得到三元组内容,如下源码所示:

  1. /* 用户需要根据设备信息完善以下宏定义中的三元组内容 */

  2. #define CLIENTID "MQTT"   /* 设备名 */

  3. #define USERNAME "366007" /* 产品ID */

  4. /* 该密码需要onenet提供的token软件计算得出 */

  5. #define PASSWORD "version=2018-10-31&res=products%2F366007%2Fdevices%2FMQTT&et=1672735919&method=md5&sign=qI0pgDJnICGoPdhNi%2BHtfg%3D%3D"
复制代码
             上述的参数是由OneNET来提供,MQTT是刚刚我们创建的设备名称,“366007”是刚刚我们创建的产品ID,而密钥是从产品概述获取,如下图所示:


7.png



           上述是OneNET平台构建MQTT服务器完成,下面我们讲解代码部分。




02 MQTT源码包和cjSON源码包下载

         MQTT官方网址(http://mqtt.org/)下载MQTT代码包;cjSON官方网址(https://sourceforge.net/projects/cjson/)下载cjSON代码包;

       然后把这些源码移植到我们工程当中,移植步骤如下所示:


       添加一下源码到工程当中


8.png



       在工程添加一下分组:


9.png



    添加这些源码头文件路径



03 连接云平台的通用模板

       (1) 新建文件onenet.h文件,该文件主要定义OneNET平台的信息,如下源码所示:

  1. /* 用户需要根据设备信息完善以下宏定义中的三元组内容 */

  2. #define CLIENTID "MQTT"   /* 设备名 */

  3. #define USERNAME "366007" /* 产品ID */

  4. /* 该密码需要onenet提供的token软件计算得出 */

  5. #define PASSWORD "version=2018-10-31&res=products%2F366007%2Fdevices%2FMQTT&et=1672735919&method=md5&sign=qI0pgDJnICGoPdhNi%2BHtfg%3D%3D"


  6. /* 以下参数的宏定义固定,不需要修改,只修改上方的参数即可 */

  7. #define HOST_NAME     "open.iot.10086.cn"  /*onenet域名 */

  8. #define HOST_PORT     1883

  9. #define DEVICE_SUBSCRIBE   "$sys/"USERNAME"/"CLIENTID"/dp/post/json/+"/* 订阅 */

  10. #define DEVICE_PUBLISH     "$sys/"USERNAME"/"CLIENTID"/dp/post/json"/* 发布 */

复制代码

         订阅和发布的写法根据OneNET的要求而定义。


        (2)在onenet.c文件定义四个函数,分别连接、获取、打开和关闭,如下源码所示:

  1. /*

  2. * @brief  通过TCP方式发送数据到TCP服务器

  3. */

  4. int lwip_transport_send_packet_buffer(int sock, unsigned char *buf,

  5. int buflen)

  6. {

  7.     int rc = 0;

  8.     rc = write(sock, buf, buflen);

  9.     return rc;

  10. }



  11. /*

  12. * @brief  阻塞方式接受TCP服务器发送的数据

  13. /

  14. int lwip_transport_getdata(uint8_t* buf, int32_t count)

  15. {

  16.     int rc = recv(mysock, buf, count, 0);

  17.     return rc;

  18. }



  19. /*

  20. * @brief  打开一个网络接口,其实就是和服务器建立一个 TCP 连接。

  21. /

  22. int lwip_transport_open(char* addr, int port)

  23. {

  24.     int* sock = &mysock;

  25.     struct hostent *server;

  26.     struct sockaddr_in serv_addr;

  27.     int timeout = 1000;



  28.     *sock = socket(AF_INET, SOCK_STREAM, 0);

  29.     if(*sock < 0)

  30.       printf("[ERROR] Create socket failed\n");

  31.    

  32.     server = gethostbyname(addr);              /* 对阿里云服务器地址解析 */

  33.     if(server == NULL)

  34.       printf("[ERROR] Get host ip failed\n");

  35.    

  36.     memset(&serv_addr,0,sizeof(serv_addr));

  37.     serv_addr.sin_family = AF_INET;

  38.     serv_addr.sin_port = htons(port);          /* 设置端口号 */

  39.     memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);

  40.    

  41.     if(connect(*sock,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)

  42.     {

  43.       printf("[ERROR] connect failed\n");

  44.           return -1;

  45.     }

  46.    

  47. setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO,

  48.             (char*)&timeout,sizeof(timeout));



  49.     return mysock;

  50. }



  51. /*

  52. @brief  关闭连接

  53. /

  54. int lwip_transport_close(int sock)

  55. {

  56.     int rc;



  57.     rc = shutdown(sock, SHUT_WR);

  58.     rc = recv(sock, NULL, (size_t)0, 0);

  59.     rc = close(sock);



  60.     return rc;

  61. }

  62.     这些函数是由用户来实现,例如连接函数,根据自己的硬件编写连接。上述的源码小编以LWIP为例。



  63. (3) 订阅和发布操作

  64. void lwip_demo(void)

  65. {

  66.     mysock = lwip_transport_open((char *)HOST_NAME, HOST_PORT);

  67.     data.clientID.cstring = CLIENTID;

  68.     data.username.cstring = USERNAME;

  69.     data.password.cstring = PASSWORD;

  70.     unsigned char payload_out[200];

  71.     int payload_out_len = 0;

  72.     uint32_t sendtick = xTaskGetTickCount();



  73.     while (1)

  74. {

  75. /* 客户端的发布操作 */

  76.         if ((xTaskGetTickCount() - sendtick) >= (send_duration * 100))

  77.         {

  78.             sendtick = xTaskGetTickCount();/* sendtick重新计数 */

  79.             taskENTER_CRITICAL();/* 进入临界区 */

  80.             temp = 30 + rand() % 10 + 1; /* 温度的数据 */

  81.             humid = 54.8 + rand() % 10 + 1; /* 湿度的数据 */

  82.             sprintf((char *)payload_out, "{"id": 123,"dp":

  83.                      { "temperatrue": [{"v": %0.1f,}],"power":

  84.                      [{"v": %0.1f,}]}}", temp, humid);

  85.             payload_out_len = strlen((char *)payload_out);

  86.             topicString.cstring = DEVICE_PUBLISH;   /* 属性上报 发布 */

  87.             len = MQTTSerialize_publish((unsigned char *)buf,

  88. buflen, 0, req_qos,

  89. retained, msgid,

  90. topicString,

  91. payload_out,

  92. payload_out_len);

  93.             rc = lwip_transport_send_packet_buffer(mysock,

  94. (unsigned char *)buf, len);

  95.             taskEXIT_CRITICAL();                    /* 退出临界区 */

  96.             if (rc == len)

  97.                 printf("send PUBLISH Successfully\r\n");

  98.             else

  99.                 printf("send PUBLISH failed\r\n");



  100.             printf("send temp(%0.1f)&humid(%0.1f) !\r\n", temp, humid);

  101.             recv_server_flag = 1;

  102.         }

  103.         

  104.         vTaskDelay(100);

  105.         

  106.         switch (msgtypes)

  107.         {



  108.             case CONNECT:  /* 客户端发送服务器的连接操作 */

  109.                 printf("进入CONNECT状态\r\n");

  110.                 len = MQTTSerialize_connect((unsigned char *)buf,

  111. buflen, &data);         /* 获取数据组长发送连接信息  */

  112.                 rc = lwip_transport_send_packet_buffer(mysock,

  113. (unsigned char *)buf, len); /* 发送返回发送数组长度 */



  114.                 if (rc == len)

  115.                     printf("发送连接成功\r\n");

  116.                 else

  117.                     printf("发送连接失败\r\n");



  118.                 printf("MQTT连接服务器!\r\n");

  119.                 printf("退出CONNECT状态\r\n\r\n");

  120.                 msgtypes = 0;

  121.                 recv_server_flag = 1;

  122.                 break;



  123.             case CONNACK:  /* 服务器发送客户端确认连接请求 */

  124.                 if (MQTTDeserialize_connack(&sessionPresent,

  125. &connack_rc, (unsigned char *)buf, buflen) != 1

  126. || connack_rc != 0)  /* 收到回执 */

  127.                 {

  128. /* 回执不一致,连接失败 */

  129.                     printf("Unable to connect, return code %d\r\n", connack_rc);   

  130.                 }

  131.                 else

  132.                 {

  133.                     printf("MQTT is concet OK!\r\n");   /* 连接成功 */

  134.                 }

  135.                 msgtypes = SUBSCRIBE;   /* 连接成功 执行 订阅 操作 */

  136.                 break;



  137.             case SUBSCRIBE:  /* 客户端发送到服务器的订阅操作 */

  138.                 topicString.cstring = DEVICE_SUBSCRIBE;

  139.                 len = MQTTSerialize_subscribe((unsigned char *)buf,

  140. buflen, 0, msgid, 1, &topicString, &req_qos);

  141.                 rc = lwip_transport_send_packet_buffer(mysock,

  142. (unsigned char *)buf, len);



  143.                 if (rc == len)

  144.                     printf("send SUBSCRIBE Successfully\r\n");

  145.                 else

  146.                 {

  147.                     printf("send SUBSCRIBE failed\r\n");

  148.                     t++;



  149.                     if (t >= 10)

  150.                     {

  151.                         t = 0;

  152.                         msgtypes = CONNECT;

  153.                     }

  154.                     else

  155.                         msgtypes = SUBSCRIBE;



  156.                     break;

  157.                 }

  158.                 msgtypes = 0;

  159.                 recv_server_flag = 1;

  160.                 break;



  161.             case SUBACK:  /* 服务器发送到客户端的订阅确认 */

  162. /* 有回执  QoS */

  163.                 rc = MQTTDeserialize_suback(&submsgid, 1, &subcount,

  164.                                                   &granted_qos, (unsigned char *)buf,

  165.                                                    buflen);  

  166.                 printf("granted qos is %d\r\n", granted_qos);    /* 打印 Qos */

  167.                 msgtypes = 0;

  168.                 break;



  169.             case PUBLISH:  /* 服务器的发布操作 */

  170.                 /* 服务器的发布数据,自行编写 */

  171.                 break;



  172.             case PUBACK:   /* 发布成功 */

  173.                 msgtypes = 0;

  174.                 break;



  175.             default:

  176.                 break;



  177.         }

  178.         

  179.         if (recv_server_flag == 1)

  180.         {

  181.             memset(buf, 0, buflen);

  182. /* 轮询,读MQTT返回数据,*/

  183.             rc = MQTTPacket_read((unsigned char *)buf, buflen,

  184.                                       lwip_transport_getdata);

  185.             if (rc > 0) /* 如果有数据,进入相应状态。*/

  186.             {

  187.                 msgtypes = rc;

  188.             }

  189.             recv_server_flag = 0;

  190.         }

  191.     }

  192. }
复制代码


04 下载验证


10.png


阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出40入514汤圆

发表于 2022-4-24 10:51:24 | 显示全部楼层
看得有点蒙,好像没有提到是基于什么联网模块
看具体代码好像是基于lwip,是自己mcu跑网络协议的才有参考价值了吧

出16170入6148汤圆

发表于 2022-4-24 10:58:13 来自手机 | 显示全部楼层
看起来不复杂。

出0入0汤圆

发表于 2022-4-24 23:34:28 | 显示全部楼层
数据自动保存在云端?这个计费是什么模式?

出0入0汤圆

发表于 2022-4-26 12:50:30 | 显示全部楼层
正点原子的例程有freertos+lwip的?

出0入0汤圆

发表于 2022-4-27 08:08:46 | 显示全部楼层
智涅 发表于 2022-4-24 10:51
看得有点蒙,好像没有提到是基于什么联网模块
看具体代码好像是基于lwip,是自己mcu跑网络协议的才有参考价 ...
(引用自2楼)

网络是分层的,lwip解决了数据链路层+传输层的TCP UDP。
而MQTT是基于TCP,属于应用层的。
lwip库 稳定可靠,没有必要自己再写轮子。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 19:40

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表