华为IoT平台NB编解码插件开发详细教程【上篇】

目录

0、前言

一、环境搭建

1.1 安装JDK

1.2 安装eclipse

1.3 安装Maven

二、Profile说明

三、插件编写

3.1 源文件说明

3.2 修改文件路径(包含)

3.3 修改pom.xml

3.4 导入工程

3.5 代码实现

3.6 生成jar包


0、前言

本教程分为上、下篇,原作者是我的同事llb90,征得其同意后在这里再次发布,希望能帮到有需求的人,demo可在Github下载。

本文通过一个比较简单又不失全面的例子,说明一下华为IoT平台编解码插件线下开发的整个开发流程。对于环境的搭建尽量一笔带过,对核心编码部分做比较详细的讲解。第二章Profile部分会先出给一个小例子作为demo,编解码的编写按照该pfofile中定义的字段来解析,以方便大家理解编解码插件中的代码。本文编写过程中主要参考了“华为IoT平台NB-IoT设备集成开发指南.pdf”。

一、环境搭建

开发编解码插件使用的IDE是eclipse,语言是Java。本文尽量以简单的方式告诉你如何将华为提供的编解码样例修改为适合自己的编解码插件。即使你没有什么Java基础,只要懂得编程逻辑就好。跟着一起来吧!

1.1 安装JDK

JDK版本1.8以上。参考网络教程:https://blog.csdn.net/u010058695/article/details/100983213

1.2 安装eclipse

下载并安装eclipse。eclipse下载后解压缩到本地即可运行。

1.3 安装Maven

下载地址是: http://maven.apache.org/download.cgi  下载后的文件解压缩即可,然后添加环境变量。

在eclipse中配置maven插件。打开eclipse,点击window->Preferences,弹出如下窗口:

在弹出的窗口左侧栏中,依次找到并点击Maven->Installations,在右侧点击Add按钮,弹出如下图所示窗口:

点击Directory,选择Maven的路径,然后Finish。到此,Maven配置完成。

二、Profile说明

Profile实际上是一系列关于设备模型的描述文件,每个文件都使用JSON格式(键值对)。

Profile中首先需要说明设备的基本信息,包括厂商ID,厂商名称,设备类型,接入协议,以及设备可以提供的哪些服务等;其次,profile中要针对每一项服务,用一个独立的文件进行详细描述。服务,可以理解为是对设备消息(上下行)功能的一个分类,一个服务就代表一类功能;每个服务下包含若干属性和命令,每个属性对应上报消息中的某一个数据,每个命令字段则对应下行消息中的某些字段。比如,一个电表设备,会上报电池电量、功率、电能、电压等,可以将电池电量放在Battery服务中,属性值为batteryLevel,将功率、电能、电压都放在Transmission服务中,分别对应该服务下的Power、Energy、Voltage属性。可以在一条消息中上报所有服务的所有属性,也可以分开上报。

本例中提供的profile信息,基本信息如下:

设备类型: MyType
设备型号: MyModel
厂商ID  : ThirdParty
厂商名称: ThirdParty
协议:     Coap

数据服务有两项:Battery,包含一个属性BatteryLevel,两个字节;Transmission,包含一个属性upData,不定长数组(profile中表示不定长数组,需将属性类型定义为string,长度设为一个比较大的数);包含一条下行命令CLOUDREQ,有两个命令字段;cmdType,一个字节;downData,不定长数组。

profile采用在线开发的方式,如下图所示:

本例中,采用一条消息上报所有服务属性的方式。上报数据格式为:前两个字节表示batteryLevel属性,大端方式;第三个字节表示后续数据长度;第四个字节至最后,表示upData属性。下行命令数据格式为:第一个字节表示cmdType;第二个字节至最后,表示downData。(请仔细理解该数据格式,插件的编写就是按照数据格式解析出对应的属性值)。

三、插件编写

3.1 源文件说明

从华为资源中心下载编解码插件Demo,并解压到本地。文件结构如下图所示:

源代码在src文件夹下;编译生成的插件包在target文件夹下。src 文件夹包含 main 、test 两个子文件夹,main下存放源码,test下是单元测试代码。官网下载的Demo中,源码的路径是:src\main\java\com\Huawei\NBIoTDevice\WaterMeter,单元测试代码的路径是:src\test\java\com\Huawei\NBIoTDevice\WaterMeter。

插件源码文件有5个:

(a)ProtocolAdapterImpl.java 可以理解为是插件的入口文件,对外提供调用接口。该文件只需要修改两个字符串的定义即可:

// 厂商名称
private static final String MANU_FACTURERID = "Huawei";
// 设备型号
private static final String MODEL = "NBIoTDevice";

  修改为profile当中定义的厂商ID和设备型号。

(b)CmdProcess.java 实现下行命令的编码工作,将从收到的服务器报文中提取出命令字段对应的内容,并将其转换成字节流。需要实现的函数是:

public byte[] toByte()

(c)ReportProcess.java 实现将收到的二进制码流按照格式解码出对应profile中的属性值,并生成JSON格式。需要实现的函数是:

//根据二进制码流的格式,从中取出对应字节,转换成profile中对应属性的值
public ReportProcess(byte[] binaryData)
//将解码出来的属性值封装成JSON格式
public ObjectNode toJsonNode()

(d)ByteBufUtils.java 和 Utilty.java文件封装了一些公共方法,不用做修改。也不会使用到。

3.2 修改文件路径(包含)

插件包名的要求是:com.厂商名称.设备型号.设备类型。因此下载下来的代码,要根据自己的设备修改下文件路径。即将Huawei文件夹重命名为profile中定义的厂商名称,NBIoTDevice文件夹重命名为profile中定义的设备型号,WaterMeter文件夹重命名为profile中定义的设备类型。注意:src\main 和src\test 下都要修改。在本例中,需要修改为:

src\main\java\com\ThirdParty\MyModel\MyTyp,
src\test\java\com\ThirdParty\MyModel\MyType

3.3 修改pom.xml

打开pom.xml文件,修改第7行“artifactId”和第88行“Bundle-SymbolicName”的值为:设备类型-厂商ID-设备型号。在本例中,需要修改为:MyType-ThirdParty-MyModel。

3.4 导入工程

打开eclipse,点击file->import,在弹出窗口中选择maven工程,如下图所示:

之后在弹出的窗口中,点击Browse,选择工程路径(pom.xml文件所在路径)。工程导入后如下图所示:

从图8可以看到首次导入工程后是有错误的。这是因为我们在第2节中将文件路径修改了,与代码里面的包路径不一致引起的。解决方法为:依次打开源文件,将第一行的

package com.Huawei.NBIoTDevice.WaterMeter;

修改为

package com.ThirdParty.MyModel.MyType;

打开OSGI_INF目录下的CodeProvideHandler.xml 文件:

打开后,文件内容如下图所示:

将Name 、 Class* 内的路径也修改为对应的包路径:

3.5 代码实现

前面说明了各个源文件要修改的地方,本节中具体讲解实现的方法。

(a)修改ProtocolAdatpterImpl.java文件

在文件中找到如下两行:

// 厂商名称
private static final String MANU_FACTURERID = "Huawei";
// 设备型号
private static final String MODEL = "NBIoTDevice";

MANU_FACTURERID MODEL定义修改为profile中定义的厂商ID和设备型号,本例中需要修改为:

// 厂商名称
private static final String MANU_FACTURERID = "ThirdParty";
// 设备型号
private static final String MODEL = "MyModel";

(b)解码实现

解码,是将NB模组上报的二进制码流按格式解析出对应字段的过程。解码的代码在ReportProcess.java 文件中。

第一个函数:public ReportProcess(byte[] binaryData) 入参 byte[] binaryData就是NB模组上报的二进制码流。解码得到数据存储在成员变量当中。本例中的代码实现如下:

NB上报二进制数据的格式为:前两个字节表示batteryLevel,大端,整型;第三个字节表示后边还有多少字节;第四个字节往后表示不定长字段upData。因此,解码的思路便是:

  1. 首先判断数据长度是否合法,至少应为3个字节,对应第37行代码;数据长度应不小于第3个字节的值加上3,对应第42行代码。该部分代码属于保护性代码。
  2. 将前两个字节拼成一个16位的整型数据,表示batteryLevel,对应第47行代码。
  3. 根据第三个字节的值,创建一个Byte数组,将第四个字节往后的内容拷贝至该数组内,得到upData。对应第50~53行代码。

System.arraycopy 是JDK提供的数组拷贝函数:第一个参数是源数组,第二个参数是偏移,表示从源数组的第几个字节开始拷贝,第三个参数是目的数组,第四个参数是目的数组的偏移,第5个参数表示拷贝的长度。

第二个函数:public ObjectNode toJsonNode() 返回一个ObjectNode对象(JSON)该函数的功能,是将解码后得到的数据,按照规定格式填入一个JSON对象中。本例中,生成的JSON对象的内容格式如下图所示:

JSON对象的内容格式要求是:"msgType":  "deviceReq",  表示设备上报数据,固定不动;“data”:数组对象,数组中的每个元素分别对应profile中的一个服务;“serviceID”的值是profile中定义的服务名称;“serviceData”的值是该服务下所有的属性值。(本例中,profile定义了两个服务,Battery服务中有一个BatteryLevel属性;Transmission服务中有一个upData属性)。由图13的“upData”的值可以看出,数组类型的值,需要将二进制流转成base64编码的格式。

该函数的代码实现如下图所示:

该函数代码比较简单,主要是用到了 ObjectMapper 这个类,该类提供了JAVA中操作JSON数据的方法,可对照图13上报数据格式,仔细理解该部分代码。

(c)编码实现

编码,是将IoT平台收到的服务器下行数据(服务器下行数据是http或者https协议),从中提取出下行字段,并将其拼成二进制码流。编码部分的代码在 CmdProcess.java 文件中。需要实现的函数是:public byte[] toByte()

本例中,该函数的实现代码如下图所示:

服务器下行命令的JSON数据格式是:

"msgType": "cloudReq", 固定值,表示服务器下行命令;

"serviceId",profile中对应的服务,本例中是"Transmission",

"cmd",profile中定义的下行命令,本例中是"CLOUDREQ",

"paras",profile中定义的下行命令的各个字段,本例中是cmdType和downData两个字段;图16中,cmdType的值是2,downData是一个不定长数组,base64编码格式。

因此,编码的思路是:

  1. 判断下行命令是否是profile中定义的。对应第77行代码。
  2. 获取cmdType字段的值,该值占一个字节。对应第78行代码。
  3. 获取downData的值,该值是base64编码形式,需转成二进制码流,对应第79行代码。
  4. 将两个字段的值拼接成一个二进制数组,并返回。对应第81~84行代码。

3.6 生成jar包

经过前面的工作后,代码就已经准备好了,接下来是生成JAR包。在DOS窗口中进入pom.xml文件所在路径,执行 mvn package 命令,最后弹出如下图所示的结果,则表明生成Jar包成功。如果有错误,则根据提示再去修改代码,然后重新执行 mvn package。

在工程目录的target文件夹下,存放生成的JAR包“MyType-ThirdParty-MyModel-1.0.0.jar”。JAR包的命名规则是:

设备类型-厂商ID-设备型号-版本号.jar

好,至此插件编写任务完成。插件打包、插件质检、插件签名等内容见下篇教程。

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/405444.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用MySQL实现微博关注关系的方案分析

关注关系产生的四种关系状态 关注粉丝双向关注(互粉)无关系用词follower表示粉丝 -- 追随者 用词following表示关注 -- 追随 设计的结构必须能满足以下功能: 查询关注列表查询粉丝列表查询双向关注列表判断两个用户的关系查询带关系状态的任一列表第一种方案 用一行…

带你封装一个上传图片组件(ant design+react)

目录 需求实现 实现效果 代码封装 UploadImage组件 备注 BaseUploadImage组件 index.less 样式文件 父组件引用 需求实现 1可以支持上传最多九张图片 2图片支持预览 替换 删除 3支持自定义上传文件大小 格式 未上传提示 实现效果 代码封装 UploadImage组件 * Descri…

计算机面试的时候写过的代码,程序员悲催瞬间:来之不易的美团面试,我尽然挂了(还原真实场景)...

一面1、自我介绍答:自我介绍是面试中唯一的自己主动介绍自己的环节,一定要好好把握好,你数据结构学的号可以手撕一个红黑树你就说我数据结构掌握地很好,反正就是要把自己的优势凸显出来,比如自己对于java的知识较熟悉&…

华为IoT平台NB编解码插件开发详细教程【下篇】

上篇文章介绍了编解码开发汇总的环境搭建、Profile说明和插件编写,本篇教程就插件打包、插件质检和插件签名详解。 目录 四、插件打包 五、插件质检 六、插件签名 七、附件 四、插件打包 1、新建package文件,包含一个“preload”子文件夹&#xff…

【PostGIS】PostgreSQL15+对应PostGIS安装教程及空间数据可视化

一、PostgreSQL15与对应PostGIS安装 PostgreSQL15安装:下载地址PostGIS安装:下载地址(选择倒数第二个) 1、PostgreSQL安装 下载安装包;开始安装,这里使用默认安装,一直next直到安装完成&…

React实现图片自适应

数据格式 [1xxxx,2xxxx,3xxxx,4xxxx,5xxxx,6xxxx,7xxxx,8,xxxx,9xxxx] 运行效果 代码部分 <divgutter{24}style{{width: 100%,display: flex,justifyContent: space-between,flexWrap: wrap ,}}>{item.imgList &&item.imgList.map((itemList, index) > (<…

上交大计算机复试机师难不难,本科复旦,考研上海交大复试第一,我感觉难度并不大...

我本人去年考研上海交大凯原法学院法学硕士&#xff0c;初试370分&#xff0c;排名第四。复试182分&#xff0c;排名第一。本科复旦&#xff0c;有过转专业经历因此法学院课程只学了3年&#xff0c;比较匆忙&#xff0c;基础不算好。2020年国家法律职业资格考试和考研同时备考&…

前端问题记录1:debounce is not a function

目录 项目场景&#xff1a; 问题描述&#xff1a; 原因分析&#xff1a; 解决方案&#xff1a; 项目场景&#xff1a; 问题描述&#xff1a; 原因分析&#xff1a; 变量重名 解决方案&#xff1a; 变量重名 关注我 一起进入前端学习群 谢谢

Linux Shell 通配符、元字符、转义符使用实例介绍

From: http://www.cnblogs.com/chengmo/archive/2010/10/17/1853344.html 说到shell通配符&#xff08;wildcard&#xff09;&#xff0c;大家在使用时候会经常用到。下面是一个实例&#xff1a; ?1?1234[chengmolocalhost ~/shell]$ lsa.txt b.txt c.old#2?1234[chengmo…

ant design model实现图片预览

代码部分 <divgutter{16}style{{width: 100%,display: flex,justifyContent: space-between,flexWrap: wrap ,}}>{detailMsg.imgList &&detailMsg.imgList.map((item, index) > (<div style{{ width: 30% }} key{index} onClick{() > this.handleClick(…

VMware Workstation Pro 无法在Windows 上运行的 解决办法

一、问题描述 国庆期间window10来了一次更新&#xff0c;导致VMware Workstation 无法在windows上运行&#xff0c;我的虚拟机版本是VMware Pro14。有两种方法解决该问题&#xff0c;第一种是直接卸载新安装的windows安装包&#xff0c;然后重启。第二种方式是升级VMware到最新…

机器学习之深度学习

本文基于台大机器学习技法系列课程进行的笔记总结。 一、主要内容 topic 1 深度神经网络结构 从类神经网络结构中我们已经发现了神经网络中的每一层实际上都是对前一层进行的特征转换&#xff0c;也就是特征抽取。一般的隐藏层&#xff08;hidden layer&#xff09;较少的类神…

FlexViewer2.3中拉帘Widget下载

http://www.giser.net/?p280 由于最新的ArcGIS API for flex2.x使用了Flex SDK4&#xff0c;因此造成了对之前ArcGIS API for flex1.x制 作的拉帘Widget无法使用&#xff0c;因此重新制作了拉帘工具供大家使用。 下载地址&#xff1a; Swipe 使用方法&#xff1a;将下载后的sw…

五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O

From: http://blog.163.com/xychenbaihuyeah/blog/static/13222965520112163171778/ 五种I/O 模式&#xff1a; 【1】 阻塞 I/O (Linux下的I/O操作默认是阻塞I/O&#xff0c;即open和socket创建的I/O都是阻塞I/O) 【2】 非阻塞 I/O (可以通过f…

Linux tm time_t timeval timespec以及与时间相关函数用法

一、时间类型 linux中编程通常需要用到时间变量&#xff0c;和相关的时间操作函数。常用的时间类型有&#xff1a; time_t 、struct timeval、struct timespec、struct tm。 在用到相关的类型和函数时&#xff0c;需要加上头文件&#xff1a;#include <time.h> …

C语言编程对缓冲区的理解

解析C语言编程对缓冲区的理解 转载自&#xff1a;http://soft.chinabyte.com/database/47/12481547.shtml 下面介绍缓冲区的知识。 一、什么是缓冲区 缓冲区又称为缓存&#xff0c;它是内存空间的一部分。也就是说&#xff0c;在内存空间中预留了一定的存储空间&#xff0c;这些…

ftp文档服务器设置,ftp服务器基本设置

ftp服务器基本设置 内容精选换一换在迁移Agent中输入华为云账号AK/SK以后&#xff0c;AK/SK校验失败。Windows系统提示用户&#xff1a;"AK/SK authentication failed. Ensure that the system time is consistent with the standard time and the AK and SK are corre服务…

树莓派移植SX1278 LoRa通信--使用wiringPiSPI移植SPI通信接口

一、SPI接口 树莓派3B上的SPI接口如下所示&#xff0c;有两组SPI&#xff0c;分别由CE0和CE1来进行选择。 首先查看树莓派的SPI是否启用&#xff0c;在/dev查看是否有spidev0.0和spidev0.1 如果不存在spi设备号&#xff0c;需要在raspi-config中启用&#xff0c;在命令行输入&…

饥荒专用服务器全图显示代码,饥荒开全图代码

用记事本打开游戏目录\data\DLC0001\scripts\prefabs\player_common.lua文件&#xff0c;在inst:AddComponent("resurrectable")下一行插inst:AddComponent("resurrectable")下一行插入以下内容&#xff1a;  TheInput:AddKeyUpHandler(KEY_1&#xff0c…

树莓派移植SX1278 LoRa通信--使用wiringPi 移植GPIO中断

一、SX1278 数字接口状态映射 从官方文档可知sx1278的数字接口状态映射明细&#xff0c;移植的代码中主要用查询的方式来判断在连续模式下是否接收和发送完成&#xff0c;因此只需要用到DIO0。如果要用到CAD&#xff0c;则需要DIO1管脚。 发送时&#xff1a;DioMapping1寄存器…