Implementation Sample Interpretation
In the DEMO project of the codec (click here to obtain), an example codec is provided. The following figure shows the sample project structure.
This project is a Maven project. You can modify the following content based on this sample project to obtain the required codec.
Use the encryption algorithms supported by the JDK. For details about these encryption algorithms, see Appendix: Encryption Algorithms Supported by the JDK.
- Maven configuration file
In the pom.xml file, modify the name of the codec according to the naming rule.
<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> <!-- Change it to the name of your codec. The naming rule is as follows: device type-manufacturer ID-device model, for example: WaterMeter-Huawei-NBIoTDevice.--> <artifactId>WaterMeter-Huawei-NBIoTDevice</artifactId> <version>1.0.0</version> <!-- Check that the value is bundle. The value cannot be 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> <!-- Used by unit test --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <!-- Used by logs --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.api.version}</version> </dependency> <!-- Used for converting JSON; mandatory --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${fasterxml.jackson.version}</version> </dependency> <!-- Codec API provided by Huawei; mandatory --> <!-- Replace systemPath with your local \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> <!-- In this example, the JAR file used for data conversion is written here. Enter artifactId in the Embed-Dependency. --> <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> <classifier>jdk15</classifier> </dependency> </dependencies> <build> <plugins> <!-- The JDK1.8 version must be used. --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <!-- OSGi packaging configuration --> <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> <!-- Change it to the name of your codec. The naming rule is as follows: device type-manufacturer ID-device model, for example: WaterMeter-Huawei-NBIoTDevice. --> <Bundle-SymbolicName>WaterMeter-Huawei-NBIoTDevice</Bundle-SymbolicName> <Export-Package></Export-Package> <!-- Import packages in the code and use commas (,) to separate them. [JAR packages that start with java.** and that are referenced in Embed-Dependency do not need to be imported in Import-Package. Otherwise, the codec cannot be started.] --> <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> <!-- For all dependency packages except junit, slf4j-api, jackson-databind, and protocol-jar, set artifactId of each package to Embed-Dependency. Separate artifactId values by commas (,). During Maven packaging, pack your dependency packages into your JAR package. --> <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>
- Codec code implementation
- In the ProtocolAdapterImpl.java file, change the values of MANU_FACTURERID and MODEL. The IoT platform associates the codec with the profile file using the manufacturer ID and device model.
1 2 3 4 5
private static final Logger logger = LoggerFactory.getLogger(ProtocolAdapterImpl.class); //Manufacturer name private static final String MANU_FACTURERID = "Huawei"; //Model private static final String MODEL = "NBIoTDevice";
- Modify the code in the CmdProcess.java file so that the codec can encode delivered commands and responses to reported data.
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(); /* The IoT platform receives messages reported by the device and encodes the ACK message. { "identifier":"0", "msgType":"cloudRsp", "request": ***,//Stream reported by the device "errcode":0, "hasMore":0 } * */ if (msgType.equals("cloudRsp")) { //Assemble the values of fields in the ACK message. this.errcode = input.get("errcode").asInt(); this.hasMore = input.get("hasMore").asInt(); } else { /* The IoT platform delivers a command to the device with parameters specified as follows: { "identifier":0, "msgType":"cloudReq", "serviceId":"WaterMeter", "cmd":"SET_DEVICE_LEVEL", "paras":{"value":"20"}, "hasMore":0 } * */ //Compatibility must be considered. If the MID is not transferred, it is not encoded. 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")) { /* The NA delivers a control command. In this example, there is only one command: SET_DEVICE_LEVEL. If there are other commands, determine them. * */ 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); //Compatibility must be considered. If the MID is not transferred, it is not encoded. 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; } } /* After receiving the data reported by the device, the IoT platform encodes the ACK message as required and responds to the device. If null is returned, the IoT platform does not need to respond. * */ 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; } } }
- Modify the code in the ReportProcess.java file so that the codec can decode data reported by devices and command execution results.
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: Payload of the CoAP packet sent by the device to the IoT platform * Input parameters in this example: AA 72 00 00 32 08 8D 03 20 62 33 99 * byte[0]--byte[1]: AA 72 command header * byte[2]: 00 mstType: 00 represents deviceReq, which indicates that data is reported by the device. * byte[3]: 00 hasMore: 0 indicates that there is no subsequent data and 1 indicates that there is subsequent data. If the hasMore field is not contained, the value 0 is used. * byte[4]--byte[11]: indicates service data, which is parsed as required.//If the service data is deviceRsp, byte[4] indicates whether the MID is carried and byte[5] to byte[6] indicate the short command ID. * @return */ public ReportProcess(byte[] binaryData) { //The identifier parameter can be obtained based on the input parameter stream. In this example, the default value is 123. // identifier = "123"; /* If the data is reported by the device, the return value is in the following format: { "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; } /* If the data is a response sent by the device to a command of the IoT platform, the return value is in the following format: { "identifier":"123", "msgType":"deviceRsp", "errcode":0, "body" :{****} Note that the body is a JSON structure. } */ else if (binaryData[2] == bDeviceRsp) { msgType = "deviceRsp"; errcode = binaryData[3]; //Compatibility must be considered. If the MID is not transferred, it is not encoded. if (binaryData[4] == hasMid) { mid = Utilty.getInstance().bytes2Int(binaryData, 5, 2); if (Utilty.getInstance().isValidofMid(mid)) { isContainMid = true; } } } else { return; } } public ObjectNode toJsonNode() { try { //Assemble the body. ObjectMapper mapper = new ObjectMapper(); ObjectNode root = mapper.createObjectNode(); // root.put("identifier", this.identifier); root.put("msgType", this.msgType); //Assemble the message body based on the msgType field. 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); //Compatibility must be considered. If the MID is not transferred, it is not encoded. if (isContainMid) { root.put("mid", this.mid);//mid } //Assemble the body. The body must be an ObjectNode object. ObjectNode body = mapper.createObjectNode(); body.put("result", 0); root.put("body", body); } return root; } catch (Exception e) { e.printStackTrace(); return null; } } }
- In the ProtocolAdapterImpl.java file, change the values of MANU_FACTURERID and MODEL. The IoT platform associates the codec with the profile file using the manufacturer ID and device model.
Feedback
Was this page helpful?
Provide feedbackThank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot