
# 使用JavaScript开发插件
物联网平台支持JavaScript脚本编解码的功能，根据您提交的脚本文件，实现设备二进制格式与JSON格式相互转换或JSON格式之间的转换。本文以烟感设备为例，介绍如何开发一个支持设备属性上报和命令下发的JavaScript编解码脚本，并介绍JavaScript脚本开发编解码插件的格式转换要求和调试方法。
![](https://support.huaweicloud.com/devg-iothub/public_sys-resources/note_3.0-zh-cn.png)
2024年12月1日后新用户不再提供JavaScript插件功能，推荐使用FunctionGraph进行JavaScript脚本编写，详细请参考[FunctionGraph开发说明](https://support.huaweicloud.com/devg-iothub/iot_02_0011.html)。
![](https://support.huaweicloud.com/devg-iothub/public_sys-resources/note_3.0-zh-cn.png)
- JavaScript语法规则需要遵循[ECMAScript 5.1规范](https://www.ecma-international.org/ecma-262/5.1/)。
- 脚本编解码插件只支持es6的let和const，其他不支持，如箭头函数等。
- JavaScript脚本大小不能超过1M。
- 产品部署JavaScript脚本插件后，该产品下所有设备的上下行数据都会进行JavaScript脚本解析。开发者实现JavaScript插件时需要注意实现设备所有的上下行场景。
- 上行数据JavaScript解码后的JSON数据需要符合平台的格式要求，具体格式要求见： [数据解码格式定义] 。
- 平台下行指令的JSON格式定义见：[数据编码格式定义]，使用JavaScript编码时需要根据平台对应的JSON格式转换为对应的二进制码流或JSON。
- 脚本编辑提供自动保存功能，每次保存的间隔时间为10秒，在脚本输入框右上角勾选自动保存即可开启此功能。
 
#### 烟感设备样例
**场景说明**
有一款烟感设备，具有如下特征：
- 具有烟雾报警功能（火灾等级）和温度上报功能。
- 支持远程控制命令，可远程打开报警功能。比如火灾现场温度，远程打开烟雾报警，提醒住户疏散。
- 该款烟感设备，设备能力比较弱，无法按照设备接口定义的JSON格式上报数据，只能上报简单的二进制数据。
**产品模型定义**
在烟感产品的开发空间，完成[产品模型](https://support.huaweicloud.com/devg-iothub/iot_01_0017.html)定义。
- level：火灾级别，用于表示火灾的严重程度。
- temperature：温度，用于表示火灾现场温度。
- SET_ALARM：打开或关闭告警命令，value=0表示关闭，value=1表示打开。
  图1模型定义-smokedetector   
  ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001950352374.png "点击放大") 
 
**编解码插件开发**
1. 在烟感产品的详情页面，选择"插件开发"，单击"脚本化开发"。 
   图2插件开发-脚本化开发   
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001950358042.png "点击放大")
   
   
2. 编写脚本，实现二进制数据到JSON数据的转换。脚本需要实现如下两个方法： 
   - decode：将设备上报的二进制数据转换为平台产品模型中定义的JSON格式。具体的JSON格式要求见： [数据解码格式定义] 。
   
   - encode：平台有下行数据发送给设备时，将平台的JSON格式数据转换为设备支持的二进制格式。平台的JSON格式见：[数据编码格式定义]。
   
   
   针对当前烟感产品实现的JavaScript样例如下：
   ```
   //上行消息类型
   var MSG_TYPE_PROPERTIES_REPORT = 'properties_report'; //设备属性上报
   var MSG_TYPE_COMMAND_RSP = 'command_response'; //设备返回命令响应
   var MSG_TYPE_PROPERTIES_SET_RSP = 'properties_set_response'; //设备返回属性设置响应
   var MSG_TYPE_PROPERTIES_GET_RSP = 'properties_get_response'; //设备返回属性查询响应
   var MSG_TYPE_MESSAGE_UP = 'message_up'; //设备消息上报
   //下行消息类型
   var MSG_TYPE_COMMANDS = 'commands'; //平台命令下发
   var MSG_TYPE_PROPERTIES_SET = 'properties_set'; //平台下发属性设置请求
   var MSG_TYPE_PROPERTIES_GET = 'properties_get'; //平台下发属性查询请求
   var MSG_TYPE_MESSAGE_DOWN = 'messages'; //平台消息下发
   //MQTT设备上行消息，topic同消息类型的映射表
   var TOPIC_REG_EXP = {
       'properties_report': new RegExp('\\$oc/devices/(\\S+)/sys/properties/report'),
       'properties_set_response': new RegExp('\\$oc/devices/(\\S+)/sys/properties/set/response/request_id=(\\S+)'),
       'properties_get_response': new RegExp('\\$oc/devices/(\\S+)/sys/properties/get/response/request_id=(\\S+)'),
       'command_response': new RegExp('\\$oc/devices/(\\S+)/sys/commands/response/request_id=(\\S+)'),
       'message_up': new RegExp('\\$oc/devices/(\\S+)/sys/messages/up')
   };
   /*
   示例：烟感设备上报属性和回复命令响应时，携带的是二进制码流，通过javascript脚本将二进制码流数据解码为符合产品模型定义的json格式数据
   传入参数：
     payload:[0x00, 0x50, 0x00, 0x5a]
     topic:$oc/devices/cf40f3c4-7152-41c6-a201-a2333122054a/sys/properties/report
   输出结果:
     {"msg_type":"properties_report","services":[{"service_id":"smokedetector","properties":{"level":80,"temperature":90}}]}
   传入参数:
     payload: [0x02, 0x00, 0x00, 0x01]
     topic: $oc/devices/cf40f3c4-7152-41c6-a201-a2333122054a/sys/commands/response/request_id=bf40f0c4-4022-41c6-a201-c5133122054a
   输出结果:
     {"msg_type":"command_response","result_code":0,"command_name":"SET_ALARM","service_id":"smokedetector","paras":{"value":"1"}}
   */
   function decode(payload, topic) {
       var jsonObj = {};
       var msgType = '';
       //如果有topic参数，根据topic参数解析消息类型
       if (null != topic) {
           msgType = topicParse(topic);
       }
       //将payload通过0xFF进行与操作，获取其对应的补码
       var uint8Array = new Uint8Array(payload.length);
       for (var i = 0; i < payload.length; i++) {
           uint8Array[i] = payload[i] & 0xff;
       }
       var dataView = new DataView(uint8Array.buffer, 0);
       //判断是属性上报的话，将二进制数据转换为属性上报格式
       if (msgType == MSG_TYPE_PROPERTIES_REPORT) {
           //设置serviceId参数值，该参数值对应产品模型中的服务类型smokedetector
           var serviceId = 'smokedetector';
           //从码流中获取level值
           var level = dataView.getInt16(0);
           //从码流中获取temperature值
           var temperature  = dataView.getInt16(2);
           //转换为属性上报的JSON格式
           jsonObj = {"msg_type":"properties_report","services":[{"service_id":serviceId,"properties":{"level":level,"temperature":temperature}}]};
       }else if (msgType == MSG_TYPE_COMMAND_RSP) { //判断是命令响应的话，将二进制数据转换为命令响应格式
           //设置serviceId参数值，该参数值对应产品模型中的服务类型smokedetector
           var serviceId = 'smokedetector';
           var command = dataView.getInt8(0); //从二进制码流中获取命令名ID
           var command_name = '';
           if (2 == command) {
               command_name = 'SET_ALARM';
           }
           var result_code  = dataView.getInt16(1); //从二进制码流中获取命令执行结果
           var value = dataView.getInt8(3); //从二进制码流中获取命令执行结果返回值
           //转换为命令响应的JSON格式
           jsonObj = {"msg_type":"command_response","result_code":result_code,"command_name":command_name,"service_id":serviceId,"paras":{"value":value}};
       }
       //转换为JSON格式的字符串数据
       return JSON.stringify(jsonObj);
   }
   /*
   示例数据：命令下发时，通过javascript的encode方法将平台JSON格式的数据，编码为二进制码流
   传入参数 ->
       {"msg_type":"commands","command_name":"SET_ALARM","service_id":"smokedetector","paras":{"value":1}}
   输出结果 ->
       [0x01,0x00, 0x00, 0x01]
   */
   function encode(json) {
       //转换为JSON对象
       var jsonObj = JSON.parse(json);
       //获取消息类型
       var msgType = jsonObj.msg_type;
       var payload = [];
       //将JSON格式数据转换为二进制数据
       if (msgType == MSG_TYPE_COMMANDS) // 命令下发
       {
           payload = payload.concat(buffer_uint8(1)); // 标识命令下发
           if (jsonObj.command_name == 'SET_ALARM') {
               payload = payload.concat(buffer_uint8(0)); // 标识命令名称
           }
           var paras_value = jsonObj.paras.value;
           payload = payload.concat(buffer_int16(paras_value)); // 设置命令属性值
       }
       //返回编码后的二进制数据
       return payload;
   }
   //根据topic名称解析出消息类型
   function topicParse(topic) {
       for(var type in TOPIC_REG_EXP){
           var pattern = TOPIC_REG_EXP[type];
           if (pattern.test(topic)) {
               return type;
           }
       }
       return '';
   }
   //将8位无符号整型转换为byte数组
   function buffer_uint8(value) {
       var uint8Array = new Uint8Array(1);
       var dataView = new DataView(uint8Array.buffer);
       dataView.setUint8(0, value);
       return [].slice.call(uint8Array);
   }
   //将16位无符号整型转换为byte数组
   function buffer_int16(value) {
       var uint8Array = new Uint8Array(2);
       var dataView = new DataView(uint8Array.buffer);
       dataView.setInt16(0, value);
       return [].slice.call(uint8Array);
   }
   //将32位无符号整型转换为byte数组
   function buffer_int32(value) {
       var uint8Array = new Uint8Array(4);
       var dataView = new DataView(uint8Array.buffer);
       dataView.setInt32(0, value);
       return [].slice.call(uint8Array);
   }
   ```
   
   
3. 在线调试脚本。脚本编辑完成后，在模拟输入下，选择模拟类型，输入模拟数据在线调试脚本。 
   1. 模拟设备上报属性数据时将二进制码流转换为JSON数据。
      - 在topic输入框中选择设备上报的topic：$oc/devices/{device_id}/sys/properties/report。
      
      - 选择模拟类型为"解码"，输入以下模拟的设备数据，然后单击"调试"。
        ```
        0050005a
        ```
        
      
      - 脚本编解码引擎会根据输入的参数和您提交javascript脚本中的decode方法，将二进制码流转换为JSON格式，并将调试结果显示在输入框中。
        图3脚本化开发-调试解码   
        ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001981477477.png "点击放大") 
      
      - 检查调试结果是否符合预期，如果不符合预期，则修改代码后重新进行调试。
       
   
   2. 模拟将应用下发的命令编码为设备能识别的二进制码流。
      - 选择模拟类型为"编码"，输入需要模拟的命令下发格式，然后单击"调试"。
        ```
        {
        "msg_type": "commands",
        "request_id": "42aa08ea-84c1-4025-a7b2-c1f6efe547c2",
        "command_name": "SET_ALARM",
        "service_id": "smokedetector",
        "paras": {
        "value": "1"
        }
        }
        ```
        
      
      - 脚本编解码引擎会根据输入的参数和您提交javascript脚本中的encode方法，将JSON格式数据转换为二进制码流，并将调试结果显示在输入框中。
        图4脚本化开发-调试编码   
        ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001981317625.png "点击放大") 
      
      - 检查调试结果是否符合预期，如果不符合预期，则修改代码后重新进行调试。
       
   
   
   
   
4. 部署脚本。确认脚本可以正确进行编解码后，单击"部署"，将该脚本提交到物联网平台，以供数据上下行时，物联网平台调用该脚本进行编解码。 
   图5脚本化开发-部署   
   ![](https://support.huaweicloud.com/devg-iothub/figure/zh-cn_image_0000001950358050.png "点击放大")
   
   
5. 使用真实设备调试。正式使用脚本之前，请使用真实设备与物联网平台进行上下行消息通信，以验证物联网平台能顺利调用脚本，解析上下行数据。
 
#### JavaScript编解码插件模板
以下为JavaScript编解码插件的模板，开发者需要按照平台提供的模板，实现对应的接口。
```
/**
 * 设备上报数据到物联网平台时调用此接口进行解码, 将设备的原始数据解码为符合产品模型定义的JSON格式数据。
 * 该接口名称和入参已经定义好，开发者只需要实现具体接口即可。
 * @param byte[] payload   设备上报的原始码流
 * @param string topic     MQTT设备上报数据时的topic，非MQTT设备上报数据时不携带该参数
 * @return string json     符合产品模型定义的JSON格式字符串
 */
function decode(payload, topic) {
    var jsonObj = {};
    return JSON.stringify(jsonObj);
}
/**
 * 物联网平台下发指令时，调用此接口进行编码, 将产品模型定义的JSON格式数据编码为设备的原始码流。
 * 该接口名称和入参格式已经定义好，开发者只需要实现具体接口即可。
 * @param string json      符合产品模型定义的JSON格式字符串
 * @return byte[] payload  编码后的原始码流
 */
function encode(json) {
    var payload = [];
    return payload;
}
```
#### MQTT设备接入时JavaScript编解码插件样例
以下为MQTT设备JavaScript编解码插件的样例，开发者可以根据样例实现对应场景的二进制和JSON格式的转换。
```
//上行消息类型
var MSG_TYPE_PROPERTIES_REPORT = 'properties_report'; //设备属性上报
var MSG_TYPE_COMMAND_RSP = 'command_response'; //设备返回命令响应
var MSG_TYPE_PROPERTIES_SET_RSP = 'properties_set_response'; //设备返回属性设置响应
var MSG_TYPE_PROPERTIES_GET_RSP = 'properties_get_response'; //设备返回属性查询响应
var MSG_TYPE_MESSAGE_UP = 'message_up'; //设备消息上报
//下行消息类型
var MSG_TYPE_COMMANDS = 'commands'; //平台命令下发
var MSG_TYPE_PROPERTIES_SET = 'properties_set'; //平台下发属性设置请求
var MSG_TYPE_PROPERTIES_GET = 'properties_get'; //平台下发属性查询请求
var MSG_TYPE_MESSAGE_DOWN = 'messages'; //平台消息下发
//MQTT设备上行消息，topic同消息类型的映射表
var TOPIC_REG_EXP = {
    'properties_report': new RegExp('\\$oc/devices/(\\S+)/sys/properties/report'),
    'properties_set_response': new RegExp('\\$oc/devices/(\\S+)/sys/properties/set/response/request_id=(\\S+)'),
    'properties_get_response': new RegExp('\\$oc/devices/(\\S+)/sys/properties/get/response/request_id=(\\S+)'),
    'command_response': new RegExp('\\$oc/devices/(\\S+)/sys/commands/response/request_id=(\\S+)'),
    'message_up': new RegExp('\\$oc/devices/(\\S+)/sys/messages/up')
};
/*
示例：烟感设备上报属性和回复命令响应时，携带的是二进制码流，通过javascript脚本将二进制码流数据解码为符合产品模型定义的json格式数据
传入参数：
  payload:[0x00, 0x50, 0x00, 0x5a]
  topic:$oc/devices/cf40f3c4-7152-41c6-a201-a2333122054a/sys/properties/report
输出结果:
  {"msg_type":"properties_report","services":[{"service_id":"smokedetector","properties":{"level":80,"temperature":90}}]}
传入参数:
  payload: [0x02, 0x00, 0x00, 0x01]
  topic: $oc/devices/cf40f3c4-7152-41c6-a201-a2333122054a/sys/commands/response/request_id=bf40f0c4-4022-41c6-a201-c5133122054a
输出结果:
  {"msg_type":"command_response","result_code":0,"command_name":"SET_ALARM","service_id":"smokedetector","paras":{"value":"1"}}
*/
function decode(payload, topic) {
    var jsonObj = {};
    var msgType = '';
    //如果有topic参数，根据topic参数解析消息类型
    if (null != topic) {
        msgType = topicParse(topic);
    }
    //将payload通过0xFF进行与操作，获取其对应的补码
    var uint8Array = new Uint8Array(payload.length);
    for (var i = 0; i < payload.length; i++) {
        uint8Array[i] = payload[i] & 0xff;
    }
    var dataView = new DataView(uint8Array.buffer, 0);
    //判断是属性上报的话，将二进制数据转换为属性上报格式
    if (msgType == MSG_TYPE_PROPERTIES_REPORT) {
        //设置serviceId参数值，该参数值对应产品模型中的服务类型smokedetector
        var serviceId = 'smokedetector';
        //从码流中获取level值
        var level = dataView.getInt16(0);
        //从码流中获取temperature值
        var temperature = dataView.getInt16(2);
        //转换为属性上报的JSON格式
        jsonObj = {
            "msg_type": "properties_report",
            "services": [{"service_id": serviceId, "properties": {"level": level, "temperature": temperature}}]
        };
    } else if (msgType == MSG_TYPE_COMMAND_RSP) { //判断是命令响应的话，将二进制数据转换为命令响应格式
        //设置serviceId参数值，该参数值对应产品模型中的服务类型smokedetector
        var serviceId = 'smokedetector';
        var command = dataView.getInt8(0); //从二进制码流中获取命令名ID
        var command_name = '';
        if (2 == command) {
            command_name = 'SET_ALARM';
        }
        var result_code = dataView.getInt16(1); //从二进制码流中获取命令执行结果
        var value = dataView.getInt8(3); //从二进制码流中获取命令执行结果返回值
        //转换为命令响应的JSON格式
        jsonObj = {
            "msg_type": "command_response",
            "result_code": result_code,
            "command_name": command_name,
            "service_id": serviceId,
            "paras": {"value": value}
        };
    } else if (msgType == MSG_TYPE_PROPERTIES_SET_RSP) {
        //转换为属性设置响应的JSON格式
        //jsonObj = {"msg_type":"properties_set_response","result_code":0,"result_desc":"success"};
    } else if (msgType == MSG_TYPE_PROPERTIES_GET_RSP) {
        //转换为属性查询响应的JSON格式
        //jsonObj = {"msg_type":"properties_get_response","services":[{"service_id":"analog","properties":{"PhV_phsA":"1","PhV_phsB":"2"}}]};
    } else if (msgType == MSG_TYPE_MESSAGE_UP) {
        //转换为消息上报的JSON格式
        //jsonObj = {"msg_type":"message_up","content":"hello"};
    }
    //转换为JSON格式的字符串数据
    return JSON.stringify(jsonObj);
}
/*
示例数据：命令下发时，通过javascript的encode方法将平台JSON格式的数据，编码为二进制码流
传入参数 ->
    {"msg_type":"commands","command_name":"SET_ALARM","service_id":"smokedetector","paras":{"value":1}}
输出结果 ->
    [0x01,0x00, 0x00, 0x01]
*/
function encode(json) {
    //转换为JSON对象
    var jsonObj = JSON.parse(json);
    //获取消息类型
    var msgType = jsonObj.msg_type;
    var payload = [];
    //将JSON格式数据转换为二进制数据
    if (msgType == MSG_TYPE_COMMANDS) {// 命令下发
        //命令下发格式样例： {"msg_type":"commands","command_name":"SET_ALARM","service_id":"smokedetector","paras":{"value":1}}
        //根据命令下发的格式转换为二进制码流
        payload = payload.concat(buffer_uint8(1)); // 标识命令下发
        if (jsonObj.command_name == 'SET_ALARM') {
            payload = payload.concat(buffer_uint8(0)); // 标识命令名称
        }
        var paras_value = jsonObj.paras.value;
        payload = payload.concat(buffer_int16(paras_value)); // 设置命令属性值
    } else if (msgType == MSG_TYPE_PROPERTIES_SET) {
        //属性设置格式样例：{"msg_type":"properties_set","services":[{"service_id":"Temperature","properties":{"value":57}}]}
        //开发者有对应属性设置场景时需要根据该JSON格式转换为对应的二进制码流
    } else if (msgType == MSG_TYPE_PROPERTIES_GET) {
        //属性查询格式样例：{"msg_type":"properties_get","service_id":"Temperature"}
        //开发者有对应属性查询场景时需要根据该JSON格式转换为对应的二进制码流
    } else if (msgType == MSG_TYPE_MESSAGE_DOWN) {
        //消息下发格式样例：{"msg_type":"messages","content":"hello"}
        //开发者对应消息下发场景时需要根据该JSON格式转换为对应的二进制码流
    }
    //返回编码后的二进制数据
    return payload;
}
//根据topic名称解析出消息类型
function topicParse(topic) {
    for (var type in TOPIC_REG_EXP) {
        var pattern = TOPIC_REG_EXP[type];
        if (pattern.test(topic)) {
            return type;
        }
    }
    return '';
}
//将8位无符号整型转换为byte数组
function buffer_uint8(value) {
    var uint8Array = new Uint8Array(1);
    var dataView = new DataView(uint8Array.buffer);
    dataView.setUint8(0, value);
    return [].slice.call(uint8Array);
}
//将16位无符号整型转换为byte数组
function buffer_int16(value) {
    var uint8Array = new Uint8Array(2);
    var dataView = new DataView(uint8Array.buffer);
    dataView.setInt16(0, value);
    return [].slice.call(uint8Array);
}
//将32位无符号整型转换为byte数组
function buffer_int32(value) {
    var uint8Array = new Uint8Array(4);
    var dataView = new DataView(uint8Array.buffer);
    dataView.setInt32(0, value);
    return [].slice.call(uint8Array);
}
```
#### NB-IoT设备接入时JavaScript编解码插件样例
以下为NB-IoT设备JavaScript编解码插件的样例，开发者可以根据样例实现NB-IoT设备数据上报和命令下发的编解码插件开发。
```
//上行消息类型
var MSG_TYPE_PROPERTIES_REPORT = 'properties_report'; //设备属性上报
var MSG_TYPE_COMMAND_RSP = 'command_response'; //设备返回命令响应
//下行消息类型
var MSG_TYPE_COMMANDS = 'commands'; //平台命令下发
var MSG_TYPE_PROPERTIES_REPORT_REPLY = 'properties_report_reply'; //设备属性上报的响应消息
//消息类型列表
var MSG_TYPE_LIST = {
    0: MSG_TYPE_PROPERTIES_REPORT,          //码流中0字节标识为设备属性上报
    1: MSG_TYPE_PROPERTIES_REPORT_REPLY,    //码流中1字节标识为设备属性上报的响应消息
    2: MSG_TYPE_COMMANDS,                   //码流中2字节标识为平台命令下发
    3: MSG_TYPE_COMMAND_RSP                 //码流中3字节标识为设备返回命令响应
};
/*
示例：烟感设备上报属性和回复命令响应时，携带的是二进制码流，通过javascript脚本将二进制码流数据解码为符合产品模型定义的json格式数据
传入参数：
  payload:[0x00, 0x00, 0x50, 0x00, 0x5a]
输出结果:
  {"msg_type":"properties_report","services":[{"service_id":"smokedetector","properties":{"level":80,"temperature":90}}]}
传入参数:
  payload: [0x03, 0x01, 0x00, 0x00, 0x01]
输出结果:
  {"msg_type":"command_response","request_id":1,"result_code":0,"paras":{"value":"1"}}
*/
function decode(payload, topic) {
    var jsonObj = {};
    //将payload通过0xFF进行与操作，获取其对应的补码
    var uint8Array = new Uint8Array(payload.length);
    for (var i = 0; i < payload.length; i++) {
        uint8Array[i] = payload[i] & 0xff;
    }
    var dataView = new DataView(uint8Array.buffer, 0);
    //从消息码流中的第一个字节获取消息类型
    var messageId = dataView.getInt8(0);
    //判断是属性上报的话，将二进制数据转换为属性上报格式
    if (MSG_TYPE_LIST[messageId] == MSG_TYPE_PROPERTIES_REPORT) {
        //设置serviceId参数值，该参数值对应产品模型中的服务类型smokedetector
        var serviceId = 'smokedetector';
        //从码流中获取level值
        var level = dataView.getInt16(1);
        //从码流中获取temperature值
        var temperature  = dataView.getInt16(3);
        //转换为属性上报的JSON格式
        jsonObj = {"msg_type":"properties_report","services":[{"service_id":serviceId,"properties":{"level":level,"temperature":temperature}}]};
    }else if (MSG_TYPE_LIST[messageId] == MSG_TYPE_COMMAND_RSP) { //判断是命令响应的话，将二进制数据转换为命令响应格式
        var requestId = dataView.getInt8(1);
        var result_code  = dataView.getInt16(2); //从二进制码流中获取命令执行结果
        var value = dataView.getInt8(4); //从二进制码流中获取命令执行结果返回值
        //转换为命令响应的JSON格式
        jsonObj = {"msg_type":"command_response","request_id":requestId,"result_code":result_code,"paras":{"value":value}};
    }
    //转换为JSON格式的字符串数据
    return JSON.stringify(jsonObj);
}
/*
示例数据：命令下发时，通过javascript的encode方法将平台JSON格式的数据，编码为二进制码流
传入参数 ->
    {"msg_type":"commands","request_id":1,"command_name":"SET_ALARM","service_id":"smokedetector","paras":{"value":1}}
输出结果 ->
    [0x02, 0x00, 0x00, 0x00, 0x01]
示例数据：设备上报属性时返回响应消息，通过javascript的encode方法将平台JSON格式的数据，编码为二进制码流
传入参数 ->
    {"msg_type":"properties_report_reply","request":"000050005a","result_code":0}
输出结果 ->
    [0x01, 0x00]
*/
function encode(json) {
    //转换为JSON对象
    var jsonObj = JSON.parse(json);
    //获取消息类型
    var msgType = jsonObj.msg_type;
    var payload = [];
    //将JSON格式数据转换为二进制数据
    if (msgType == MSG_TYPE_COMMANDS) { // 命令下发
        payload = payload.concat(buffer_uint8(2)); // 标识命令下发
        payload = payload.concat(buffer_uint8(jsonObj.request_id)); // 命令ID
        if (jsonObj.command_name == 'SET_ALARM') {
            payload = payload.concat(buffer_uint8(0)); // 标识命令名称
        }
        var paras_value = jsonObj.paras.value;
        payload = payload.concat(buffer_int16(paras_value)); // 设置命令属性值
    } else if (msgType == MSG_TYPE_PROPERTIES_REPORT_REPLY) { // 设备属性上报的响应消息
        payload = payload.concat(buffer_uint8(1)); // 标识属性上报的响应消息
        if (0 == jsonObj.result_code) {
            payload = payload.concat(buffer_uint8(0)); // 标识属性上报消息处理成功
        }
    }
    //返回编码后的二进制数据
    return payload;
}
//将8位无符号整型转换为byte数组
function buffer_uint8(value) {
    var uint8Array = new Uint8Array(1);
    var dataView = new DataView(uint8Array.buffer);
    dataView.setUint8(0, value);
    return [].slice.call(uint8Array);
}
//将16位无符号整型转换为byte数组
function buffer_int16(value) {
    var uint8Array = new Uint8Array(2);
    var dataView = new DataView(uint8Array.buffer);
    dataView.setInt16(0, value);
    return [].slice.call(uint8Array);
}
//将32位无符号整型转换为byte数组
function buffer_int32(value) {
    var uint8Array = new Uint8Array(4);
    var dataView = new DataView(uint8Array.buffer);
    dataView.setInt32(0, value);
    return [].slice.call(uint8Array);
}
```
#### JavaScript编解码插件格式要求
**数据解码格式定义**
数据解析场景，平台收到设备侧的数据时，平台会将设备侧payload中的二进制码流，通过decode方法传到javascript脚本，脚本的decode方法需要实现数据的解码，解码为平台能识别的产品模型中定义的JSON格式，平台对解析后的JSON要求如下：
- 设备属性上报
  ```
  {
      "msg_type": "properties_report",
      "services": [{
          "service_id": "Battery",
          "properties": {
              "batteryLevel": 57
          },
          "event_time": "20151212T121212Z"
      }]
  }
  ```
  
  |   字段名    | 必选/可选 |           类型            |                 参数描述                  |
  |---|---|---|---|
  | msg_type | 必选    | String                  | 属性上报的消息类型，固定为：properties_report       |
  | services | 必选    | List\<ServiceProperty\> | 设备服务数据列表（具体结构参考下表ServiceProperty定义表）。 |
     
  ServiceProperty结构定义：
  
  | 字段名        | 必选/可选 | 类型     | 参数描述                                                                                                                               |
  |:---|:---|:---|:---|
  | service_id | 必选    | String | 设备的服务ID。                                                                                                                           |
  | properties | 必选    | Object | 设备服务的属性列表，具体字段在设备关联的产品模型中定义。                                                                                                       |
  | event_time | 可选    | String | 设备采集数据UTC时间（格式：yyyyMMddTHHmmssZ），如：20161219T114920Z。 设备上报数据不带该参数或参数格式错误时，则数据上报时间以平台时间为准。 |
     
  

- 平台设置设备属性的响应消息
  ```
  {
     "msg_type": "properties_set_response",
     "request_id": "42aa08ea-84c1-4025-a7b2-c1f6efe547c2",
     "result_code": 0,
     "result_desc": "success"
  }
  ```
  
  |     字段名     | 必选/可选 |   类型    |                                      参数描述                                       |
  |---|---|---|---|
  | msg_type    | 必选    | String  | 属性上报的消息类型，固定为： properties_set_response |
  | request_id  | 可选    | String  | 用于唯一标识这次请求，设备侧收到的消息带该参数时，响应消息需要将该参数值返回给平台。如果解码后的消息不带该字段，则以topic中带的request_id为准。 |
  | result_code | 可选    | Integer | 命令的执行结果，0表示成功，其他表示失败。不带默认认为成功。                                                  |
  | result_desc | 可选    | String  | 属性设置的响应描述。                                                                      |
     
  
- 平台查询设备属性的响应消息
  ```
  {
  "msg_type": "properties_get_response",
  "request_id": "42aa08ea-84c1-4025-a7b2-c1f6efe547c2",
      "services": [
          {
              "service_id": "analog",
              "properties": {
                  "PhV_phsA": "1",
                  "PhV_phsB": "2"
              },
              "event_time": "20190606T121212Z"
          }
      ]
  }
  ```
  
  |    字段名     | 必选/可选 |           类型            |                                      参数描述                                       |
  |---|---|---|---|
  | msg_type   | 必选    | String                  | 固定为：properties_get_response                                                     |
  | request_id | 可选    | String                  | 用于唯一标识这次请求，设备侧收到的消息带该参数时，响应消息需要将该参数值返回给平台。如果解码后的消息不带该字段，则以topic中带的request_id为准。 |
  | services   | 必选    | List\<ServiceProperty\> | 设备服务数据列表（具体结构参考下表ServiceProperty定义表）。                                           |
     
  ServiceProperty结构定义：
  
  | 字段名        | 必选/可选 | 类型     | 参数描述                                                                                                                              |
  |:---|:---|:---|:---|
  | service_id | 必选    | String | 设备的服务ID。                                                                                                                          |
  | properties | 必选    | Object | 设备服务的属性列表，具体字段在设备关联的产品模型中定义。                                                                                                      |
  | event_time | 可选    | String | 设备采集数据UTC时间（格式：yyyyMMddTHHmmssZ），如：20161219T114920Z。 设备上报数据不带该参数或参数格式错误时，则数据上报时间以平台时间为准。 |
     
  
- 平台命令下发的响应消息
  ```
  {
    "msg_type": "command_response",
    "request_id": "42aa08ea-84c1-4025-a7b2-c1f6efe547c2",
     "result_code": 0,
    "command_name": "ON_OFF",
    "service_id": "WaterMeter",
    "paras": {
      "value": "1"
    }  
  }
  ```
  
  |      字段名      | 必选/可选 |   类型    |                                      参数描述                                       |
  |---|---|---|---|
  | msg_type      | 必选    | String  | 固定为：command_response                                                            |
  | request_id    | 可选    | String  | 用于唯一标识这次请求，设备侧收到的消息带该参数时，响应消息需要将该参数值返回给平台。如果解码后的消息不带该字段，则以topic中带的request_id为准。 |
  | result_code   | 可选    | Integer | 标识命令的执行结果，0表示成功，其他表示失败。不带默认认为成功。                                                |
  | response_name | 可选    | String  | 命令的响应名称，在设备关联的产品模型中定义。                                                          |
  | paras         | 可选    | Object  | 命令的响应参数，具体字段在设备关联的产品模型中定义。                                                      |
     
  
- 设备消息上报
  ```
  {
    "msg_type": "message_up",
    "content": "hello"
  }
  ```
  
  |   字段名    | 必选/可选 |   类型   |      参数描述      |
  |---|---|---|---|
  | msg_type | 必选    | String | 固定为：message_up |
  | content  | 可选    | String | 消息内容。          |
     
  
**数据编码格式定义**
数据解析场景，平台指令下发时，平台会将产品模型定义的JSON格式数据（如果不是该格式的数据则可能会导致编解码失败），通过encode方法传给javascript脚本，脚本的encode方法需要实现数据的编码将JSON格式的数据，编码为设备可以识别的二进制码流，编码时平台传递到脚本的JSON格式如下：
- 设备命令下发
  ```
  { 
    "msg_type": "commands", 
     "request_id": "42aa08ea-84c1-4025-a7b2-c1f6efe547c2",
    "command_name": "ON_OFF", 
    "service_id": "WaterMeter", 
    "paras": { 
      "value": 1
    } 
  }
  ```
  
  | 字段名          | 必选/可选 | 类型     | 参数描述                         |
  |:---|:---|:---|:---|
  | msg_type     | 必选    | String | 固定为：commands                 |
  | request_id   | 必选    | String | 用于唯一标识这次请求，该标识会通过topic下发给设备。 |
  | service_id   | 可选    | String | 设备的服务ID。                     |
  | command_name | 可选    | String | 设备命令名称，在设备关联的产品模型中定义。        |
  | paras        | 可选    | Object | 设备命令的执行参数，具体字段在设备关联的产品模型中定义。 |
     
  
- 平台设置设备属性
  ```
  { 
  "msg_type": "properties_set",
  "request_id": "42aa08ea-84c1-4025-a7b2-c1f6efe547c2",
      "services": [{ 
              "service_id": "Temperature", 
              "properties": { 
                  "value": 57 
              } 
          }, 
          { 
              "service_id": "Battery", 
              "properties": { 
                  "level": 80 
              } 
          } 
      ] 
  }
  ```
  
  |    字段名     | 必选/可选 |           类型            |                    参数描述                    |
  |---|---|---|---|
  | msg_type   | 必选    | String                  | 固定为：properties_set                         |
  | request_id | 必选    | String                  | 用于唯一标识这次请求，设备侧收到的消息带该参数时，响应消息需要将该参数值返回给平台。 |
  | services   | 必选    | List\<ServiceProperty\> | 设备服务数据列表。                                  |
     
  ServiceProperty结构定义：
  
  | 字段名        | 必选/可选 | 类型     | 参数描述                    |
  |:---|:---|:---|:---|
  | service_id | 必选    | String | 设备的服务ID。                |
  | properties | 必选    | Object | 设备服务的属性列表，具体字段在产品模型里定义。 |
     
  
- 平台查询设备属性
  ```
  { 
     "msg_type": "properties_get",
     "request_id": "42aa08ea-84c1-4025-a7b2-c1f6efe547c2",
     "service_id": "Temperature" 
  }
  ```
  
  |    字段名     | 必选/可选 |   类型   |             参数描述             |
  |---|---|---|---|
  | msg_type   | 必选    | String | 固定为：properties_get           |
  | request_id | 必选    | String | 用于唯一标识这次请求，该标识会通过topic下发给设备。 |
  | service_id | 可选    | String | 设备的服务ID。                     |
     
  
- 属性上报的响应消息（NB-IoT设备接入时属性上报对应的响应）
  ```
  { 
    "msg_type": "properties_report_reply",
    "request": "213355656",
    "result_code": 0
  }
  ```
  
  |     字段名     | 必选/可选 |   类型    |            参数描述             |
  |---|---|---|---|
  | msg_type    | 必选    | String  | 固定为：properties_report_reply |
  | request     | 可选    | String  | 属性上报的BASE64编码字符串。           |
  | result_code | 可选    | Integer | 属性上报的执行结果。                  |
  | has_more    | 可选    | Boolean | 是否存在缓存命令。                   |
     
  
- 设备消息下发
  ```
  { 
    "msg_type": "messages",
    "content": "hello"
  }
  ```
  
  |   字段名    | 必选/可选 |   类型   |     参数描述     |
  |---|---|---|---|
  | msg_type | 必选    | String | 固定为：messages |
  | content  | 可选    | String | 消息下发的内容。     |
     
  
 
