01 概述

NB-IoT

NB-IoT(Narrow Band Internet of Things)是一种基于蜂窝的窄带物联网技术,支持低功耗设备在低功耗广域物联(LPWAN)进行蜂窝数据连接。

LWM2M协议

LwM2M的全称是Lightweight Machine-To-Machine,是由OMA(Open Mobile Alliance)组织制定的轻量化协议,主要面向基于蜂窝的窄带物联网(NB-IoT)场景下物联网应用。

  1. 基本架构和接口

1.1 逻辑实体

  • LWM2M Server(接入机):平台服务器接口;
  • LWM2M client(客户端):负责执行服务器 的命令和上报执行结果;
  • Bootstrap server(引导机):负责 配置 LWM2M 客户端。
    1.2 逻辑接口
  • Bootstrap(引导接口):向LwM2M客户端提供注册到LwM2M服务器的必要信息;
  • Client Registration(客户端注册接口):使LwM2M客户端与LwM2M服务器互联,将LwM2M客户端的相关信息存储在LwM2M服务器上;
  • Device Management and Service Enablement(设备管理与服务实现接口): 主控方为LwM2M服务器,服务器向客户端发送指令,客户端对指令做出回应并将回应消息发送给服务器;
  • Information Reporting(信息上报接口):允许LwM2M服务器端向客户端订阅资源信息,客户端接收订阅后按照约定的模式向服务器端报告自己的资源变化情况。
  1. 特点

  • 基于REST架构;
  • 消息传递是通过CoAP协议来实现的;
  • 定义了一个紧凑高效又不乏扩展性的数据模型。
  1. 对象和资源
    LwM2M协议定义了一个以资源(Resource)为基本单位的模型,每个资源都可以携带数值,可以指向地址,以表示LwM2M客户端中每一项可用的信息。而资源都存在于对象实例中(Object Instance),即对象(Object)的实例化。
    LwM2M协议预定义了8种对象(Object)来满足基本的需求,分别是:
Object Object ID
Security(安全对象) 0
Server(服务器对象) 1
Access Control(访问控制对象) 2
Device(设备对象) 3
Connectivity Monitoring(连通性监控对象) 4
Firmware(固件对象) 5
Location(位置对象) 6
Connectivity Statistics(连通性统计对象) 7

在客户端向平台注册的阶段,LwM2M客户端把携带了资源信息的对象实例传递给LwM2M服务器,以通知服务器自身设备所具备的能力。

OneNET平台

OneNET是中国移动的IoT物联网平台,提供多种协议接入和应用。其中移动 OneNET 平台的NB-IoT就是采用基于上述 NB-IOT 的 LWM2M 协议和 CoAP 协议实现 UE(User Equipment) 与平台的通信,其中 LWM2M 协议为应用层协议,CoAP 协议为传输层协议。

  1. OneNET LwM2M对象和资源
    OneNET针对LwM2M协议提供丰富的对象(object)和属性(resource),对象和属性的定义基于OMA规范做了部分修改,具体可以查看OneNET LwM2M对象和属性。
  • Digital Input(数字输入对象)
    object:3200
    resource:

    id name type
    5500 Digital Input State boolean
    5501 Digital Input Counter integer
    5502 Digital Input Polarity boolean
    5503 Digital Input Debounce integer
    5504 Digital Input Edge Selection integer
    5750 Application Type string
    5751 Sensor Type string
  • Analog Input(模拟输入对象)
    object:3202
    resource:

    id name type
    5600 Analog Input Current Value float
    5601 Min Measured Value float
    5602 Max Measured Value float
    5603 Min Range Value float
    5604 Max Range Value float
    5750 Application Type string
    5751 Sensor Type string

以上是列举的部分对象和资源,操作时需要注意资源的读写属性。
2. 设备接入流程
2.1 准备工作

  • 物联网SIM卡
    如果我们选择的物联网卡运营商为中国移动,那么就可以和OneNET平台无缝对接,如果是联通或电信,则需要开通相应限制。
  • 实现了OneNET对应接口固件的MCU
  • 移植好OneNET平台SDK的NB通信模组
    2.2 设备接入步骤
  • OneNET平台创建产品和设备
  • 设备软硬件初始化
  • 创建设备和资源
  • 注册到OneNET平台
  • 平台完成订阅和发现设备资源

02 实现

硬件设计

  1. BC26模块设计
    这个大家可以参考官方的《硬件设计手册》,下面列举一般的应用电路。
  • 供电电路
    在靠近VBAT输入端增加一个TVS 管以提高模块的浪涌电压承受能力。

  • 串口通信电路
    因为模块的串口电压域为1.8V,所以应用到非1.8V的系统,需要进行电平转换,可以用专门的电平转换芯片,也可以自己搭转换电路。

  • 开机电路

  • 复位电路

  • 网络状态指示电路

  • USIM卡电路
    在外部USIM 卡座的引脚增加TVS 管,确保有良好的ESD防护性能。

  • 天线电路
    默认情况下,C1、C2 不贴,只在R1 贴0 欧姆电阻。


2. 整体硬件设计
供电后,接入MCU的UART和POWER_EN、PWRKEY、RESET、PSM EINT的控制信号即可对模块进行操控。

固件设计

BC26模块配置

  1. AT指令收发
/** 根据AT指令手册枚举指令表*/
typedef enum
{/** product info*/AT_CMD,ATI_CMD,AT_CGMI_CMD,AT_CGMM_CMD,AT_CGMR_CMD,AT_CGSN_Q_CMD,AT_CCLK_Q_CMD,/** ...*//** oneNET*/AT_MIPLCONFIG_CMD,AT_MIPLCREATE_CMD,AT_MIPLDELETE_CMD,AT_MIPLVER_CMD,AT_MIPLADDOBJ_CMD,AT_MIPLDELOBJ_CMD,AT_MIPLRD_CMD,AT_MIPLOPEN_CMD,AT_MIPLCLOSE_CMD,AT_MIPLDISCOVERRSP_CMD,AT_MIPLOBSERVERSP_CMD,AT_MIPLREADRSP_CMD,AT_MIPLREAD_CMD,AT_MIPLWRITERSP_CMD,AT_MIPLWRITE_CMD,AT_MIPLEXECUTERSP_CMD,AT_MIPLPAPAMETERRSP_CMD,AT_MIPLNOTIFY_CMD,AT_MIPLUPDATE_CMD,
} AT_CMT_T;
/** AT指令发送*/
/*!* @brief       Send AT command** @param       cmdType** @param       cmdBuffer** @retval      error**/
int BC26_ATCmdSend(uint8_t cmdType, AT_CMD_BUF_T cmdBuffer)
{char cmdStr[100];char lineEnd[] = "\r\n";switch(cmdType){case AT_CMD:sprintf(cmdStr, "AT%s", lineEnd);break;case ATI_CMD:sprintf(cmdStr, "ATI%s", lineEnd);break;case AT_CIMI_CMD:sprintf(cmdStr, "AT+CIMI%s", lineEnd);break;case AT_CGSN_Q_CMD:sprintf(cmdStr, "AT+CGSN=%d%s", cmdBuffer.Int[0], lineEnd);break;/** ...*/case AT_MIPLWRITERSP_CMD:sprintf(cmdStr, "AT+MIPLWRITERSP=%d,%d,%d%s",cmdBuffer.Int[0],cmdBuffer.Int[1],cmdBuffer.Int[2],lineEnd);printf(">> %s\r\n",cmdStr);break;default:return 1;}LPUART1_SendStr(cmdStr);return 0;
}
/** AT指令接收*/
/*!* @brief       Get AT ack** @param       cmdType** @param       timeout** @param       waitTime** @retval      None**/
void BC26_ATAckGet(uint8_t cmdType, uint16_t timeout, uint16_t waitTime)
{char *atAckStr;char atAckStr1[100];char atAckStr2[20];int atAckNum[11];float atAckFltNum[10];uint8_t timeoutFlag = 0;switch(cmdType){case AT_CMD:Delay_ms(waitTime);while(timeout){atAckStr = strstr((const char*)rxBufLPUART1, (const char*)"OK");if(atAckStr == NULL){Delay_ms(1);timeout--;if(timeout == 0){timeoutFlag = 1;}}else{printf("<< %s",atAckStr);break;}}break;case ATI_CMD:Delay_ms(waitTime);while(timeout){atAckStr = strstr((const char*)rxBufLPUART1, (const char*)"Quectel_Ltd");sscanf(atAckStr, "%*[^\n]\n%[^\r]%*[^:]:%[^\r]", atAckStr1,atAckStr2);if(atAckStr == NULL){Delay_ms(1);timeout--;if(timeout == 0){timeoutFlag = 1;}}else{printf("<< ET:%s\r\n",atAckStr1);printf("<< Rev:%s\r\n",atAckStr2);break;}}break;/** ...*/    case AT_MIPLWRITERSP_CMD:Delay_ms(waitTime);while(timeout){atAckStr = strstr((const char*)rxBufLPUART1, (const char*)"OK");if(atAckStr == NULL){Delay_ms(1);timeout--;if(timeout == 0){timeoutFlag = 1;}}else{printf("<< %s",atAckStr);break;}}break;default:break;}if(timeoutFlag){g_errorFlag = ERR_TIMEOUT;}memset(rxBufLPUART1,0,LPUART1_REV_LEN);rxStaLPUART1.USART_RX_STA_B.VALID_LENGHT = 0;timeoutFlag = 0;
}
  1. BC26模块初始化
/*!* @brief       Init BC26 module** @param       None** @retval      error**/
int BC26_Init(void)
{AT_CMD_BUF_T cmdBuffer;/** 自动匹配波特率*/printf("Auto match boudrate\r\n");Delay_ms(200);cmdBuffer.Int[0] = 0;BC26_ATCmdSend(AT_CMD,cmdBuffer);BC26_ATAckGet(AT_CMD,100,100);BC26_ATCmdSend(AT_CMD,cmdBuffer);BC26_ATAckGet(AT_CMD,100,100);BC26_ATCmdSend(AT_CMD,cmdBuffer);BC26_ATAckGet(AT_CMD,100,100);if(BC26_ErrorHandler()){return 1;}BC26_ATCmdSend(ATI_CMD,cmdBuffer);BC26_ATAckGet(ATI_CMD,500,500);BC26_ATCmdSend(AT_CIMI_CMD,cmdBuffer);BC26_ATAckGet(AT_CIMI_CMD,200,500);cmdBuffer.Int[0] = CGSN_IMEI;BC26_ATCmdSend(AT_CGSN_Q_CMD,cmdBuffer);BC26_ATAckGet(AT_CGSN_Q_CMD,200,500);BC26_ATCmdSend(AT_CGATT_CMD,cmdBuffer);BC26_ATAckGet(AT_CGATT_CMD,200,500);BC26_ATCmdSend(AT_QBAND_CMD,cmdBuffer);BC26_ATAckGet(AT_QBAND_CMD,200,500);BC26_ATCmdSend(AT_CSQ_CMD,cmdBuffer);BC26_ATAckGet(AT_CSQ_CMD,200,500);BC26_ATCmdSend(AT_CEREG_Q_CMD,cmdBuffer);BC26_ATAckGet(AT_CEREG_Q_CMD,200,500);cmdBuffer.Int[0] = 1;BC26_ATCmdSend(AT_CGPADDR_S_CMD,cmdBuffer);BC26_ATAckGet(AT_CGPADDR_S_CMD,200,500);if(BC26_ErrorHandler()){return 1;}return 0;
}

OneNET平台接口设计

OneNET平台支持LWM2M和IPSO定义的资源模型,用户需根据传感器类型从这两种标准中选择适合的资源模型。资源模型为Object / Instance / Resource三层结构。

  • Object(对象):表示某类传感器类型。
  • Instance(实例):同一类传感器的数量。
  • Resource(属性):传感器某些特性描述。
    设备在应用程序中创建完设备(dev)后,还需要创建object以及对应的instance和resource。
  1. 创建对象和资源
    可以将原本的AI、DI对象的资源项用于自身项目的资源。
/*!* @brief oneNET平台对象属性和燃气表数据的对照表*        对象      属性名      属性类型      操作类型              燃气表数据 *     AI(3202)   AICV(5600)     float          R            standardConditionFlow*     AI(3202)   MinMV(5601)    float          R                   NONE*     AI(3202)   MamMV(5602)    float          R                   NONE*     AI(3202)   MinRV(5603)    float          R                   NONE*     AI(3202)   MaxRV(5604)    float          R                   NONE*     AI(3202)   AT(5750)       string        W/R              gasUnitPrice*     AI(3202)   ST(5751)       string         R                   NONE**     DI(3200)   State(5500)    bool           R                   NONE*     DI(3200)   Counter(5501)  int            R                gasMeterStatus*     DI(3200)   Polarity(5502) bool          W/R               airValCTRL*     DI(3200)   Debounce(5503) int           W/R               gasSerialNum*     DI(3200)   ES(5504)       int           W/R               gasProductID*     DI(3200)   AT(5750)       string        W/R               gasMoney*     DI(3200)   ST(5751)       string         R                   NONE*/
  1. 平台注册操作
    以下是设备注册到注销注册的通信过程。
AT+MIPLCREATE
+MIPLCREATE: 0                     //成功创建通信套件实例。
OK
AT+MIPLADDOBJ=0,3200,"1",1,7,0    //添加LwM2M 对象。
OK                                //成功添加对象,且将注册ID 为0 的实例。
AT+MIPLOPEN=0,100                 //向OneNET 发送注册请求。
OK
+MIPLEVENT: 0,1 //开始连接到Bootstrap 服务器。
+MIPLEVENT: 0,2 //成功连接到Bootstrap 服务器。
+MIPLEVENT: 0,4 //成功连接到OneNET 平台。
+MIPLEVENT: 0,6 //成功注册到OneNET 平台。
+MIPLOBSERVE: 0,69234,1,3200,0,-1 //接收到订阅请求(3311/0)。
AT+MIPLOBSERVERSP=0,69234,1 //响应订阅请求,其结果码为1。
OK
+MIPLDISCOVER: 0,26384,3200 //接收到发现资源请求。
AT+MIPLDISCOVERRSP=0,26384,1,34,"5500;5501;5502;5503;5504;5750;5751"  //使用资源ID 列表响应发现资源请求。
OK
AT+MIPLDELOBJ=0,3200 //删除LwM2M 对象。
OK
AT+MIPLCLOSE=0 //向OneNET 平台发送注销请求。
OK
+MIPLEVENT: 0,15 //成功注销。
AT+MIPLDELETE=0
OK //成功删除通信套件实例。
  1. 数据上报
    注意MsgID号要和注册时下发的一致。
AT+MIPLNOTIFY=0,69234,3200,0,5501,3,4,29416122,0,0 //上报资源数据。
OK
  1. 读资源响应
+MIPLREAD: 0,3123,3200,0,5501 //接收到读取资源请求。
AT+MIPLREADRSP=0,3123,1,3299,0,5501,3,4,29416122,0,0 /响应读取请求。
OK //成功发送数据29416122到应用服务器。
  1. 写资源响应
+MIPLWRITE: 0,38017,3200,0,5750,2,5,3132333435,0,0 //接收到写入资源请求,写入12345。
AT+MIPLWRITERSP=0,38017,2 //响应写入请求,其结果码为2。
OK

OneNET平台配置

平台端创建的设备是真实设备在平台端的映射,用户可以通过平台端的“虚拟设备”对真实设备进行信息查询、命令下发、数据流管理、添加触发器等操作。

  1. 创建产品
    进入OneNET平台控制台后,点击”添加产品”按钮。在弹出页面中按照提示填写产品的基本信息,进行产品创建。

联网方式:NB-IoT;
设备接入协议选择:LWM2M;
操作系统选择:无;
网络运营商选择:移动。
这里以用移动物联网sim卡为例,最后点击确定即可完成产品的创建。

  1. 添加设备
    完成产品的创建后,点击“设备列表”,然后选择“添加设备”。填入IMEI、IMSI等信息,并开启“自动订阅”。如果开启自动订阅功能,平台会在设备注册成功后,下发指令获取设备的资源信息。

  1. 设备硬件初始化
    设备在上电以后,需要完成设备的软硬件初始化。硬件初始化包括各个硬件模块的上电、处理器的寄存器初始化、工作模式初始化等等。软件初始化包括基础通信套件初始化、应用接口初始化、应用程序初始化等等。

  2. 设备对象和资源的创建
    如上述创建对象和资源所述。

  3. 设备注册到平台
    设备的基础通信套件完成初始化以及设备资源创建完成后,可向OneNET平台上报注册请求的注册码,服务器在收到登录请求的注册码后,会验证注册码中的参数,返回注册结果。若设备注册成功,则产品的“在线状态”会变为“在线”标识。

  1. 平台订阅
    开启“自动订阅”功能后,设备注册到平台后,OneNET平台会向设备下发Observer消息。设备收到这条消息后,需要相应响应平台。

  1. 发现设备资源
    平台侧默认不开启自动发现设备资源,需要用户手动“更新实例”。点击更新后,平台和向设备下发Discover消息。设备收到这条消息后,需要相应响应平台。

若要平台自动发现资源,则需要在“设备列表”中开启“自动发现资源”选项。

下图是已经更新好资源的设备。

03 应用

小程序应用设计

平台数据推送

平台以HTTPS POST请求形式向第三方应用平台注册地址推送数据,推送数据相关信息以JSON串的形式置于HTTPS请求中的body部分。

  1. 消息
    消息有两种消息类型,分别为数据点消息和设备上下线消息。而数据点消息又分为单条数据点消息和数据点消息批量形式,数据点消息批量形式中的不同数据点是以不同时间戳区分的。
//数据点消息
{"errno": 0,"data": {"update_at": "2022-01-27 12:35:43","id": "3200_0_5504","create_time": "2022-01-17 14:11:24","current_value": 102304069},"error": "succ"
}
//数据流消息
{"errno":0,"data":{"cursor":"25971_564280_1448961152173","count":5,"datastreams":[{"datapoints":[{"at":"2022-03-01 17:10:24.981","value":"35"},{"at":"2022-03-01 17:10:53.406","value":"38"},...],"id":"3200_0_5501"},...]},"error":"succ"
}
  1. 消息相关字段说明
    相关字段可以查询OneNET平台文档,这里不赘述。

API接口

这里只列举读写资源相关的API,详细的API介绍,大家可以查看官方文档。

  1. 平台相关API
  • 查询设备信息

    项目 描述
    HTTP方法 GET
    URL https://api.heclouds.com/devices/<device_id>
    HTTP头部 api-key:xxxx-ffff-zzzzz,必须为可查看该设备的Key
    Content-Type:application/json
    请求返回 {
    “errno”: 0,
    “data”: {
    “area”: “3”,
    “private”: false,
    “create_time”: “2022-01-09 17:40:53”,
    “act_time”: “2022-01-09 17:42:52”,
    “obsv”: true,
    “auth_info”: {
    “863409058100099”: “460044813808442”
    },
    “last_ct”: “2022-01-10 21:57:58”,
    “imsi”: “460044813808442”,
    “title”: “GeehyGasMeter02”,
    “tags”: [],
    “manufacturer”: “移远通信”,
    “obsv_st”: false,
    “protocol”: “LWM2M”,
    “rg_id”: “863409058100099”,
    “imsi_old”: [
    “460044813808442”
    ],
    “online”: false,
    “location”: {
    “lat”: 0,
    “lon”: 0
    },
    “id”: “878229973”,
    “datastreams”: [
    {
    “create_time”: “2022-01-09 17:43:40”,
    “uuid”: “5cad4abc-c25a-46bd-b0e7-7f0fe7c843dd”,
    “id”: “3303_0_5700”
    },
    {
    “create_time”: “2022-01-09 20:21:40”,
    “uuid”: “b8a891af-c714-415e-ac83-0d8b83c06f82”,
    “id”: “3200_0_5501”
    },
    {
    “create_time”: “2022-01-09 20:23:11”,
    “uuid”: “4d2d2f9a-07fb-4555-b609-ef04258e3396”,
    “id”: “3200_0_5500”
    },
    {
    “create_time”: “2022-01-09 20:45:05”,
    “uuid”: “c26488b6-c394-4507-8fb9-23e207c7f94b”,
    “id”: “3202_0_5600”
    },
    {
    “create_time”: “2022-01-09 20:45:14”,
    “uuid”: “85d877f4-40b0-48a4-9bb2-77f40d6016ad”,
    “id”: “3202_0_5601”
    },
    {
    “create_time”: “2022-01-09 20:45:18”,
    “uuid”: “b419c823-d7ad-4426-9b43-19eebf45dcd8”,
    “id”: “3202_0_5602”
    },
    {
    “create_time”: “2022-01-09 20:45:21”,
    “uuid”: “0f0785c8-658c-4d58-90b4-7806606e1b41”,
    “id”: “3202_0_5603”
    },
    {
    “create_time”: “2022-01-09 20:45:23”,
    “uuid”: “28c67b22-f680-48e6-b6b3-0f570f48fa69”,
    “id”: “3202_0_5604”
    }
    ],
    “desc”: “”
    },
    “error”: “succ”
    }
  • 读数据点

    项目 描述
    HTTP方法 GET
    URL https://api.heclouds.com/devices/<device_id>/datastreams/
    HTTP头部 api-key:xxxx-ffff-zzzzz //必须为MasterKey
    HTTP参数 “resource_id”:3200_0_5504, //资源ID号,必填
    HTTP响应响应消息内容 {
    “errno”: 0,
    “data”: {
    “update_at”: “2022-01-27 12:35:43”,
    “id”: “3200_0_5504”,
    “create_time”: “2022-01-17 14:11:24”,
    “current_value”: 102304069
    },
    “error”: “succ”
    }
    说明 1、响应消息中errno表示错误码,error表示错误原因。
  • 写数据点

    项目 描述
    HTTP方法 POST
    URL https://api.heclouds.com/devices/<device_id>/datapoints
    HTTP头部 api-key:xxxx-ffff-zzzzz //必须为MasterKey
    HTTP参数 {
    “datastreams”: [{
    “id”: “3200_0_5502”,
    “datapoints”: [{
    “at”: “2022-01-28T00:32:43”,
    “value”: 1
    }
    ]
    }
    ]
    }
    HTTP内容 {
    “datastreams”: [{
    “id”: “3200_0_5502”,
    “datapoints”: [{
    “at”: “2022-01-28T00:32:43”,
    “value”: 1
    }
    ]
    }
    ]
    }
    HTTP响应响应消息内容 {
    “errno”: 0,
    “error”: “succ”
    }
    说明 1、响应消息中errno表示错误码,error表示错误原因。
  1. 设备相关API
  • 即时命令 - 读设备数据点

    项目 描述
    HTTP方法 GET
    URL https://api.heclouds.com/nbiot
    HTTP头部 api-key:xxxx-ffff-zzzzz //必须为MasterKey
    HTTP参数 “imei”:121, // nbiot设备的身份码,必填
    "obj_id":1212, //设备的object ID对应到平台模型中为数据流id,必填
    "obj_inst_id": 1212, // nbiot设备object下具体一个instance的id ,对应到平台模型中数据点key值的一部分,选填
    "res_id": 2122 ,// nbiot设备的资源id,选填
    HTTP响应响应消息内容 {
    “errno”: 0,
    “error”: “succ”,
    “data”: [{
    “obj_inst_id”:123,
    “res”:[
    {
    “res_id”:1234,
    “val”: Object //可为boolean、string、long、double类型数据
    },
    ………
    ]
    },
    ………
    ]
    }
    说明 1、响应消息中errno表示错误码,error表示错误原因。
  • 即时命令 - 写设备数据点

    项目 描述
    HTTP方法 POST
    URL https://api.heclouds.com/nbiot
    HTTP头部 api-key:xxxx-ffff-zzzzz //必须为MasterKey
    HTTP参数 “imei”:121, // nbiot设备的身份码,必填
    "obj_id":1212, //设备的object ID对应到平台模型中为数据流id,必填
    "obj_inst_id": 1212, // nbiot设备object下具体一个instance的id ,对应到平台模型中数据点key值的一部分,选填
    "mode": 1
    HTTP内容 {
    “data”:[
    {
    “res_id”:5502,
    “val”:true
    }
    ]
    }
    HTTP响应响应消息内容 {
    “errno”: 0,
    “error”: “succ”
    }
    说明 1、响应消息中errno表示错误码,error表示错误原因。
  • 缓存命令 - 读设备数据点

    项目 描述
    HTTP方法 GET
    URL http://api.heclouds.com /nbiot/offline
    HTTP头部 api-key:xxxx-ffff-zzzzz //必须为MasterKey
    HTTP参数 “imei”:121, // nbiot设备的身份码,必填
    "obj_id":1212, //设备的object ID对应到平台模型中为数据流id,必填
    "obj_inst_id": 1212, // nbiot设备object下具体一个instance的id ,对应到平台模型中数据点key值的一部分,选填
    "res_id": 2122 ,// nbiot设备的资源id,选填
    “valid_time”: “2022-03-01T17:30:00”,//命令开始生效时间,必填且大于当前时间
    “expired_time”: “2022-03-02T17:30:00”,//命令过期时间,必填且大于valid_time
    “retry”:3 // [3-10]之间,表示失败重试次数(等待下一次设备update或者上线),必填
    HTTP响应响应消息内容 {
    “errno”: 0,
    “error”: “succ”,
    “data”: {
    “uuid”: “f195c6d1-7035-5747-a4ce-b6f6b09a2d73”
    }
    }
    说明 1、响应消息中errno表示错误码,error表示错误原因。
  • 缓存命令 - 写设备数据点

    项目 描述
    HTTP方法 POST
    URL https://api.heclouds.com /nbiot/offline
    HTTP头部 api-key:xxxx-ffff-zzzzz,//必须为MasterKey
    Content-Type:application/json
    HTTP参数 “imei”:121, // nbiot设备的身份码,必填
    "obj_id":1212, //设备的object id , 对应到平台模型中为数据流id,必填
    "obj_inst_id": 1212, // nbiot设备object下具体一个instance的id ,对应到平台模型
    中数据点key值的一部分,必填
    "mode": 1
    “valid_time”: “2022-03-01T17:30:00”, //命令开始生效时间,必填大于当前时间
    “expired_time”: “2022-03-02T17:30:00”,//命令过期时间,必填且大于valid_time
    “retry”:3 //[3-10]之间,表示失败重试次数(等待下一次设备update或者上线),必填
    HTTP内容 {
    “data”: [{
    “res_id”:123,
    “type”:1, //可选,目前只支持为1,此时数据为十六进制字符串
    "val":Object //可为boolean、string、long、double
    },
    {…},

    ]
    }
    HTTP响应响应消息内容 {
    “errno”: 0,
    “error”: “succ”,
    “data”: {
    “uuid”: “432a877d-53ab-5dbb-8c51-4853f65d94fb”
    }
    }
    说明 1、响应消息中errno表示错误码,error表示错误原因。

