1# BearPi-HM_Nano开发板WiFi编程开发——MQTT连接华为IoT平台 2本示例将演示如何在BearPi-HM_Nano开发板上使用MQTT协议连接华为IoT平台,使用的是E53_IA1 智慧农业扩展板与 BearPi-HM_Nano 开发板,设备安装如下图所示。 3 4 5# 华为IoT平台 API 6 7## 初始化 8### 设备信息 9> void device_info_init(char *client_id, char * username, char *password); 10 11设置设备信息,在调用oc_mqtt_init()前要先设置设备信息。 12 13| **参数** | **描述** | 14| :----- | :----- | 15|无 | 无 | 16| **返回** | **描述** | 17|0 | 成功。 | 18|-1 | 获得设备信息失败。 | 19|-2 | mqtt 客户端初始化失败。 | 20 21 22### 华为IoT平台 初始化 23 24> int oc_mqtt_init(void); 25 26华为IoT平台初始化函数,需要在使用 华为IoT平台 功能前调用。 27 28| **参数** | **描述** | 29| :----- | :----- | 30|无 | 无 | 31| **返回** | **描述** | 32|0 | 成功。 | 33|-1 | 获得设备信息失败。 | 34|-2 | mqtt 客户端初始化失败。 | 35 36### 设置命令响应函数 37 38> 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)); 39 40设置命令响应回调函数。 41 42| **参数** | **描述** | 43| :----- | :----- | 44|recv_data | 接收到的数据。 | 45|recv_size | 数据的长度。 | 46|resp_data | 响应数据。 | 47|resp_size | 响应数据的长度。 | 48| **返回** | **描述** | 49|无 | 无 | 50 51## 数据上传 52 53### 设备消息上报 54 55> int oc_mqtt_profile_msgup(char *deviceid,oc_mqtt_profile_msgup_t *payload); 56 57是指设备无法按照产品模型中定义的属性格式进行数据上报时,可调用此接口将设备的自定义数据上报给平台,平台将设备上报的消息转发给应用服务器或华为云别的云服务上进行存储和处理。 58 59| **参数** | **描述** | 60| :----- | :----- | 61|deviceid | 设备id。 | 62|payload | 要上传的消息。 | 63| **返回** | **描述** | 64|0 | 上传成功。 | 65|1 | 上传失败。 | 66 67### 设备上报属性数据 68 69> int oc_mqtt_profile_propertyreport(char *deviceid,oc_mqtt_profile_service_t *payload); 70 71用于设备按产品模型中定义的格式将属性数据上报给平台。 72 73| **参数** | **描述** | 74| :----- | :----- | 75|deviceid | 设备id。 | 76|payload | 要上传的消息。 | 77| **返回** | **描述** | 78|0 | 上传成功。 | 79|1 | 上传失败。 | 80 81>**属性上报和消息上报的区别,请查看[消息通信说明](https://support.huaweicloud.com/usermanual-iothub/iot_01_0045_2.html)。** 82 83### 网关批量上报属性数据 84 85> int oc_mqtt_profile_gwpropertyreport(char *deviceid,oc_mqtt_profile_device_t *payload); 86 87用于批量设备上报属性数据给平台。网关设备可以用此接口同时上报多个子设备的属性数据。 88 89| **参数** | **描述** | 90| :----- | :----- | 91|deviceid | 设备id。 | 92|payload | 要上传的消息。 | 93| **返回** | **描述** | 94|0 | 上传成功。 | 95|1 | 上传失败。 | 96 97### 属性设置的响应结果 98 99int oc_mqtt_profile_propertysetresp(char *deviceid,oc_mqtt_profile_propertysetresp_t *payload); 100 101 102| **参数** | **描述** | 103| :----- | :----- | 104|deviceid | 设备id。 | 105|payload | 消息。 | 106| **返回** | **描述** | 107|0 | 上传成功。 | 108|1 | 上传失败。 | 109 110### 属性查询响应结果 111 112> int oc_mqtt_profile_propertygetresp(char *deviceid,oc_mqtt_profile_propertygetresp_t *payload); 113 114 115| **参数** | **描述** | 116| :----- | :----- | 117|deviceid | 设备id。 | 118|payload | 消息。 | 119| **返回** | **描述** | 120|0 | 上传成功。 | 121|1 | 上传失败。 | 122 123### 将命令的执行结果返回给平台 124 125> int oc_mqtt_profile_cmdresp(char *deviceid,oc_mqtt_profile_cmdresp_t *payload); 126平台下发命令后,需要设备及时将命令的执行结果返回给平台,如果设备没回响应,平台会认为命令执行超时。 127 128| **参数** | **描述** | 129| :----- | :----- | 130|deviceid | 设备id。 | 131|payload | 要上传的消息。 | 132| **返回** | **描述** | 133|0 | 上传成功。 | 134|1 | 上传失败。 | 135 136 137 138## 软件设计 139 140 141 142### 连接平台 143在连接平台前需要获取CLIENT_ID、USERNAME、PASSWORD,访问[这里](https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/),填写[注册设备](https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0182125275_section108992615509)后生成的设备ID(DeviceId)和密钥(DeviceSecret),生成连接信息(ClientId、Username、Password)。 144```c 145WifiConnect("BearPi","0987654321"); 146device_info_init(CLIENT_ID,USERNAME,PASSWORD); 147oc_mqtt_init(); 148oc_set_cmd_rsp_cb(oc_cmd_rsp_cb); 149``` 150 151### 推送数据 152 153当需要上传数据时,需要先拼装数据,让后通过oc_mqtt_profile_propertyreport上报数据。代码示例如下: 154 155```c 156static void deal_report_msg(report_t *report) 157{ 158 oc_mqtt_profile_service_t service; 159 oc_mqtt_profile_kv_t temperature; 160 oc_mqtt_profile_kv_t humidity; 161 oc_mqtt_profile_kv_t luminance; 162 oc_mqtt_profile_kv_t led; 163 oc_mqtt_profile_kv_t motor; 164 165 service.event_time = NULL; 166 service.service_id = "Agriculture"; 167 service.service_property = &temperature; 168 service.nxt = NULL; 169 170 temperature.key = "Temperature"; 171 temperature.value = &report->temp; 172 temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT; 173 temperature.nxt = &humidity; 174 175 humidity.key = "Humidity"; 176 humidity.value = &report->hum; 177 humidity.type = EN_OC_MQTT_PROFILE_VALUE_INT; 178 humidity.nxt = &luminance; 179 180 luminance.key = "Luminance"; 181 luminance.value = &report->lum; 182 luminance.type = EN_OC_MQTT_PROFILE_VALUE_INT; 183 luminance.nxt = &led; 184 185 led.key = "LightStatus"; 186 led.value = g_app_cb.led ? "ON" : "OFF"; 187 led.type = EN_OC_MQTT_PROFILE_VALUE_STRING; 188 led.nxt = &motor; 189 190 motor.key = "MotorStatus"; 191 motor.value = g_app_cb.motor ? "ON" : "OFF"; 192 motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING; 193 motor.nxt = NULL; 194 195 oc_mqtt_profile_propertyreport(USERNAME, &service); 196 return; 197} 198``` 199 200 201 202 203### 命令接收 204 205华为IoT平台支持下发命令,命令是用户自定义的。接收到命令后会将命令数据发送到队列中,task_main_entry函数中读取队列数据并调用deal_cmd_msg函数进行处理,代码示例如下: 206 207```c 208 209void oc_cmd_rsp_cb(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size) 210{ 211 app_msg_t *app_msg; 212 213 int ret = 0; 214 app_msg = malloc(sizeof(app_msg_t)); 215 app_msg->msg_type = en_msg_cmd; 216 app_msg->msg.cmd.payload = (char *)recv_data; 217 218 printf("recv data is %.*s\n", recv_size, recv_data); 219 ret = osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U); 220 if (ret != 0) { 221 free(recv_data); 222 } 223 *resp_data = NULL; 224 *resp_size = 0; 225} 226 227///< COMMAND DEAL 228#include <cJSON.h> 229static void DealCmdMsg(cmd_t *cmd) 230{ 231 cJSON *obj_root, *obj_cmdname, *obj_paras, *obj_para; 232 233 int cmdret = 1; 234 235 obj_root = cJSON_Parse(cmd->payload); 236 if (obj_root == NULL) { 237 oc_cmdresp(cmd, cmdret); 238 } 239 240 obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name"); 241 if (obj_cmdname == NULL) { 242 cJSON_Delete(obj_root); 243 } 244 if (strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_light") == 0) { 245 obj_paras = cJSON_GetObjectItem(obj_root, "paras"); 246 if (obj_paras == NULL) { 247 cJSON_Delete(obj_root); 248 } 249 obj_para = cJSON_GetObjectItem(obj_paras, "Light"); 250 if (obj_para == NULL) { 251 cJSON_Delete(obj_root); 252 } 253 ///< operate the LED here 254 if (strcmp(cJSON_GetStringValue(obj_para), "ON")) { 255 g_app_cb.led = 1; 256 LightStatusSet(ON); 257 printf("Light On!"); 258 } else { 259 g_app_cb.led = 0; 260 LightStatusSet(OFF); 261 printf("Light Off!"); 262 } 263 cmdret = 0; 264 } else if (strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_Motor") == 0) { 265 obj_paras = cJSON_GetObjectItem(obj_root, "Paras"); 266 if (obj_paras == NULL) { 267 cJSON_Delete(obj_root); 268 } 269 obj_para = cJSON_GetObjectItem(obj_paras, "Motor"); 270 if (obj_para == NULL) { 271 cJSON_Delete(obj_root); 272 } 273 ///< operate the Motor here 274 if (strcmp(cJSON_GetStringValue(obj_para), "ON") == 0) { 275 g_app_cb.motor = 1; 276 MotorStatusSet(ON); 277 printf("Motor On!"); 278 } else { 279 g_app_cb.motor = 0; 280 MotorStatusSet(OFF); 281 printf("Motor Off!"); 282 } 283 cmdret = 0; 284 } 285 286 cJSON_Delete(obj_root); 287} 288``` 289 290 291## 编译调试 292 293 294### 登录 295 296设备接入华为云平台之前,需要在平台注册用户账号,华为云地址:<https://www.huaweicloud.com/> 297 298在华为云首页单击产品,找到IoT物联网,单击设备接入IoTDA 并单击立即使用,如下图所示。 299 300 301 302 303 304### 创建产品 305 306在设备接入页面可看到总览界面,展示了华为云平台接入的协议与域名信息,根据需要选取MQTT通讯必要的信息备用。 307 308接入协议(端口号):MQTT 1883 309 310域名:iot-mqtts.cn-north-4.myhuaweicloud.com 311 312选中侧边栏产品页,单击右上角“创建产品”,如下图所示。 313 314 315 316在页面中选中所属资源空间,并且按要求填写产品名称,选中MQTT协议,数据格式为JSON,并填写厂商名称,在下方模型定义栏中选择所属行业以及添加设备类型,并单击右下角“立即创建”,如下图所示。 317 318 319 320创建完成后,在产品页会自动生成刚刚创建的产品,单击“查看”可查看创建的具体信息,如下图所示。 321 322 323 324 325单击产品详情页的自定义模型,在弹出页面中新增服务,如下图所示。 326 327服务ID:`Agriculture`(必须一致) 328 329服务类型:`Senser`(可自定义) 330 331 332在“Agriculture”的下拉菜单下点击“添加属性”填写相关信息“Temperature”, 333“Humidity”,“Luminance”,“LightStatus”,“MotorStatus”,如下图所示。 334 335 336 337 338 339 340 341 342 343 344 345 346在“Agriculture”的下拉菜单下点击“添加命令”填写相关信息,如下图所示。 347 348命令名称:`Agriculture_Control_light` 349 350参数名称:`Light` 351 352数据类型:`string` 353 354长度:`3` 355 356枚举值:`ON,OFF` 357 358 359 360命令名称:`Agriculture_Control_Motor` 361 362参数名称:`Motor` 363 364数据类型:`string` 365 366长度:`3` 367 368枚举值:`ON,OFF` 369 370 371 372#### 注册设备 373 374在侧边栏中单击“设备”,进入设备页面,单击右上角“注册设备”,勾选对应所属资源空间并选中刚刚创建的产品,注意设备认证类型选择“秘钥”,按要求填写秘钥,如下图所示。 375 376 377 378记录下设备ID和设备密钥,如下图所示。 379 380 381注册完成后,在设备页面单击“所有设备”,即可看到新建的设备,同时设备处于未激活状态,如下图所示。 382 383 384 385 386### 修改代码中设备信息 387在连接平台前需要获取CLIENT_ID、USERNAME、PASSWORD,访问[这里](https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/),填写注册设备时生成的设备ID和设备密钥生成连接信息(ClientId、Username、Password),并将修改代码对应位置,如下图所示。 388 389 390 391 392修改wifi热点信息,如下图所示。 393 394 395 396### 修改 BUILD.gn 文件 397 398修改 `device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `oc_mqtt` 参与编译。 399 400```r 401#"D1_iot_wifi_sta:wifi_sta", 402#"D2_iot_wifi_sta_connect:wifi_sta_connect", 403#"D3_iot_udp_client:udp_client", 404#"D4_iot_tcp_server:tcp_server", 405#"D5_iot_mqtt:iot_mqtt", 406"D6_iot_cloud_oc:oc_mqtt", 407``` 408示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印温湿度及光照强度信息。 409```c 410SENSOR:lum:15.83 temp:27.10 hum:39.26 411 412SENSOR:lum:15.83 temp:27.01 hum:39.36 413 414SENSOR:lum:15.83 temp:26.95 hum:39.45 415 416SENSOR:lum:15.83 temp:26.89 hum:39.56 417 418SENSOR:lum:15.83 temp:26.84 hum:39.56 419 420SENSOR:lum:13.33 temp:26.80 hum:39.64 421 422SENSOR:lum:13.33 temp:26.73 hum:39.76 423 424SENSOR:lum:12.50 temp:26.71 hum:39.78 425 426SENSOR:lum:15.83 temp:26.67 hum:39.91 427 428SENSOR:lum:16.67 temp:26.66 hum:40.00 429``` 430平台上的设备显示为在线状态,如下图所示。 431 432 433 434点击设备右侧的“查看”,进入设备详情页面,可看到上报的数据,如下图所示。 435 436 437 438在华为云平台设备详情页,单击“命令”,选择同步命令下发,选中创建的命令属性,单击“确定”,即可发送下发命令控制设备,如下图所示。 439