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

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

yuyutoo 2024-10-12 01:28 4 浏览 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函数,以便使用来自订阅的最新警报更新警报属性并使用调用更改检测检测更改()函数。


相关推荐

野路子科技!2步教你把手机改造成一个FTP服务器,支持PC互传

哈喽,大家好,我是野路子科技,今天来给大家带来一个教程,希望大家喜欢。正如标题所言,就是教大家如何把售价改造成FTP服务器,而这个时候估计有朋友会问了,把手机改造成FTP服务器有什么用呢?现在有Q...

不得不看:别样于Server-U的群晖文件存储服务器的搭建与使用

我先前的作品中,有着关于Server-U的ftp文件存储服务器的搭建与访问的头条文章和西瓜视频,而且我们通过各种方式也给各位粉丝介绍了如何突破局域网实现真正意义上的公网访问机制技术。关于Server-...

Qt三种方式实现FTP上传功能_qt引入qftp库

FTP协议FTP的中文名称是“文件传输协议”,是FileTransferProtocol三个英文单词的缩写。FTP协议是TCP/IP协议组中的协议之一,其传输效率非常高,在网络上传输大的文件时,经...

Filezilla文件服务器搭建及客户端的使用

FileZilla是一个免费开源的FTP软件,分为客户端版本和服务器版本,具备所有的FTP软件功能。可控性、有条理的界面和管理多站点的简化方式使得Filezilla客户端版成为一个方便高效的FTP客户...

美能达柯美/震旦复印机FTP扫描怎么设置?

好多网友不知道怎么安装美能达/震旦复印机扫描,用得最多是SMB和FTP扫描,相对于SMB来说,FTP扫描安装步骤更为便捷,不容易出问题,不需要设置文件夹共享,所以小编推荐FTP来扫描以美能达机器为例详...

CCD(简易FTP服务器软件)_简单ftp服务器软件

CCD简易FTP服务器软件是一款很方便的FPT搭建工具,可以将我们的电脑快速变成一个FPT服务器。使用方法非常简单,只要运行软件就会自动生效,下载银行有该资源。该工具是不提供操作界面的,其他用户可以输...

Ubuntu系统搭建FTP服务器教程_ubuntu架设服务器

在Ubuntu系统上搭建FTP服务器是文件传输的一个非常实用方法,适合需要进行大量文件交换的场景。以下是一步步指导,帮助您在Ubuntu上成功搭建FTP服务器。1.安装vsftpd软件...

理光FTP扫描设置教程_理光ftp扫描设置方法

此教程主要用来解决WIN10系统下不能使用SMB文件夹扫描的问题,由于旧的SMB协议存在安全漏洞,所以微软在新的系统,WIN8/WIN10/SERVER201220162018里使用了新的SMB传...

纯小白如何利用wireshark学习网络技术

写在前面工欲善其事必先利其器!熟悉掌握一种神器对以后的工作必然是有帮助的,下面我将从简单的描述Wireshark的使用和自己思考去写,若有错误或不足还请批评指正。...

京东买13盘位32GB内存NAS:NAS系统安装设置教程

本内容来源于@什么值得买APP,观点仅代表作者本人|作者:yasden你没有看错,我在京东自营商城购买硬件,组装了一台13盘位,32GB内存的NAS,硬盘有13个盘位!CPU是AMD的5500!本文...

FileZilla搭建FTP服务器图解教程_filezilla server搭建ftp服务器

...

python教程之FTP相关操作_python ftps

ftplib类库常用相关操作importftplibftp=ftplib.FTP()ftp.set_debuglevel(2)#打开调试级别2,显示详细信息ftp.connect(“I...

xftp怎么用,xftp怎么用,具体使用方法

Xftp是一款界面化的ftp传输工具,用起来方便简单,这里为大家分享下Xftp怎么使用?希望能帮到有需要的朋友。IIS7服务器管理工具可以批量管理、定时上传下载、同步操作、数据备份、到期提醒、自动更新...

树莓派文件上传和下载,详细步骤设置FTP服务器

在本指南中,详细记录了如何在树莓Pi上设置FTP。设置FTP可以在网络上轻松地将文件传输到Pi上。FTP是文件传输协议的缩写,只是一种通过网络在两个设备之间传输文件的方法。还有一种额外的方法,你可以用...

win10电脑操作系统,怎么设置FTP?windows10系统设置FTP操作方法

打印,打印,扫描的日常操作是每一个办公工作人员的必需专业技能,要应用FTP作用扫描文件到电脑上,最先要必须一台可以接受文件的FTP服务器。许多软件都需要收费标准进行,但人们还可以应用Windows的系...

取消回复欢迎 发表评论: