当前位置:网站首页>14天鸿蒙设备开发实战-第七章 设备联网上云 学习笔记
14天鸿蒙设备开发实战-第七章 设备联网上云 学习笔记
2022-07-27 18:22:00 【华为云】
注:本学习笔记基于以下教程,实现BearPi-HM_Nano开发板WiFi编程开发——MQTT连接华为IoT平台
bearpi_hm_nano\applications\BearPi\BearPiHM_Nano\sample\D6_iot_cloud_oc\README.md
一、开发环境、平台与硬件需求
本实验软件开发环境为VSCode,通过与Ubuntu系统远程连接映射工程文件,使用DevEco Device Tool插件在Windows中的VSCode进行编程、编译、烧录与调试。
云平台使用华为IoT平台。华为云物联网平台即华为设备接入服务(IoT Device Access),提供海量设备连接上云、设备和云端双向消息通信、批量设备管理等能力,并可将设备数据灵活流转到华为云其他服务,帮助物联网行业用户快速完成设备联网及行业应用集成。
硬件采用BearPi-HM_Nano开发板,并使用E53_IA1 智慧农业扩展板。
二、华为IoT平台API
2.1 初始化
2.1.1 设备信息初始化
void device_info_init(char *client_id, char * username, char *password);
说明:对与华为IoT平台对接的设备的有关信息进行初始化。相关信息的配置见 中说明。
| 参数 | 描述 |
|---|---|
| client_id | 设备ID |
| username | 用户名 |
| password | 密钥 |
| 返回 | 描述 |
| 0 | 成功 |
| -1 | 获得设备信息失败 |
| -2 | mqtt 客户端初始化失败 |
2.1.2 华为IoT平台 初始化
int oc_mqtt_init(void);
华为IoT平台初始化函数,需要在使用 华为IoT平台 功能前调用。
| 参数 | 描述 |
|---|---|
| 无 | 无 |
| 返回 | 描述 |
| 0 | 成功 |
| -1 | 获得设备信息失败 |
| -2 | mqtt 客户端初始化失败 |
2.1.3 设置命令响应函数
void oc_set_cmd_rsp_cb(void(*cmd_rsp_cb)(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size));
设置命令响应回调函数。
| 参数 | 描述 |
|---|---|
| void(*cmd_rsp_cb)() | 自定义回调函数 |
| recv_data | 接收到的数据 |
| recv_size | 数据的长度 |
| resp_data | 响应数据 |
| resp_size | 响应数据的长度 |
| 返回 | 描述 |
| 无 | 无 |
2.2 数据上报
2.2.1 设备上报属性数据
int oc_mqtt_profile_propertyreport(char *deviceid,oc_mqtt_profile_service_t *payload);
用于设备按产品模型中定义的格式将属性数据上报给平台。
| 参数 | 描述 |
|---|---|
| deviceid | 设备id |
| payload | 要上传的消息 |
| 返回 | 描述 |
| 0 | 上传成功 |
| 1 | 上传失败 |
2.2.2 将命令的执行结果返回给平台
int oc_mqtt_profile_cmdresp(char *deviceid,oc_mqtt_profile_cmdresp_t *payload);
平台下发命令后,需要设备及时将命令的执行结果返回给平台,如果设备没回响应,平台会认为命令执行超时。
| 参数 | 描述 |
|---|---|
| deviceid | 设备id |
| payload | 要上传的消息 |
| 返回 | 描述 |
| 0 | 上传成功 |
| 1 | 上传失败 |
注:除此之外还有其他API,但这里不需要用到,故不介绍
三、华为IoT平台设备接入
3.1 登录
设备接入华为云平台之前,需要在平台注册用户账号,华为云地址:https://www.huaweicloud.com/
在华为云首页单击产品,找到IoT物联网,单击设备接入IoTDA 并单击免费试用。

3.2 创建产品
在设备接入页面点击基础版-详情
可看到总览界面,展示了华为云平台接入的协议与域名信息,根据需要选取MQTT通讯必要的信息备用。
接入协议(端口号):MQTT 1883
域名:a1619a8401.iot-mqtts.cn-north-4.myhuaweicloud.com
选中侧边栏产品页,单击右上角“创建产品”
在页面中选中所属资源空间,并且按要求填写产品名称,选中MQTT协议,数据格式为JSON,并填写厂商名称,在下方模型定义栏中选择所属行业以及添加设备类型,并单击右下角“确定”如图:
创建完成后,在产品页会自动生成刚刚创建的产品,单击“查看”可查看创建的具体信息。
单击产品详情页自定义模型,在弹出页面中添加服务
服务ID:Agriculture(必须一致)
服务类型:Senser(可自定义)
在“Agriculture”的右侧菜单中点击“添加属性”填写相关信息“Temperature”,“Humidity”,“Luminance”,“LightStatus”,“MotorStatus”。





