|
|
|
|
公众号矩阵

OpenHarmony Neptune开发板-MQTT连接华为IoT平台

本次我修改程序,解决了CPU异常(直接不能运行)和平台命令下发错误问题,并测试20~30分钟,确保稳定运行,并将一些遇到问题做相关介绍。

作者:颢穹来源:鸿蒙社区|2021-10-11 14:14

想了解更多内容,请访问:

51CTO和华为官方战略合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

前言:

之前有发过Neptune开发板-MQTT连接华为IoT平台文章,但发现写的程序有很大BUG,导致程序运行到开发板经常发生CPU异常(直接不能运行)和平台命令下发错误,在此和之前使用我写的程序发生问题的人说一句抱歉,本次我修改程序,解决了CPU异常(直接不能运行)和平台命令下发错误问题,并测试20~30分钟,确保稳定运行,并将一些遇到问题做相关介绍。

介绍:

本示例将演示如何在Neptune开发板上使用MQTT协议连接华为IoT平台,使用的是ATH20温湿度传感器模块与Neptune开发板

本示例实现AHT20温湿度数据上报华为IoT平台,IoT平台下发命令控制LED灯的开关

使用W800 SDK功能包中libemqtt来实现连接华为IoT平台

程序设计

一、MQTT初始化

  1. void mqtt_init(mqtt_broker_handle_t* broker, const char* clientid); 

初始化要连接到代理的信息

二、写入username与password

  1. void mqtt_init_auth(mqtt_broker_handle_t* broker, const char* username, const charpassword); 

启用身份验证以连接到代理。

三、建立TCP连接

编写TCP连接函数,代码示例如下:

  1. static int init_socket(mqtt_broker_handle_t *broker, const char *hostname, short port, int keepalive) 
  2.     int flag = 1; 
  3.     struct hostent *hp; 
  4.  
  5.     // 创建套接字 
  6.     if((socket_id = socket(PF_INET, SOCK_STREAM, 0)) < 0) 
  7.         return -1; 
  8.  
  9.     // 禁用Nagle算法 
  10.     if (setsockopt(socket_id, IPPROTO_TCP, 0x01, (char *)&flag, sizeof(flag)) < 0) 
  11.     { 
  12.         close_socket(&mqtt_broker); 
  13.         return -2; 
  14.     } 
  15.  
  16.     // 查询主机IP启动 
  17.     hp = gethostbyname(hostname); 
  18.     if (hp == NULL ) 
  19.     { 
  20.         close_socket(&mqtt_broker); 
  21.         return -2; 
  22.     } 
  23.  
  24.     struct sockaddr_in socket_address; 
  25.     memset(&socket_address, 0, sizeof(struct sockaddr_in)); 
  26.     socket_address.sin_family = AF_INET; 
  27.     socket_address.sin_port = htons(port); 
  28.     memcpy(&(socket_address.sin_addr), hp->h_addr, hp->h_length); 
  29.  
  30.     // 连接套接字 
  31.     if((connect(socket_id, (struct sockaddr *)&socket_address, sizeof(socket_address))) < 0) 
  32.     { 
  33.         close_socket(&mqtt_broker); 
  34.         return -1; 
  35.     } 
  36.  
  37.     // MQTT stuffs 
  38.     mqtt_set_alive(broker, mqtt_keepalive); 
  39.     broker->socketid = socket_id; 
  40.     broker->mqttsend = send_packet; 
  41.     return 0; 

四、建立MQTT连接

  1. int mqtt_connect(mqtt_broker_handle_t* broker); 

五、订阅MQTT

编写订阅MQTT主题函数,代码示例如下:

  1. static int subscribe_topic(char *topic)//订阅主题 
  2.     unsigned short msg_id = 0, msg_id_rcv = 0; 
  3.     int packet_lengthgth = 0; 
  4.     int ret = -1; 
  5.   
  6.     if(topic == NULL) { 
  7.         return -1; 
  8.     } 
  9.      
  10.     ret = mqtt_subscribe(&mqtt_broker, topic, &msg_id); 
  11.     if( ret == -1 ) { 
  12.         close_socket(&mqtt_broker); 
  13.         return -1; 
  14.     } 
  15.     packet_lengthgth = read_packet(MQTT_DEMO_READ_TIME_SEC, MQTT_DEMO_READ_TIME_US); 
  16.     if(packet_lengthgth < 0) 
  17.     { 
  18.         printf("Error(%d) on read packet!\n", packet_lengthgth); 
  19.         close_socket(&mqtt_broker); 
  20.         return -1; 
  21.     } 
  22.   
  23.     if(MQTTParseMessageType(pcaket_buffer) != MQTT_MSG_SUBACK) 
  24.     { 
  25.         printf("SUBACK expected!\n"); 
  26.         close_socket(&mqtt_broker); 
  27.         return -2; 
  28.     } 
  29.   
  30.     msg_id_rcv = mqtt_parse_msg_id(pcaket_buffer); 
  31.     if(msg_id != msg_id_rcv) 
  32.     { 
  33.         printf("%d message id was expected, but %d message id was found!\n", msg_id, msg_id_rcv); 
  34.         close_socket(&mqtt_broker); 
  35.         return -3; 
  36.     } 
  37.   
  38.     return 0; 

数据推送与解析

采用cJSON封包与解包(使用W800 SDK功能包中cJSON实现),共有两个封包(一个设备属性上报,一个命令应答上报),一个解包解析IoT平台命令,其他不过多赘述具体详见华为IoTDA 设备接入文档:设备接入 IoTDA 文档

例如设备属性上报,代码示例如下:

  1. /*************************打包发布请求*****************/ 
  2. static int packPublishReq(char *jsonBuffer) 
  3.     cJSON *jsRet = NULL
  4.     cJSON *jsArray = NULL
  5.     int ackLen = 0; 
  6.      
  7.     jsRet = cJSON_CreateObject(); 
  8.     if(jsRet) 
  9.     {    
  10.         jsArray = cJSON_CreateArray(); 
  11.         cJSON_AddItemToObject(jsRet, "services", jsArray); 
  12.         { 
  13.             cJSON *arrayObj_1 = cJSON_CreateObject(); 
  14.             cJSON_AddItemToArray(jsArray, arrayObj_1); 
  15.             cJSON_AddStringToObject(arrayObj_1, "service_id""Temperature"); 
  16.  
  17.             cJSON *arrayObj_2 = cJSON_CreateObject(); 
  18.             cJSON_AddItemToObject(arrayObj_1, "properties", arrayObj_2); 
  19.             cJSON_AddStringToObject(arrayObj_2, "temp", Temperature.temp); 
  20.             cJSON_AddStringToObject(arrayObj_2, "humi", Temperature.humi); 
  21.             cJSON_AddStringToObject(arrayObj_2, "led",  Temperature.ON_OFF); 
  22.              
  23.             cJSON_AddStringToObject(arrayObj_1,"event_time", Temperature.timestamp); 
  24.         } 
  25.         char *databuf = cJSON_PrintUnformatted(jsRet); 
  26.         if(databuf) { 
  27.             if( jsonBuffer ) { 
  28.                 ackLen = strlen(databuf); 
  29.                 memcpy( jsonBuffer, databuf,ackLen); 
  30.             } 
  31.             tls_mem_free(databuf); 
  32.         } 
  33.         cJSON_Delete(jsRet);  
  34.     } 
  35.     return ackLen; 

数据应答(重点)

按照华为云IoT设备平台命令下发文档需要将

下行中的request_id={request_id} 复制到上行中,只有这样下行与上行request_id相同才能保证平台命令数据下发成功任务

  1. 下行 $oc/devices/{device_id}/sys/commands/request_id={request_id} 
  1. 上行:$oc/devices/{device_id}/sys/commands/response/request_id={request_id} 

