产品定价 立即试用
云平台
北美地区
文档 > 部件 > 部件开发 > 基础部件API
入门
指南 API 常见问题
目录

基础部件API

概述

所有与部件相关的代码位于 JavaScript 区域。 内置变量 self 为部件实例的引用。 每个部件函数应定义为 self 变量的属性。 self 变量具有 ctx 属性,类型为 WidgetContext,即部件上下文的引用,包含部件实例使用的所有必要 API和数据。 以下为部件上下文属性的简要说明:

Property Type Description
$container jQuery Object 部件容器元素。可使用jQuery API动态访问或修改部件DOM。
$scope IDynamicWidgetComponent 当前部件组件的引用。当部件基于Angular方式构建时,可用于访问/修改组件属性。
width Number 部件容器当前宽度(像素)。
height Number 部件容器当前高度(像素)。
isEdit Boolean 指示dashboard处于查看还是编辑状态。
isMobile Boolean 指示dashboard视图宽度是否小于960px(默认移动端断点)。
widgetConfig WidgetConfig 通用部件配置,包含 color(文本颜色)、backgroundColor(部件背景色)等属性。
settings Object 部件设置,按定义的 settings json schema 包含部件专属属性。
datasources Array<Datasource> 已解析的部件 datasources 数组。见 Subscription object
data Array<DatasourceData> datasources 最新数据数组。见 Subscription object
timeWindow WidgetTimewindow 当前部件timewindow(适用于timeseries部件)。包含当前timewindow边界信息:minTime - UTC毫秒最小时间,maxTime - UTC毫秒最大时间,interval - 当前聚合间隔(毫秒)。
units String 可选属性,定义部件显示值的单位文本。适用于卡片、仪表盘等简单部件。
decimals Number 可选属性,定义显示数值小数部分的位数。
hideTitlePanel Boolean 控制部件标题面板可见性。适用于自定义标题面板或多种状态的部件。修改此属性后必须调用 updateWidgetParams()
widgetTitle String 若设置,将覆盖已配置的部件标题文本。修改此属性后必须调用 updateWidgetParams()
detectChanges() Function 触发当前部件的变更检测。当部件数据变更导致HTML模板绑定需更新时应调用。
updateWidgetParams() Function 用运行时设置(如 widgetTitlehideTitlePanel 等)更新部件。修改这些属性后必须调用以使修改生效。
pageLink(pageSize, page, textSearch, sortOrder) PageLink 用于创建GET请求的排序配置。pageSize - 每页实体数,page - 页码,textSearch - 按文本过滤实体,sortOrder - 实体显示顺序。
defaultSubscription IWidgetSubscription 默认部件订阅对象,按部件类型包含全部订阅信息(含当前数据)。见 Subscription object
timewindowFunctions TimewindowFunctions 管理部件数据时间范围的 timewindow 函数对象。适用于 Time-series 或 Alarm 部件。见 Timewindow functions
controlApi RpcApi 为 RPC(Control)部件提供 API 函数的对象。见 Control API
actionsApi WidgetActionsApi 与用户自定义动作相关的 API 函数集。见 Actions API
stateController IStateController Dashboard 状态控制器引用,提供管理当前 dashboard 状态的 API。见 State Controller

实现新部件时,应定义以下JavaScript函数(注:每个函数均为可选,可按部件具体行为实现):

Function Description
onInit() 部件就绪初始化时调用的首个函数。用于准备部件DOM、处理部件设置并处理初始订阅信息。
onDataUpdated() 部件订阅有新数据时调用。最新数据可通过部件上下文 ctxdefaultSubscription object 访问。
onResize() 部件容器尺寸改变时调用。最新宽高可从部件上下文 ctx 获取。
onEditModeChanged() dashboard编辑模式切换时调用。当前模式由 ctx 的isEdit属性提供。
onMobileModeChanged() dashboard视图宽度越过移动端断点时调用。当前状态由 ctx 的isMobile属性提供。
onDestroy() 部件元素销毁时调用。应在必要时用于释放所有资源。
getSettingsSchema() 可选函数,返回部件settings schema json,作为 Settings schema sectionSettings tab 的替代。
getDataKeySettingsSchema() 可选函数,返回特定data key的settings schema json,作为 Settings schema sectionData key settings schema 选项卡的替代。
typeParameters() 返回描述部件datasource参数的 WidgetTypeParameters 对象。见 Type parameters object
actionSources() 返回描述可用部件动作源的映射 (WidgetActionSource),用于定义用户动作。见 Action sources object

Subscription object

部件订阅对象为 IWidgetSubscription 的实例,按 部件类型 包含全部订阅信息(含当前数据)。 依部件类型不同,订阅对象提供不同数据结构。 Latest valuesTime-series 类型提供以下属性:

  • datasources - array of datasources (Array<Datasource>) used by this subscription, it has the following structure:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    datasources = [
        {  // datasource
           type: 'entity',// type of the datasource. Can be "function" or "entity"
           name: 'name', // name of the datasource (in case of "entity" usually Entity name)
           aliasName: 'aliasName', // name of the alias used to resolve this particular datasource Entity
           entityName: 'entityName', // name of the Entity used as datasource
           entityType: 'DEVICE', // datasource Entity type (for ex. "DEVICE", "ASSET", "TENANT", etc.)
           entityId: '943b8cd0-576a-11e7-824c-0b1cb331ec92', // entity identificator presented as string uuid. 
           dataKeys: [ //  array of keys (Array<DataKey>) (attributes or timeseries) of the entity used to fetch data 
               { // dataKey
                    name: 'name', // the name of the particular entity attribute/timeseries 
                    type: 'timeseries', // type of the dataKey. Can be "timeseries", "attribute" or "function" 
                    label: 'Sin', // label of the dataKey. Used as display value (for ex. in the widget legend section) 
                    color: '#ffffff', // color of the key. Can be used by widget to set color of the key data (for ex. lines in line chart or segments in the pie chart).  
                    funcBody: "", // only applicable for datasource with type "function" and "function" key type. Defines body of the function to generate simulated data.
                    settings: {} // dataKey specific settings with structure according to the defined Data key settings json schema. See "Settings schema section".
               },
               //...
           ]
        },
        //...
    ]
  • data - 此订阅范围内接收到的最新数据数组 (Array<DatasourceData>),结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    data = [
        {
            datasource: {}, // datasource object of this data. See datasource structure above.
            dataKey: {}, // dataKey for which the data is held. See dataKey structure above.
            data: [ // array of data points
                [   // data point
                    1498150092317, // unix timestamp of datapoint in milliseconds
                    1, // value, can be either string, numeric or boolean
                ],
                //...
            ]
        },
        //...
    ]

Alarm widget 类型提供以下属性:

  • alarmSource - (Datasource) 获取告警的实体信息,结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    alarmSource = {
         type: 'entity',// type of the alarm source. Can be "function" or "entity"
         name: 'name', // name of the alarm source (in case of "entity" usually Entity name)
         aliasName: 'aliasName', // name of the alias used to resolve this particular alarm source Entity
         entityName: 'entityName', // name of the Entity used as alarm source
         entityType: 'DEVICE', // alarm source Entity type (for ex. "DEVICE", "ASSET", "TENANT", etc.)
         entityId: '943b8cd0-576a-11e7-824c-0b1cb331ec92', // entity identificator presented as string uuid. 
         dataKeys: [ // array of keys indicating alarm fields used to display alarms data 
            { // dataKey
                 name: 'name', // the name of the particular alarm field 
                 type: 'alarm', // type of the dataKey. Only "alarm" in this case. 
                 label: 'Severity', // label of the dataKey. Used as display value (for ex. as a column title in the Alarms table) 
                 color: '#ffffff', // color of the key. Can be used by widget to set color of the key data.  
                 settings: {} // dataKey specific settings with structure according to the defined Data key settings json schema. See "Settings schema section".
            },
            //...
          ] 
    }
  • alarms - 此订阅范围内接收到的告警数组 (Array<Alarm>),结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    alarms = [
        { // alarm
            id: { // alarm id 
                entityType: "ALARM", 
                id: "943b8cd0-576a-11e7-824c-0b1cb331ec92"
            },
            createdTime: 1498150092317, // Alarm created time (unix timestamp)
            startTs: 1498150092316, // Alarm started time (unix timestamp)
            endTs: 1498563899065, // Alarm end time (unix timestamp)
            ackTs: 0, // Time of alarm acknowledgment (unix timestamp)
            clearTs: 0, // Time of alarm clear (unix timestamp)
            originator: { // Originator - id of entity produced this alarm 
                entityType: "ASSET", 
                id: "ceb16a30-4142-11e7-8b30-d5d66714ea5a"
            },
            originatorName: "Originator Name", // Name of originator entity
            type: "Temperature", // Type of the alarm
            severity: "CRITICAL", // Severity of the alarm ("CRITICAL", "MAJOR", "MINOR", "WARNING", "INDETERMINATE") 
            status: "ACTIVE_UNACK", // Status of the alarm 
                                    // ("ACTIVE_UNACK" - active unacknowledged, 
                                    // "ACTIVE_ACK" - active acknowledged, 
                                    // "CLEARED_UNACK" - cleared unacknowledged, 
                                    // "CLEARED_ACK" - cleared acknowledged)
            details: {} // Alarm details object derived from alarm details json.
        }
    ]

