訂閱
糾錯(cuò)
加入自媒體

一文教你如何利用鴻蒙OS實(shí)現(xiàn)智慧家居·LOT上云項(xiàng)目

三、軟件編寫

我們使用的鴻蒙OS源碼,已經(jīng)包含了MQTT等常用的模塊,在示例工程中可以方便的查找。這里先簡(jiǎn)單講一下目錄結(jié)構(gòu),熟悉一下整個(gè)鴻蒙OS在源碼框架上的細(xì)節(jié)。

這里使用的鴻蒙源碼工程,由HPM包管理器獲取,具體源碼結(jié)構(gòu)如下:

我們列一張表,看看每一個(gè)文件夾具體承擔(dān)了哪些職能:

文件名稱描述applicationsBearPi-HM_Nano開發(fā)板應(yīng)用案例base系統(tǒng)的基礎(chǔ)服務(wù),主要使用DFX子系統(tǒng)、啟動(dòng)文件、硬件適配接口等kernel內(nèi)核子系統(tǒng)ohos_bundles廠家提供的一些組件和服務(wù)third_party第三方組件foundation系統(tǒng)服務(wù)框架子系統(tǒng)、WAN開發(fā)headers存放main頭文件src存放 main源文件utils公共基礎(chǔ)庫(kù)testXTS認(rèn)證子系統(tǒng)vendor硬件抽象層build編譯構(gòu)建子系統(tǒng)out存放編譯文件bin存放二進(jìn)制文件

適合本文項(xiàng)目的代碼示例,在applications文件夾,具體目錄為:applicationsBearPiBearPi-HM_NanosampleD6_iot_cloud_oc。這里列一下目錄文件結(jié)構(gòu):

文件名稱描述E53_IA1.c擴(kuò)展板驅(qū)動(dòng)oc_mqtt_profile_package.c打包和配置MQTT數(shù)據(jù)oc_mqtt.cMQTT連接服務(wù)wifi_connet.cwifi連接服務(wù)iot_cloud_oc_sample.c業(yè)務(wù)邏輯代碼

我們主要要用到的API如下,具體實(shí)現(xiàn)的細(xì)節(jié),可以到源文件里面去閱讀。可以分為初始化和數(shù)據(jù)上傳兩個(gè)部分。

1. 初始化1)設(shè)備信息

void device_info_init(char *client_id, char * username, char *password);

設(shè)置設(shè)備信息,在調(diào)用oc_mqtt_init()前要先設(shè)置設(shè)備信息

參數(shù)描述無(wú)無(wú)返回描述0成功-1獲得設(shè)備信息失敗-2mqtt 客戶端初始化失敗2)華為IoT平臺(tái) 初始化

int oc_mqtt_init(void);

華為IoT平臺(tái)初始化函數(shù),需要在使用 華為IoT平臺(tái) 功能前調(diào)用。

參數(shù)描述無(wú)無(wú)返回描述0成功-1獲得設(shè)備信息失敗-2mqtt 客戶端初始化失敗3)設(shè)置命令響應(yīng)函數(shù)

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));

設(shè)置命令響應(yīng)回調(diào)函數(shù)。

參數(shù)描述recv_data接收到的數(shù)據(jù)recv_size數(shù)據(jù)的長(zhǎng)度resp_data響應(yīng)數(shù)據(jù)resp_size響應(yīng)數(shù)據(jù)的長(zhǎng)度返回描述無(wú)無(wú)2. 數(shù)據(jù)上傳1)設(shè)備消息上報(bào)

int oc_mqtt_profile_msgup(char *deviceid,oc_mqtt_profile_msgup_t *payload);

是指設(shè)備無(wú)法按照產(chǎn)品模型中定義的屬性格式進(jìn)行數(shù)據(jù)上報(bào)時(shí),可調(diào)用此接口將設(shè)備的自定義數(shù)據(jù)上報(bào)給平臺(tái),平臺(tái)將設(shè)備上報(bào)的消息轉(zhuǎn)發(fā)給應(yīng)用服務(wù)器或華為云其他云服務(wù)上進(jìn)行存儲(chǔ)和處理。

參數(shù)描述deviceid設(shè)備idpayload要上傳的消息返回描述0上傳成功1上傳失敗2)設(shè)備上報(bào)屬性數(shù)據(jù)

int oc_mqtt_profile_propertyreport(char *deviceid,oc_mqtt_profile_service_t *payload);

用于設(shè)備按產(chǎn)品模型中定義的格式將屬性數(shù)據(jù)上報(bào)給平臺(tái)。

參數(shù)描述deviceid設(shè)備idpayload要上傳的消息返回描述0上傳成功1上傳失敗

屬性上報(bào)和消息上報(bào)的區(qū)別,請(qǐng)查看消息通信說(shuō)明

3)網(wǎng)關(guān)批量上報(bào)屬性數(shù)據(jù)

int oc_mqtt_profile_gwpropertyreport(char *deviceid,oc_mqtt_profile_device_t *payload);

用于批量設(shè)備上報(bào)屬性數(shù)據(jù)給平臺(tái)。網(wǎng)關(guān)設(shè)備可以用此接口同時(shí)上報(bào)多個(gè)子設(shè)備的屬性數(shù)據(jù)。

參數(shù)描述deviceid設(shè)備idpayload要上傳的消息返回描述0上傳成功1上傳失敗4)屬性設(shè)置的響應(yīng)結(jié)果

int oc_mqtt_profile_propertysetresp(char *deviceid,oc_mqtt_profile_propertysetresp_t *payload);

參數(shù)描述deviceid設(shè)備idpayload消息返回描述0上傳成功1上傳失敗5)屬性查詢響應(yīng)結(jié)果

int oc_mqtt_profile_propertygetresp(char *deviceid,oc_mqtt_profile_propertygetresp_t *payload);

參數(shù)描述deviceid設(shè)備idpayload消息返回描述0上傳成功1上傳失敗6)將命令的執(zhí)行結(jié)果返回給平臺(tái)

int oc_mqtt_profile_cmdresp(char *deviceid,oc_mqtt_profile_cmdresp_t *payload);平臺(tái)下發(fā)命令后,需要設(shè)備及時(shí)將命令的執(zhí)行結(jié)果返回給平臺(tái),如果設(shè)備沒回響應(yīng),平臺(tái)會(huì)認(rèn)為命令執(zhí)行超時(shí)。

參數(shù)描述deviceid設(shè)備idpayload要上傳的消息返回描述0上傳成功1上傳失敗3. 編寫業(yè)務(wù)邏輯1)連接平臺(tái)

準(zhǔn)備好上文我們獲取的連接信息(ClientId、Username、Password),一個(gè)可以上網(wǎng)的WIFI(賬戶和密碼),注意不可以用5G頻段。

#define CLIENT_ID "60cdaf505f880902bcaa161c_senser_0_0_2021062002"
#define USERNAME "60cdaf505f880902bcaa161c_senser"
#define PASSWORD "e7f839333a8d3618a975e2626df1462f67202f3f4103080fe8d6f05df0fa7ce3"
WifiConnect("TP-LINK_65A8","0987654321");
device_info_init(CLIENT_ID,USERNAME,PASSWORD);
oc_mqtt_init();
oc_set_cmd_rsp_cb(oc_cmd_rsp_cb);
2)推送數(shù)據(jù)

當(dāng)需要上傳數(shù)據(jù)時(shí),需要先拼裝數(shù)據(jù),然后通過(guò)oc_mqtt_profile_propertyreport上報(bào)數(shù)據(jù)。代碼示例如下:

*
* @brief   處理上報(bào)的數(shù)據(jù)。
* @details   Process the reported data.
* @param[in] report  需要上報(bào)的數(shù)據(jù)。The data to be reported.
* @return    None
**
static void deal_report_msg(report_t *report)
{
* 定義服務(wù)ID句柄
   oc_mqtt_profile_service_t    service;
   * 定義溫度的上報(bào)數(shù)據(jù)句柄
   oc_mqtt_profile_kv_t         temperature;
   * 定義濕度的上報(bào)數(shù)據(jù)句柄
   oc_mqtt_profile_kv_t         humidity;
   * 定義亮度的上報(bào)數(shù)據(jù)句柄
   oc_mqtt_profile_kv_t         luminance;
   * 定義電燈的上報(bào)數(shù)據(jù)句柄
   oc_mqtt_profile_kv_t         led;
   * 定義電機(jī)的上報(bào)數(shù)據(jù)句柄
   oc_mqtt_profile_kv_t         motor;
* 初始化要上報(bào)的服務(wù)ID數(shù)據(jù)
   service.event_time = NULL;
   service.service_id = "Agriculture";
   service.service_property = &temperature;
   service.nxt = NULL;

* 初始化要上報(bào)的溫度數(shù)據(jù)
   temperature.key = "Temperature";
   temperature.value = &report->temp;
   temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT;
   temperature.nxt = &humidity;
   
* 初始化要上報(bào)的濕度數(shù)據(jù)
   humidity.key = "Humidity";
   humidity.value = &report->hum;
   humidity.type = EN_OC_MQTT_PROFILE_VALUE_INT;
   humidity.nxt = &luminance;
   
* 初始化要上報(bào)的亮度數(shù)據(jù)
   luminance.key = "Luminance";
   luminance.value = &report->lum;
   luminance.type = EN_OC_MQTT_PROFILE_VALUE_INT;
   luminance.nxt = &led;
   
* 初始化要上報(bào)的電燈數(shù)據(jù)
   led.key = "LightStatus";
   led.value = g_app_cb.led?"ON":"OFF";
   led.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
   led.nxt = &motor;
   
* 初始化要上報(bào)的電機(jī)數(shù)據(jù)
   motor.key = "MotorStatus";
   motor.value = g_app_cb.motor?"ON":"OFF";
   motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
   motor.nxt = NULL;

* 將屬性數(shù)據(jù)上報(bào)給平臺(tái)
   oc_mqtt_profile_propertyreport(USERNAME,&service);
   return;
}
3)命令接收

華為IoT平臺(tái)支持下發(fā)命令,命令是用戶自定義的。接收到命令后會(huì)將命令數(shù)據(jù)發(fā)送到隊(duì)列中,task_main_entry函數(shù)中讀取隊(duì)列數(shù)據(jù)并調(diào)用deal_cmd_msg函數(shù)進(jìn)行處理,代碼示例如下:

*
* @brief   將命令數(shù)據(jù)發(fā)送到隊(duì)列。
* @details   Send command data to the queue.
* @param[in] recv_data  接收的數(shù)據(jù)
* @param[in] recv_size  接收數(shù)據(jù)的大小
* @param[in] resp_data  接收的上報(bào)數(shù)據(jù)
* @param[in] resp_size  接收的上報(bào)數(shù)據(jù)的大小
* @return    None
**
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", recv_size, recv_data);
   
   * 送入隊(duì)列
   ret = osMessageQueuePut(mid_MsgQueue,&app_msg,0U, 0U);
   
   if(ret != 0){
       free(recv_data);
   }
   *resp_data = NULL;
   *resp_size = 0;
}
*
* @brief   線程入口,讀取隊(duì)列數(shù)據(jù)并處理。
* @details   Thread entry, read queue data and process.
* @param[in] None
* @return    None
**
static int task_main_entry( void )
{
   app_msg_t *app_msg;

* 連接WIFI
WifiConnect("TP-LINK_65A8","0987654321");
* 注冊(cè)設(shè)備的連接信息
device_info_init(CLIENT_ID,USERNAME,PASSWORD);
* 初始化MQTT
oc_mqtt_init();
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:
                   deal_cmd_msg(&app_msg->msg.cmd);
                   break;
               case en_msg_report:
                   deal_report_msg(&app_msg->msg.report);
                   break;
               default:
                   break;
           }
           free(app_msg);
       }
   }
   return 0;
}
*
* @brief   解析命令,并給出處理的結(jié)果。
* @details   Thread entry, read queue data and process.
* @param[in] cmd 命令。
* @return    None
**
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. 編譯調(diào)試