在“Agriculture”的右侧菜单中点击“添加命令”填写相关信息。
命令名称:Agriculture_Control_light
参数名称:Light
数据类型:string
长度:3
枚举值:ON,OFF

命令名称:Agriculture_Control_Motor
参数名称:Motor
数据类型:string
长度:3
枚举值:ON,OFF

3.3 注册设备
在产品详情页点击“在线调试”,再点击“新增测试设备”。
选择设备类型为真实设备,设置设备名称为 Agriculture_Device(可自定义),设置设备标识码(可自定义),如 123456789,设备注册方式默认不加密,点击确定。
注意记录下设备ID和设备密钥
注册完成后,在设备页面单击“所有设备”,即可看到新建的设备,同时设备处于未激活状态
通过华为云设备接入提供的MQTT ClientId生成工具获取CLIENT_ID、USERNAME、PASSWORD。
输入上面记录的设备ID和设备密钥,点击Generate,保存生成的CLIENT_ID、USERNAME、PASSWORD。
四、软件设计
基于例程代码bearpi_hm_nano\applications\BearPi\BearPi_HM_Nano\sample\D6_iot_cloud_oc\iot_cloud_oc_sample.c
4.1 创建消息队列和任务
本实验设备端数据上报以及命令下发到设备端需要借助消息队列。即设备端要上报的数据打包成消息放入消息队列,而云平台下发的命令数据包也放入消息队列。
mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, 10, NULL);//添加消息队列 if (mid_MsgQueue == NULL) { printf("Falied to create Message Queue!\n"); }创建两个任务task_main_entry()与task_sensor_entry()。
osThreadAttr_t attr; attr.name = "task_main_entry"; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = 10240; attr.priority = 24; if (osThreadNew((osThreadFunc_t)task_main_entry, NULL, &attr) == NULL) { printf("Falied to create task_main_entry!\n"); } attr.stack_size = 2048; attr.priority = 25; attr.name = "task_sensor_entry"; if (osThreadNew((osThreadFunc_t)task_sensor_entry, NULL, &attr) == NULL) { printf("Falied to create task_sensor_entry!\n"); }4.2 主任务task_main_entry()实现
task_main_entry()为主任务,负责实现设备连接平台,以及获取队列中的消息,实现数据上报以及命令解析。
任务实现代码如下:
static int task_main_entry(void){ app_msg_t *app_msg; //连接wifi uint32_t ret = WifiConnect(SELECT_WIFI_SSID,SELECT_WIFI_PASSWORD);//需要在同一个局域网中 //设备信息初始化 device_info_init(CLIENT_ID, USERNAME, PASSWORD); //初始化oc_mqtt oc_mqtt_init(); //华为IoT平台初始化 oc_set_cmd_rsp_cb(oc_cmd_rsp_cb); while (1) { app_msg = NULL; //获取队列中的消息 (void)osMessageQueueGet(mid_MsgQueue, (void **)&app_msg, NULL, 0U); if (NULL != app_msg) { switch (app_msg->msg_type)//判断消息类型 { case en_msg_cmd://若为cmd(命令)消息 deal_cmd_msg(&app_msg->msg.cmd); break; case en_msg_report://若为report(上报)消息 deal_report_msg(&app_msg->msg.report); break; default: break; } free(app_msg); } } return 0;}1.连接平台包括连接Wifi、设备信息初始化以及华为IoT平台初始化。
//连接wifi uint32_t ret = WifiConnect(SELECT_WIFI_SSID,SELECT_WIFI_PASSWORD);//需要在同一个局域网中 //设备信息初始化 device_info_init(CLIENT_ID, USERNAME, PASSWORD); //初始化oc_mqtt oc_mqtt_init(); //华为IoT平台初始化 oc_set_cmd_rsp_cb(oc_cmd_rsp_cb);其中
(1)WifiConnect(SELECT_WIFI_SSID,SELECT_WIFI_PASSWORD)的两个参数为wifi的SSID以及密码。注意这里配置的wifi为设备端连接的wifi,需要与登录华为IoT平台的PC端连接的wifi保持一致,即保证处于同一个局域网中。
(2)device_info_init(CLIENT_ID, USERNAME, PASSWORD)的三个参数即为3.3节中生成的CLIENT_ID、USERNAME、PASSWORD。
(3)oc_set_cmd_rsp_cb(oc_cmd_rsp_cb)的参数为自定义的命令响应回调函数。当云平台下发命令时,会回调oc_cmd_rsp_cb函数,在其中将下发的数据打包成命令型消息并放入消息队列中。
oc_cmd_rsp_cb函数实现如下:
void oc_cmd_rsp_cb(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size){ app_msg_t *app_msg; int ret = 0; app_msg = malloc(sizeof(app_msg_t)); app_msg->msg_type = en_msg_cmd; app_msg->msg.cmd.payload = (char *)recv_data; printf("recv data is %.*s\n", recv_size, recv_data); ret = osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U); if (ret != 0) { free(recv_data); } *resp_data = NULL; *resp_size = 0;}2.在任务主循环中,等待并获取消息队列中的信息,当队列有消息时,判断消息类型。若为命令型消息(来自云平台的命令下发),则调用
deal_cmd_msg(&app_msg->msg.cmd)进行命令解析;若为上报型消息(来自设备端的传感器任务),则调用deal_report_msg(&app_msg->msg.report)进行数据上报。
4.3 数据上报
当需要上报数据时,需要先进行json数据拼装,然后通过oc_mqtt_profile_propertyreport上报数据。代码示例如下:
///< REPORT DEAL 上报消息处理函数static void deal_report_msg(report_t *report){ oc_mqtt_profile_service_t service; oc_mqtt_profile_kv_t temperature; oc_mqtt_profile_kv_t humidity; oc_mqtt_profile_kv_t luminance; oc_mqtt_profile_kv_t led; oc_mqtt_profile_kv_t motor; //json数据拼装 service.event_time = NULL; service.service_id = "Agriculture";//在华为云设备接入中创建的产品BearPi_HM_Nano中创建的服务Agriculture service.service_property = &temperature;//属性名称(属性的第一个为temperature) service.nxt = NULL; temperature.key = "Temperature"; temperature.value = &report->temp; temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT; temperature.nxt = &humidity;//nxt 下一个属性 humidity.key = "Humidity"; humidity.value = &report->hum; humidity.type = EN_OC_MQTT_PROFILE_VALUE_INT; humidity.nxt = &luminance; luminance.key = "Luminance"; luminance.value = &report->lum; luminance.type = EN_OC_MQTT_PROFILE_VALUE_INT; luminance.nxt = &led; led.key = "LightStatus"; led.value = g_app_cb.led ? "ON" : "OFF"; led.type = EN_OC_MQTT_PROFILE_VALUE_STRING; led.nxt = &motor; motor.key = "MotorStatus"; motor.value = g_app_cb.motor ? "ON" : "OFF"; motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING; motor.nxt = NULL; oc_mqtt_profile_propertyreport(USERNAME, &service);//mqtt数据上报 return;}4.4 命令解析
由3.2节知,当设备接收到华为IoT平台下发的命令后会将命令数据发送到队列中,task_main_entry函数中读取队列数据并调用deal_cmd_msg函数进行处理。
命令解析函数deal_cmd_msg()首先进行json数据(也就是华为IoT平台下发的命令数据)解析,根据解析得到的指令进行灯、电机的开关处理,并调用oc_mqtt_profile_cmdresp向平台响应,表达命令执行成功(由于命令并未设置响应参数,故这里响应数据为空)。
代码示例如下:
///< COMMAND DEAL 命令消息处理函数,作json解析与灯、电机的开关处理#include <cJSON.h>static void deal_cmd_msg(cmd_t *cmd){ cJSON *obj_root; cJSON *obj_cmdname; cJSON *obj_paras; cJSON *obj_para; int cmdret = 1; oc_mqtt_profile_cmdresp_t cmdresp; obj_root = cJSON_Parse(cmd->payload); if (NULL == obj_root) { goto EXIT_JSONPARSE; } obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name"); if (NULL == obj_cmdname) { goto EXIT_CMDOBJ; } if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_light")) { obj_paras = cJSON_GetObjectItem(obj_root, "paras"); if (NULL == obj_paras) { goto EXIT_OBJPARAS; } obj_para = cJSON_GetObjectItem(obj_paras, "Light"); if (NULL == obj_para) { goto EXIT_OBJPARA; } ///< operate the LED here if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON")) { g_app_cb.led = 1; Light_StatusSet(ON); printf("Light On!"); } else { g_app_cb.led = 0; Light_StatusSet(OFF); printf("Light Off!"); } cmdret = 0; } else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_Motor")) { obj_paras = cJSON_GetObjectItem(obj_root, "Paras"); if (NULL == obj_paras) { goto EXIT_OBJPARAS; } obj_para = cJSON_GetObjectItem(obj_paras, "Motor"); if (NULL == obj_para) { goto EXIT_OBJPARA; } ///< operate the Motor here if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON")) { g_app_cb.motor = 1; Motor_StatusSet(ON); printf("Motor On!"); } else { g_app_cb.motor = 0; Motor_StatusSet(OFF); printf("Motor Off!"); } cmdret = 0; }EXIT_OBJPARA:EXIT_OBJPARAS:EXIT_CMDOBJ: cJSON_Delete(obj_root);EXIT_JSONPARSE: ///< do the response cmdresp.paras = NULL; cmdresp.request_id = cmd->request_id; cmdresp.ret_code = cmdret; cmdresp.ret_name = NULL; (void)oc_mqtt_profile_cmdresp(NULL, &cmdresp); return;}4.5 传感器任务task_sensor_entry()实现
task_sensor_entry()为传感器任务,负责传感器初始化,以及读取传感器数据、并将传感器数据打包成消息放入消息队列中。
代码实现如下:
tatic int task_sensor_entry(void){ app_msg_t *app_msg; E53_IA1_Data_TypeDef data; E53_IA1_Init();//传感器初始化 while (1) { E53_IA1_Read_Data(&data);//读取传感器数据 app_msg = malloc(sizeof(app_msg_t)); printf("SENSOR:lum:%.2f temp:%.2f hum:%.2f\r\n", data.Lux, data.Temperature, data.Humidity); if (NULL != app_msg) { app_msg->msg_type = en_msg_report;//消息类型为上报消息 app_msg->msg.report.hum = (int)data.Humidity; app_msg->msg.report.lum = (int)data.Lux; app_msg->msg.report.temp = (int)data.Temperature; if (0 != osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U))//将消息放入消息队列中 { free(app_msg); } } sleep(3); } return 0;}五、编译、烧录与调试
5.1 修改 BUILD.gn文件
修改 applications\sample\BearPi\BearPi-HM_Nano路径下 BUILD.gn 文件,指定 oc_mqtt 参与编译(即取消注释)。
#"D1_iot_wifi_sta:wifi_sta",#"D2_iot_wifi_sta_connect:wifi_sta_connect", #"D3_iot_udp_client:udp_client",#"D4_iot_tcp_server:tcp_server",#"D5_iot_mqtt:iot_mqtt", "D6_iot_cloud_oc:oc_mqtt",#"D7_iot_cloud_onenet:onenet_mqtt",5.2 编译、烧录
通过hpm dist在终端处进行编译。
编译成功后,点击Upload进行烧录(借助DevEco Device Tool插件)。
烧录完成后,点击Monitor,并按下开发板的RESET按键,查看串口打印日志,可看到在连接到平台后,不断打印温湿度及光照强度等信息。
<--System Init--><--Wifi Init-->register wifi event succeed!callback function for wifi scan:0, 0+NOTICE:SCANFINISHcallback function for wifi scan:1, 7WaitSacnResult:wait success[1]s********************no:001, ssid:RMWiFi , rssi: -37no:002, ssid:GL-AX1800 , rssi: -52no:003, ssid:GL-AX1800-132-Guest , rssi: -53no:004, ssid:zdq , rssi: -72no:005, ssid:HC5861B_1AD2 , rssi: -84no:006, ssid:scut-student , rssi: -66no:007, ssid:scut-student , rssi: -85********************Select: 3 wireless, Waiting...+NOTICE:CONNECTEDSENSOR:lum:32.50 temp:28.09 hum:58.37WaitConnectResult:wait success[1]sWiFi connect succeed!begain to dhcp<-- DHCP state:Inprogress --><-- DHCP state:Inprogress --><-- DHCP state:Inprogress -->SENSOR:lum:32.50 temp:28.10 hum:58.64<-- DHCP state:Inprogress --><-- DHCP state:Inprogress --><-- DHCP state:OK -->server : server_id : 192.168.9.1 mask : 255.255.255.0, 1 gw : 192.168.9.1 T0 : 43200 T1 : 21600 T2 : 37800clients <1> : mac_idx mac addr state lease tries rto 0 681131d4046d 192.168.9.241 10 0 1 4 SENSOR:lum:32.50 temp:28.09 hum:58.03SENSOR:lum:32.50 temp:28.12 hum:58.14SENSOR:lum:32.50 temp:28.10 hum:57.76SENSOR:lum:31.67 temp:28.12 hum:56.74SENSOR:lum:32.50 temp:28.13 hum:56.13SENSOR:lum:32.50 temp:28.12 hum:55.95……5.3 查看华为IoT平台数据上报信息以及命令下发
登录华为IoT平台,进入设备接入页面,点击左侧“设备-所有设备”,可看到之前注册的设备已处于“在线状态”。
点击设备右侧的“查看”,进入设备详情页面,可看到上报的数据。
在产品页面,点击“在线调试”,点击设备右侧的“调试”。
可看到这里显示上报的数据以及发送的命令。
点击右侧的“命令下发”,选择“服务”类型为Sensor,选择之前配置的“命令”,并设置枚举值。如选择Agriculture_Control_light,并设置为ON,点击“发送”。
可看到数据显示栏中显示命令发送成功。
同时设备上灯点亮。
同理,发送其他命令也可显示对应的现象(如灯开、灯光、电机开、电机关等)。
至此,实验成功。
边栏推荐
- Academic sharing | Tsinghua University, Kang Chongqing: power system carbon measurement technology and application (matlab code implementation)
- Users and permissions revoke user permissions
- 软件测试面试题:已知一个队列,如: [1, 3, 5, 7], 如何把第一个数字,放到第三个位置,得到:[3, 5, 1, 7]
- 【程序人生】“阶段总结“-不甘平凡
- MySQL log query log
- MySQL basic queries and operators
- SLIM:自监督点云场景流与运动估计(ICCV 2021)
- 推荐一款强大的搜索工具Listary
- Hcip day 5
- 【毕设教程】YOLOv7 目标检测网络解读
猜你喜欢

【分层强化学习】HAC论文及代码

Why does Alibaba prohibit more than three forms from joining?

LabVIEW学习笔记五:按钮按下后无法返回原状

五大知名人士对于AI的忧虑

After working for bytek for two years, he got 15 offers at one go
![[benefit activity] stack a buff for your code! Click](/img/2d/dabf0ad5d7bd553dada5921abf6c06.png)
[benefit activity] stack a buff for your code! Click "tea" to receive the gift

EasyCVR平台添加RTSP设备时,出现均以TCP方式连接的现象是什么原因?

RK3399平台入门到精通系列讲解(导读篇)21天学习挑战介绍

人家这才叫软件测试工程师,你那只是混口饭吃(附HR面试宝典)

Download of MySQL driver jar package -- nanny tutorial
随机推荐
Best practices for Oracle kingbasees migration of Jincang database (4. Oracle database migration practice)
认识传输介质网络通信的介质
推荐一款强大的搜索工具Listary
Users and permissions revoke user permissions
Software test interview question: how to output "0001" when a number is known to be 1
海康设备接入EasyCVR,出现告警信息缺失且不同步该如何解决?
金仓数据库 KingbaseES异构数据库移植指南 (2. 概述)
征服所有程序员的3件IT装备 →
软件测试面试题:已知一个字符串为“hello_world_yoyo”, 如何得到一个队列 [“hello“,“world“,“yoyo“]
[dataset display annotation] VOC file structure + dataset annotation visualization + code implementation
Babbitt | metauniverse daily must read: Tencent News suspended the sales service of digital collections, users left messages asking for a "refund", and phantom core also fell into the dilemma of "unsa
好开不贵,舒适安全!深度体验比亚迪宋Pro DM-i
MYSQL设计优化生成列
Analysis on the optimization of login request in IM development of instant messaging mobile terminal
How does the industrial switch enter the web management interface?
认识网络模型OSI模型
User and authority modify user password
【程序人生】“阶段总结“-不甘平凡
做测试, 就得去大厂,内部披露BAT大厂招聘“潜规则”
Laboratory management system implemented by SSM framework +jsp [source code + database + system paper]