网络
虚拟私有云 VPC
弹性公网IP EIP
弹性负载均衡 ELB
NAT网关 NAT
云专线 DC
虚拟专用网络 VPN
云连接 CC
VPC终端节点 VPCEP
企业路由器 ER
企业交换机 ESW
全球加速 GA
企业连接 EC
云原生应用网络 ANC
安全与合规
安全技术与应用
Web应用防火墙 WAF
企业主机安全 HSS
云防火墙 CFW
安全云脑 SecMaster
DDoS防护 AAD
数据加密服务 DEW
数据库安全服务 DBSS
云堡垒机 CBH
数据安全中心 DSC
云证书管理服务 CCM
威胁检测服务 MTD
认证测试中心 CTC
边缘安全 EdgeSec
应用中间件
微服务引擎 CSE
分布式消息服务Kafka版
分布式消息服务RabbitMQ版
分布式消息服务RocketMQ版
API网关 APIG
分布式缓存服务 DCS
多活高可用服务 MAS
事件网格 EG
管理与监管
统一身份认证服务 IAM
消息通知服务 SMN
云监控服务 CES
应用运维管理 AOM
应用性能管理 APM
云日志服务 LTS
云审计服务 CTS
标签管理服务 TMS
配置审计 Config
应用身份管理服务 OneAccess
资源访问管理 RAM
组织 Organizations
资源编排服务 RFS
优化顾问 OA
IAM 身份中心
云运维中心 COC
资源治理中心 RGC
解决方案
高性能计算 HPC
SAP
混合云灾备
开天工业工作台 MIW
Haydn解决方案工厂
数字化诊断治理专家服务
云生态
云商店
合作伙伴中心
华为云开发者学堂
华为云慧通差旅
开发与运维
软件开发生产线 CodeArts
需求管理 CodeArts Req
流水线 CodeArts Pipeline
代码检查 CodeArts Check
编译构建 CodeArts Build
部署 CodeArts Deploy
测试计划 CodeArts TestPlan
制品仓库 CodeArts Artifact
移动应用测试 MobileAPPTest
CodeArts IDE Online
开源镜像站 Mirrors
性能测试 CodeArts PerfTest
应用管理与运维平台 ServiceStage
云应用引擎 CAE
开源治理服务 CodeArts Governance
华为云Astro轻应用
CodeArts IDE
Astro工作流 AstroFlow
代码托管 CodeArts Repo
漏洞管理服务 CodeArts Inspector
联接 CodeArtsLink
软件建模 CodeArts Modeling
Astro企业应用 AstroPro
CodeArts 盘古助手
华为云Astro大屏应用
计算
弹性云服务器 ECS
Flexus云服务
裸金属服务器 BMS
云手机服务器 CPH
专属主机 DeH
弹性伸缩 AS
镜像服务 IMS
函数工作流 FunctionGraph
云耀云服务器(旧版)
VR云渲游平台 CVR
Huawei Cloud EulerOS
云化数据中心 CloudDC
网络
虚拟私有云 VPC
弹性公网IP EIP
弹性负载均衡 ELB
NAT网关 NAT
云专线 DC
虚拟专用网络 VPN
云连接 CC
VPC终端节点 VPCEP
企业路由器 ER
企业交换机 ESW
全球加速 GA
企业连接 EC
云原生应用网络 ANC
CDN与智能边缘
内容分发网络 CDN
智能边缘云 IEC
智能边缘平台 IEF
CloudPond云服务
安全与合规
安全技术与应用
Web应用防火墙 WAF
企业主机安全 HSS
云防火墙 CFW
安全云脑 SecMaster
DDoS防护 AAD
数据加密服务 DEW
数据库安全服务 DBSS
云堡垒机 CBH
数据安全中心 DSC
云证书管理服务 CCM
威胁检测服务 MTD
认证测试中心 CTC
边缘安全 EdgeSec
大数据
MapReduce服务 MRS
数据湖探索 DLI
表格存储服务 CloudTable
可信智能计算服务 TICS
推荐系统 RES
云搜索服务 CSS
数据可视化 DLV
数据接入服务 DIS
数据仓库服务 GaussDB(DWS)
数据治理中心 DataArts Studio
湖仓构建 LakeFormation
智能数据洞察 DataArts Insight
应用中间件
微服务引擎 CSE
分布式消息服务Kafka版
分布式消息服务RabbitMQ版
分布式消息服务RocketMQ版
API网关 APIG
分布式缓存服务 DCS
多活高可用服务 MAS
事件网格 EG
开天aPaaS
应用平台 AppStage
开天企业工作台 MSSE
开天集成工作台 MSSI
API中心 API Hub
云消息服务 KooMessage
交换数据空间 EDS
云地图服务 KooMap
云手机服务 KooPhone
组织成员账号 OrgID
云空间服务 KooDrive
管理与监管
统一身份认证服务 IAM
消息通知服务 SMN
云监控服务 CES
应用运维管理 AOM
应用性能管理 APM
云日志服务 LTS
云审计服务 CTS
标签管理服务 TMS
配置审计 Config
应用身份管理服务 OneAccess
资源访问管理 RAM
组织 Organizations
资源编排服务 RFS
优化顾问 OA
IAM 身份中心
云运维中心 COC
资源治理中心 RGC
区块链
区块链服务 BCS
数字资产链 DAC
华为云区块链引擎服务 HBS
解决方案
高性能计算 HPC
SAP
混合云灾备
开天工业工作台 MIW
Haydn解决方案工厂
数字化诊断治理专家服务
价格
成本优化最佳实践
专属云商业逻辑
云生态
云商店
合作伙伴中心
华为云开发者学堂
华为云慧通差旅
其他
管理控制台
消息中心
产品价格详情
系统权限
客户关联华为云合作伙伴须知
公共问题
宽限期保留期
奖励推广计划
活动
云服务信任体系能力说明
开发与运维
软件开发生产线 CodeArts
需求管理 CodeArts Req
流水线 CodeArts Pipeline
代码检查 CodeArts Check
编译构建 CodeArts Build
部署 CodeArts Deploy
测试计划 CodeArts TestPlan
制品仓库 CodeArts Artifact
移动应用测试 MobileAPPTest
CodeArts IDE Online
开源镜像站 Mirrors
性能测试 CodeArts PerfTest
应用管理与运维平台 ServiceStage
云应用引擎 CAE
开源治理服务 CodeArts Governance
华为云Astro轻应用
CodeArts IDE
Astro工作流 AstroFlow
代码托管 CodeArts Repo
漏洞管理服务 CodeArts Inspector
联接 CodeArtsLink
软件建模 CodeArts Modeling
Astro企业应用 AstroPro
CodeArts 盘古助手
华为云Astro大屏应用
存储
对象存储服务 OBS
云硬盘 EVS
云备份 CBR
高性能弹性文件服务 SFS Turbo
弹性文件服务 SFS
存储容灾服务 SDRS
云硬盘备份 VBS
云服务器备份 CSBS
数据快递服务 DES
云存储网关 CSG
专属分布式存储服务 DSS
数据工坊 DWR
地图数据 MapDS
键值存储服务 KVS
容器
云容器引擎 CCE
云容器实例 CCI
容器镜像服务 SWR
云原生服务中心 OSC
应用服务网格 ASM
华为云UCS
数据库
云数据库 RDS
数据复制服务 DRS
文档数据库服务 DDS
分布式数据库中间件 DDM
云数据库 GaussDB
云数据库 GeminiDB
数据管理服务 DAS
数据库和应用迁移 UGO
云数据库 TaurusDB
人工智能
AI开发平台ModelArts
华为HiLens
图引擎服务 GES
图像识别 Image
文字识别 OCR
自然语言处理 NLP
内容审核 Moderation
图像搜索 ImageSearch
医疗智能体 EIHealth
企业级AI应用开发专业套件 ModelArts Pro
人脸识别服务 FRS
对话机器人服务 CBS
语音交互服务 SIS
人证核身服务 IVS
视频智能分析服务 VIAS
城市智能体
自动驾驶云服务 Octopus
盘古大模型 PanguLargeModels
IoT物联网
设备接入 IoTDA
全球SIM联接 GSL
IoT数据分析 IoTA
路网数字化服务 DRIS
IoT边缘 IoTEdge
设备发放 IoTDP
企业应用
域名注册服务 Domains
云解析服务 DNS
企业门户 EWP
ICP备案
商标注册
华为云WeLink
华为云会议 Meeting
隐私保护通话 PrivateNumber
语音通话 VoiceCall
消息&短信 MSGSMS
云管理网络
SD-WAN 云服务
边缘数据中心管理 EDCM
云桌面 Workspace
应用与数据集成平台 ROMA Connect
ROMA资产中心 ROMA Exchange
API全生命周期管理 ROMA API
政企自服务管理 ESM
视频
实时音视频 SparkRTC
视频直播 Live
视频点播 VOD
媒体处理 MPC
视频接入服务 VIS
数字内容生产线 MetaStudio
迁移
主机迁移服务 SMS
对象存储迁移服务 OMS
云数据迁移 CDM
迁移中心 MGC
专属云
专属计算集群 DCC
开发者工具
SDK开发指南
API签名指南
DevStar
华为云命令行工具服务 KooCLI
Huawei Cloud Toolkit
CodeArts API
云化转型
云架构中心
云采用框架
用户服务
账号中心
费用中心
成本中心
资源中心
企业管理
工单管理
客户运营能力
国际站常见问题
支持计划
专业服务
合作伙伴支持计划
我的凭证
华为云公共事业服务云平台
工业软件
工业数字模型驱动引擎
硬件开发工具链平台云服务
工业数据转换引擎云服务