API测试工具

在开始小程序应用设计之前,我们需要用一些API测试工具来验证相关API接口是否正确。一般我们会用到“Fiddler”或者“ApiPost”这两款软件。

  1. ApiPost使用方法

    以读取平台数据点为例。新建API接口,选择HTTP方法为GET,填入读取平台数据点的URL。然后在HTTP头部填入api-key,最后点击”发送“按钮,即可获得平台的实时响应。

  1. Fiddler使用方法

以读取平台数据点为例。在“组合器”选项卡选择HTTP方法为GET,填入读取平台数据点的URL。然后在HTTP头部填入api-key,最后点击”执行“按钮。

等待一会即可在左侧的“查看器”看到响应。双击响应之后,可以查看JSON串等详细信息。

小程序的UI设计

这里只列举部分UI,以气度数为例。

  • 在.js页面文件中定义并初始化数据变量。
Page({/*** 页面的初始数据*/data: {device_info:{flowQty:0,serialNum:0,productID:0,stdFlow:0.0,gasMoney:0.0,gasUnitPrice:0.0,gasMeterStatus:0,gasOnlineStatus:0,airValSta:false,//气度数stdFlowArr: [0,0,0,0,0,0,0,0],deviceName:"str",apiKey:"str",deviceID:0,deviceIMEI:0,deviceIMSI:0,deviceConnectStatus:false},},
}
  • 设计好UI并将页面数据绑定。
<view class="bg-white margin-top"><view class="flex flex-wrap solid-bottom padding-top padding-bottom align-center"><view class="basis-xs padding-left"><text class="text-cut">气度数:</text></view><view class="basis-lo justify-start text-center"><view class="grid col-10 align-center"><view class="bg-green-gs number-gs-f"><text class="text-white">{{gas_meter_info.stdFlowArr[0]}}</text></view><view class="bg-green-gs number-gs"><text class="text-white">{{gas_meter_info.stdFlowArr[1]}}</text></view><view class="bg-green-gs number-gs"><text class="text-white">{{gas_meter_info.stdFlowArr[2]}}</text></view><view class="bg-green-gs number-gs"><text class="text-white">{{gas_meter_info.stdFlowArr[3]}}</text></view><view class="bg-green-gs number-gs"><text class="text-white">{{gas_meter_info.stdFlowArr[4]}}</text></view><view class="bg-green-gs number-gs"><text class="text-white">.</text></view><view class="bg-orange-gs number-gs"><text class="text-white">{{gas_meter_info.stdFlowArr[5]}}</text></view><view class="bg-orange-gs number-gs"><text class="text-white">{{gas_meter_info.stdFlowArr[6]}}</text></view><view class="bg-orange-gs number-gs"><text class="text-white">{{gas_meter_info.stdFlowArr[7]}}</text></view><view class="padding-left"><text>m³</text></view></view></view></view>
</view>

小程序的API请求实现

  1. 基础信息定义
    定义平台API和设备名称、接口等信息。
//onenet device info
var Test01 = {deviceName:"Test 01",apiKey:"XD=MV2btSD8Es022II=2hSKgM4=",deviceID:897824175,deviceIMEI:0,deviceIMSI:0,deviceConnectStatus:false,
}const Host = "api.heclouds.com"
//get/post datapoints
const datapointsInfoURL = "https://api.heclouds.com/devices/"
const deviceInfoURL = "https://api.heclouds.com/devices/"
//get/post device resource cmd
const devResourceURL = "https://api.heclouds.com/nbiot?imei="    //在线
const devResOfflineURL = "http://api.heclouds.com/nbiot/offline?imei="  //离线const stdFlowID = "3202_0_5600"        //标况量
const moneyID = "3200_0_5750"          //余额
  1. 获取设备信息
getDeviceInfo:function(e) {var that = thiswx.request({url: deviceInfoURL + Test01.deviceID,header: {"api-key": Test01.apiKey},data: {},method:"GET",success(res) {console.log("**********getDeviceInfo start***********")console.log(res)Test01.deviceIMEI = res.data.data.rg_idTest01.deviceIMSI = res.data.data.imsiif (res.data.data.online) {Test01.deviceConnectStatus = truethat.setData({"device_info[1].devOnlineStatus":1})console.log("online:%s",that.data.onlineStatus[that.data.device_info[1].gasOnlineStatus])} else {Test01.deviceConnectStatus = falsethat.setData({"device_info[1].gasOnlineStatus":0})console.log("offline:%s",that.data.onlineStatus[that.data.device_info[1].gasOnlineStatus])}that.data.device_info[1].deviceName = Test01.deviceNamethat.data.device_info[1].apiKey = Test01.apiKeythat.data.device_info[1].deviceID = Test01.deviceIDthat.data.device_info[1].deviceIMEI = Test01.deviceIMEIthat.data.device_info[1].deviceIMSI = Test01.deviceIMSIthat.data.device_info[1].deviceConnectStatus = Test01.deviceConnectStatus},fail(res) {console.log("getDeviceInfo 请求失败")app.showToast("请求数据失败")Test01.deviceConnectStatus = falsethat.data.device_info[1].deviceConnectStatus = false},complete() {console.log("**********getDeviceInfo end***********")}})}
  1. 读写平台数据
  • 读取平台数据点
getPlatfromDatapoint:function(apiKey, deviceID, objID, objInsID, resID) {var that = thisvar getUrl = datapointsInfoURL + deviceID + "/datastreams/" +  objID +'_' + objInsID + '_' + resIDreturn new Promise(function (resolve, reject) {wx.request({url: getUrl,header: {"Host":Host,"api-key":apiKey},data: {},method:'GET',success(res) {//通过resolve返回请求的数据resolve(res)},fail(res) {console.log("getPlatfromDatapoint 请求失败")},complete() {}})})
}
  • 写平台数据点
//获取json时间戳
formatTimeStamp:function() {var timeStamp = new Date()var year = timeStamp.getFullYear()var month = (timeStamp.getMonth() + 1).toString()var day = timeStamp.getDate().toString()var hour = timeStamp.getHours().toString()var minute = timeStamp.getMinutes().toString()var second = timeStamp.getSeconds().toString()month = month.length < 2 ? '0' + month : monthday = day.length < 2 ? '0' + day : dayhour = hour.length < 2 ? '0' + hour : hourminute = minute.length < 2 ? '0' + minute : minutesecond = second.length < 2 ? '0' + second : secondtimeStampJSON = year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second
}
//写平台数据点
setPlatfromDatapoint:function(apiKey, deviceID, objID, objInsID, resID, value) {var that = thisvar datastreamsID = objID + '_' + objInsID + '_' + resIDvar postUrl = datapointsInfoURL + deviceID + "/datapoints"that.formatTimeStamp()let data ={"datastreams": [{"id": datastreamsID,"datapoints": [{"at": timeStampJSON,"value": value}]}]}return new Promise(function (resolve, reject) {wx.request({url: postUrl,method:'POST',header: {"Host":Host,"api-key":apiKey,"content-type": 'application/json',},data: JSON.stringify(data),success(res) {//通过resolve返回请求的数据resolve(res)},fail(res) {console.log("setPlatfromDatapoint 请求失败")},complete() {}})})
}
  1. 读写设备数据(缓存命令)
    在设备离线状态下,我们可以调用缓存命令对设备进行操作。其原理是用户设置命令开始生效时间和命令过期时间,在此时间段内,OneNET平台对缓存命令进行缓存,当终端设备上线时,平台下发缓存的命令到终端设备。如果超过此有效时间段,平台将清处缓存命令缓存。
    和“即时”读写设备的区别在于API中去掉缓存命令读写设备数据的offline及expired_time字段。大家感兴趣,可以查阅官方API手册实现。
  • 离线获取设备数据点
//合成命令过期时间
expiredTimeStamp:function() {var timeStamp = new Date()var year = timeStamp.getFullYear()var month = (timeStamp.getMonth() + 1).toString()var day = (timeStamp.getDate() + 1).toString()var hour = timeStamp.getHours().toString()var minute = timeStamp.getMinutes().toString()var second = timeStamp.getSeconds().toString()month = month.length < 2 ? '0' + month : monthday = day.length < 2 ? '0' + day : dayhour = hour.length < 2 ? '0' + hour : hourminute = minute.length < 2 ? '0' + minute : minutesecond = second.length < 2 ? '0' + second : secondexpiredTimeStamp = year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second
},
//离线获取设备数据点
getDeviceDatapointOffline:function(apiKey, deviceID, objID, objInsID, resID) {var that = thisvar retry = 3that.expiredTimeStamp()var getUrl = devResOfflineURL + that.data.gas_meter_info.deviceIMEI + "&obj_id=" + objID + "&obj_inst_id=" + objInsID + "&res_id=" + resID + '&expired_time=' + expiredTimeStamp + '&retry' + retryreturn new Promise(function (resolve, reject) {wx.request({url: getUrl,header: {"Host":Host,"api-key":apiKey,},data: {},method:'GET',success(res) {resolve(res)},fail(res) {console.log("getDeviceDatapointOffline 请求失败")},complete() {}})})
},
  • 离线写设备数据点
//离线写设备数据点
setDeviceDatapointOffline:function(apiKey, deviceID, objID, objInsID, resID, value) {var that = thisvar retry = 3var mode = 2let data ={"data":[{"res_id":resID,"val":value}]}that.expiredTimeStamp()var postUrl = devResOfflineURL + that.data.gas_meter_info.deviceIMEI + "&obj_id=" + objID + "&obj_inst_id=" + objInsID + '&expired_time=' + expiredTimeStamp + '&retry' + retry + '&mode=' + modereturn new Promise(function (resolve, reject) {wx.request({url: postUrl,method:'POST',header: {"Host":Host,"api-key":apiKey,"content-type": 'application/json',},data: JSON.stringify(data),success(res) {resolve(res)},fail(res) {console.log("setDeviceDatapointOffline 请求失败")},complete() {}})})
}

OneNET平台物联网硬件的配置和应用相关推荐

  1. SIM900A模块开发:通过GPRS连接OneNet平台发送GPS信息

    SIM900A模块开发:通过GPRS连接OneNet平台发送GPS信息 1. SIM900A模块介绍 1.1 SIM900A模块具有以下特点: 1.2 模块TTL接口图 1.3 硬件连接方法 2. O ...

  2. 移远NB-IOT BC28 模组 接入移动OneNET平台

    1 部件 开发板:NB dongle(物联网俱乐部 www.iotclub.net) 模块:Quectel移远 BC28 固件版本:BC28JAR01A01_ONT 通信方式:NB-IOT 通信运营商 ...

  3. NBIOT 设备接入ONENET平台

    NBIOT 设备接入ONENET平台 一.ONENET平台的注册与配置 1.1.注册与创建产品 1.2.添加设备: 1.2.1 获取 IMEI 及 IMSI 二.连接NB-IOT 2.1 ONETET ...

  4. ESP01 连接OneNet平台

    ESP01 连接OneNet平台 ESP01 连接OneNet平台 1.硬件准备 2.ESP8266 Arudino环境搭建 3. ESP8266采集DHT11数据 4.OneNet平台搭建 5.ES ...

  5. 【IoT】物联网NB-IoT之移动oneNET平台硬件接入

    主要实现开发者实际的终端设备在 OneNET 平台上的创建.连接和数据交互.在完成用户注册和产品创建后,即可根据相关所创建产品的协议类型选择相应的硬件接入的开发. 接入流程可参见下图: 1.LWM2M ...

  6. 【IoT】物联网NB-IoT之移动oneNET平台简析

    1.平台架构 OneNET在物联网的基本架构如下图所示,作为PaaS层,OneNET为SaaS层和设备层搭建连接桥梁,为终端层提供设备接入,为SaaS层提供应用开发能力. 2.优势特点 2.1.高并发 ...

  7. 物联网仪表ADW300接入ONENET平台介绍

    摘要 物联网时代的蓬勃发展,促成了各行各业的智能化变革,传统的电力行业也开始向着智能电网进发.安科瑞电气股份有限公司作为一家为智能电网用户端提供各类解决方案的企业,也推出了物联网系列智能仪表.本文将介 ...

  8. 基于JavaWeb平台的常用物联网硬件接口对接代码总结文档_田超凡

    基于JavaWeb平台的常用物联网硬件接口对接代码总结文档                                                                       ...

  9. 【IoT】开放 IoT 平台:电信 NB-IoT 物联网开放平台与移动 oneNET 平台对比分析

    1.电信物联网开放平台 优点:开发较为灵活,支持自定义数据传输格式 缺点:需要用户编写适配服务端的 profile 文件 和 开发编解码插件 关于其他特性请参考文章: 电信物联网开放平台详细解析 2. ...

最新文章

  1. 会声会影如何渲染高清视频
  2. 基于Boost::beast模块的无栈协程WebSocket服务器
  3. 三维CNN:收集一些最近的3d卷积网络PointNet++
  4. java里面运行js_在java中利用rhino执行javascript
  5. Source Generator 单元测试
  6. 编程面试题之——简答题(持续更新...)
  7. 神龙神龙你擦亮眼,阿里巴巴要“上天”!
  8. 代理ip池的ip是重复利用的吗_爬虫被封怎么办?用Node.js构建一个私人IP代理池...
  9. Atitit 互联网技术公司防爆指南技术规范标准流程 30个危险物品
  10. 天敏G10数位板安装完PS无压感,观看此教程
  11. 学习Nginx这一篇就够了(非本人原创文章)
  12. Rocketmq简介及部署、原理和使用介绍
  13. ListView在工程中的详细应用(简易记账本)
  14. arm64 blr指令
  15. upnp 二级路由_下载宝作为二级路由折腾记-小白篇 - Padavan - 恩山无线论坛 - Powered by Discuz!...
  16. .net core 下的 Strings.StrConv 繁简转换
  17. background-attachment
  18. Java锁机制了解一下
  19. 微信小程序公众号后台回复中文乱码问题
  20. android操作系统

热门文章

  1. 新建的Maven项目里面没有.iml文件怎么办
  2. 直放站引起上行高干扰 小区处理案例
  3. WAVE Sample Files
  4. Linux 操作系统课程练习题(二)VI 编辑器
  5. 计算机注销命令,如何用DOS命令实现定时自动关机,注销
  6. 微服务解决方案_微服务为您提供正确的解决方案
  7. iOS -录音-音频的拼接剪切以及边录边压缩转码
  8. 全球最昂贵的域名和国内著名的域名交易
  9. Discuz! X3 数据字典
  10. word嵌入对象依损坏_word的操作问题.