RPCStatic 部件类型中,订阅对象为可选且不包含必要信息。

Timewindow functions

用于管理部件数据时间范围的timewindow函数对象 (TimewindowFunctions)。适用于 Time-seriesAlarm 部件。路径:widgetContext.dashboard

Function Description
onUpdateTimewindow(startTimeMs, endTimeMs) 可将当前订阅时间范围更新为 startTimeMsendTimeMs 指定的历史时间段。
onResetTimewindow() 将订阅时间范围重置为默认值,默认由部件timewindow组件或dashboard timewindow根据部件设置决定。

Control API

Control API (RpcApi) 为 Control widgets 提供API函数。路径:widgetContext.controlApi

Function Description
sendOneWayCommand(method, params, timeout) 向设备发送单向(无响应)RPC命令。返回命令执行promise。method - RPC方法名(字符串),params - RPC方法参数(自定义json对象),timeout - 等待响应/确认的最大毫秒数。
sendTwoWayCommand(method, params, timeout) 向设备发送双向(有响应)RPC命令。返回命令执行promise,成功回调中包含响应体。
completedCommand() 停止设备的RPC执行。

Actions API

处理用户自定义动作的API函数集 (WidgetActionsApi)。路径:widgetContext.actionsApi

Function Description
getActionDescriptors(actionSourceId) 返回指定 actionSourceId 的动作描述符列表。
handleWidgetAction($event, descriptor, entityId, entityName) 处理特定动作源产生的动作。$event - 关联的事件对象,descriptor - 动作描述符,entityIdentityName - 动作源提供的当前实体id与名称(如有)。
getActiveEntityInfo() 返回部件中首个实体的信息。
openDashboardStateInSeparateDialog(targetDashboardStateId, params?, dialogTitle?, hideDashboardToolbar?, dialogWidth?, dialogHeight?) 在独立对话框中打开dashboard状态。targetDashboardStateId - 要打开的状态ID,params - 状态实体及附加信息,dialogTitle - 对话框标题,hideDashboardToolbar - 是否隐藏dashboard工具栏,dialogWidthdialogHeight - 对话框宽高。
openDashboardStateInPopover($event, targetDashboardStateId, params?, hideDashboardToolbar?, preferredPlacement?, hideOnClickOutside?, popoverWidth?, popoverHeight?, popoverStyle?) 在弹出窗口中打开dashboard状态。$event - 关联的事件对象,targetDashboardStateId - 弹出窗口中的状态id,params - 状态实体及附加信息,hideDashboardToolbar - 是否隐藏dashboard工具栏,preferredPlacement - 弹出位置,hideOnClickOutside - 点击外部是否关闭,popoverStyle - 弹出窗口样式,popoverWidthpopoverHeight - 弹出窗口宽高。

Widget Subscription API

处理自定义订阅的API函数集 (WidgetSubscriptionApi)。路径:widgetContext.subscriptionApi

Function Description
createSubscription(options, subscribe?) 创建数据订阅。options - 订阅信息,subscribe - 控制是否接收更新数据。
createSubscriptionFromInfo(type, subscriptionsInfo, options, useDefaultComponents, subscribe) 创建数据订阅。type - 部件类型,subscriptionsInfo - 订阅数据描述,options - 订阅信息,useDefaultComponents - 是否使用默认订阅设置,subscribe - 控制是否接收更新数据。
removeSubscription(id) 移除订阅。id - 订阅ID。

State Controller

Dashboard状态控制器引用 (IStateController),提供管理当前 dashboard状态的API。路径:widgetContext.dashboard.stateController

Function Description
openState(id, params, openRightLayout) 导航到新dashboard状态。id - 目标状态id,params - 新状态使用的状态参数对象,openRightLayout - 可选,移动端下强制打开右侧布局。
updateState(id, params, openRightLayout) 更新当前dashboard状态。id - 可选,替换当前状态的目标状态id,params - 要更新的状态参数对象,openRightLayout - 可选,移动端下强制打开右侧布局。
resetState() 重置当前dashboard状态。
getStateId() 返回当前dashboard状态id。
getStateIndex() 返回状态嵌套深度。
getStateIdAtIndex(index) 按索引返回 stateId
getCurrentStateName() 返回当前状态的 name
getStateParams() 返回当前dashboard状态参数。
getEntityId(entityParamName) 按状态实体参数名返回 entityIdentityParamName - 状态实体参数名。
getStateParamsByStateId(id) 返回指定 id 的dashboard状态参数。
openRightLayout() 打开当前状态的右侧布局(移动端模式)。
preserveState() 将状态参数保存到 preservedState
cleanupPreservedStates() 清空 preservedState

Broadcast Service

Broadcast Service (BroadcastService) 用于部件间的UI级数据交换。

Function Description
broadcast(name, args) 向订阅者发送数据。name - 唯一标识符,args - 要发送的数据。
on(name, listener) 使用唯一标识符订阅数据并处理。可添加多个订阅者。name 为订阅的唯一标识符,listener 为处理接收数据的函数。

例如,将数据从部件1发送到部件2:

image

在部件1中需使用broadcast(…) 发送数据:

1
2
3
4
5
6
7
8
9
self.onInit = function() {
    ...
    let $scope = self.ctx.$scope;
    self.ctx.broadcastService = $scope.$injector.get(self.ctx.servicesMap.get('broadcastService'));
    $scope.click = function() {
        self.ctx.broadcastService.broadcast('ID', 'Some data');
    }
    ...
}

在部件2中需使用on(…) 订阅数据:

1
2
3
4
5
6
7
8
9
10
11
self.onInit = function() {
    ...
    let $scope = self.ctx.$scope;
    $scope.widgetText = 'Ready to get data';
    self.ctx.broadcastService = $scope.$injector.get(self.ctx.servicesMap.get('broadcastService'));
    self.ctx.broadcastService.on('ID', (event, args) => {
        $scope.widgetText = args[0];
        self.ctx.detectChanges();
    });
    ...
}

结果在部件2中可看到数据:

image

Type parameters object

描述部件datasource参数的 WidgetTypeParameters 对象,具有以下属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
    return {
        maxDatasources: -1, // Maximum allowed datasources for this widget, -1 - unlimited
        maxDataKeys: -1, //Maximum allowed data keys for this widget, -1 - unlimited
        dataKeysOptional: false, //Whether this widget can be configured with datasources without data keys
        datasourcesOptional: false, //Whether this widget can be configured without datasources
        singleEntity: false, //Whether this widget will work with only one entity
        hasAdditionalLatestDataKeys: false, //Whether this widget will support additional latest data keys
        ignoreDataUpdateOnIntervalTick: true, //Use for time series widgets. if true, onDataUpdate will trigger when new data is received otherwise it will be triggered each second.
        previewWidth: 250px, //Default size of preview X axis
        previewHeight: 250px, //Default size of preview Y axis
        embedTitlePanel: false, //Whether hide title panel
        hideDataSettings: false, //Whether data settings will hide (appearance tab)
    }

Action sources object

描述可用于分配用户动作的部件动作源映射 (WidgetActionSource),结构如下:

1
2
3
4
5
6
   return {
        'headerButton': { // Action source Id (unique action source identificator)
           name: 'Header button', // Display name of action source, used in widget settings ('Actions' tab).
           multiple: true // Boolean property indicating if this action source supports multiple action definitions (for ex. multiple buttons in one cell, or only one action can by assigned on table row click.)
        }
    };

Creating simple widgets

以下教程展示如何创建各类部件的最简实现。 为精简代码,将使用ThingsBoard UI基于的Angular框架。 你也可在部件代码中使用纯JavaScript或jQuery API。

Latest Values widget

In the Widgets Bundle view, click the big “+” button at the bottom-right part of the screen and then click the “Create new widget type” button. 在 Select widget type 弹窗中点击 Latest ValuesWidget Editor 将打开,并预填默认 Latest Values 模板内容。

  • 清空 “Resources” 区域中CSS选项卡的内容。
  • 将以下HTML代码放入 “Resources” 区域的HTML选项卡:
1
2
3
4
5
6
7
8
  <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” 区域:
1
2
3
4
5
6
7
    self.onInit = function() {
       self.ctx.$scope.data = self.ctx.defaultSubscription.data;
    }

    self.onDataUpdated = function() {
        self.ctx.detectChanges();
    }
  • 点击 Widget Editor Toolbar 中的 Run 按钮,在 Widget preview 区域查看结果。

image

此例将 subscriptiondata 属性赋值给 $scope,从而在HTML模板中可访问。 HTML中使用 *ngFor 结构指令遍历dataKeys与datapoints,渲染最新值及对应时间戳。

Time-Series widget

In the Widgets Bundle view, click the big “+” button at the bottom-right part of the screen, then click the “Create new widget type” button. 在 Select widget type 弹窗中点击 Time-SeriesWidget Editor 将打开,并预填默认 Time-Series 模板内容。

  • Replace content of the CSS tab in “Resources” section with the following one:
1
2
3
.my-data-table th {
    text-align: left;
}
  • 将以下HTML代码放入 “Resources” 区域的HTML选项卡:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  <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” 区域:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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();
}
  • 点击 Widget Editor Toolbar 中的 Run 按钮,在 Widget preview 区域查看结果。

image

此例将 subscriptiondatasourcesdata 属性赋值给 $scope,从而在HTML模板中可访问。 引入 $scope.datasourceData 按datasource索引映射其dataKeys数据,便于在HTML中灵活访问。 HTML中使用 *ngFor 指令遍历datasources并渲染对应选项卡。 每个选项卡根据 datasourceData 的datasource索引获取dataKeys渲染表格。 表格列通过遍历 dataKeyData 渲染,数据点通过遍历各 dataKeyDatadata 数组渲染时间戳与值。 注意本代码中 onDataUpdated 调用了 detectChanges,以便新数据到达时执行变更检测。

RPC (Control) widget

In the Widgets Bundle view, click the big “+” button at the bottom-right part of the screen and then click the “Create new widget type” button. 在 Select widget type 弹窗中点击 Control WidgetWidget Editor 将打开,并预填默认 Control 模板内容。

  • Clear content of the CSS tab of “Resources” section.
  • 将以下HTML代码放入 “Resources” 区域的HTML选项卡:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    <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内容放入 Settings schema section 的 “Settings schema” 选项卡:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
    "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” 区域:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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();
            }

        );
    }

}
  • Widget title 字段填写部件类型名称,例如 “My first control widget”。
  • 点击 Widget Editor Toolbar 中的 Run 按钮,在 Widget preview 区域查看结果。
  • 在预览区域点击dashboard编辑按钮调整部件尺寸,然后点击dashboard应用按钮。最终部件效果见下图。

image

  • 点击 Widget Editor Toolbar 中的 Save 按钮保存部件类型。

要测试该部件的RPC功能,需将其放入dashboard并绑定到支持RPC的设备。步骤如下:

  • 以租户管理员身份登录。
  • 进入 Devices 创建新设备,例如命名 “My RPC Device”。
  • 打开设备详情,点击 “Copy Access Token” 复制设备访问令牌。
  • 下载 mqtt-js-rpc-from-server.shmqtt-js-rpc-from-server.js,放在同一目录。 编辑 mqtt-js-rpc-from-server.sh,将 $ACCESS_TOKEN 替换为设备访问令牌,然后安装mqtt客户端库。
  • 运行 mqtt-js-rpc-from-server.sh 脚本,控制台应显示 “connected”。
  • 进入 Dashboards 创建新dashboard,例如 “My first control dashboard”,并打开。
  • 点击dashboard的 “edit” 按钮。在编辑模式下,点击dashboard工具栏上的 “Entity aliases” 按钮。

image

  • Entity aliases 弹窗中点击 “Add alias”。
  • 填写 “Alias name” 字段,例如 “My RPC Device Alias”。
  • 在 “Filter type” 中选择 “Entity list”。
  • 在 “Type” 中选择 “Device”。
  • 在 “Entity list” 中选择设备,此例为 “My RPC Device”。

image

  • Entity aliases 中点击 “Add” 再点击 “Save”。
  • 点击dashboard的 “+” 按钮,然后点击 “Create new widget” 按钮。

image

  • 选择保存RPC部件的 Widget Bundle,并选择 “Control widget” 选项卡。
  • 点击你的部件,此例为 “My first control widget”。
  • Add Widget 弹窗的 Target device 中选择设备别名,此例为 “My RPC Device Alias”。
  • 点击 Add。Control部件将出现在dashboard上。点击dashboard的 Apply changes 保存并退出编辑。
  • RPC method 填写RPC方法名,例如 “TestMethod”。
  • RPC params 填写RPC参数,例如 “{ param1: “value1” }”。
  • 点击 Send RPC command 按钮,部件中将显示响应。

image

设备控制台将输出如下内容:

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

要测试“Two way”RPC模式,需修改对应的部件设置。步骤如下:

  • 点击dashboard的 “edit” 按钮。在编辑模式下,点击Control部件顶部的 Edit widget 按钮。
  • 在部件详情中选择 “Advanced” 选项卡,取消勾选 “Is One Way Command”。

image

  • 点击部件详情顶部的 Apply changes,关闭详情后再点击dashboard的 Apply changes
  • 按前述步骤填写RPC方法名和参数。 点击 Send RPC command 按钮,部件中将显示响应。

image

  • 停止 mqtt-js-rpc-from-server.sh 脚本。 点击 Send RPC command 按钮,部件中将显示如下响应。

image

此例使用 controlApi 发送RPC命令,并引入自定义部件设置以配置RPC模式与RPC请求超时。 设备响应由 commandObservable 处理,包含成功与失败回调,分别接收响应或包含请求执行结果的拒绝对象。

Alarm widget

In the Widgets Bundle view, click the big “+” button at the bottom-right part of the screen and then click the “Create new widget type” button. Click the Alarm Widget button on the Select widget type popup. Widget Editor 将打开,并预填默认 Alarm 模板内容。

  • 将 “Resources” 区域中CSS选项卡内容替换为以下内容:
1
2
3
.my-alarm-table th {
    text-align: left;
}
  • 将以下HTML代码放入 “Resources” 区域的HTML选项卡:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  <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内容放入 Settings schema section 的 “Settings schema” 选项卡:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
    "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” 区域:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
self.onInit = function() {
    var pageLink = self.ctx.pageLink(100);

    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();
}
  • 点击 Widget Editor Toolbar 中的 Run 按钮,在 Widget preview 区域查看结果。

image

此例将 subscriptionalarmSourcealarms 赋值给 $scope,从而在HTML模板中可访问。 HTML中使用 *ngFor 指令遍历 alarmSource 的dataKeys渲染列。 表格行通过遍历 alarms 数组渲染,单元格通过遍历 dataKeys 渲染。 getAlarmValue 获取告警值,并通过 ctxdate 属性使用 DatePipe 格式化 createdTimegetAlarmCellStyle 为告警单元格设置自定义样式。本例引入 alarmSeverityColorFunction 设置,根据告警级别返回颜色。 getAlarmCellStyle 内调用 alarmSeverityColorFunction 获取告警级别单元格颜色。 注意本代码中 onDataUpdated 用订阅的最新告警更新 alarms,并调用 detectChanges() 执行变更检测。

Static widget

In the Widgets Bundle view, click the big “+” button at the bottom-right part of the screen and then click the “Create new widget type” button. 在 Select widget type 弹窗中点击 Static WidgetWidget Editor 将打开,并预填默认 Static 模板内容。

  • 将以下HTML代码放入 “Resources” 区域的HTML选项卡:
1
2
3
4
  <div fxFlex fxLayout="column" style="height: 100%;" fxLayoutAlign="space-around stretch">
    <h3 style="text-align: center;">My first static widget.</h3>
    <button mat-raised-button color="primary" (click)="showAlert()">Click me</button>
  </div>
  • 将以下JSON内容放入 Settings schema section 的 “Settings schema” 选项卡:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
    "schema": {
        "type": "object",
        "title": "Settings",
        "properties": {
            "alertContent": {
                "title": "Alert content",
                "type": "string",
                "default": "Content derived from alertContent property of widget settings."
            }
        }
    },
    "form": [
        "alertContent"
    ]
}
  • 将以下JavaScript代码放入 “JavaScript” 区域:
1
2
3
4
5
6
7
8
9
10
11
self.onInit = function() {

    self.ctx.$scope.showAlert = function() {
        var alertContent = self.ctx.settings.alertContent;
        if (!alertContent) {
            alertContent = "Content derived from alertContent property of widget settings.";
        }
        window.alert(alertContent);  
    };

}
  • 点击 Widget Editor Toolbar 中的 Run 按钮,在 Widget preview 区域查看结果。

image

这是一个纯静态HTML部件,无订阅数据,也未使用特殊部件API。 仅实现自定义 showAlert 函数,用部件设置的 alertContent 显示弹窗。 可在 Widget preview 区域切换到dashboard编辑模式,在部件详情的 “Advanced” 选项卡中修改 alertContent。 修改后即可看到新的弹窗内容。