芯片开放社区
直播中

h1654155598.0450

12年用户 668经验值
私信 关注
[技术讨论]

分布式物模型开发实战过程

1 概述

云端要想与IoT设备进行数据交互,那么就必须知道IoT设备具备哪些功能,具有哪些属性,而要描述这些功能和属性,就需要物模型的概念。物模型是物理空间中的实体(如传感器、车载装置、楼宇、工厂等)在云端的数字化表示,从属性、服务和事件三个维度,分别描述了该实体是什么、能做什么、可以对外提供哪些信息。定义了物模型的这三个维度,即完成了产品功能的定义。因此,要实现云端对IoT设备的操作及状态的显示(例如通过APP等),需要在云端定义IoT设备的物模型。

另一方面,我们知道,在BLE Mesh网络中,网关对子设备的各种状态设置及状态获取,都是通过既定的mesh model来实现的,网关和子设备根据对应mesh model中规定的opcode/状态等进行数据的交互和解析。

这样一来,要想通过云端(例如通过APP)来对网关下的BLE Mesh子设备进行控制或状态显示,需要经过云端物模型与Mesh model之间的协议转换。以往的做法,都是在网关设备中,将已知的物模型与mesh model之间做转换。既然只针对“已知”的物模型与mesh model,那么这种方法就有一个天然的缺陷,即每增加一个新的物模型或mesh model,网关就得做一次升级,来完成新的物模型与mesh model之间的转换,每次这种转换的开发都会带来额外的工作量。


为了解决上述问题,网关SDK提供了一套基于Javascript脚本的轻量的分布式物模型开发方法,基于这个开发方法,用户可在不修改网关代码的基础上,仅开发Javascript脚本并在OCC上发布即可完成物模型的转换功能。

2 开发步骤

对于开发者,最快速的开发方式就是基于SDK内提供的模板进行扩展或修改,模板可在已发布SDK中solution/ble_mesh_gateway_demo/script/js_demo下获得。下面介绍如何根据模板进行开发。

2.1 确认mesh model

确认所需开发设备的mesh model,包括对应的opcode,然后在模板对应的类型上进行扩展,如模板实现的onoff model的ModelID及相关opcode如下

// id of the mesh model standard
var ModelID = {
    UNKNOWN: 0,
    GEN_ONOFF_CLI: 0x1001,
};// opcode of the mesh model standard
var OpCode = {
    UNKNOWN: 0,
    // for model sig onoff
    ONOFF_GET: 0x8201,
    ONOFF_SET_ACK: 0x8202,
    ONOFF_SET: 0x8203,
    ONOFF_STATUS: 0x8204,      
};2.2 实现mesh model类及对应encode/decode方法

云端物模型转换为mesh raw data的操作,使用模板的encode方法,而mesh data转换为云端物模型的操作对应模板的decode方法。用户要实现新的model,可以参考模板中onoff model类及对应encode/decode的实现,在继承了model_base的基础上实现对应opcode的encode/decode方法。

以onoff model中设置开关状态(Generic OnOff Set ACK)为例,OnOff Set消息格式如下

字段

字段长度(字节)

备注

opcode

2

0x8202

目标开关状态

1

需设置的目标开关状态

TID

1

TID

渐变时间

1

可选字段

延迟时间

1

可选字段

对应到js中的encode方法就是

                                                                // encode to ONOFF_SET_ACK/ONOFF_SET mesh protocol
                this.encode = function(dev) {
                    var data = [];
                    var tid_key = "tid_0x" + this.model_id.toString(16);  
                    var tid = dev.value.get(tid_key);
            
                    data[0] = (this.opcode & 0xff00) >> 8;
                    data[1] = (this.opcode & 0xff);
                    data[2] = this.onoff_status;
                    data[3] = tid;
                    console.log("tid=" + tid);
            
                    if (this.trans) {
                        data[4] = this.trans;
                        data[5] = this.delay;
                    }
               
                    return data;
                }
其它消息的处理与此类似,只需在js脚本的encode/decode方法中实现各消息的转化即可。下面是Gereric onoff model完整的类实现

// implements for generic onoff cli model
function model_sig_onoff() {
    // extends the model_base class
    inherits(model_sig_onoff, model_base, this);

    this.model_id = ModelID.GEN_ONOFF_CLI;
    this.opcodes = [
        {
            codes: [OpCode.ONOFF_GET],
            opclass: function() {
                // encode to ONOFF_GET mesh protocol
                this.encode = function(dev) {
                    var data = [];
            
                    data[0] = (this.opcode & 0xff00) >> 8;
                    data[1] = (this.opcode & 0xff);
               
                    return data;
                }
            }
        },
        {
            codes: [OpCode.ONOFF_SET_ACK, OpCode.ONOFF_SET],
            opclass: function() {
                this.onoff_status = 0;
                this.trans = 0;
                this.delay = 1;
                // encode to ONOFF_SET_ACK/ONOFF_SET mesh protocol
                this.encode = function(dev) {
                    var data = [];
                    var tid_key = "tid_0x" + this.model_id.toString(16);  
                    var tid = dev.value.get(tid_key);
            
                    data[0] = (this.opcode & 0xff00) >> 8;
                    data[1] = (this.opcode & 0xff);
                    data[2] = this.onoff_status;
                    data[3] = tid;
                    console.log("tid=" + tid);
            
                    if (this.trans) {
                        data[4] = this.trans;
                        data[5] = this.delay;
                    }
               
                    return data;
                }
            }
        },
        {
            codes: [OpCode.ONOFF_STATUS],
            opclass: function() {
                this.min_len = 1;
                this.onoff_status = 0;
                // decode from ONOFF_STATUS mesh protocol
                this.decode = function(dev, data) {
                    if (data && data.length >= this.min_len) {
                        this.onoff_status = data[0];
                        return 0;
                    }
                    return -1;
                }
            }
        }
    ];
}2.3 实现所需开发设备model的实例

这个实例汇集了所有需要实现的mesh model

// instance of the mesh management
var Mesh = {
    // register mesh models
    mesh_models: [
        new model_sig_onoff()
    ],
    ... ...
}2.4 修改json字符串

修改cloud_to_device/device_to_cloud方法中云端物模型相关key值,如模板对应飞燕云上子设备物模型开关属性的json字串为{"powerstate", 1},因此在cloud_to_device/device_to_cloud方法中json值为powerstate,用户可根据实际物模型进行修改

var runner = {
    /**
     * convert the IoT cloud platform object model protocol into a device
     * protocol and send it to the underlying physical link
     * example=> {"powerstate":1}->8202 01 01
     * @param dev the virtual terminal sub device
     * @param cloud_data downstream of the IoT cloud platform
     * @return 0/-1
     */
    cloud_to_device: function (dev, cloud_data) {
        // cloud_data may be a json-string, convert to a json object
        var json = JSON.parse(cloud_data);
        if (json) {
            var val = json['powerstate'];
            if (val != null) {
                ... ...
            }
        }
        
        return -1;
    },
    /**
     * convert the device protocol to the IoT cloud platform object
     * model protocol and send it to the cloud
     * example=> 8204 01->{"powerstate":1}
     * @param dev the virtual terminal sub device
     * @param dev_data upstream of the sub device
     * @return 0/-1
     */
    device_to_cloud: function (dev, dev_data) {
        if (!(dev && dev_data && dev_data.opcode && dev_data.data)) {
            console.log('params is UNKNOWN');
            return null;
        }
        // get op instance by the opcode
        var op = Mesh.get_opcode(dev_data.opcode);
        if (op) {
            // convert to protocol of the IoT cloud platform object model protocol
            var rc = op.decode(dev, dev_data.data);
            if (rc == 0) {
                var json = new Object();
   
                json["powerstate"] = op.onoff_status;
                // convert to json string from a json object
                var data = JSON.stringify(json);
                // send IoT cloud object model protocol to the cloud
                return dev.send_to_cloud(data);
            }
        }

        return -1;
    }3 物模型配置

在完成js脚本后,需要在平头哥芯片开放社区(OCC)上提交该脚本并进行配置。

在OCC上正确创建子设备产品后,点击【产品管理】->选择产品,点击【编辑】-> 点击【物模型配置】页签,进入物模型配置页面。OCC提供了一个简单的js脚本编辑器。新建产品的脚本输入框中会自动填充物模型模版,在模版基础上可以根据实际场景开发。其中:cloud_to_devicedevice_to_cloud 不能修改名称,参数dev是系统内置,在线调试不需要单独传入。编写好的脚本会自动存入草稿,也可以通过点击脚本编辑器下方的保存按钮,存入到草稿。编辑好物模型脚本后,可以对其进行简单测试:

a.模拟输入下,选择对应的模拟类型

b.输入模拟的设备上报数据或者设备接收数据,单击执行

在线调试脚本能正常可用后,单击提交,将脚本发布到OCC。

发布之后可以在脚本编辑器的右上方点击的草稿线上运行脚本切换草稿和线上脚本。

编辑器界面如下:


4 总结

在按照上述开发步骤,将位于solution/ble_mesh_gateway_demo/script/js_demo下的js脚本进行修改或扩展,并在occ上成功进行发布后,网关就会根据自身的pid,从occ上自动拉取对应的js脚本并解析,完成云端物模型与BLE Mesh model之间的协议转换,实现云端与BLE Mesh子设备之间的数据交互。




文章转载自:平头哥芯片开放社区 作者:何佩奇

更多回帖

发帖
×
20
完善资料,
赚取积分