电脑上登录智慧云平台怎么弄 智慧云登录窗口_电脑上登录智慧云平台怎么弄

一、前言

今天使用鸿蒙OS,做一个LOT上云的智慧家居项目。我们想实现的场景是这样的:云端WEB有一个控制界面,能够操控家房间里的灯和风扇,同时将房间里温度、湿度、光强实时显示出来。

二、案例思路

先讲一下大致的思路,可以分为两个部分:先配置云服务器,再编写底层MCU的业务代码,实现数据采集与联网上报。逻辑上没有复杂的东西,但贵在走通整个流程。和普通RTOS上云的方案差不多,具体差异在软件方面。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_上传_02

1、准备工作

云服务器的配置,不算复杂,主要是前端的处理和显示,可以先在服务器调通,再根据云服务提供的API,进行访问。

硬件环境使用小熊派·鸿蒙季开发板和E53_IA1扩展板(有温湿度光强传感器和电机)。

具体如何创建工程,可以参考我的上一篇文章,这里采用Windows环境下的开发方式。无论是基于HPM还是Docker环境获取鸿蒙源码创建工程,都很简单。

这个Demo,我们将会用到鸿蒙OS的内核子系统和驱动子系统。内核子系统主要使用线程相关的API(基于CMSIS-2.0)和网络服务相关的API(socket);驱动子系统主要调用底层的GPIO和硬件I2C,控制外部设备。

在内核子系统和驱动子系统上,我们还需要一个组件(软件包),物联网通信协议MQTT,利用它进行上云服务。

列一下主要的资源和工具:

硬件:

  • 小熊派 · 鸿蒙季开发板
  • E53_IA1扩展板

源码:

  • Hi3861开发板的源码,来源Hb,适用于windows环境

IDE

  • vscode(IDE平台)
  • DevEco Device Tool (IDE组件,可选)
  • RaiDrive

本地环境:

  • windows10 64位
  • ubuntu18.04

云环境:

  • HUAWEI-LoTCloud(云服务器平台)
  • CloudIDE(可选,用于在线调试API接口)

下面,跟着我具体的操作,一步一步实现整个方案,内容比较多,务必提前装好环境,可以先看看前面的文章,把环境搭建起来。

2. 云端操作

先讲云服务器这里。为了方便验证,我们首选华为云服务器(腾讯云、阿里云也可,原理大同小异)。

操作流程大致如下:

电脑上登录智慧云平台怎么弄 智慧云登录窗口_初始化_03

设备接入华为云平台之前,需要在平台注册用,已注册过的可忽略这一步。华为云地址:https://www.huaweicloud.com/

登陆以后,在华为云首页单击控制台,进入产品控制终端,这里包含了各种云服务的产品。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_电脑上登录智慧云平台怎么弄_04


选择云服务器的地点为华为-北京四

电脑上登录智慧云平台怎么弄 智慧云登录窗口_初始化_05

点击左侧的 服务器,找到物联网,选择设备接入IoTDA 并立即使用。或者在搜索输入 设备接入IoTDA跳转过去。下次选择这个服务时,直接点击搜索栏下的最近访问的服务,就能快速进入相应的服务当中,非常方便。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_初始化_06

点击产品,选择创建产品,填写产品信息。「所属资源空间」选择默认,「产品名称」这里填写一个Smart_House(根据自己喜好写一个),「协议类型」选择MQTT就好,「数据格式」为JSON,「厂商名称」填写一口Linux,「设备类型」填写senser。点击确定,完成产品的创建。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_数据_07

创建完毕,弹出产品创建成功的窗口消息。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_电脑上登录智慧云平台怎么弄_08


点击产品列表的「查看」,进行设备的相关操作。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_初始化_09


定义一个服务模型,「服务ID」随便起名字,这里填入Agriculture,「服务类型」填入senser。点击确定,完成服务的添加。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_初始化_10