修改 applicationssampleBearPiBearPi-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",

示例代碼編譯燒錄代碼后,按下開發(fā)板的RESET按鍵,通過(guò)串口助手查看日志,會(huì)打印溫濕度及光照強(qiáng)度信息。

sdk ver:Hi3861V100R001C00SPC025 2020-09-03 18:10:00
FileSystem mount ok.
wifi init success!
00 00:00:00 0 68 D 0/HIVIEW: hilog init success.
00 00:00:00 0 68 D 0/HIVIEW: log limit init success.
00 00:00:00 0 68 I 1/SAMGR: Bootstrap core services(count:3).
00 00:00:00 0 68 I 1/SAMGR: Init service:0x4b8040 TaskPool:0xfa9a4
00 00:00:00 0 68 I 1/SAMGR: Init service:0x4b8064 TaskPool:0xfb014
00 00:00:00 0 68 I 1/SAMGR: Init service:0x4b81c8 TaskPool:0xfb1d4
00 00:00:00 0 100 I 1/SAMGR: Init service 0x4b8064

回到華為云平臺(tái),平臺(tái)上的設(shè)備顯示為在線狀態(tài)

點(diǎn)擊設(shè)備右側(cè)的“查看”,進(jìn)入設(shè)備詳情頁(yè)面,可看到上報(bào)的數(shù)據(jù)

在華為云平臺(tái)設(shè)備詳情頁(yè),單擊“命令”,選擇同步命令下發(fā),選中創(chuàng)建的命令屬性,單擊“確定”,即可發(fā)送下發(fā)命令控制設(shè)備。

看一下現(xiàn)象:串口打印云端接收的數(shù)據(jù),并執(zhí)行點(diǎn)燈的指令。

5. 調(diào)試華為云API

點(diǎn)擊「API檢索和調(diào)試」,進(jìn)入API調(diào)測(cè)界面。

目前開放有Java、python、node.js、php等,可以根據(jù)個(gè)人的需求,構(gòu)建前端。這里我們先調(diào)試API,選擇一個(gè)設(shè)備命令,按照?qǐng)D示操作。注意Body里面的參數(shù),與我們上文產(chǎn)品的屬性是一樣的,其中paras的參數(shù),填寫要符合圖片給出的規(guī)范,也就是JSON的格式。

最后點(diǎn)擊調(diào)式,給出調(diào)試結(jié)果,我們的開發(fā)板上,燈也被點(diǎn)亮!

四、總結(jié)

云端的操作,要注意和終端軟件編寫的信息相同,一個(gè)是MQTT的連接信息不能出錯(cuò),還有就是注意名稱之間的大小寫要相同;終端MCU軟件的編寫,注意分層設(shè)計(jì),先寫好各自的功能模塊,最后再實(shí)現(xiàn)相關(guān)的業(yè)務(wù)邏輯;注意調(diào)測(cè),利用好串口和云端MQTT信息跟蹤服務(wù);整體走下來(lái),工作量還是蠻大的,需要注意的地方有很多,所以要特別細(xì)心。源代碼后臺(tái)回復(fù)鴻蒙獲取,工程文件可以參考上個(gè)文章獲取。

<上一頁(yè)  1  2  
聲明: 本文由入駐維科號(hào)的作者撰寫,觀點(diǎn)僅代表作者本人,不代表OFweek立場(chǎng)。如有侵權(quán)或其他問題,請(qǐng)聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請(qǐng)輸入評(píng)論內(nèi)容...

請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字

您提交的評(píng)論過(guò)于頻繁,請(qǐng)輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無(wú)評(píng)論

暫無(wú)評(píng)論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號(hào)
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯(cuò)
x
*文字標(biāo)題:
*糾錯(cuò)內(nèi)容:
聯(lián)系郵箱:
*驗(yàn) 證 碼:

粵公網(wǎng)安備 44030502002758號(hào)