设备能力描述文件 profile 开发
1)新增产品 设备的 Profile 文件是用来描述设备类型和设备服务能力的文件。定义了同一类设备具备的服务能力, 属性,命令等。
Step 1 登录开发者 Portal,单击“Profile 开发>产品”,单击页面右上角的“自定义产品”,转至“产品模板”页面。
−您可以使用模板定义您的产品,单击产品模板的“立即使用”,这里的参数需要根据您的设备进行定义。
−您也可单击右上角的“创建全新产品”,直接定义您的产品,这里以创建全新产品为例。
Step 3 在产品详情页面单击“新建服务”,根据界面提示信息,增加基本信息,属性或命令,单击“保存”。
− 新增服务基本信息,服务的名称采用驼峰的命名方式,这里以 Light 为例。描述可选,有多个服务就新增多条服务。
2)新增属性
3)新增命令 命令名称:指示设备可以执行的命令。如门磁的 Lock 命令、摄像头的 VIDEO_RECORD 命令
4)新增命令下发字段 命令名与参数 共同构成一个完整的命令,在页面上单击“新增字段”。
完成设备能力描述文件 profile 开发
设备数据编解码中间件开发(仅适用于与 NB-IoT 场景)
开发完 Profile 文件后,可以在界面上通过图形化的方式完成设备与平台之间的消息映射。在平台中 预集成了编解码插件的模板,可以根据设备类型和接入协议在插件模板中选择模板修改开发编解码插 件。 登录开发者 Portal,单击“插件开发”,单击右上角的“添加插件”,转到“插件模板”页签,单击“查 看”,您可以查看各个模板的内容。 • 若您的业务和模板中类似,可使用模板再根据实际来修改。 • 若您不需要使用模板,则可自己新建插件。下面以新建插件来说明如何开发编解码插件。使用模 板的类似修改即可。
-
新建插件
Step 1 单击上图右上角的“新建插件”,进入设计插件页面,选择前面做的 Profile
说明:您可以单击右上角的“新手指导”,查看插件的实现原理。
报)。
Step 2 新增数据上报消息。单击“新增消息”,输入消息的名称、描述和消息类型(这里选数据上
Step 3 添加字段。单击“添加字段”,添加上报数据的字段。
Step 4 新增命令下发消息。单击“新增消息”,输入消息的名称(这里以 Control 为例)、描述和 消息类型(这里选命令下发)。
Step 5 添加字段。单击“添加字段”,添加命令下发的字段。 名字:本例以 Switch 例。 数据类型:本例为 string 例。 长度:本例均以长度为 3 为例。 默认值:该字段在码流中的参考值。 偏移值:当前字段到本条消息码流起始位置的字节数,比如设置为 2-3,则这个字段在码流中的第 23 位。这个为插件设置自动分配的
Step 5 建立 profile 属性、命令与消息的映射关系。根据自己定义的 profile,来设计插件中的消 息。通过拖拉服务中的属性或命令,与消息中的字段进行关联。属性对应于数据上报中的字段列表。 有多个服务就新增多个消息。为便于理解,字段名称建议和属性名设置为相同。
Step 6 完成映射关系后,单击页面右上角的“部署”,部署成功后,系统会将您的设计结果自动生成编解码插件包。
相关信息
IoT 平台提供了设备模拟器,可以模拟真实设备发上来的消息码流,检查插件包+profile 文件是否开发正确。
Step 1 注册模拟设备
应用新增设备
开发部署成功后,您可以将您的设备接入到 IoT 平台。
Step 1 登录开发者 Portal,单击“我的设备”,进入设备列表页面。单击右上角的“注册设备”,转向注册设备页面,选择您需要注册设备的 Profile。
Step 2 单击 Profile,进入 Profile 详情页面,在页面底部填写设备名称和设备标识码,这里的设备名称可以自己取,设备标识码为模块上的 IMEI 号或者通过 AT+CGSN=1 获取,单击“注册”,完成设备的 注册。
南向设备开发接入
前置条件
下载基于 LiteOS 的源码: github.com/iot-club/EVB_M1_LiteOS
相关信息
设备接入方式:CoAP 非加密方式
AT 命令使用流程:
模组上电
设置CDP服务器地址 AT+NCDP=
发送数据 AT+NMGS=
检查是否 入网成功 AT+CGATT?
软件重启模组 AT+NRB
YES
NO
返回值等于1
300s后,AT+CGATT? 查询返回值不等于1
相关 API 调用流程:
初始化内核 LOS_KernelInit();
创建传感器数据采集任务 creat_data_collection_task();
创建NB-IoT数据上报任务 creat_data_report_task();
初始化模组 los_nb_init
注册下发命令回调函数 los_nb_notify
发送CoAP消息数据 los_nb_report
采集光照强度数据 Convert_BH1750
初始化硬件 HardWare_Init();
应用开发
串口助手 AT 命令对接平台
这部分内容是通过电脑串口调试软件,手动发 AT 指令,直接发给 NB-IoT 模块。NB 模块返回的信息, 直接到电脑串口调试软件。一步一步动手操作,实现连接 OceanConnect 平台。采用的通讯协议是CoAP 协议。 Step 1 配置对接平台地址
指令:AT+NCDP=
例:AT+NCDP= 139.159.140.34,5683
Step 2 软件重启模组
指令:AT+NRB //配置完配置对接平台地址后需要重启模块才能生效
REBOOTING
Step 3 检查是否入网成功
指令:AT+CGATT?
+CGATT:1 //返回 1 表示入网成功,返回 0 入网失败,300s 后依然为 0,则重启模组
OK
Step 4 发送数据
指令:AT+NMGS=
结果示例
LiteOS API 方式接入
这部分的通过单片机搭载华为 LiteOS 操作系统,并移植了可兼容所有 AT 指令型的 AT 框架程序,调用 AT 框架的 API 接口实现快速连接华为 OceanConnect 平台。并能实时接收平台下发的命令,实现对设备的控 制,以下讲解调用 API 实现的方式。
Step 1 分析主程序
int main(void)
{ UINT32 uwRet = LOS_OK;
HardWare_Init();
uwRet = LOS_KernelInit();
if (uwRet != LOS_OK)
{ return LOS_NOK; }
uwRet = creat_data_collection_task();
if (uwRet != LOS_OK)
{ return LOS_NOK; }
uwRet = creat_data_report_task();
if (uwRet != LOS_OK)
{ return LOS_NOK; }
LOS_Start(); }
主程序主要包括初始化硬件外设、初始化内核、创建传感器数据采集任务、创建数据上报任务,接下来讲
详细讲解主要部分的实现方式。
Step 2 初始化硬件
VOID HardWare_Init(VOID) { HAL_Init();
/* Configure the system clock /
SystemClock_Config();
/ Initialize all configured peripherals */
dwt_delay_init(SystemCoreClock);
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("Welcome to IoT-Club, This is EVB-M1 Board.\r\n"); }
首先调用 HAL_Init() 初始化 HAL 库;SystemClock_Config(),用于系统时钟的配置;再调用 MX_GPIO_Init() 初始化相应的 GPIO;最后初始化单片机 debug 串口。
Step 3 创建传感器采集任务
VOID data_collection_task(VOID)
{ UINT32 uwRet = LOS_OK;
short int Lux;
Init_BH1750();
while (1)
{
printf("This is data_collection_task !\r\n"); Lux=(int)Convert_BH1750();
printf("\r\n******************************BH1750 Value is %d\r\n",Lux);
sprintf(BH1750_send.Lux, "%5d", Lux);
uwRet=LOS_TaskDelay(1000);
if(uwRet !=LOS_OK) return; } }
这部分为传感器数据采集部分,首先是通过 Init_BH1750() 函数初始化光照传感器 BH1750 所对应的单片机 管脚及传感器。
void Init_BH1750(void) { I2C_InitGPIO();
Cmd_Write_BH1750(0x01); }
通过 Convert_BH1750() 函数采集传感器数据
float Convert_BH1750(void)
{ Start_BH1750();
LOS_TaskDelay(180);
Read_BH1750();
result=BUF[0];
result=(result<<8)+BUF[1];
result_lx=(float)(result/1.2);
return result_lx; }
最后将传感器数据以字符串的形式存入到数组中,用于发送到平台上。
sprintf(BH1750_send.Lux, "%5d", Lux);
Step 3 创建数据上报任务
VOID data_report_task(VOID)
{ UINT32 uwRet = LOS_OK;
define AT_DTLS 0
if AT_DTLS
sec_param_s sec;
sec.pskid = "868744031131026";
sec.psk = "d1e1be0c05ac5b8c78ce196412f0cdb0";
endif
printf("\r\nSTEP1: Init NB Module( NB Init )");
if AT_DTLS
los_nb_init((const int8_t)"180.101.147.115",(const int8_t)"5684",&sec); #else
los_nb_init((const int8_t)"180.101.147.115",(const int8_t)"5683",NULL);
los_nb_notify("+NNMI:",strlen("+NNMI:"),nb_cmd_data_ioctl,OC_cmd_match); LOS_TaskDelay(3000);
printf("\r\nSTEP3: Report Data to Server( NB Report )");
while(1) {
if(los_nb_report((const char*)(&BH1750_send),sizeof(BH1750_send))>=0) printf("ocean_send_data OK!\n");
else { printf("ocean_send_data Fail!\n"); }
uwRet=LOS_TaskDelay(1000); if(uwRet !=LOS_OK) return; } }
这部分程序主要包括连接平台、注册下发命令的回调函数以及上报数据到平台,以下将讲解如何实现这三 部分。 1) 连接平台 连接平台的方式分为加密和非加密两种,通过#define AT_DTLS 来实现连接方式的选择,定义为 0 时为非 加密,此教程以非加密为例讲解,实现程序如下
define AT_DTLS 0 #if AT_DTLS
sec_param_s sec; sec.pskid = "868744031131026";
sec.psk = "d1e1be0c05ac5b8c78ce196412f0cdb0";
endif printf printf("\r\nSTEP1: Init NB Module( NB Init )");
if AT_DTLS los_nb_init((const int8_t)"139.159.140.34",(const int8_t)"5684",&sec);
else los_nb_init((const int8_t)"139.159.140.34",(const int8_t)"5683",NULL);
此部分通调用 los_nb_init 函数初始化模组,等待连接网络,设置平台对接地址实现对接平台。三个参数分 别为设备对接 IP、设备对接端口以及加密的 PSK 码。
int los_nb_init(const int8_t* host, const int8_t* port, sec_param_s* psk) { int ret; int timecnt = 0; //if(port == NULL) //return -1; at.init();
nb_reboot(); LOS_TaskDelay(2000); if(psk != NULL)//encryption v1.9
{
if(psk->setpsk) nb_send_psk(psk->pskid, psk->psk); else nb_set_no_encrypt(); }
while(1) { ret = nb_hw_detect(); printf("call nb_hw_detect,ret is %d\n",ret); if(ret == AT_OK) break; //LOS_TaskDelay(1000); } //nb_get_auto_connect(); //nb_connect(NULL, NULL, NULL);
while(timecnt < 120) { ret = nb_get_netstat(); nb_check_csq(); if(ret != AT_FAILED) { ret = nb_query_ip(); break; } //LOS_TaskDelay(1000); timecnt++; } if(ret != AT_FAILED) { nb_query_ip(); } ret = nb_set_cdpserver((char *)host, (char *)port); return ret; }
2) 注册下发命令回调函数 注册下发命令回调函数可实现对平台下发命令的快速相应并处理
los_nb_notify("+NNMI:",strlen("+NNMI:"),nb_cmd_data_ioctl,OC_cmd_match);
第一个参数为要匹配数据字段,第二个参数为匹配字段的长度、第三个参数为命令回调的执行函数、第 四个为注册字段的匹配函数。
int32_t nb_cmd_data_ioctl(void* arg, int8_t * buf, int32_t len) { int readlen = 0; char tmpbuf[1064] = {0}; if (NULL == buf || len <= 0)
{ AT_LOG("param invailed!"); return -1; } sscanf((char )buf,"\r\n+NNMI:%d,%s\r\n",&readlen,tmpbuf); memset(bc95_net_data.net_nmgr, 0, 30); if (readlen > 0) { HexStrToStr(tmpbuf, bc95_net_data.net_nmgr,readlen2); } AT_LOG("cmd is:%s\n",bc95_net_data.net_nmgr); if(strcmp(bc95_net_data.net_nmgr,"ON")==0) { HAL_GPIO_WritePin(Light_GPIO_Port,Light_Pin,GPIO_PIN_RESET); } if(strcmp(bc95_net_data.net_nmgr,"OFF")==0) { HAL_GPIO_WritePin(Light_GPIO_Port,Light_Pin,GPIO_PIN_SET); } /*******************************END**********************************************/ return 0; }
命令回调处理函数主要实现命令的解析以及实现控制相应的设备,此处以控制 LED 灯为例 int32_t OC_cmd_match(const char buf, char featurestr,int len)
{
if(strstr(buf,featurestr) != NULL) return 0; else return -1;
} 注册字段匹配函数用于验证数据是否与注册字段匹配/
3) 上报数据 while(1)
{
if(los_nb_report((const char)(&BH1750_send),sizeof(BH1750_send))>=0)
printf("ocean_send_data OK!\n");
{ printf("ocean_send_data Fail!\n"); }
uwRet=LOS_TaskDelay(1000);
if(uwRet !=LOS_OK) return; } 上报数据调用的 API 为 los_nb_report 填入的参数为数据与数据长度,这个函数里封装了发送 coap 消息 的 AT 指令以及查询发送的消息量的 AT 指令 int32_t nb_send_payload(const char buf, int len)
{ char cmd1 = "AT+NMGS="; char cmd2 = "AT+NQMGS\r"; int ret; char str = NULL; int curcnt = 0; int rbuflen; static int sndcnt = 0; if(buf == NULL || len > AT_MAX_PAYLOADLEN) { AT_LOG("payload too long"); return -1; } memset(tmpbuf, 0, AT_DATA_LEN); memset(wbuf, 0, AT_DATA_LEN); str_to_hex(buf, len, tmpbuf); memset(rbuf, 0, AT_DATA_LEN); snprintf(wbuf, AT_DATA_LEN,"%s%d,%s%c",cmd1,(int)len,tmpbuf,'\r'); ret = at.cmd((int8_t)wbuf, strlen(wbuf), "OK", NULL,NULL); if(ret < 0) return -1; ret = at.cmd((int8_t*)cmd2, strlen(cmd2), "SENT=", rbuf,&rbuflen); if(ret < 0) return -1; str = strstr(rbuf,"SENT="); if(str == NULL) return -1; sscanf(str,"SENT=%d,%s",&curcnt,wbuf); if(curcnt == sndcnt) return -1; sndcnt = curcnt; return ret; }
程序编写完后烧录程序并打开串口助手可看到以下结果
结果示例
日志输出串口波特率为 115200
应用平台显示数据
命令下发
⚫ 回到设备列表,进入下发命令界面
设置 LED 下发控制命令。