接下来为服务设置属性和命令,这里规定了数据通信的基本格式。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_初始化_11


点击「添加属性」,以温度为例,「属性名称」填写Temperature,「属性描述」填写温度,「数据类型」为整型,「访问权限」为可读,剩下的默认即可。其中「属性名称」的内容,要与后面我们在MCU中发送的信息保持一致,这里先提一句。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_电脑上登录智慧云平台怎么弄_12


与温度类似,我们依次填写如下内容,不同的是灯和电机,两个的「数据类型」是字符串,「长度」为3。下图列举了灯的属性和其他的设备属性总览。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_数据_13


电脑上登录智慧云平台怎么弄 智慧云登录窗口_初始化_14


接着添加服务命令,点击「添加命令」,依次输入「命令名称」,再点击「新增输入参数」。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_电脑上登录智慧云平台怎么弄_15

新增输入参数和服务属性差不多,这里是字符串的数据类型,输入枚举值,用英文逗号做分割。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_上传_16


我们来看一下所有的属性和命令,差不多就这样:

电脑上登录智慧云平台怎么弄 智慧云登录窗口_上传_17

我们往下进行,点击「设备」,
选择「注册设备」填写设备属性,
「所属资源空间」选择默认账户的即可,
「所属产品」选择上面自己创建的产品,
「设备标识码」填写senser,
「设备名称」填写house,其他保持默认,
点击确定完成创建。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_数据_18


设备创建成功以后,有两个重要信息需要保存,分别是设备ID和设备密钥。

设备ID:   60cdaf505f880902bcaa161c_senser
设备密钥: 4a423f69b41806de0d8ed77e145534e7

电脑上登录智慧云平台怎么弄 智慧云登录窗口_初始化_19

接着我们利用获取的密钥,生成直连MQTT所需的ClentID,通过这个链接跳转:https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

电脑上登录智慧云平台怎么弄 智慧云登录窗口_上传_20

以上,我们云服务器的配置,先到此为止,接下来就是MCU终端上的软件编写。在我们完成软件编写以后,在进行两边的联调测试。

三、软件编写

我们使用的鸿蒙OS源码,已经包含了MQTT等常用的模块,在示例工程中可以方便的查找。这里先简单讲一下目录结构,熟悉一下整个鸿蒙OS在源码框架上的细节。

这里使用的鸿蒙源码工程,由HPM包管理器获取,具体源码结构如下:

电脑上登录智慧云平台怎么弄 智慧云登录窗口_数据_21


我们列一张表,看看每一个文件夹具体承担了哪些职能:

文件名称

描述

applications

BearPi-HM_Nano开发板应用案例

base

系统的基础服务,主要使用DFX子系统、启动文件、硬件适配接口等

kernel

内核子系统

ohos_bundles

厂家提供的一些组件和服务

third_party

第三方组件

foundation

系统服务框架子系统、WAN开发

headers

存放main头文件

src

存放 main源文件

utils

公共基础库

test

XTS认证子系统

vendor

硬件抽象层

build

编译构建子系统

out

存放编译文件

bin

存放二进制文件

适合本文项目的代码示例,在applications文件夹,具体目录为:applications\BearPi\BearPi-HM_Nano\sample\D6_iot_cloud_oc。这里列一下目录文件结构:

文件名称

描述

E53_IA1.c

扩展板驱动

oc_mqtt_profile_package.c

打包和配置MQTT数据

oc_mqtt.c

MQTT连接服务

wifi_connet.c

wifi连接服务

iot_cloud_oc_sample.c

业务逻辑代码

我们主要要用到的API如下,具体实现的细节,可以到源文件里面去阅读。可以分为初始化和数据上传两个部分。

1. 初始化

1)设备信息

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

设置设备信息,在调用oc_mqtt_init()前要先设置设备信息

参数

描述



返回

描述

0

成功

-1

获得设备信息失败

-2

mqtt 客户端初始化失败

2)华为IoT平台 初始化

int oc_mqtt_init(void);

华为IoT平台初始化函数,需要在使用 华为IoT平台 功能前调用。

参数

描述



返回

描述

0

成功

-1

获得设备信息失败

-2

mqtt 客户端初始化失败

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

设置命令响应回调函数。

参数

描述

recv_data

接收到的数据

recv_size

数据的长度

resp_data

响应数据

resp_size

响应数据的长度

返回

描述



2. 数据上传

1)设备消息上报

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

是指设备无法按照产品模型中定义的属性格式进行数据上报时,可调用此接口将设备的自定义数据上报给平台,平台将设备上报的消息转发给应用服务器或华为云其他云服务上进行存储和处理。

参数

描述

deviceid

设备id

payload

要上传的消息

返回

描述

0

上传成功

1

上传失败

2)设备上报属性数据

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

用于设备按产品模型中定义的格式将属性数据上报给平台。

参数

描述

deviceid

设备id

payload

要上传的消息

返回

描述

0

上传成功

1

上传失败

属性上报和消息上报的区别,请查看消息通信说明

3)网关批量上报属性数据

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

用于批量设备上报属性数据给平台。网关设备可以用此接口同时上报多个子设备的属性数据。

参数

描述

deviceid

设备id

payload

要上传的消息

返回

描述

0

上传成功

1

上传失败

4)属性设置的响应结果

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

参数

描述

deviceid

设备id

payload

消息

返回

描述

0

上传成功

1

上传失败

5)属性查询响应结果

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

参数

描述

deviceid

设备id

payload

消息

返回

描述

0

上传成功

1

上传失败

6)将命令的执行结果返回给平台

int oc_mqtt_profile_cmdresp(char *deviceid,oc_mqtt_profile_cmdresp_t *payload);
平台下发命令后,需要设备及时将命令的执行结果返回给平台,如果设备没回响应,平台会认为命令执行超时。

参数

描述

deviceid

设备id

payload

要上传的消息

返回

描述

0

上传成功

1

上传失败

3. 编写业务逻辑

1)连接平台

准备好上文我们获取的连接信息(ClientId、Username、Password),一个可以上网的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)推送数据

当需要上传数据时,需要先拼装数据,然后通过oc_mqtt_profile_propertyreport上报数据。代码示例如下:

/**
 * @brief	  处理上报的数据。
 * @details   Process the reported data.
 * @param[in] report  需要上报的数据。The data to be reported.
 * @return    None
***/
static void deal_report_msg(report_t *report)
{
	/** 定义服务ID句柄 */
    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;

	/** 初始化要上报的服务ID数据 */
    service.event_time = NULL;
    service.service_id = "Agriculture";
    service.service_property = &temperature;
    service.nxt = NULL;
	
	/** 初始化要上报的温度数据 */
    temperature.key = "Temperature";
    temperature.value = &report->temp;
    temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    temperature.nxt = &humidity;
    
	/** 初始化要上报的湿度数据 */
    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);
    return;
}

3)命令接收

华为IoT平台支持下发命令,命令是用户自定义的。接收到命令后会将命令数据发送到队列中,task_main_entry函数中读取队列数据并调用deal_cmd_msg函数进行处理,代码示例如下:

/**
 * @brief	  将命令数据发送到队列。
 * @details   Send command data to the queue.
 * @param[in] recv_data  接收的数据
 * @param[in] recv_size  接收数据的大小
 * @param[in] resp_data  接收的上报数据
 * @param[in] resp_size  接收的上报数据的大小
 * @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\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;
}

/**
 * @brief	  线程入口,读取队列数据并处理。
 * @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");
	/** 注册设备的连接信息*/
	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	  解析命令,并给出处理的结果。
 * @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. 编译调试

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

示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印温湿度及光照强度信息。

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 <time: 0ms> success!
00 00:00:00 0 0 I 1/SAMGR: Init service 0x4b8040 <time: 0ms> success!
00 00:00:00 0 200 D 0/HIVIEW: hiview init success.
00 00:00:00 0 200 I 1/SAMGR: Init service 0x4b81c8 <time: 0ms> success!
00 00:00:00 0 200 I 1/SAMGR: Initialized all core system services!
00 00:00:00 0 0 I 1/SAMGR: Bootstrap system and application services(count:0).
00 00:00:00 0 0 I 1/SAMGR: Initialized all system and application services!
00 00:00:00 0 0 I 1/SAMGR: Bootstrap dynamic registered services(count:0).
SENSOR:lum:107.50 temp:33.34 hum:63.95
<--System Init-->
<--Wifi Init-->
register wifi event succeed!
callback function for wifi scan:0, 0
+NOTICE:SCANFINISH
callback function for wifi scan:1, 24
WaitSacnResult:wait success[1]s
********************
no:001, ssid:养只狗叫瑞邦            , rssi:  -53
no:002, ssid:电信302                     , rssi:  -63
no:003, ssid:412                           , rssi:  -64
no:004, ssid:DIRECT-IXLAPTOP-O3K3OKASmsUK  , rssi:  -69
...
********************
Select:  2 wireless, Waiting...
+NOTICE:CONNECTED
SENSOR:lum:67.50 temp:33.17 hum:68.33
WaitConnectResult:wait success[1]s
WiFi connect succeed!
begain to dhcp
<-- DHCP state:Inprogress -->
<-- DHCP state:Inprogress -->
<-- DHCP state:OK -->
server :
        server_id : 192.168.1.1
        mask : 255.255.255.0, 1
        gw : 192.168.1.1
        T0 : 7200
        T1 : 3600
        T2 : 6300
clients <1> :
        mac_idx mac             addr            state   lease   tries   rto
        0       e81131641696    192.168.1.123   10      0       1       3
SENSOR:lum:79.17 temp:32.77 hum:60.45
SENSOR:lum:38.33 temp:32.51 hum:52.88
SENSOR:lum:42.50 temp:32.30 hum:50.59
SENSOR:lum:42.50 temp:32.11 hum:49.73
SENSOR:lum:40.00 temp:31.91 hum:49.74
SENSOR:lum:41.67 temp:31.75 hum:49.96

回到华为云平台,平台上的设备显示为在线状态

电脑上登录智慧云平台怎么弄 智慧云登录窗口_初始化_22

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

电脑上登录智慧云平台怎么弄 智慧云登录窗口_上传_23

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

电脑上登录智慧云平台怎么弄 智慧云登录窗口_电脑上登录智慧云平台怎么弄_24

看一下现象:串口打印云端接收的数据,并执行点灯的指令。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_上传_25


电脑上登录智慧云平台怎么弄 智慧云登录窗口_数据_26

5. 调试华为云API

点击「API检索和调试」,进入API调测界面。

电脑上登录智慧云平台怎么弄 智慧云登录窗口_初始化_27

目前开放有Java、python、node.js、php等,可以根据个人的需求,构建前端。这里我们先调试API,选择一个设备命令,按照图示操作。
注意Body里面的参数,与我们上文产品的属性是一样的,其中paras的参数,填写要符合图片给出的规范,也就是JSON的格式。

最后点击调式,给出调试结果,我们的开发板上,灯也被点亮!

电脑上登录智慧云平台怎么弄 智慧云登录窗口_电脑上登录智慧云平台怎么弄_28

四、总结

  1. 云端的操作,要注意和终端软件编写的信息相同,一个是MQTT的连接信息不能出错,还有就是注意名称之间的大小写要相同;
  2. 终端MCU软件的编写,注意分层设计,先写好各自的功能模块,最后再实现相关的业务逻辑;
  3. 注意调测,利用好串口和云端MQTT信息跟踪服务;
  4. 整体走下来,工作量还是蛮大的,需要注意的地方有很多,所以要特别细心。