使用JavaScript开发插件

更新时间:2025-02-14 GMT+08:00
分享

物联网平台支持JavaScript脚本编解码的功能,根据您提交的脚本文件,实现设备二进制格式与JSON格式相互转换或JSON格式之间的转换。本文以烟感设备为例,介绍如何开发一个支持设备属性上报和命令下发的JavaScript编解码脚本,并介绍JavaScript脚本开发编解码插件的格式转换要求和调试方法。

说明:
  • 2024年12月1日后新用户不再提供JavaScript插件功能,推荐使用FunctionGraph,详细请参考FunctionGraph开发
  • JavaScript语法规则需要遵循ECMAScript 5.1规范
  • 脚本编解码插件只支持es6的let和const,其他不支持,如箭头函数等。
  • JavaScript脚本大小不能超过1M。
  • 产品部署JavaScript脚本插件后,该产品下所有设备的上下行数据都会进行JavaScript脚本解析。开发者实现JavaScript插件时需要注意实现设备所有的上下行场景。
  • 上行数据JavaScript解码后的JSON数据需要符合平台的格式要求,具体格式要求见: 数据解码格式定义
  • 平台下行指令的JSON格式定义见:数据编码格式定义,使用JavaScript编码时需要根据平台对应的JSON格式转换为对应的二进制码流或JSON。
  • 脚本编辑提供自动保存功能,每次保存的间隔时间为10秒,在脚本输入框右上角勾选自动保存即可开启此功能。

烟感设备样例

场景说明

有一款烟感设备,具有如下特征:

  • 具有烟雾报警功能(火灾等级)和温度上报功能。
  • 支持远程控制命令,可远程打开报警功能。比如火灾现场温度,远程打开烟雾报警,提醒住户疏散。
  • 该款烟感设备,设备能力比较弱,无法按照设备接口定义的JSON格式上报数据,只能上报简单的二进制数据。

产品模型定义

在烟感产品的开发空间,完成产品模型定义。
  • level:火灾级别,用于表示火灾的严重程度。
  • temperature:温度,用于表示火灾现场温度。
  • SET_ALARM:打开或关闭告警命令,value=0表示关闭,value=1表示打开。
    图1 模型定义-smokedetector

编解码插件开发

  1. 在烟感产品的详情页面,选择“插件开发”,单击“脚本化开发”。

    图2 插件开发-脚本化开发

  2. 编写脚本,实现二进制数据到JSON数据的转换。脚本需要实现如下两个方法:

    • decode:将设备上报的二进制数据转换为平台产品模型中定义的JSON格式。具体的JSON格式要求见: 数据解码格式定义
    • encode:平台有下行数据发送给设备时,将平台的JSON格式数据转换为设备支持的二进制格式。平台的JSON格式见:数据编码格式定义
    针对当前烟感产品实现的JavaScript样例如下:
      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
    //上行消息类型
    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":"smokerdector","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":"smokerdector","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参数值,该参数值对应产品模型中的服务类型smokerdector
            var serviceId = 'smokerdector';
            //从码流中获取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参数值,该参数值对应产品模型中的服务类型smokerdector
            var serviceId = 'smokerdector';
            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":"smokerdector","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 脚本化开发-调试解码
      • 检查调试结果是否符合预期,如果不符合预期,则修改代码后重新进行调试。
    2. 模拟将应用下发的命令编码为设备能识别的二进制码流。
      • 选择模拟类型为“编码”,输入需要模拟的命令下发格式,然后单击“调试”。
        1
        2
        3
        4
        5
        6
        7
        8
        9
        {
        	"msg_type": "commands",
        	"request_id": "42aa08ea-84c1-4025-a7b2-c1f6efe547c2",
        	"command_name": "SET_ALARM",
        	"service_id": "smokerdector",
        	"paras": {
        		"value": "1"
        	}
        }
        
      • 脚本编解码引擎会根据输入的参数和您提交javascript脚本中的encode方法,将JSON格式数据转换为二进制码流,并将调试结果显示在输入框中。
        图4 脚本化开发-调试编码
      • 检查调试结果是否符合预期,如果不符合预期,则修改代码后重新进行调试。

  4. 部署脚本。确认脚本可以正确进行编解码后,单击“部署”,将该脚本提交到物联网平台,以供数据上下行时,物联网平台调用该脚本进行编解码。

    图5 脚本化开发-部署

  5. 使用真实设备调试。正式使用脚本之前,请使用真实设备与物联网平台进行上下行消息通信,以验证物联网平台能顺利调用脚本,解析上下行数据。

JavaScript编解码插件模板

以下为JavaScript编解码插件的模板,开发者需要按照平台提供的模板,实现对应的接口。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * 设备上报数据到物联网平台时调用此接口进行解码, 将设备的原始数据解码为符合产品模型定义的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格式的转换。

  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
//上行消息类型
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":"smokerdector","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":"smokerdector","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参数值,该参数值对应产品模型中的服务类型smokerdector
        var serviceId = 'smokerdector';
        //从码流中获取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参数值,该参数值对应产品模型中的服务类型smokerdector
        var serviceId = 'smokerdector';
        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":"smokerdector","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":"smokerdector","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设备数据上报和命令下发的编解码插件开发。

  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
//上行消息类型
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":"smokerdector","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参数值,该参数值对应产品模型中的服务类型smokerdector
        var serviceId = 'smokerdector';
        //从码流中获取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":"smokerdector","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要求如下:

  • 设备属性上报
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    {
        "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。

    设备上报数据不带该参数或参数格式错误时,则数据上报时间以平台时间为准。

  • 平台设置设备属性的响应消息
    1
    2
    3
    4
    5
    6
    {
       "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

    属性设置的响应描述。

  • 平台查询设备属性的响应消息
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    {
    "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。

    设备上报数据不带该参数或参数格式错误时,则数据上报时间以平台时间为准。

  • 平台命令下发的响应消息
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    {
      "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

    命令的响应参数,具体字段在设备关联的产品模型中定义。

  • 设备消息上报
    1
    2
    3
    4
    {
      "msg_type": "message_up",
      "content": "hello"
    }
    

    字段名

    必选/可选

    类型

    参数描述

    msg_type

    必选

    String

    固定为:message_up

    content

    可选

    String

    消息内容。

数据编码格式定义

数据解析场景,平台指令下发时,平台会将产品模型定义的JSON格式数据(如果不是该格式的数据则可能会导致编解码失败),通过encode方法传给javascript脚本,脚本的encode方法需要实现数据的编码将JSON格式的数据,编码为设备可以识别的二进制码流,编码时平台传递到脚本的JSON格式如下:

  • 设备命令下发
    1
    2
    3
    4
    5
    6
    7
    8
    9
    { 
      "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

    设备命令的执行参数,具体字段在设备关联的产品模型中定义。

  • 平台设置设备属性
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    { 
    "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

    设备服务的属性列表,具体字段在产品模型里定义。

  • 平台查询设备属性
    1
    2
    3
    4
    5
    { 
       "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设备接入时属性上报对应的响应)
    1
    2
    3
    4
    5
    { 
      "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

    是否存在缓存命令。

  • 设备消息下发
    1
    2
    3
    4
    { 
      "msg_type": "messages",
      "content": "hello"
    }
    

    字段名

    必选/可选

    类型

    参数描述

    msg_type

    必选

    String

    固定为:messages

    content

    可选

    String

    消息下发的内容。

提示

您即将访问非华为云网站,请注意账号财产安全

文档反馈

文档反馈

意见反馈

0/500

标记内容

同时提交标记内容