基于 Thingsboard 平台自定义 RPC 控制类小部件示例

1. 小部件介绍

小部件(Thingboard Widget)是可以轻松集成进平台仪表板(Dashboard)的 UI 组件,它可以提供数据可视化、远程设备控制、警报管理、展示静态 Html 内容等功能。根据提供的特性,每个小部件定义代表一个特定的小部件类型。


2. 创建小部件

使用 tenant 或 sysadmin 帐号登陆系统,点击【部件库】菜单 -> 右上角【+】号 -> 【创建新的部件组】

在这里插入图片描述
根据提示填写标题、描述信息,如果有图片可以上传


添加完成后,在列表中打开该部件组

在这里插入图片描述

点击【添加新的部件类型】-> 选择想要创建的部件类型(此处选择控件部件)

在这里插入图片描述

此时出现该类型控件对应的默认示例

在这里插入图片描述


3. 部件编辑器

3.1 简介

部件编辑器是一个用来开发自定义部件的小型集成开发环境,主要包括顶部功能工具栏和四个主要部分

  • 资源 / HTML / CSS
  • JavaScript
  • 设置模式(Settings schema)
  • 部件预览(Widget preview)
3.2 资源 / HTML / CSS

在这里插入图片描述

这部分包含三个页签:

  1. 资源

    用于加载部件所使用的外部 JS / CSS 资源。

  2. HTML

    编写部件 HTML 代码。

  3. CSS

    编写部件样式。

3.3 JavaScript

这部分包含所有与部件相关的 JS 代码,根据官方提供的 Widget API

3.4 设置模式 (Settings schema)

这部分包含三个页签:

在这里插入图片描述

  1. 设置模式

    用于指定小部件 UI 表单设置的 json 模式,该表单是通过 react-schema-form builder 自动生成的 ,该设置显示在小部件设置的高级(Advanced)选项卡中。由该模式序列化的 Settings 对象用于存储特定的小部件设置,并可通过小部件JavaScript 代码访问。

  2. 数据键设置模式

    用于指定数据键设置的 json 模式,以便使用 react-schema-form builder 自动生成UI表单。这个生成的 UI 表单显示在数据键设置模式对话框的高级(Advanced)选项卡中。由该模式序列化的 Settings 对象用于存储小部件中定义的数据源的每个数据键的特定设置,这些设置可以通过小部件 JavaScript 代码访问。

  3. Widget settings

    用于配置部件缩略图及描述信息。

3.5 部件预览 (Widget preview)

此部分用于预览和测试自定义的小部件。它作为一个迷你仪表板来显示当前自定义小部件的一个实例。
在这里插入图片描述


4. 基础部件 API

所有与部件相关的代码都位于 JavaScript 部分,可以使用内置变量 self,它是一个部件实例的引用。
部件的每一个函数都应该作为 self 变量的属性来定义。
self 变量有一个 WidgetContext 类型的 ctx 属性,它是包含这个部件实例所有必要的 API 和数据的一个上下文引用。

要创建一个新部件,需要实现下列函数,但每个函数都是可选的,可以根据小部件特定的行为来实现。

函数名描述
onInit()小部件准备好进行初始化时调用的第一个函数。用于准备小部件DOM、处理小部件设置和初始订阅信息。
onDataUpdated()当从小部件订阅获得新数据时调用。
onResize()当小部件容器调整大小时调用。
onEditModeChanged()在更改仪表板编辑模式时调用。
onMobileModeChanged()当仪表板视图宽度跨越移动断点时调用。
onDestroy()销毁时调用。
getSettingsSchema()返回设置模式 json,作为设置模式选项卡对应部分的替代选项。
getDataKeySettingsSchema()返回数据键设置模式 json,作为数据键设置模式选项卡对应部分的替代选项。
typeParameters()返回描述小部件数据源参数的 WidgetTypeParameters 对象。
actionSources()返回描述定义用户操作的可用小部件操作源 (WidgetActionSource) 的映射。
4.1 订阅对象 (Subscription object)

小部件订阅对象是 IWidgetSubscription 的实例,根据小部件类型包含所有订阅信息,也包括当前数据。订阅对象根据小部件类型提供不同的数据结构。

4.2 时间窗口函数 (Timewindow functions)

用于管理带有时间窗口的小部件数据的时间框架,可以在时间序列或报警部件中使用。

4.3 控制 API (Control API)

为 RPC (控制) 小部件提供 API 函数的对象。

函数名描述
sendOneWayCommand(method, params, timeout)发送单向(无响应) RPC 命令到设备。
sendTwoWayCommand(method, params, timeout)发送双向(带响应) RPC 命令到设备。
4.4 动作 API (Actions API)

一个用于执行用户自定义动作的 API 函数集。

4.5 状态控制器 (State Controller)

仪表板状态控制器 (IStateController) 的实例引用,提供 API 来管理当前仪表板状态。

4.6 类型参数对象 (Type parameters object)

描述部件数据源参数的对象。

4.7 动作资源对象 (Action sources object)

描述可用的小部件动作源的映射,用户动作可以分配给它。


5. 创建 RPC(控制)部件示例

  • 清空 CSS 编辑器中的内容

  • 在 HTML 中填入如下代码

        <form #rpcForm="ngForm" (submit)="sendCommand()">
          <div class="mat-content mat-padding" fxLayout="column">
            <mat-form-field class="mat-block">
              <mat-label>RPC method</mat-label>
              <input matInput required name="rpcMethod" #rpcMethodField="ngModel" [(ngModel)]="rpcMethod"/>
              <mat-error *ngIf="rpcMethodField.hasError('required')">
                RPC method name is required.
              </mat-error>
            </mat-form-field>
            <mat-form-field class="mat-block">
              <mat-label>RPC params</mat-label>
              <input matInput required name="rpcParams" #rpcParamsField="ngModel" [(ngModel)]="rpcParams"/>
              <mat-error *ngIf="rpcParamsField.hasError('required')">
                RPC params is required.
              </mat-error>
            </mat-form-field>
            <button [disabled]="rpcForm.invalid || !rpcForm.dirty" mat-raised-button color="primary" type="submit" >
              Send RPC command
            </button>
            <div>
              <label>RPC command response</label>
              <div style="width: 100%; height: 100px; border: solid 2px gray" [innerHTML]="rpcCommandResponse">
              </div>
            </div>
          </div>
        </form>
    
  • 在设置模式中填入如下代码

        {
            "schema": {
                "type": "object",
                "title": "Settings",
                "properties": {
                    "oneWayElseTwoWay": {
                        "title": "Is One Way Command",
                        "type": "boolean",
                        "default": true
                    },
                    "requestTimeout": {
                        "title": "RPC request timeout",
                        "type": "number",
                        "default": 500
                    }
                },
                "required": []
            },
            "form": [
                "oneWayElseTwoWay",
                "requestTimeout"
            ]
        } 
    
    
  • 在 JavaScript 中填入如下代码

    self.onInit = function() {
        
        self.ctx.$scope.sendCommand = function() {
            var rpcMethod = self.ctx.$scope.rpcMethod;
            var rpcParams = self.ctx.$scope.rpcParams;
            var timeout = self.ctx.settings.requestTimeout;
            var oneWayElseTwoWay = self.ctx.settings.oneWayElseTwoWay ? true : false;
    
            var commandObservable;
            if (oneWayElseTwoWay) {
                commandObservable = self.ctx.controlApi.sendOneWayCommand(rpcMethod, rpcParams, timeout);
            } else {
                commandObservable = self.ctx.controlApi.sendTwoWayCommand(rpcMethod, rpcParams, timeout);
            }
            commandObservable.subscribe(
                function (response) {
                    if (oneWayElseTwoWay) {
                        self.ctx.$scope.rpcCommandResponse = "Command was successfully received by device.<br> No response body because of one way command mode.";
                    } else {
                        self.ctx.$scope.rpcCommandResponse = "Response from device:<br>";                    
                        self.ctx.$scope.rpcCommandResponse += JSON.stringify(response, undefined, 2);
                    }
                    self.ctx.detectChanges();
                },
                function (rejection) {
                    self.ctx.$scope.rpcCommandResponse = "Failed to send command to the device:<br>"
                    self.ctx.$scope.rpcCommandResponse += "Status: " + rejection.status + "<br>";
                    self.ctx.$scope.rpcCommandResponse += "Status text: '" + rejection.statusText + "'";
                    self.ctx.detectChanges();
                }
                
            );
        }
    }
    
    
  • 输入部件名称,点击保存,再点击运行,红框处即小部件预览效果,如下图:

在这里插入图片描述

为了测试控件 RPC 控制功能,需要将其放在一个仪表板中,并绑定到一个使用 RPC 控制的设备。步骤如下:

  1. 使用租户(tenant)管理员登陆

  2. 在【设备】菜单下添加新设备

在这里插入图片描述

  1. 打开设备详情页,点击【复制访问令牌】按钮

在这里插入图片描述

  1. 下载 mqtt-js-rpc-from-server.shmqtt-js-rpc-from-server.js 并放入同一个文件夹下
  • 编辑 mqtt-js-rpc-from-server.sh , 将 $ACCESS_TOKEN 替换为刚才复制的访问令牌

在这里插入图片描述

  • 如果是本地源码启动的 TB 服务,需要编辑 mqtt-js-rpc-from-server.js , 修改服务器地址为 localhost

在这里插入图片描述

  1. 使用 Linux Shell 执行 mqtt-js-rpc-from-server.sh,运行成功则显示 connected

在这里插入图片描述

  1. 在【仪表板库】菜单下新建仪表板并打开,点击【实体别名】-【添加别名】

在这里插入图片描述

  1. 点击【添加新的部件】,选择之前创建的控制部件

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  1. 填入 RPC method 和 RPC params,点击 Send RPC commond 发送模拟命令,收到如下响应
    在这里插入图片描述
    此时设备端收到如下内容

在这里插入图片描述

  1. 测试发送双向 RPC 命令,编辑部件,在【高级】页签中,取消勾选【Is One Way Command】,保存即可。

在这里插入图片描述

填入上一步单向命令的方法和参数,点击发送命令按钮

在这里插入图片描述

关闭设备端 js 脚本,再次发送命令,响应如下:

在这里插入图片描述

在本例中,使用 controlApi 发送 RPC 命令。此外,为了配置 RPC 命令模式和 RPC 请求超时,引入了自定义小部件设置。来自设备的响应由 commandObservable 处理。它具有成功回调和失败回调,并具有相应的响应,或者包含关于请求执行结果信息的拒绝对象。

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值