Trendz 提供简单的 REST API,用于下载视图报告数据。
- 在 Trendz 中创建包含所需字段的表格视图。
- 复制该视图的链接并提取视图 ID(链接末尾的 UUID 字符串)。
- 执行 HTTP POST 请求:
URL:http://localhost:8888/apiTrendz/publicApi/buildReport?jwt=YYYYYYY
请求体:
1
2
3
4
5
6
{
"viewConfigId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"rangeStartTs": 1609462861000,
"rangeEndTs": 1630497968000,
"filters": {}
}
参数说明:
viewConfigId- 要执行的视图 ID,必填。rangeStartTs- 报告时间范围的起始时间(毫秒),可选。未填时从已保存视图获取。rangeEndTs- 报告时间范围的结束时间(毫秒),可选。未填时从已保存视图获取。filters- 覆盖已保存视图中过滤器的自定义过滤器,可选。jwt- 用于请求认证的 JWT 令牌。
认证
所有请求需携带 JWT 令牌进行认证,可作为查询参数或 HTTP 头添加,参数名均为 jwt。
可通过 ThingsBoard REST API 获取 JWT 令牌。
请求示例:
1
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{"username":"tenant@thingsboard.org", "password":"tenant"}' 'http://THINGSBOARD_URL/api/auth/login'
响应示例:
1
{"token":"$YOUR_JWT_TOKEN", "refreshToken":"$YOUR_JWT_REFRESH_TOKEN"}
将 $YOUR_JWT_TOKEN 作为 jwt 参数用于请求认证。
响应格式
响应示例:
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
{
"columnLabels": [
"Building",
"Date",
"energyUsage"
],
"dataTable": [
{
"Building": "Building ABC",
"Date": "1606773600000",
"energyUsage": 3.422654173312068
},
{
"Building": "Building ABC",
"Date": "1619816400000",
"energyUsage": 9.189473684210526
},
{
"Building": "Building XYZ",
"Date": "1617224400000",
"energyUsage": 7.015277777777778
},
{
"Building": "Building XYZ",
"Date": "1612130400000",
"energyUsage": 6.513392857142857
}
]
}
columnLabels:报告包含的字段标签。
dataTable:表格形式的视图报告数据。
过滤器修改
若已配置视图包含过滤字段,可在请求时修改过滤选项。需在请求体中添加 filters 字段。
示例:
1
2
3
4
5
6
7
{
"viewConfigId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"filters": {
"building": ["Building ABC"],
"apartment": ["Apt 101", "Apt 407"]
}
}
filters 对象中的键需与视图中过滤器名称一致,值为要应用到该过滤字段的值数组。
在自定义 ThingsBoard 部件中使用
若需具有特定逻辑的自定义部件,可使用 Trendz REST API 加载数据,并结合 ThingsBoard 自定义部件功能实现可视化。 以下示例说明如何从 Trendz API 加载数据、应用仪表板时间并从部件数据源设置过滤器。
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
self.onInit = function() {
let requestObj = buildTrendzRequest("edee0e57-41b9-4df3-acdb-08900cf53653", false, 'building');
loadDataFromTrendz(requestObj)
.subscribe(
data => console.log('数据正常', data),
err => console.log('出错了', err)
);
}
self.onDataUpdated = function() {
let requestObj = buildTrendzRequest("edee0e57-41b9-4df3-acdb-08900cf53653", false, 'building');
loadDataFromTrendz(requestObj)
.subscribe(
data => console.log('数据正常', data),
err => console.log('出错了', err)
);
}
function buildTrendzRequest(viewId, useDashboardTime, filterKey) {
let requestObj = {};
requestObj.viewConfigId = viewId;
if(useDashboardTime) {
applyDashboardTime(requestObj);
}
applyFilters(requestObj, filterKey);
return requestObj;
}
function applyFilters(requestObj, key) {
let filterValues = getAliasValues();
if(filterValues.length) {
requestObj.filters = {};
requestObj.filters[key] = filterValues;
}
}
function applyDashboardTime(requestObj) {
let timeWindow = $scope.ctx.dashboard.dashboardTimewindow;
if (timeWindow.realtime) {
requestObj.rangeStartTs = Date.now() - timeWindow.realtime.timewindowMs;
requestObj.rangeEndTs = Date.now();
} else if (timeWindow.history) {
if (timeWindow.history.fixedTimewindow && timeWindow.history.historyType === 1) {
requestObj.rangeStartTs = timeWindow.history.fixedTimewindow.startTimeMs;
requestObj.rangeEndTs = timeWindow.history.fixedTimewindow.endTimeMs;
} else if (timeWindow.history.timewindowMs && timeWindow.history.historyType === 0) {
requestObj.rangeStartTs = Date.now() - timeWindow.history.timewindowMs;
requestObj.rangeEndTs = Date.now();
}
}
}
function loadDataFromTrendz(requestObj) {
let trendzDomain = 'http://localhost:8888';
let dataUrl = trendzDomain + '/apiTrendz/publicApi/buildReport?jwt=' + getToken();
return self.ctx.http.post(dataUrl, requestObj);
}
function getAliasValues() {
let filterValues = [];
if(self.ctx && self.ctx.defaultSubscription && self.ctx.defaultSubscription.data && self.ctx.defaultSubscription.data.length > 0) {
for(let i = 0; i<self.ctx.defaultSubscription.data.length; i++ ) {
let value = getDescendantProp(self.ctx.defaultSubscription.data[i], 'data.0.1');
if (value && value !== 'Unresolved') {
filterValues.push(value);
}
}
}
return filterValues;
}
function getDescendantProp(obj, path) {
return path.split('.').reduce((acc, part) => acc && acc[part], obj)
}
function getToken() {
let jwtToken = localStorage.getItem('jwt_token');
if(jwtToken) {
jwtToken = jwtToken.replace(/"/g, '');
}
return jwtToken;
}
self.onResize = function() {
}
self.onDestroy = function() {
}
self.onInit- ThingsBoard 部件生命周期事件,部件首次初始化时调用。self.onDataUpdated- ThingsBoard 部件生命周期事件,部件数据源或别名更新时调用。buildTrendzRequest- 初始化发往 Trendz API 的请求对象,按需从仪表板时间窗口设置时间范围并设置过滤器。applyFilters- 从数据源读取数据,并将其作为 Trendz API 请求的过滤器。applyDashboardTime- 将仪表板时间窗口的时间范围应用到 Trendz API 请求。loadDataFromTrendz- 添加 jwt 令牌并执行实际 API 请求。
如需自定义部件开发帮助,请联系我们。
限制
Trendz REST API 有两项可配置限制:
SIMPLE_API_RATE_LIMITER_QUEUE_CAPACITY- 等待执行的最大排队请求数,超出后将被拒绝,默认队列大小为 10。SIMPLE_API_RATE_LIMITER_THREAD_POOL_SIZE- 并行执行的请求数。
响应码说明
403- JWT 令牌无效或已过期。415- 不支持的媒体类型,需在 HTTP 请求中将Content-Type头设为 application/json。429- 请求过多,已达到 API 限制,需等待后重试或修改 Trendz 配置中的 API 限制。