Browse Source

Merge branch 'master' into feature/api-limits

pull/440/head
Igor Kulikov 9 years ago
parent
commit
db9fc098bd
  1. 9
      extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/telemetry/SubscriptionManager.java
  2. 3
      extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/telemetry/handlers/TelemetryRpcMsgHandler.java
  3. 8
      extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/telemetry/handlers/TelemetryWebsocketMsgHandler.java
  4. 4
      extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/telemetry/sub/Subscription.java
  5. 1
      extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/telemetry/sub/SubscriptionState.java
  6. 1
      extensions-core/src/main/proto/telemetry.proto
  7. 8
      ui/src/app/app.run.js
  8. 4
      ui/src/app/common/utils.service.js
  9. 81
      ui/src/app/widget/lib/flot-widget.js
  10. 2
      ui/src/app/widget/lib/map-widget.js
  11. 2
      ui/src/app/widget/lib/timeseries-table-widget.tpl.html

9
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/telemetry/SubscriptionManager.java

@ -33,6 +33,7 @@ import org.thingsboard.server.extensions.core.plugin.telemetry.sub.SubscriptionU
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
/** /**
* @author Andrew Shvayka * @author Andrew Shvayka
@ -174,9 +175,13 @@ public class SubscriptionManager {
} }
public void onLocalSubscriptionUpdate(PluginContext ctx, EntityId entityId, SubscriptionType type, Function<Subscription, List<TsKvEntry>> f) { public void onLocalSubscriptionUpdate(PluginContext ctx, EntityId entityId, SubscriptionType type, Function<Subscription, List<TsKvEntry>> f) {
onLocalSubscriptionUpdate(ctx, entityId, s -> type == s.getType(), f);
}
public void onLocalSubscriptionUpdate(PluginContext ctx, EntityId entityId, Predicate<Subscription> filter, Function<Subscription, List<TsKvEntry>> f) {
Set<Subscription> deviceSubscriptions = subscriptionsByEntityId.get(entityId); Set<Subscription> deviceSubscriptions = subscriptionsByEntityId.get(entityId);
if (deviceSubscriptions != null) { if (deviceSubscriptions != null) {
deviceSubscriptions.stream().filter(s -> type == s.getType()).forEach(s -> { deviceSubscriptions.stream().filter(filter).forEach(s -> {
String sessionId = s.getWsSessionId(); String sessionId = s.getWsSessionId();
List<TsKvEntry> subscriptionUpdate = f.apply(s); List<TsKvEntry> subscriptionUpdate = f.apply(s);
if (!subscriptionUpdate.isEmpty()) { if (!subscriptionUpdate.isEmpty()) {
@ -206,7 +211,7 @@ public class SubscriptionManager {
public void onAttributesUpdateFromServer(PluginContext ctx, EntityId entityId, String scope, List<AttributeKvEntry> attributes) { public void onAttributesUpdateFromServer(PluginContext ctx, EntityId entityId, String scope, List<AttributeKvEntry> attributes) {
Optional<ServerAddress> serverAddress = ctx.resolve(entityId); Optional<ServerAddress> serverAddress = ctx.resolve(entityId);
if (!serverAddress.isPresent()) { if (!serverAddress.isPresent()) {
onLocalSubscriptionUpdate(ctx, entityId, SubscriptionType.ATTRIBUTES, s -> { onLocalSubscriptionUpdate(ctx, entityId, s -> SubscriptionType.ATTRIBUTES == s.getType() && scope.equals(s.getScope()), s -> {
List<TsKvEntry> subscriptionUpdate = new ArrayList<TsKvEntry>(); List<TsKvEntry> subscriptionUpdate = new ArrayList<TsKvEntry>();
for (AttributeKvEntry kv : attributes) { for (AttributeKvEntry kv : attributes) {
if (s.isAllKeys() || s.getKeyStates().containsKey(kv.getKey())) { if (s.isAllKeys() || s.getKeyStates().containsKey(kv.getKey())) {

3
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/telemetry/handlers/TelemetryRpcMsgHandler.java

@ -114,7 +114,7 @@ public class TelemetryRpcMsgHandler implements RpcMsgHandler {
} }
Map<String, Long> statesMap = proto.getKeyStatesList().stream().collect(Collectors.toMap(SubscriptionKetStateProto::getKey, SubscriptionKetStateProto::getTs)); Map<String, Long> statesMap = proto.getKeyStatesList().stream().collect(Collectors.toMap(SubscriptionKetStateProto::getKey, SubscriptionKetStateProto::getTs));
Subscription subscription = new Subscription( Subscription subscription = new Subscription(
new SubscriptionState(proto.getSessionId(), proto.getSubscriptionId(), EntityIdFactory.getByTypeAndId(proto.getEntityType(), proto.getEntityId()), SubscriptionType.valueOf(proto.getType()), proto.getAllKeys(), statesMap), new SubscriptionState(proto.getSessionId(), proto.getSubscriptionId(), EntityIdFactory.getByTypeAndId(proto.getEntityType(), proto.getEntityId()), SubscriptionType.valueOf(proto.getType()), proto.getAllKeys(), statesMap, proto.getScope()),
false, msg.getServerAddress()); false, msg.getServerAddress());
subscriptionManager.addRemoteWsSubscription(ctx, msg.getServerAddress(), proto.getSessionId(), subscription); subscriptionManager.addRemoteWsSubscription(ctx, msg.getServerAddress(), proto.getSessionId(), subscription);
} }
@ -127,6 +127,7 @@ public class TelemetryRpcMsgHandler implements RpcMsgHandler {
builder.setEntityId(cmd.getEntityId().getId().toString()); builder.setEntityId(cmd.getEntityId().getId().toString());
builder.setType(cmd.getType().name()); builder.setType(cmd.getType().name());
builder.setAllKeys(cmd.isAllKeys()); builder.setAllKeys(cmd.isAllKeys());
builder.setScope(cmd.getScope());
cmd.getKeyStates().entrySet().forEach(e -> builder.addKeyStates(SubscriptionKetStateProto.newBuilder().setKey(e.getKey()).setTs(e.getValue()).build())); cmd.getKeyStates().entrySet().forEach(e -> builder.addKeyStates(SubscriptionKetStateProto.newBuilder().setKey(e.getKey()).setTs(e.getValue()).build()));
ctx.sendPluginRpcMsg(new RpcMsg(address, SUBSCRIPTION_CLAZZ, builder.build().toByteArray())); ctx.sendPluginRpcMsg(new RpcMsg(address, SUBSCRIPTION_CLAZZ, builder.build().toByteArray()));
} }

8
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/telemetry/handlers/TelemetryWebsocketMsgHandler.java

@ -131,7 +131,7 @@ public class TelemetryWebsocketMsgHandler extends DefaultWebsocketMsgHandler {
keys.forEach(key -> subState.put(key, 0L)); keys.forEach(key -> subState.put(key, 0L));
attributesData.forEach(v -> subState.put(v.getKey(), v.getTs())); attributesData.forEach(v -> subState.put(v.getKey(), v.getTs()));
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, SubscriptionType.ATTRIBUTES, false, subState); SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, SubscriptionType.ATTRIBUTES, false, subState, cmd.getScope());
subscriptionManager.addLocalWsSubscription(ctx, sessionId, entityId, sub); subscriptionManager.addLocalWsSubscription(ctx, sessionId, entityId, sub);
} }
@ -168,7 +168,7 @@ public class TelemetryWebsocketMsgHandler extends DefaultWebsocketMsgHandler {
Map<String, Long> subState = new HashMap<>(attributesData.size()); Map<String, Long> subState = new HashMap<>(attributesData.size());
attributesData.forEach(v -> subState.put(v.getKey(), v.getTs())); attributesData.forEach(v -> subState.put(v.getKey(), v.getTs()));
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, SubscriptionType.ATTRIBUTES, true, subState); SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, SubscriptionType.ATTRIBUTES, true, subState, cmd.getScope());
subscriptionManager.addLocalWsSubscription(ctx, sessionId, entityId, sub); subscriptionManager.addLocalWsSubscription(ctx, sessionId, entityId, sub);
} }
@ -234,7 +234,7 @@ public class TelemetryWebsocketMsgHandler extends DefaultWebsocketMsgHandler {
sendWsMsg(ctx, sessionRef, new SubscriptionUpdate(cmd.getCmdId(), data)); sendWsMsg(ctx, sessionRef, new SubscriptionUpdate(cmd.getCmdId(), data));
Map<String, Long> subState = new HashMap<>(data.size()); Map<String, Long> subState = new HashMap<>(data.size());
data.forEach(v -> subState.put(v.getKey(), v.getTs())); data.forEach(v -> subState.put(v.getKey(), v.getTs()));
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, SubscriptionType.TIMESERIES, true, subState); SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, SubscriptionType.TIMESERIES, true, subState, cmd.getScope());
subscriptionManager.addLocalWsSubscription(ctx, sessionId, entityId, sub); subscriptionManager.addLocalWsSubscription(ctx, sessionId, entityId, sub);
} }
@ -262,7 +262,7 @@ public class TelemetryWebsocketMsgHandler extends DefaultWebsocketMsgHandler {
Map<String, Long> subState = new HashMap<>(keys.size()); Map<String, Long> subState = new HashMap<>(keys.size());
keys.forEach(key -> subState.put(key, startTs)); keys.forEach(key -> subState.put(key, startTs));
data.forEach(v -> subState.put(v.getKey(), v.getTs())); data.forEach(v -> subState.put(v.getKey(), v.getTs()));
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, SubscriptionType.TIMESERIES, false, subState); SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, SubscriptionType.TIMESERIES, false, subState, cmd.getScope());
subscriptionManager.addLocalWsSubscription(ctx, sessionId, entityId, sub); subscriptionManager.addLocalWsSubscription(ctx, sessionId, entityId, sub);
} }

4
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/telemetry/sub/Subscription.java

@ -51,6 +51,10 @@ public class Subscription {
return getSub().getType(); return getSub().getType();
} }
public String getScope() {
return getSub().getScope();
}
public boolean isAllKeys() { public boolean isAllKeys() {
return getSub().isAllKeys(); return getSub().isAllKeys();
} }

1
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/telemetry/sub/SubscriptionState.java

@ -33,6 +33,7 @@ public class SubscriptionState {
@Getter private final SubscriptionType type; @Getter private final SubscriptionType type;
@Getter private final boolean allKeys; @Getter private final boolean allKeys;
@Getter private final Map<String, Long> keyStates; @Getter private final Map<String, Long> keyStates;
@Getter private final String scope;
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {

1
extensions-core/src/main/proto/telemetry.proto

@ -27,6 +27,7 @@ message SubscriptionProto {
string type = 5; string type = 5;
bool allKeys = 6; bool allKeys = 6;
repeated SubscriptionKetStateProto keyStates = 7; repeated SubscriptionKetStateProto keyStates = 7;
string scope = 8;
} }
message SubscriptionUpdateProto { message SubscriptionUpdateProto {

8
ui/src/app/app.run.js

@ -20,7 +20,13 @@ import UrlHandler from './url.handler';
export default function AppRun($rootScope, $window, $injector, $location, $log, $state, $mdDialog, $filter, loginService, userService, $translate) { export default function AppRun($rootScope, $window, $injector, $location, $log, $state, $mdDialog, $filter, loginService, userService, $translate) {
$window.Flow = Flow; $window.Flow = Flow;
var frame = $window.frameElement; var frame = null;
try {
frame = $window.frameElement;
} catch(e) {
// ie11 fix
}
var unauthorizedDialog = null; var unauthorizedDialog = null;
var forbiddenDialog = null; var forbiddenDialog = null;

4
ui/src/app/common/utils.service.js

@ -553,7 +553,9 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t
var aspect = imageAspectMap[urlHashCode]; var aspect = imageAspectMap[urlHashCode];
if (angular.isUndefined(aspect)) { if (angular.isUndefined(aspect)) {
var testImage = document.createElement('img'); // eslint-disable-line var testImage = document.createElement('img'); // eslint-disable-line
testImage.style.visibility = 'hidden'; testImage.style.position = 'absolute';
testImage.style.left = '-99999px';
testImage.style.top = '-99999px';
testImage.onload = function() { testImage.onload = function() {
aspect = testImage.width / testImage.height; aspect = testImage.width / testImage.height;
document.body.removeChild(testImage); //eslint-disable-line document.body.removeChild(testImage); //eslint-disable-line

81
ui/src/app/widget/lib/flot-widget.js

@ -238,6 +238,7 @@ export default class TbFlot {
if (this.ticksFormatterFunction) { if (this.ticksFormatterFunction) {
return this.ticksFormatterFunction(value); return this.ticksFormatterFunction(value);
} }
var factor = this.tickDecimals ? Math.pow(10, this.tickDecimals) : 1, var factor = this.tickDecimals ? Math.pow(10, this.tickDecimals) : 1,
formatted = "" + Math.round(value * factor) / factor; formatted = "" + Math.round(value * factor) / factor;
if (this.tickDecimals != null) { if (this.tickDecimals != null) {
@ -248,9 +249,12 @@ export default class TbFlot {
formatted = (precision ? formatted : formatted + ".") + ("" + factor).substr(1, this.tickDecimals - precision); formatted = (precision ? formatted : formatted + ".") + ("" + factor).substr(1, this.tickDecimals - precision);
} }
} }
formatted += ' ' + this.tickUnits; if (this.tickUnits) {
formatted += ' ' + this.tickUnits;
}
return formatted; return formatted;
} };
this.yaxis.tickFormatter = ctx.yAxisTickFormatter; this.yaxis.tickFormatter = ctx.yAxisTickFormatter;
@ -262,6 +266,16 @@ export default class TbFlot {
this.yaxis.labelFont.color = this.yaxis.font.color; this.yaxis.labelFont.color = this.yaxis.font.color;
this.yaxis.labelFont.size = this.yaxis.font.size+2; this.yaxis.labelFont.size = this.yaxis.font.size+2;
this.yaxis.labelFont.weight = "bold"; this.yaxis.labelFont.weight = "bold";
if (angular.isNumber(settings.yaxis.tickSize)) {
this.yaxis.tickSize = settings.yaxis.tickSize;
} else {
this.yaxis.tickSize = null;
}
if (angular.isNumber(settings.yaxis.tickDecimals)) {
this.yaxis.tickDecimals = settings.yaxis.tickDecimals
} else {
this.yaxis.tickDecimals = null;
}
if (settings.yaxis.ticksFormatter && settings.yaxis.ticksFormatter.length) { if (settings.yaxis.ticksFormatter && settings.yaxis.ticksFormatter.length) {
try { try {
this.yaxis.ticksFormatterFunction = new Function('value', settings.yaxis.ticksFormatter); this.yaxis.ticksFormatterFunction = new Function('value', settings.yaxis.ticksFormatter);
@ -405,9 +419,13 @@ export default class TbFlot {
} }
} }
series.lines = { series.lines = {
fill: keySettings.fillLines === true, fill: keySettings.fillLines === true
show: this.chartType === 'line' ? keySettings.showLines !== false : keySettings.showLines === true
}; };
if (this.chartType === 'line' || this.chartType === 'state') {
series.lines.show = keySettings.showLines !== false
} else {
series.lines.show = keySettings.showLines === true;
}
if (angular.isDefined(keySettings.lineWidth)) { if (angular.isDefined(keySettings.lineWidth)) {
series.lines.lineWidth = keySettings.lineWidth; series.lines.lineWidth = keySettings.lineWidth;
@ -487,9 +505,19 @@ export default class TbFlot {
createYAxis(keySettings, units) { createYAxis(keySettings, units) {
var yaxis = angular.copy(this.yaxis); var yaxis = angular.copy(this.yaxis);
var tickDecimals, tickSize;
var label = keySettings.axisTitle && keySettings.axisTitle.length ? keySettings.axisTitle : yaxis.label; var label = keySettings.axisTitle && keySettings.axisTitle.length ? keySettings.axisTitle : yaxis.label;
var tickDecimals = angular.isDefined(keySettings.axisTickDecimals) ? keySettings.axisTickDecimals : 0; if (angular.isNumber(keySettings.axisTickDecimals)) {
tickDecimals = keySettings.axisTickDecimals;
} else {
tickDecimals = yaxis.tickDecimals;
}
if (angular.isNumber(keySettings.axisTickSize)) {
tickSize = keySettings.axisTickSize;
} else {
tickSize = yaxis.tickSize;
}
var position = keySettings.axisPosition && keySettings.axisPosition.length ? keySettings.axisPosition : "left"; var position = keySettings.axisPosition && keySettings.axisPosition.length ? keySettings.axisPosition : "left";
var min = angular.isDefined(keySettings.axisMin) ? keySettings.axisMin : yaxis.min; var min = angular.isDefined(keySettings.axisMin) ? keySettings.axisMin : yaxis.min;
@ -500,6 +528,7 @@ export default class TbFlot {
yaxis.max = max; yaxis.max = max;
yaxis.tickUnits = units; yaxis.tickUnits = units;
yaxis.tickDecimals = tickDecimals; yaxis.tickDecimals = tickDecimals;
yaxis.tickSize = tickSize;
yaxis.alignTicksWithAxis = position == "right" ? 1 : null; yaxis.alignTicksWithAxis = position == "right" ? 1 : null;
yaxis.position = position; yaxis.position = position;
@ -545,7 +574,7 @@ export default class TbFlot {
} }
} }
yaxis.hidden = hidden; yaxis.hidden = hidden;
var newIndex = -1; var newIndex = 1;
if (!yaxis.hidden) { if (!yaxis.hidden) {
this.options.yaxes.push(yaxis); this.options.yaxes.push(yaxis);
newIndex = this.options.yaxes.length; newIndex = this.options.yaxes.length;
@ -928,6 +957,16 @@ export default class TbFlot {
"title": "Ticks formatter function, f(value)", "title": "Ticks formatter function, f(value)",
"type": "string", "type": "string",
"default": "" "default": ""
},
"tickDecimals": {
"title": "The number of decimals to display",
"type": "number",
"default": 0
},
"tickSize": {
"title": "Step size between ticks",
"type": "number",
"default": null
} }
} }
} }
@ -986,6 +1025,8 @@ export default class TbFlot {
"items": [ "items": [
"yaxis.min", "yaxis.min",
"yaxis.max", "yaxis.max",
"yaxis.tickDecimals",
"yaxis.tickSize",
"yaxis.showLabels", "yaxis.showLabels",
"yaxis.title", "yaxis.title",
"yaxis.titleAngle", "yaxis.titleAngle",
@ -1010,24 +1051,24 @@ export default class TbFlot {
static datakeySettingsSchema(defaultShowLines) { static datakeySettingsSchema(defaultShowLines) {
return { return {
"schema": { "schema": {
"type": "object", "type": "object",
"title": "DataKeySettings", "title": "DataKeySettings",
"properties": { "properties": {
"showLines": { "showLines": {
"title": "Show lines", "title": "Show lines",
"type": "boolean", "type": "boolean",
"default": defaultShowLines "default": defaultShowLines
}, },
"fillLines": { "fillLines": {
"title": "Fill lines", "title": "Fill lines",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"showPoints": { "showPoints": {
"title": "Show points", "title": "Show points",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"tooltipValueFormatter": { "tooltipValueFormatter": {
"title": "Tooltip value format function, f(value)", "title": "Tooltip value format function, f(value)",
@ -1059,6 +1100,11 @@ export default class TbFlot {
"type": "number", "type": "number",
"default": 0 "default": 0
}, },
"axisTickSize": {
"title": "Axis step size between ticks",
"type": "number",
"default": null
},
"axisPosition": { "axisPosition": {
"title": "Axis position", "title": "Axis position",
"type": "string", "type": "string",
@ -1072,7 +1118,7 @@ export default class TbFlot {
}, },
"required": ["showLines", "fillLines", "showPoints"] "required": ["showLines", "fillLines", "showPoints"]
}, },
"form": [ "form": [
"showLines", "showLines",
"fillLines", "fillLines",
"showPoints", "showPoints",
@ -1085,6 +1131,7 @@ export default class TbFlot {
"axisMax", "axisMax",
"axisTitle", "axisTitle",
"axisTickDecimals", "axisTickDecimals",
"axisTickSize",
{ {
"key": "axisPosition", "key": "axisPosition",
"type": "rc-select", "type": "rc-select",
@ -1401,4 +1448,4 @@ export default class TbFlot {
} }
} }
/* eslint-enable angular/angularelement */ /* eslint-enable angular/angularelement */

