设备接入服务(IoT Device Access)是华为云的物联网平台,提供海量设备连接上云、设备和云端双向消息通信、批量设备管理、远程控制和监控、OTA升级、设备联动规则等能力,并可将设备数据灵活流转到华为云其他服务,帮助物联网行业用户快速完成设备联网及行业应用集成。
无论是集成LiteOS的物联网终端设备,还是集成HarmonyOS的终端设备,都可以接入华为云IoT平台,实现属性上报与命令下发。
为此,您需要:
在本次Codelab中,您将使用DevEco Device Tool和设备侧MQTT接口,开发设备端功能,实现:
嵌入式C语言基础开发能力。
产品模型是用来描述设备能力的文件,通过JSON的格式定义了设备的基本属性、上报数据和下发命令的消息格式。定义产品模型,即在物联网平台构建一款设备的抽象模型,使平台理解该款设备支持的属性信息。
需要注册设备,获取设备ID和密钥。
docker run -it -v d:\harmonyos:/home/openharmony swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:0.0.5
mkdir code01; cd code01
hpm init -t default
hpm install @bearpi/bearpi_hm_nano
执行命令后,进入代码下载和解压阶段,可能会耗费几分钟时间,出现如下界面表示代码下载完成:
下载完成后,会在D盘下,产生一个harmonyos目录,打开harmonyos目录并将code01文件夹拖拽到Visual Studio Code中打开。
源码目录介绍
目录名 | 描述 |
applications | 应用程序样例 |
base | 基础软件服务子系统集&硬件服务子系统集 |
build | 组件化编译、构建和配置脚本 |
docs | 说明文档 |
domains | 增强软件服务子系统集 |
drivers | 驱动子系统 |
foundation | 系统基础能力子系统集 |
kernel | 内核子系统 |
prebuilts | 编译器及工具链子系统 |
test | 测试子系统 |
third_party | 开源第三方组件 |
utils | 常用的工具集 |
vendor | 厂商提供的软件 |
build.py | 编译脚本文件 |
#include
#include "ohos_init.h"
void Hello_World(void)
{
printf("Hello World!\r\n");
}
APP_FEATURE_INIT(Hello_World);
static_library("app") {
sources = [
"iot_cloud_oc_sample.c"
]
include_dirs = [
"//utils/native/lite/include"
]
}
import("//build/lite/config/component/lite_component.gni")
lite_component("app") {
features = [
"e53_sc1_smart_light_sample:app",
]
}
hpm dist
编译过程中会打印相应的编译日志,编译完成后会提示build success编译完成信息。
编译完成后,在code01目录下会产生out目录,存放着编译完成的二进制文件。
通过TypeC数据线,把电脑与BearPi-HM Nano连接。
打开电脑设备管理器,查看开发板的串口(请先安装软件准备中的CH341SER.EXE驱动)
HUAWEI DevEco Device Tool智能设备一站式集成开发环境支持在windows环境下烧录代码。
首先找到D:\harmonyos\code01\out\bearpi_hm_nano\bearpi_hm_nano目录下编译产生的二进制文件Hi3861_wifiiot_app_allinone.bin
根据驱动提示的串口信息设置烧录选项
在"Partition Configuration"页签,设置烧录二进制文件。
点击"Binary"选择框下,选择编译产生的二进制文件"Hi3861_wifiiot_app_allinone.bin",并设置对应二进制文件。
设置完成,点击"Save"按钮,然后单击"Open"按钮打开工程。
启动烧录后,显示如下提示信息时,请按开发板上的RST按钮重启开发板。
重新上电后,启动烧录,界面提示如下信息时,表示烧录成功。
Visual Studio Code主界面,点击"Serial Monitor"工具按钮,即可连接3861设备串口。
#include
#include
#include
#include
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_connect.h"
#include
#include
#include
#include "E53_SC1.h"
#include
#include
#define CONFIG_WIFI_SSID "ChinaNet-SecS" //修改为自己的WiFi 热点账号
#define CONFIG_WIFI_PWD "rupzd252" //修改为自己的WiFi 热点密码
#define CONFIG_APP_SERVERIP "121.36.42.100"
#define CONFIG_APP_SERVERPORT "1883"
#define CONFIG_APP_DEVICEID "6124ad7a0ad1ed02866267bb_20210826081000" //替换为注册设备后生成的deviceid
#define CONFIG_APP_DEVICEPWD "12345678" //替换为注册设备后生成的密钥
#define CONFIG_APP_LIFETIME 60 ///< seconds
#define CONFIG_QUEUE_TIMEOUT (5*1000)
#define MSGQUEUE_OBJECTS 16 // number of Message Queue Objects
typedef enum
{
en_msg_cmd = 0,
en_msg_report,
}en_msg_type_t;
typedef struct
{
char *request_id;
char *payload;
} cmd_t;
typedef struct
{
int lum;
} report_t;
typedef struct
{
en_msg_type_t msg_type;
union
{
cmd_t cmd;
report_t report;
} msg;
} app_msg_t;
typedef struct
{
queue_t *app_msg;
int connected;
int led;
} app_cb_t;
static app_cb_t g_app_cb;
//use this function to push all the message to the buffer
static int msg_rcv_callback(oc_mqtt_profile_msgrcv_t *msg)
{
int ret = 0;
char *buf;
int buf_len;
app_msg_t *app_msg;
if((NULL == msg)|| (msg->request_id == NULL) || (msg->type != EN_OC_MQTT_PROFILE_MSG_TYPE_DOWN_COMMANDS)){
return ret;
}
buf_len = sizeof(app_msg_t) + strlen(msg->request_id) + 1 + msg->msg_len + 1;
buf = malloc(buf_len);
if(NULL == buf){
return ret;
}
app_msg = (app_msg_t *)buf;
buf += sizeof(app_msg_t);
app_msg->msg_type = en_msg_cmd;
app_msg->msg.cmd.request_id = buf;
buf_len = strlen(msg->request_id);
buf += buf_len + 1;
memcpy(app_msg->msg.cmd.request_id, msg->request_id, buf_len);
app_msg->msg.cmd.request_id[buf_len] = '\0';
buf_len = msg->msg_len;
app_msg->msg.cmd.payload = buf;
memcpy(app_msg->msg.cmd.payload, msg->msg, buf_len);
app_msg->msg.cmd.payload[buf_len] = '\0';
ret = queue_push(g_app_cb.app_msg,app_msg,10);
if(ret != 0){
free(app_msg);
}
return ret;
}
static int task_main_entry(void)
{
app_msg_t *app_msg;
uint32_t ret ;
WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
dtls_al_init();
mqtt_al_init();
oc_mqtt_init();
g_app_cb.app_msg = queue_create("queue_rcvmsg",10,1);
if(NULL == g_app_cb.app_msg){
printf("Create receive msg queue failed");
}
oc_mqtt_profile_connect_t connect_para;
(void) memset( &connect_para, 0, sizeof(connect_para));
connect_para.boostrap = 0;
connect_para.device_id = CONFIG_APP_DEVICEID;
connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
connect_para.server_addr = CONFIG_APP_SERVERIP;
connect_para.server_port = CONFIG_APP_SERVERPORT;
connect_para.life_time = CONFIG_APP_LIFETIME;
connect_para.rcvfunc = msg_rcv_callback;
connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
ret = oc_mqtt_profile_connect(&connect_para);
if((ret == (int)en_oc_mqtt_err_ok)){
g_app_cb.connected = 1;
printf("oc_mqtt_profile_connect succed!\r\n");
}
else
{
printf("oc_mqtt_profile_connect faild!\r\n");
}
return 0;
}
static void OC_Demo(void)
{
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");
}
}
APP_FEATURE_INIT(OC_Demo);
static_library("app") {
sources = [
"iot_cloud_oc_sample.c",
"src/wifi_connect.c",
"src/E53_SC1.c"
]
cflags = [ "-Wno-unused-variable" ]
cflags += [ "-Wno-unused-but-set-variable" ]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
"//base/iot_hardware/interfaces/kits/wifiiot_lite",
"//foundation/communication/interfaces/kits/wifi_lite/wifiservice",
"//vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include/",
"//third_party/cJSON",
"//third_party/iot_link/oc_mqtt/oc_mqtt_al",
"//third_party/iot_link/oc_mqtt/oc_mqtt_profile_v5",
"//third_party/iot_link/inc",
"//third_party/iot_link/queue",
"include"
]
deps = [
"//third_party/iot_link:iot_link",
]
}
static void deal_report_msg(report_t *report)
{
oc_mqtt_profile_service_t service;
oc_mqtt_profile_kv_t luminance;
oc_mqtt_profile_kv_t led;
if(g_app_cb.connected != 1){
return;
}
service.event_time = NULL;
service.service_id = "Light";
service.service_property = &luminance;
service.nxt = NULL;
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 = NULL;
oc_mqtt_profile_propertyreport(NULL,&service);
return;
}
修改task_main_entry函数,添加红色标识代码段:
static int task_main_entry(void)
{
app_msg_t *app_msg;
uint32_t ret ;
WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
dtls_al_init();
mqtt_al_init();
oc_mqtt_init();
g_app_cb.app_msg = queue_create("queue_rcvmsg",10,1);
if(NULL == g_app_cb.app_msg){
printf("Create receive msg queue failed");
}
oc_mqtt_profile_connect_t connect_para;
(void) memset( &connect_para, 0, sizeof(connect_para));
connect_para.boostrap = 0;
connect_para.device_id = CONFIG_APP_DEVICEID;
connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
connect_para.server_addr = CONFIG_APP_SERVERIP;
connect_para.server_port = CONFIG_APP_SERVERPORT;
connect_para.life_time = CONFIG_APP_LIFETIME;
connect_para.rcvfunc = msg_rcv_callback;
connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
ret = oc_mqtt_profile_connect(&connect_para);
if((ret == (int)en_oc_mqtt_err_ok)){
g_app_cb.connected = 1;
printf("oc_mqtt_profile_connect succed!\r\n");
}
else
{
printf("oc_mqtt_profile_connect faild!\r\n");
}
while (1)
{
app_msg = NULL;
(void)queue_pop(g_app_cb.app_msg,(void **)&app_msg,0xFFFFFFFF);
if (NULL != app_msg)
{
switch (app_msg->msg_type)
{
case en_msg_report:
deal_report_msg(&app_msg->msg.report);
break;
default:
break;
}
free(app_msg);
}
}
return 0;
}
在task_main_entry函数后面,新增传感器数采处理函数:
static int task_sensor_entry(void)
{
app_msg_t *app_msg;
float Lux;
E53_SC1_Init();
while (1)
{
Lux = E53_SC1_Read_Data();
app_msg = malloc(sizeof(app_msg_t));
printf("Lux data:%f\r\n", Lux);
if (NULL != app_msg)
{
app_msg->msg_type = en_msg_report;
app_msg->msg.report.lum = (int)Lux;
if(0 != queue_push(g_app_cb.app_msg,app_msg,CONFIG_QUEUE_TIMEOUT)){
free(app_msg);
}
}
sleep(3);
}
return 0;
}
修改OC_Demo主函数,添加红色标识代码段:
static void OC_Demo(void)
{
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 = 4096;
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");
}
}
///< COMMAND DEAL
#include
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), "Light_Control_Led"))
{
obj_paras = cJSON_GetObjectItem(obj_root, "paras");
if (NULL == obj_paras)
{
goto EXIT_OBJPARAS;
}
obj_para = cJSON_GetObjectItem(obj_paras, "Led");
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("Led On!\r\n");
}
else
{
g_app_cb.led = 0;
Light_StatusSet(OFF);
printf("Led Off!\r\n");
}
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;
}
修改task_main_entry函数,添加红色标识代码段:
static int task_main_entry(void)
{
app_msg_t *app_msg;
uint32_t ret ;
WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
dtls_al_init();
mqtt_al_init();
oc_mqtt_init();
g_app_cb.app_msg = queue_create("queue_rcvmsg",10,1);
if(NULL == g_app_cb.app_msg){
printf("Create receive msg queue failed");
}
oc_mqtt_profile_connect_t connect_para;
(void) memset( &connect_para, 0, sizeof(connect_para));
connect_para.boostrap = 0;
connect_para.device_id = CONFIG_APP_DEVICEID;
connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
connect_para.server_addr = CONFIG_APP_SERVERIP;
connect_para.server_port = CONFIG_APP_SERVERPORT;
connect_para.life_time = CONFIG_APP_LIFETIME;
connect_para.rcvfunc = msg_rcv_callback;
connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
ret = oc_mqtt_profile_connect(&connect_para);
if((ret == (int)en_oc_mqtt_err_ok)){
g_app_cb.connected = 1;
printf("oc_mqtt_profile_connect succed!\r\n");
}
else
{
printf("oc_mqtt_profile_connect faild!\r\n");
}
while (1)
{
app_msg = NULL;
(void)queue_pop(g_app_cb.app_msg,(void **)&app_msg,0xFFFFFFFF);
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;
}
干得好,您已经成功完成了codelab并学到了:
您可以阅读下面链接,了解更多相关的信息:
相关文档
本Codelab中所用Demo源码下载地址如下: