帮助文档

FAQ


Gateway Plugin 开发指南

<p>[TOC]</p> <h2>1、背景</h2> <p>瑞瀛 ZigBee 网关的整体技术架构如下图所示: <img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=3955ba65b03ae0d002a38cb30fb63e2e&amp;amp;file=file.png" alt="" /> 其中 ZigBee 模组上运行的程序实现了核心的 ZigBee 协议栈,在 ZigBee 网络中作为网络协调器(COO)使用,通过串口接入 Linux 主机。串口通讯协议为 Rexense Wireless Protocol (RWP)。 Wireless SDK 以动态库的形式部署在 Linux 主机上,主要的工作是封装了串口操作,并且将大部分 ZigBee Device Object (ZDO) 的处理逻辑封装起来,使得上层应用能够很方便地处理设备入网离网的操作。 绝大部分的业务逻辑在网关主应用程序中处理,主要的功能有:</p> <ul> <li>ZCL 解析:实现了《ZigBee Cluster Library Specification》中定义的常用功能,针对于标准设备可以实现免对接接入;</li> <li>物模型管理:根据《子设备品类》中定义的物模型,将 ZigBee 中的 Attribute/Command 映射为 IoT 物模型中的 Property/Event/Service;</li> <li>子设备管理:实现了子设备的基础信息和属性值的缓存;</li> <li>本地场景管理:实现了场景引擎和对外提供的操作接口;</li> <li>内置 Web 服务:提供独立的 RESTful API 接口来实现纯网关控制;</li> <li>插件管理:动态加载插件。</li> </ul> <p>北向与平台的通讯使用插件的形式嵌入到应用中,在插件中可以独立实现部分业务逻辑。同时,在主要的与设备进行通讯的环节均能接收到来自主应用框架的通知。本文主要就是针对于插件开发作出的说明。</p> <h2>2、概览</h2> <h3>2.1、生命周期</h3> <p>插件的生命周期如下图所示: <img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=93a8f4a95c7b78e259c45093351e7b8a&amp;amp;file=file.png" alt="" /> 插件被放置于固定的路径下:/lib/plugin/。网关主应用在启动时会扫描该路径下的所有.so动态库,并逐一加载和初始化。网关的插件管理模块提供插件的启用和禁用接口,根据数据库中保存的信息判断已加载的插件是否需要启动。在初始化工作完成后进入网关的运行状态,网关应用将以通知的形式将数据传递到插件,同时插件在接收外部指令的时候也可以向网关发起功能调用命令。在程序正常退出时会先停止插件的运行,最后销毁插件的运行实例。</p> <h3>2.2、子设备入网流程</h3> <p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=e051d604eb940753f06b44bf31c09d05&amp;amp;file=file.png" alt="" /> 子设备入网需要子设备和网关同时开启配网(至少要求双方开启配网的时间窗重叠,先后不重要)。插件调用网关的配网命令 (CMD_PAIR) 让网关开启配网,如果有子设备成功入网,则会有入网通知 (MSG_TYPE_NODE_ADDED) 通知到插件以方便通知平台。</p> <h3>2.3、子设备离网流程</h3> <p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=18f83a01593aad0e11d200f0cb4b521c&amp;amp;file=file.png" alt="" /> 子设备离网情况比较复杂,南向和北向都有可能主动发起离网请求。为了确保平台和网关对于设备列表的同步,网关的设备管理模块对于子设备的状态做了软状态设计:平台发起离网请求时子设备可能不在线,子设备主动离网时平台也有可能通讯不畅,定义了CONNECT_STATE_LEAVING和CONNECT_STATE_DELETING两种中间状态,前者为平台发起请求时等待子设备离网的中间态,后者为子设备主动离网时等待平台确认的中间态。</p> <h2>3、开发指南</h2> <h3>3.1、插件必须实现的接口</h3> <h4>3.1.1、插件初始化 rex_init</h4> <pre><code>int rex_init(RexInitParameter_t *parameter,void *ctx);</code></pre> <p>应用初始化插件时将若干功能函数以回调函数的形式提供给插件,具体的结构定义和回调函数见 3.3.1,额外提供的上下文指针在每个回调函数中均可能用到。</p> <h4>3.1.2、插件销毁 rex_deinit</h4> <pre><code>void rex_deinit();</code></pre> <p>网关应用退出时应通知插件安全销毁,释放全局资源等操作。</p> <h4>3.1.3、插件启动 rex_start</h4> <pre><code>int rex_start();</code></pre> <p>插件启动和初始化不同之处在于,在网关应用的全生命周期中插件的初始化和销毁仅出现一次,而启动和停止则会出现调用多次,因此对于资源的分配和释放需要根据实际情况合理进行分配。</p> <h4>3.1.4、插件停止 rex_stop</h4> <pre><code>int rex_stop();</code></pre> <p>rex_stop接口与rex_start配对使用。在应用运行的过程中可以动态开启或停止某个插件的运行。</p> <h4>3.1.5、ZigBee 消息通知 rex_notify</h4> <pre><code>int rex_notify(RexMessage_t *msg);</code></pre> <p>网关应用将消息通知到插件的主要接口,具体的类型见RexMessage_t的类型定义。</p> <h4>3.1.6、获取插件信息 rex_get_info</h4> <pre><code>const RexPluginInfo_t * rex_get_info();</code></pre> <p>网关应用在运行期需要动态获得插件的信息,包括名称、版本等信息,见RexPluginInfo_t的定义。</p> <h4>3.1.7、插件配置 rex_get_data</h4> <pre><code>#define REQUEST_TYPE_GET_CONF &amp;quot;GETPLUGINCONF&amp;quot; #define REQUEST_TYPE_POST_CONF &amp;quot;POSTPLUGINCONF&amp;quot; typedef void (*GetDataCallBack)(void *, void *responseData); int rex_get_data(void *ctx, const char *requestType, const void *requestData, GetDataCallBack getDataCb);</code></pre> <p>该接口用于传递插件的自定义配置给到应用,应用可以方便地将这些内容通过通用的 RESTful API 的形式暴露给外界进行插件配置的读写操作。</p> <h3>3.2、插件调用应用的接口</h3> <h4>3.2.1、命令调用 ProcessCmd</h4> <pre><code>typedef int (*ProcessCmd)(void *ctx, RexCommand_t *cmd);</code></pre> <p>插件调用网关应用程序功能的主入口,其中:</p> <ul> <li>ctx:rex_init调用时传递进来的上下文句柄</li> <li>cmd:详见RexCommand_t的定义</li> <li>返回值:0 表示成功,非 0 返回错误代码</li> </ul> <h4>3.2.2、获取设备列表 GetDevList</h4> <pre><code>typedef int (*GetDevList)(void *ctx, int *size, RexDev_t **devList);</code></pre> <p>获取设备列表:</p> <ul> <li>ctx:rex_init调用时传递进来的上下文句柄</li> <li>size:返回设备数量,包含网关本身</li> <li>devList:返回设备的信息,其中第 0 个元素是网关本身,返回的该列表需要调用者释放内存</li> <li>返回值:0 表示成功,非 0 返回错误代码</li> </ul> <h4>3.2.3、读配置 ReadConfigure</h4> <pre><code>typedef int (*ReadConfigure)(void *ctx, const char *key, void *buffer, int bufferLen);</code></pre> <p>网关应用提供默认的持久化能力,编写插件时可以借用网关应用的持久化能力,也可以自己实现持久化方法。该接口即为调用网关的持久化能力,以键值的形式存取:</p> <ul> <li>ctx:rex_init调用时传递进来的上下文句柄</li> <li>key:自定义的键</li> <li>buffer:预分配的缓冲区</li> <li>bufferLen:缓冲区大小</li> <li>返回值:写入数据的尺寸</li> </ul> <h4>3.2.4、写配置 WriteConfigure</h4> <pre><code>typedef int (*WriteConfigure)(void *ctx, const char *key, const void *buffer, int bufferLen);</code></pre> <p>参数含义基本与读配置相当。</p> <h4>3.2.5、日志打印 Log</h4> <pre><code>typedef int (*Log)(void *ctx, int level, char * format,...);</code></pre> <p>网关应用支持将插件的日志与网关应用的日志合并处理,插件也可以不使用该接口而自行管理日志。通常来说,日志合并带来的最大好处是在分析日志时相对方便看到前后的调用关系。</p> <h4>3.2.6、获取网络信息 GetZbNetInfo</h4> <pre><code>typedef int (*GetZbNetInfo)(void *ctx,char *netInfoBuffer,int bufferLen);</code></pre> <p>ZigBee 的网络参数在建网之后大部分是固定不动的,但是会有NetworkFrameCounter和ApsFrameCounter这两个计数器在不断累加,为了能够实现在网关发生故障后快速替换网关而无需重建网络的功能,网关的网络参数需要不断更新,然后在需要的时候用最新的网络参数去加入已有网络。正常情况下网关应用会不定期地将网络参数通过消息通知的方式告诉插件,但是在某些特殊情况下插件也可以通过该接口主动获取网络参数。</p> <h4>3.2.7、设置设备别名</h4> <pre><code>typedef int (*SetDevAlias)(void *, const char *mac, const char *alias);</code></pre> <h3>3.3、主要的数据类型</h3> <h4>3.3.1、RexInitParameter_t</h4> <pre><code>typedef int (*GetVerInfo)(void *, int *size, RexVersionInfo_t **verInfoList); typedef int (*SetDevList)(void *, int size, RexDev_t *devList); typedef struct { int version; // 协议版本 ProcessCmd processCmd; // 处理命令 GetDevList getDevList; // 获取设备列表 ReadConfigure readConf; // 读配置 WriteConfigure writeConf; // 写配置 Log log; // 写日志 GetZbNetInfo getZbNetInfo; // 获取网络信息 SetDevAlias setDevAlias; // 设置设备别名 GetVerInfo getVerInfo; // 获取网关内部所有相关依赖的版本信息 SetDevList setDevList; // 云端将设备列表同步给网关 void *endptr; // 尾部指针赋值为NULL } RexInitParameter_t;</code></pre>

页面列表

ITEM_HTML