当前位置:网站首页>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,点击“发送”。
可看到数据显示栏中显示命令发送成功。
同时设备上灯点亮。
同理,发送其他命令也可显示对应的现象(如灯开、灯光、电机开、电机关等)。
至此,实验成功。
边栏推荐
- [Numpy] 广播机制(Broadcast)
- 国际权威认可!OceanBase入选Forrester Translytical数据平台报告
- Ten year test old bird talk about mobile terminal compatibility test
- Introduction to JVs Foundation
- 力扣解法汇总592-分数加减运算
- How to monitor the running status and usage of NVIDIA Jetson
- [design tutorial] yolov7 target detection network interpretation
- 金仓数据库 KingbaseES异构数据库移植指南 (2. 概述)
- 软件测试面试题:已知一个数字为1,如何输出“0001
- Swiftui view onReceive method receives "redundant" event resolution
猜你喜欢

Analysis on the optimization of login request in IM development of instant messaging mobile terminal

hcip第五天

未定义变量 “Lattice“ 或类 “Lattice.latticeEasy“(Matlab)

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

To do the test, you have to go to the big factory and disclose the "hidden rules" of bat big factory recruitment internally
![[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
![[efficiency] abandon notepad++, this open source substitute is more awesome!](/img/41/495bbe4d1e6d953ba5c4d8984f81e7.jpg)
[efficiency] abandon notepad++, this open source substitute is more awesome!

Some contents related to cmsis-rtos

Arduino development (II)_ RGB light control method based on Arduino uno development board
![[Alibaba security × ICDM 2022] 200000 bonus pool! The risk commodity inspection competition on the large-scale e-commerce map is in hot registration](/img/38/9fadea0d37053a3ebb73806a9963f1.jpg)
[Alibaba security × ICDM 2022] 200000 bonus pool! The risk commodity inspection competition on the large-scale e-commerce map is in hot registration
随机推荐
Hcip day 5
Things about stack migration
To do the test, you have to go to the big factory and disclose the "hidden rules" of bat big factory recruitment internally
Some contents related to cmsis-rtos
How to monitor the running status and usage of NVIDIA Jetson
【Dart】一门为跨端开发而生的编程语言
Openresty Lua resty core use
SQL高级技巧CTE和递归查询
Software test interview question: if a string is known as "hello_world_yoyo", how to get a queue ["hello", "world", "yoyo"]
Arduino开发(二)_基于Arduino UNO开发板的RGB灯光控制方法
从0开始写bootloader
Kingbasees heterogeneous database migration guide (3. Kingbasees migration capability support system)
用户和权限限制用户使用资源
VI working mode (3 kinds) and mode switching (conversion)
你了解数据同步吗?
MySQL log error log
[Numpy] 数组属性
One week activity express | in simple terms, issue 8; Meetup Chengdu station registration in progress
How to solve the problem of missing alarm information and synchronization when Haikang equipment is connected to easycvr?
Software test interview question: given a queue, such as: [1, 3, 5, 7], how to put the first number into the third position to get: [3, 5, 1, 7]