这里展示一小段代码:

  1. len = mqtt_parse_pub_topic(pcaket_buffer, topic);    //接收平台下发的topic 
  2.         topic[len] = '\0'
  3.         len = mqtt_parse_publish_msg(pcaket_buffer, &msg); 
  4.            strncpy(request_id,topic+63,47);                         
  5.            sprintf(ACK_TOPIC,"%s%s",MQTT_DEMO_ACK_TOPIC,request_id);//复制request_id={request_id} 

这里我出的问题就在->strncpy(request_id,topic+63,47);在我之前是topic+62 而且再我之前创建demo平台下发成功,就没想了,但在这几天测试时就发现这问题故说明。

CPU中断异常问题

由于定时器使用不当,导致CPU中断异常,致程序崩溃(以更改)

华为IoT平台配置

请参考:BearPi-HM_Nano开发板WiFi编程开发——MQTT连接华为IoT平台(Demo我以导出模型)

添加华为云IoT参数:(这只是示例,无法使用)

  1. #define MQTT_DEMO_CLIENT_ID            "616268529fff74057ddd731b_202110101314_0_0_2021101006"                        //ID 
  2. #define MQTT_DEMO_DEVICE_ID            "616268529fff74057ddd731b_202110101314" 
  3. #define MQTT_DEMO_PASSWORD             "b6fd9631cd69eee9ce565a36564b93d26760a49ace05be96cbe9dfaab91f275d" 
  4. #define MQTT_DEMO_SUB_TOPIC            "$oc/devices/616268529fff74057ddd731b_202110101314/sys/commands/#"             //订阅主题 
  5. #define MQTT_DEMO_PUB_TOPIC            "$oc/devices/616268529fff74057ddd731b_202110101314/sys/properties/report"      //发布主题 
  6. #define MQTT_DEMO_ACK_TOPIC            "$oc/devices/616268529fff74057ddd731b_202110101314/sys/commands/response/" 

在wifi_connecter.h修改wifi热点信息

示例代码编译烧录代码后,按下开发板的RESET按键:

OpenHarmony Neptune开发板-MQTT连接华为IoT平台-鸿蒙HarmonyOS技术社区

点击设备右侧的“查看”,进入设备详情页面,可看到上报的数据。

OpenHarmony Neptune开发板-MQTT连接华为IoT平台-鸿蒙HarmonyOS技术社区

在华为云平台设备详情页,单击“命令”,选择同步命令下发,选中创建的命令属性,单击“确定”,即可发送下发命令控制设备。

OpenHarmony Neptune开发板-MQTT连接华为IoT平台-鸿蒙HarmonyOS技术社区

总结:

现以解决经常发生CPU异常(直接不能运行)和平台命令下发错误,同时创建使用两个定时器,一个20秒上报AHT20数据,一个1分钟ping一次(用以保活),使之稳定运行,支持1.0版本与1.1版本。

注意:!!!需要将libemqtt.h下!!!

  1. MQTT_CONF_USERNAME_LENGTH 修改为64 
  2. MQTT_CONF_PASSWORD_LENGTH 修改为64+8 
  3. clientid[50]修改为clientid[64] 

想了解更多内容,请访问:

51CTO和华为官方战略合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

【编辑推荐】

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区
  2. HarmonyOS实战— ProgressBar进度条组件基本使用
  3. HarmonyOS基础之PageSlider和PageFlipper
  4. 《基于Python鸿蒙开发板外设控制》直播图文及答疑
  5. 鸿蒙开源全场景应用开发—通讯协议
  6. 鸿蒙应用开发:如何与组件库(Glide)衔接?
【责任编辑:jianghua TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

订阅专栏+更多

视频课程+更多

DBA MySQL数据库工程师(2021版)

DBA MySQL数据库工程师(2021版)

讲师:张岩峰3492人学习过

Linux下PHP多进程编程

Linux下PHP多进程编程

讲师:可用行师26602人学习过

华为SDN关键技术EVPN详解

华为SDN关键技术EVPN详解

讲师:一方654人学习过

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊

51CTO服务号

51CTO官微