2
ui/src/app/widget/lib/map-widget.js

@ -276,7 +276,7 @@ export default class TbMapWidget {
this.locationsSettings[i].useMarkerImage = true; this.locationsSettings[i].useMarkerImage = true;
var url = this.ctx.settings.markerImage; var url = this.ctx.settings.markerImage;
var size = this.ctx.settings.markerImageSize || 34; var size = this.ctx.settings.markerImageSize || 34;
this.locationSettings.currentImage = { this.locationsSettings[i].currentImage = {
url: url, url: url,
size: size size: size
}; };

2
ui/src/app/widget/lib/timeseries-table-widget.tpl.html

@ -41,7 +41,7 @@
<md-tabs flex md-selected="vm.sourceIndex" ng-class="{'tb-headless': vm.sources.length === 1}" <md-tabs flex md-selected="vm.sourceIndex" ng-class="{'tb-headless': vm.sources.length === 1}"
id="tabs" md-border-bottom flex> id="tabs" md-border-bottom flex>
<md-tab ng-repeat="source in vm.sources" label="{{ source.datasource.name }}"> <md-tab ng-repeat="source in vm.sources" label="{{ source.datasource.name }}">
<md-table-container class="tb-absolute-fill layout-column"> <md-table-container class="flex">
<table md-table> <table md-table>
<thead md-head md-order="source.query.order" md-on-reorder="vm.onReorder(source)"> <thead md-head md-order="source.query.order" md-on-reorder="vm.onReorder(source)">
<tr md-row> <tr md-row>

Loading…
Cancel
Save