百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

Thingsboard二次开发系列拷贝篇-10widget(03创建简单的小部件)

yuyutoo 2024-10-12 01:28 15 浏览 0 评论

素材和版本

tb-release:3.2.2

小部件(Widget类型)

最新值小部件

Widgets Bundle视图中,单击屏幕右下角的大“+”按钮,然后单击“创建新的小部件类型”按钮。单击选择小部件类型弹出窗口最新值按钮控件编辑器将打开,预先填充默认的内容最新值小部件模板。

  • 清除“资源”部分 CSS 选项卡的内容。

  • 将以下 HTML 代码放在“资源”部分的 HTML 选项卡中:

  <div fxFlex fxLayout="column" style="height: 100%;" fxLayoutAlign="center stretch">
    <div>My first latest values widget.</div>
    <div fxFlex fxLayout="row" *ngFor="let dataKeyData of data" fxLayoutAlign="space-around center">
        <div>{{dataKeyData.dataKey.label}}:</div>
        <div>{{(dataKeyData.data[0] && dataKeyData.data[0][0]) | date : 'yyyy-MM-dd HH:mm:ss' }}</div>
        <div>{{dataKeyData.data[0] && dataKeyData.data[0][1]}}</div>
    </div>
  </div>
  • 将以下 JavaScript 代码放入“JavaScript”部分:

    self.onInit = function() {
       self.ctx.$scope.data = self.ctx.defaultSubscription.data;
    }
        
    self.onDataUpdated = function() {
        self.ctx.detectChanges();
    }
  • 单击小部件编辑器工具栏运行按钮,以便在小部件预览部分查看结果

在这个例子中,订阅的数据属性被分配给$scope并且可以在 HTML 模板中访问。在 HTML 中,使用特殊的*ngFor结构角度指令来迭代可用的数据键和数据点,然后使用相应的时间戳呈现最新值。

时间序列小部件

Widgets Bundle视图中,单击屏幕右下角的大“+”按钮,然后单击“创建新的小部件类型”按钮。单击选择小部件类型弹出窗口时间序列按钮控件编辑器将打开,预先填充默认时间序列模板控件的内容。

  • 将“资源”部分中 CSS 选项卡的内容替换为以下内容:

.my-data-table th {
    text-align: left;}
  • 将以下 HTML 代码放在“资源”部分的 HTML 选项卡中:

  <mat-tab-group style="height: 100%;">
      <mat-tab *ngFor="let datasource of datasources; let $dsIndex = index" label="{{datasource.name}}">
          <table class="my-data-table" style="width: 100%;">
              <thead>
                  <tr>
                      <th>Timestamp</th>
                      <th *ngFor="let dataKeyData of datasourceData[$dsIndex]">{{dataKeyData.dataKey.label}}</th>
                  <tr>          
              </thead>
              <tbody>
                  <tr *ngFor="let data of datasourceData[$dsIndex][0].data; let $dataIndex = index">
                      <td>{{data[0] | date : 'yyyy-MM-dd HH:mm:ss'}}</td>
                      <td *ngFor="let dataKeyData of datasourceData[$dsIndex]">{{dataKeyData.data[$dataIndex] && dataKeyData.data[$dataIndex][1]}}</td>
                  </tr>      
              </tbody>          
          </table>          
      </mat-tab>       
  </mat-tab-group>
  • 将以下 JavaScript 代码放入“JavaScript”部分:

self.onInit = function() {
    self.ctx.widgetTitle = 'My first Time-Series widget';
    self.ctx.$scope.datasources = self.ctx.defaultSubscription.datasources;
    self.ctx.$scope.data = self.ctx.defaultSubscription.data;
    
    self.ctx.$scope.datasourceData = [];
    
    var currentDatasource = null;
    var currentDatasourceIndex = -1;
    
    for (var i=0;i<self.ctx.$scope.data.length;i++) {
        var dataKeyData = self.ctx.$scope.data[i];
        if (dataKeyData.datasource != currentDatasource) {
            currentDatasource = dataKeyData.datasource
            currentDatasourceIndex++;
            self.ctx.$scope.datasourceData[currentDatasourceIndex] = [];
            
        } 
        self.ctx.$scope.datasourceData[currentDatasourceIndex].push(dataKeyData);
    }
    self.ctx.updateWidgetParams();}self.onDataUpdated = function() {
    self.ctx.detectChanges();}
  • 单击小部件编辑器工具栏运行按钮,以便在小部件预览部分查看结果

在此示例中,订阅 数据源和数据属性被分配给$scope并在 HTML 模板中变得可访问。在$ scope.datasourceData属性介绍了数据源指数为HTML模板中灵活地访问数据源的具体dataKeys数据映射。在 HTML 中,使用特殊的*ngFor结构角度指令来迭代可用数据源并呈现相应的选项卡。在每个选项卡内,使用从数据源索引访问的 datasourceData 范围属性获取的dataKeys 呈现表。每个表通过遍历所有dataKeyData 来呈现列对象并通过迭代每个dataKeyData 的数据数组来呈现所有可用的数据点以呈现时间戳和值。请注意,在这段代码,onDataUpdated功能与一个呼叫实现detectChanges功能,必要时接收到新的数据来执行新的变更检测周期。

RPC(控制)小部件

Widgets Bundle视图中,单击屏幕右下角的大“+”按钮,然后单击“创建新的小部件类型”按钮。单击“选择小部件类型”弹出窗口上的控制小部件”按钮控件编辑器将打开,预先填充的默认控件模板控件的内容。

  • 清除“资源”部分 CSS 选项卡的内容。

  • 将以下 HTML 代码放在“资源”部分的 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>
  • 将以下 JSON 内容放在设置架构部分的“设置架构”选项卡中

{
    "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 代码放入“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 命令的设备。为此,请执行以下步骤:

以租户管理员身份登录。

导航到设备并使用某个名称创建新设备,例如。“我的 RPC 设备”。

打开设备详细信息,然后单击“复制访问令牌”按钮将设备访问令牌复制到剪贴板。

下载mqtt-js-rpc-from-server.sh和mqtt-js-rpc-from-server.js。将这些文件放在一个文件夹中。编辑mqtt-js-rpc-from-server.sh - 用剪贴板中的设备访问令牌替换$ACCESS_TOKEN。并安装 mqtt 客户端库。

运行mqtt-js-rpc-from-server.sh脚本。您应该会在控制台中看到“已连接”消息。

导航到仪表板并创建一个具有某些名称的新仪表板,例如。“我的第一个控制仪表板”。打开此仪表板。

单击仪表板“编辑”按钮。在仪表板编辑模式下,单击仪表板工具栏上的“实体别名”按钮。

  • 实体别名弹出窗口中单击“添加别名”。

  • 填写“别名”字段,例如。“我的 RPC 设备别名”。

  • 在“过滤器类型”字段中选择“实体列表”。

  • 在“类型”字段中选择“设备”。

  • 在“实体列表”字段中选择您的设备。在此示例中为“我的 RPC 设备”。

  • 实体别名中单击“添加”,然后单击“保存”

  • 单击仪表板“+”按钮,然后单击“创建新小部件”按钮。

  • 然后选择保存 RPC 小部件的小部件包选择“控制小部件”选项卡。

  • 单击您的小部件。在这个例子中,“我的第一个控件小部件”。

  • 从“添加小部件”弹出窗口中,在“目标设备”部分中选择您的设备别名在此示例中为“我的 RPC 设备别名”。

  • 单击添加您的控制小部件将出现在仪表板中。单击仪表板应用更改按钮以保存仪表板并退出编辑模式。

  • 使用 RPC 方法名称填充RPC 方法字段。例如。“测试方法”。

  • 用 RPC params填充RPC params字段。例如。“{ param1: “value1” }”。

  • 单击发送 RPC 命令按钮。您应该会在小部件中看到以下响应。

应在设备控制台中打印以下输出:

1
2  request.topic: v1/devices/me/rpc/request/0
  request.body: {"method":"TestMethod","params":"{ param1: \"value1\" }"}

为了测试“双向”RPC 命令模式,我们需要更改相应的小部件设置属性。为此,请执行以下步骤:

  • 单击仪表板“编辑”按钮。在仪表板编辑模式下,单击位于控件小部件标题中的编辑小部件按钮。

  • 在小部件详细信息中,查看选择“高级”选项卡并取消选中“单向命令”复选框。

  • 单击小部件详细信息标题上的应用更改按钮。关闭详细信息并单击仪表板应用更改按钮。

  • 像前面的步骤一样,用 RPC 方法名称和参数填充小部件字段。单击发送 RPC 命令按钮。您应该会在小部件中看到以下响应。

  • 停止mqtt-js-rpc-from-server.sh脚本。单击发送 RPC 命令按钮。您应该会在小部件中看到以下响应。

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

闹钟小工具

在Widgets Bundle视图中,单击屏幕右下角的大“+”按钮,然后单击“创建新的小部件类型”按钮。单击“选择小部件类型”弹出窗口上的“警报小部件”按钮。该控件编辑器将被打开,预填充了默认的内容报警模板窗口小部件。

将“资源”部分中 CSS 选项卡的内容替换为以下内容:

1
2
3.my-alarm-table th {
text-align: left;}

将以下 HTML 代码放在“资源”部分的 HTML 选项卡中:

<div fxFlex fxLayout="column" style="height: 100%;">
<div>My first Alarm widget.</div>
<table class="my-alarm-table" style="width: 100%;">
<thead>
<tr>
<th *ngFor="let dataKey of alarmSource?.dataKeys">{{dataKey.label}}</th>
<tr>
</thead>
<tbody>
<tr *ngFor="let alarm of alarms">
<td *ngFor="let dataKey of alarmSource?.dataKeys"
[ngStyle]="getAlarmCellStyle(alarm, dataKey)">
{{getAlarmValue(alarm, dataKey)}} </td>
</tr>
</tbody>
</table>
</div>

将以下 JSON 内容放在设置架构部分的“设置架构”选项卡中:

{
"schema": {
"type": "object",
"title": "AlarmTableSettings",
"properties": {
"alarmSeverityColorFunction": {
"title": "Alarm severity color function: f(severity)",
"type": "string",
"default": "if(severity == 'CRITICAL') {return 'red';} else if (severity == 'MAJOR') {return 'orange';} else return 'green'; "
}
},
"required": []
},
"form": [
{
"key": "alarmSeverityColorFunction",
"type": "javascript"
}
]}

将以下 JavaScript 代码放入“JavaScript”部分:

self.onInit = function() {
var pageLink = self.ctx.pageLink();

pageLink.typeList = self.ctx.widgetConfig.alarmTypeList;
pageLink.statusList = self.ctx.widgetConfig.alarmStatusList;
pageLink.severityList = self.ctx.widgetConfig.alarmSeverityList;
pageLink.searchPropagatedAlarms = self.ctx.widgetConfig.searchPropagatedAlarms;

self.ctx.defaultSubscription.subscribeForAlarms(pageLink, null);
self.ctx.$scope.alarmSource = self.ctx.defaultSubscription.alarmSource;

var alarmSeverityColorFunctionBody = self.ctx.settings.alarmSeverityColorFunction;
if (typeof alarmSeverityColorFunctionBody === 'undefined' || !alarmSeverityColorFunctionBody.length) {
alarmSeverityColorFunctionBody = "if(severity == 'CRITICAL') {return 'red';} else if (severity == 'MAJOR') {return 'orange';} else return 'green';";
}

var alarmSeverityColorFunction = null;
try {
alarmSeverityColorFunction = new Function('severity', alarmSeverityColorFunctionBody);
} catch (e) {
alarmSeverityColorFunction = null;
}

self.ctx.$scope.getAlarmValue = function(alarm, dataKey) {
var alarmKey = dataKey.name;
if (alarmKey === 'originator') {
alarmKey = 'originatorName';
}
var value = alarm[alarmKey];
if (alarmKey === 'createdTime') {
return self.ctx.date.transform(value, 'yyyy-MM-dd HH:mm:ss');
} else {
return value;
}
}

self.ctx.$scope.getAlarmCellStyle = function(alarm, dataKey) {
var alarmKey = dataKey.name;
if (alarmKey === 'severity' && alarmSeverityColorFunction) {
var severity = alarm[alarmKey];
var color = alarmSeverityColorFunction(severity);
return {
color: color
};
}
return {};
}}self.onDataUpdated = function() {
self.ctx.$scope.alarms = self.ctx.defaultSubscription.alarms.data;
self.ctx.detectChanges();}

单击小部件编辑器工具栏上的运行按钮,以便在小部件预览部分查看结果。

在这个例子中,订阅的alarmSource和alarms属性被分配给$scope并且可以在 HTML 模板中访问。在 HTML 中,使用了一个特殊的*ngFor结构角度指令,以便迭代alarmSource的可用警报dataKeys并呈现相应的列。表格行通过迭代警报数组呈现,相应的单元格通过迭代dataKeys呈现。该功能getAlarmValue被取报警值和格式化createdTime使用报警属性DatePipe可通过ctx 的date属性访问角管。函数getAlarmCellStyle用于为每个警报单元格分配自定义单元格样式。在此示例中,我们引入了名为alarmSeverityColorFunction 的新设置属性,其中包含根据警报严重性返回颜色的函数体。在getAlarmCellStyle函数中,有相应的调用带有严重性值的alarmSeverityColorFunction以获取警报严重性单元格的颜色。请注意,在此代码中实现了onDataUpdated函数,以便使用来自订阅的最新警报更新警报属性并使用调用更改检测检测更改()函数。


相关推荐

Mysql和Oracle实现序列自增(oracle创建序列的sql)

Mysql和Oracle实现序列自增/*ORACLE设置自增序列oracle本身不支持如mysql的AUTO_INCREMENT自增方式,我们可以用序列加触发器的形式实现,假如有一个表T_WORKM...

关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)

概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...

MySQL CREATE TABLE 简单设计模板交流

推荐用MySQL8.0(2018/4/19发布,开发者说同比5.7快2倍)或同类型以上版本....

mysql学习9:创建数据库(mysql5.5创建数据库)

前言:我也是在学习过程中,不对的地方请谅解showdatabases;#查看数据库表createdatabasename...

MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别

执行"CREATETABLE新表ASSELECT*FROM原表;"后,新表与原表的字段一致,但主键、索引不会复制到新表,会把原表的表记录复制到新表。...

Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出

在街上看到的PandaDunk的超载可能让一些球鞋迷们望而却步,但Dunk的浪潮仍然强劲,看不到尽头。我们看到的很多版本都是为女性和儿童制作的,这种新配色为后者引入了一种令人耳目一新的新选择,而...

美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍

多功能雷达AN/SPY-1的特性和技术能力,该雷达已经在美国海军服役了30多年,其修改-AN/SPY-1A、AN/SPY-1B(V)、AN/SPY-1D、AN/SPY-1D(V),以及雷神...

汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)

全面分析汽车音响使用或安装技术常识一:主机是大多数人最熟习的音响器材,有关主机的各种性能及规格,也是耳熟能详的事,以下是一些在使用或安装时,比较需要注意的事项:LOUDNESS:几年前的主机,此按...

【推荐】ProAc Response系列扬声器逐个看

有考牌(公认好声音)扬声器之称ProAcTablette小音箱,相信不少音响发烧友都曾经,或者现在依然持有,正当大家逐渐掌握Tablette的摆位设定与器材配搭之后,下一步就会考虑升级至表现更全...

#本站首晒# 漂洋过海来看你 — BLACK&amp;DECKER 百得 BDH2000L无绳吸尘器 开箱

作者:初吻给了烟sco混迹张大妈时日不短了,手没少剁。家里有了汪星人,吸尘器使用频率相当高,偶尔零星打扫用卧式的实在麻烦(汪星人:你这分明是找借口,我掉毛是满屋子都有,铲屎君都是用卧式满屋子吸的,你...

专题|一个品牌一件产品(英国篇)之Quested(罗杰之声)

Quested(罗杰之声)代表产品:Q212FS品牌介绍Quested(罗杰之声)是录音监听领域的传奇品牌,由英国录音师RogerQuested于1985年创立。在成立Quested之前,Roger...

常用半导体中英对照表(建议收藏)(半导体英文术语)

作为一个源自国外的技术,半导体产业涉及许多英文术语。加之从业者很多都有海外经历或习惯于用英文表达相关技术和工艺节点,这就导致许多英文术语翻译成中文后,仍有不少人照应不上或不知如何翻译。为此,我们整理了...

Fyne Audio F502SP 2.5音路低音反射式落地音箱评测

FyneAudio的F500系列,有新成员了!不过,新成员不是新的款式,却是根据原有款式提出特别版。特别版产品在原有型号后标注了SP字样,意思是SpecialProduction。Fyne一共推出...

有哪些免费的内存数据库(In-Memory Database)

以下是一些常见的免费的内存数据库:1.Redis:Redis是一个开源的内存数据库,它支持多种数据结构,如字符串、哈希表、列表、集合和有序集合。Redis提供了快速的读写操作,并且支持持久化数据到磁...

RazorSQL Mac版(SQL数据库查询工具)

RazorSQLMac特别版是一款看似简单实则功能非常出色的SQL数据库查询、编辑、浏览和管理工具。RazorSQLformac特别版可以帮你管理多个数据库,支持主流的30多种数据库,包括Ca...

取消回复欢迎 发表评论: