NB-IoT 智慧路灯开发

设备能力描述文件 profile 开发
1)新增产品 设备的 Profile 文件是用来描述设备类型和设备服务能力的文件。定义了同一类设备具备的服务能力, 属性,命令等。
Step 1 登录开发者 Portal,单击“Profile 开发>产品”,单击页面右上角的“自定义产品”,转至“产品模板”页面。
−您可以使用模板定义您的产品,单击产品模板的“立即使用”,这里的参数需要根据您的设备进行定义。
−您也可单击右上角的“创建全新产品”,直接定义您的产品,这里以创建全新产品为例。

Step 2 根据实际填写“设备类型”、“设备型号”、“厂商 ID”、“厂商名称”等数据。单击“确定”,添加产品完成。

Step 3 在产品详情页面单击“新建服务”,根据界面提示信息,增加基本信息,属性或命令,单击“保存”。
− 新增服务基本信息,服务的名称采用驼峰的命名方式,这里以 Light 为例。描述可选,有多个服务就新增多条服务。
2)新增属性

3)新增命令 命令名称:指示设备可以执行的命令。如门磁的 Lock 命令、摄像头的 VIDEO_RECORD 命令

4)新增命令下发字段 命令名与参数 共同构成一个完整的命令,在页面上单击“新增字段”。



完成设备能力描述文件 profile 开发
设备数据编解码中间件开发(仅适用于与 NB-IoT 场景)
开发完 Profile 文件后,可以在界面上通过图形化的方式完成设备与平台之间的消息映射。在平台中 预集成了编解码插件的模板,可以根据设备类型和接入协议在插件模板中选择模板修改开发编解码插 件。 登录开发者 Portal,单击“插件开发”,单击右上角的“添加插件”,转到“插件模板”页签,单击“查 看”,您可以查看各个模板的内容。 • 若您的业务和模板中类似,可使用模板再根据实际来修改。 • 若您不需要使用模板,则可自己新建插件。下面以新建插件来说明如何开发编解码插件。使用模 板的类似修改即可。
  1. 新建插件
    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=<ip_addr>[,<port>]
发送数据 AT+NMGS=<length>,<data>
检查是否 入网成功 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=<ip_addr>[,<port>] <ip_addr>:填写平台设备接入地址 <port>:填写接入方式的端口号
例: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=<length>,<data>
<length>:数据长度 <data>:数据(十六进制格式)
结果示例

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 下发控制命令。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 家传的佛珠,漆黑扎眼。有股檀香。 母亲交给他时,他考上大学,正准备上学。母亲颤微微的递给他时,他感觉到无形的压力。...
    邵村树阅读 711评论 0 1
  • 《房子不是随便盖的》第8期(收听节目点这里) 我国古代,帝王都有求仙问道的习惯。无论是秦皇汉武,还是唐宗宋祖都参与...
    畅听旅行阅读 643评论 0 0
  • 这两天迷茫颓废,目光呆滞,困倦乏力,简直无法因果语言来形容! 前脚跟我说完的事儿后脚就忘了!早上吃完饭,中午想...
    猫公主喵阅读 215评论 1 1