更新时间:2022-02-21 GMT+08:00
实现样例讲解
在编解码插件的DEMO工程(点击获取)中,提供了编解码插件样例,样例工程结构如下图所示。
图1 样例工程结构图
本工程是一个Maven工程,开发者可在此样例工程的基础上修改如下部分,适配成自己需要的编解码插件:
说明:
加密算法请使用JDK自带的加密算法,JDK支持的加密算法,详见附录:JDK支持的加密算法。
- Maven的配置文件
在pom.xml文件中,根据命令规范,修改编解码插件的名字。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.thrid.party</groupId> <!-- 请修改为你的编解码插件的名字,命名规范:设备类型-厂商ID-设备型号,例如:WaterMeter -Huawei-NBIoTDevice --> <artifactId>WaterMeter-Huawei-NBIoTDevice</artifactId> <version>1.0.0</version> <!-- 请检查这里的值为bundle,不能为jar --> <packaging>bundle</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <junit.version>4.11</junit.version> <fasterxml.jackson.version>2.7.4</fasterxml.jackson.version> <felix.maven.plugin.version>2.5.4.fixed2</felix.maven.plugin.version> <json.lib.version>2.4</json.lib.version> <m2m.cig.version>1.3.1</m2m.cig.version> <slf4j.api.version>1.7.6</slf4j.api.version> </properties> <dependencies> <!-- 单元测试使用 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <!-- 日志使用 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.api.version}</version> </dependency> <!-- 转换JSON使用,必须 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${fasterxml.jackson.version}</version> </dependency> <!-- Huawei提供的编解码接口,必须 --> <!-- systemPath请替换成你本地的目录 \codecDemo\lib\com.huawei.m2m.cig.tup-1.3.1.jar --> <dependency> <groupId>com.huawei</groupId> <artifactId>protocal-jar</artifactId> <version>1.3.1</version> <scope>system</scope> <systemPath>${basedir}/lib/com.huawei.m2m.cig.tup-1.3.1.jar</systemPath> </dependency> <!-- 本例中数据转换使用到的jar,你用到的jar请写到这里,记得把artifactId填入后面的Embed-Dependency --> <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> <classifier>jdk15</classifier> </dependency> </dependencies> <build> <plugins> <!-- 编码需要使用JDK1.8版本 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <!-- OSGI规范打包配置 --> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>${felix.maven.plugin.version}</version> <extensions>true</extensions> <configuration> <buildDirectory>./target</buildDirectory> <archive> <addMavenDescriptor>false</addMavenDescriptor> </archive> <instructions> <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment> <Bundle-Activator></Bundle-Activator> <Service-Component>OSGI-INF/*</Service-Component> <!-- 请修改为你的编解码插件的名字,命名规范:设备类型-厂商ID-设备型号,例如:WaterMeter-Huawei-NBIoTDevice --> <Bundle-SymbolicName>WaterMeter-Huawei-NBIoTDevice</Bundle-SymbolicName> <Export-Package></Export-Package> <!-- 把代码中import的package都引入进来,使用逗号分隔。【有两种jar不需要的填到Import-Package,否则插件无法启动,这两种jar分别为:①java.**开头的包;②引用的是Embed-Dependency里面的jar】 --> <Import-Package> org.slf4j, org.slf4j.spi, org.apache.log4j.spi, com.huawei.m2m.cig.tup.modules.protocol_adapter, com.fasterxml.jackson.databind, com.fasterxml.jackson.databind.node </Import-Package> <!-- 除junit,slf4j-api,jackson-databind,protocal-jar, 其他所有的依赖包,必须把包对应的artifactId填入Embed-Dependency。artifactId之间以逗号分隔。Maven打包时你的依赖包需要打入到你的jar内。 --> <Embed-Dependency> json-lib </Embed-Dependency> </instructions> </configuration> <executions> <execution> <id>generate-resource</id> <goals> <goal>manifest</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
- 编解码代码实现
- 在ProtocolAdapterImpl.java中,修改厂商ID(MANU_FACTURERID)和设备型号(MODEL)的取值。IoT平台通过厂商ID和设备型号将编解码插件和Profile文件进行关联。
1 2 3 4 5
private static final Logger logger = LoggerFactory.getLogger(ProtocolAdapterImpl.class); // 厂商名称 private static final String MANU_FACTURERID = "Huawei"; // 设备型号 private static final String MODEL = "NBIoTDevice";
- 修改CmdProcess.java中的代码,实现插件对下发命令和上报数据响应的编码能力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
package com.Huawei.NBIoTDevice.WaterMeter; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; public class CmdProcess { //private String identifier = "123"; private String msgType = "deviceReq"; private String serviceId = "Brightness"; private String cmd = "SET_DEVICE_LEVEL"; private int hasMore = 0; private int errcode = 0; private int mid = 0; private JsonNode paras; public CmdProcess() { } public CmdProcess(ObjectNode input) { try { // this.identifier = input.get("identifier").asText(); this.msgType = input.get("msgType").asText(); /* 平台收到设备上报消息,编码ACK { "identifier":"0", "msgType":"cloudRsp", "request": ***,//设备上报的码流 "errcode":0, "hasMore":0 } * */ if (msgType.equals("cloudRsp")) { //在此组装ACK的值 this.errcode = input.get("errcode").asInt(); this.hasMore = input.get("hasMore").asInt(); } else { /* 平台下发命令到设备,输入 { "identifier":0, "msgType":"cloudReq", "serviceId":"WaterMeter", "cmd":"SET_DEVICE_LEVEL", "paras":{"value":"20"}, "hasMore":0 } * */ //此处需要考虑兼容性,如果没有传mId,则不对其进行编码 if (input.get("mid") != null) { this.mid = input.get("mid").intValue(); } this.cmd = input.get("cmd").asText(); this.paras = input.get("paras"); this.hasMore = input.get("hasMore").asInt(); } } catch (Exception e) { e.printStackTrace(); } } public byte[] toByte() { try { if (this.msgType.equals("cloudReq")) { /* 应用服务器下发的控制命令,本例只有一条控制命令:SET_DEVICE_LEVEL 如果有其他控制命令,增加判断即可。 * */ if (this.cmd.equals("SET_DEVICE_LEVEL")) { int brightlevel = paras.get("value").asInt(); byte[] byteRead = new byte[5]; ByteBufUtils buf = new ByteBufUtils(byteRead); buf.writeByte((byte) 0xAA); buf.writeByte((byte) 0x72); buf.writeByte((byte) brightlevel); //此处需要考虑兼容性,如果没有传mId,则不对其进行编码 if (Utilty.getInstance().isValidofMid(mid)) { byte[] byteMid = new byte[2]; byteMid = Utilty.getInstance().int2Bytes(mid, 2); buf.writeByte(byteMid[0]); buf.writeByte(byteMid[1]); } return byteRead; } } /* 平台收到设备的上报数据,根据需要编码ACK,对设备进行响应,如果此处返回null,表示不需要对设备响应。 * */ else if (this.msgType.equals("cloudRsp")) { byte[] ack = new byte[4]; ByteBufUtils buf = new ByteBufUtils(ack); buf.writeByte((byte) 0xAA); buf.writeByte((byte) 0xAA); buf.writeByte((byte) this.errcode); buf.writeByte((byte) this.hasMore) return ack; } return null; } catch (Exception e) { // TODO: handle exception e.printStackTrace(); return null; } } }
- 修改ReportProcess.java中的代码,实现插件对设备上报数据和命令执行结果的解码能力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
package com.Huawei.NBIoTDevice.WaterMeter; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; public class ReportProcess { //private String identifier; private String msgType = "deviceReq"; private int hasMore = 0; private int errcode = 0; private byte bDeviceReq = 0x00; private byte bDeviceRsp = 0x01; //serviceId=Brightness字段 private int brightness = 0; //serviceId=Electricity字段 private double voltage = 0.0; private int current = 0; private double frequency = 0.0; private double powerfactor = 0.0; //serviceId=Temperature字段 private int temperature = 0; private byte noMid = 0x00; private byte hasMid = 0x01; private boolean isContainMid = false; private int mid = 0; /** * @param binaryData 设备发送给平台coap报文的payload部分 * 本例入参:AA 72 00 00 32 08 8D 03 20 62 33 99 * byte[0]--byte[1]: AA 72 命令头 * byte[2]: 00 mstType 00表示设备上报数据deviceReq * byte[3]: 00 hasMore 0表示没有后续数据,1表示有后续数据,不带按照0处理 * byte[4]--byte[11]:服务数据,根据需要解析//如果是deviceRsp,byte[4]表示是否携带mid, byte[5]--byte[6]表示短命令Id * @return */ public ReportProcess(byte[] binaryData) { // identifier参数可以根据入参的码流获得,本例指定默认值123 // identifier = "123"; /* 如果是设备上报数据,返回格式为 { "identifier":"123", "msgType":"deviceReq", "hasMore":0, "data":[{"serviceId":"Brightness", "serviceData":{"brightness":50}, { "serviceId":"Electricity", "serviceData":{"voltage":218.9,"current":800,"frequency":50.1,"powerfactor":0.98}, { "serviceId":"Temperature", "serviceData":{"temperature":25}, ] } */ if (binaryData[2] == bDeviceReq) { msgType = "deviceReq"; hasMore = binaryData[3]; //serviceId=Brightness 数据解析 brightness = binaryData[4]; //serviceId=Electricity 数据解析 voltage = (double) (((binaryData[5] << 8) + (binaryData[6] & 0xFF)) * 0.1f); current = (binaryData[7] << 8) + binaryData[8]; powerfactor = (double) (binaryData[9] * 0.01); frequency = (double) binaryData[10] * 0.1f + 45; //serviceId=Temperature 数据解析 temperature = (int) binaryData[11] & 0xFF - 128; } /* 如果是设备对平台命令的应答,返回格式为: { "identifier":"123", "msgType":"deviceRsp", "errcode":0, "body" :{****} 特别注意该body体为一层json结构。 } */ else if (binaryData[2] == bDeviceRsp) { msgType = "deviceRsp"; errcode = binaryData[3]; //此处需要考虑兼容性,如果没有传mId,则不对其进行解码 if (binaryData[4] == hasMid) { mid = Utilty.getInstance().bytes2Int(binaryData, 5, 2); if (Utilty.getInstance().isValidofMid(mid)) { isContainMid = true; } } } else { return; } } public ObjectNode toJsonNode() { try { //组装body体 ObjectMapper mapper = new ObjectMapper(); ObjectNode root = mapper.createObjectNode(); // root.put("identifier", this.identifier); root.put("msgType", this.msgType); //根据msgType字段组装消息体 if (this.msgType.equals("deviceReq")) { root.put("hasMore", this.hasMore); ArrayNode arrynode = mapper.createArrayNode(); //serviceId=Brightness 数据组装 ObjectNode brightNode = mapper.createObjectNode(); brightNode.put("serviceId", "Brightness"); ObjectNode brightData = mapper.createObjectNode(); brightData.put("brightness", this.brightness); brightNode.put("serviceData", brightData); arrynode.add(brightNode); //serviceId=Electricity 数据组装 ObjectNode electricityNode = mapper.createObjectNode(); electricityNode.put("serviceId", "Electricity"); ObjectNode electricityData = mapper.createObjectNode(); electricityData.put("voltage", this.voltage); electricityData.put("current", this.current); electricityData.put("frequency", this.frequency); electricityData.put("powerfactor", this.powerfactor); electricityNode.put("serviceData", electricityData); arrynode.add(electricityNode); //serviceId=Temperature 数据组装 ObjectNode temperatureNode = mapper.createObjectNode(); temperatureNode.put("serviceId", "Temperature"); ObjectNode temperatureData = mapper.createObjectNode(); temperatureData.put("temperature", this.temperature); temperatureNode.put("serviceData", temperatureData); arrynode.add(temperatureNode); //serviceId=Connectivity 数据组装 ObjectNode ConnectivityNode = mapper.createObjectNode(); ConnectivityNode.put("serviceId", "Connectivity"); ObjectNode ConnectivityData = mapper.createObjectNode(); ConnectivityData.put("signalStrength", 5); ConnectivityData.put("linkQuality", 10); ConnectivityData.put("cellId", 9); ConnectivityNode.put("serviceData", ConnectivityData); arrynode.add(ConnectivityNode); //serviceId=battery 数据组装 ObjectNode batteryNode = mapper.createObjectNode(); batteryNode.put("serviceId", "battery"); ObjectNode batteryData = mapper.createObjectNode(); batteryData.put("batteryVoltage", 25); batteryData.put("battervLevel", 12); batteryNode.put("serviceData", batteryData); arrynode.add(batteryNode); root.put("data", arrynode); } else { root.put("errcode", this.errcode); //此处需要考虑兼容性,如果没有传mid,则不对其进行解码 if (isContainMid) { root.put("mid", this.mid);//mid } //组装body体,只能为ObjectNode对象 ObjectNode body = mapper.createObjectNode(); body.put("result", 0); root.put("body", body); } return root; } catch (Exception e) { e.printStackTrace(); return null; } } }
- 在ProtocolAdapterImpl.java中,修改厂商ID(MANU_FACTURERID)和设备型号(MODEL)的取值。IoT平台通过厂商ID和设备型号将编解码插件和Profile文件进行关联。
父主题: 参考信息