Calculate delta node
This commit is contained in:
parent
cd3d388d21
commit
7c019a7123
@ -5,7 +5,7 @@
|
|||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@ -28,6 +28,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
|||||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||||
import org.thingsboard.rule.engine.api.TbRelationTypes;
|
import org.thingsboard.rule.engine.api.TbRelationTypes;
|
||||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||||
|
import org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||||
@ -36,6 +37,7 @@ import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
|||||||
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
|
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -44,9 +46,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
@RuleNode(type = ComponentType.ENRICHMENT,
|
@RuleNode(type = ComponentType.ENRICHMENT,
|
||||||
name = "calculate delta",
|
name = "calculate delta",
|
||||||
configClazz = CalculateDeltaNodeConfiguration.class,
|
configClazz = CalculateDeltaNodeConfiguration.class,
|
||||||
nodeDescription = "Add delta value into message by originator Entity Id",
|
nodeDescription = "Calculates and adds 'delta' value into message based on the incoming and previous value",
|
||||||
nodeDetails = "Calculates delta and period based on the previous data and current data. " +
|
nodeDetails = "Calculates delta and period based on the previous time-series reading and current data. " +
|
||||||
"Groups incoming data based on originator id of the message (i.e. particular device, asset, customer).",
|
"Delta calculation is done in scope of the message originator, e.g. device, asset or customer.",
|
||||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
configDirective = "tbEnrichmentNodeCalculateDeltaConfig")
|
configDirective = "tbEnrichmentNodeCalculateDeltaConfig")
|
||||||
public class CalculateDeltaNode implements TbNode {
|
public class CalculateDeltaNode implements TbNode {
|
||||||
@ -76,7 +78,7 @@ public class CalculateDeltaNode implements TbNode {
|
|||||||
DonAsynchron.withCallback(getLastValue(msg.getOriginator()),
|
DonAsynchron.withCallback(getLastValue(msg.getOriginator()),
|
||||||
previousData -> {
|
previousData -> {
|
||||||
double currentValue = json.get(inputKey).asDouble();
|
double currentValue = json.get(inputKey).asDouble();
|
||||||
long currentTs = json.has("ts") ? json.get("ts").asLong() : System.currentTimeMillis();
|
long currentTs = TbMsgTimeseriesNode.getTs(msg);
|
||||||
|
|
||||||
if (useCache) {
|
if (useCache) {
|
||||||
cache.put(msg.getOriginator(), new ValueWithTs(currentTs, currentValue));
|
cache.put(msg.getOriginator(), new ValueWithTs(currentTs, currentValue));
|
||||||
@ -90,7 +92,7 @@ public class CalculateDeltaNode implements TbNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.getRound() != null) {
|
if (config.getRound() != null) {
|
||||||
delta = delta.setScale(config.getRound(), BigDecimal.ROUND_HALF_UP);
|
delta = delta.setScale(config.getRound(), RoundingMode.HALF_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectNode result = (ObjectNode) json;
|
ObjectNode result = (ObjectNode) json;
|
||||||
@ -102,8 +104,7 @@ public class CalculateDeltaNode implements TbNode {
|
|||||||
}
|
}
|
||||||
ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(result)));
|
ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(result)));
|
||||||
},
|
},
|
||||||
t -> ctx.tellFailure(msg, t)
|
t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor());
|
||||||
, ctx.getDbCallbackExecutor());
|
|
||||||
} else if (config.isTellFailureIfInputValueKeyIsAbsent()) {
|
} else if (config.isTellFailureIfInputValueKeyIsAbsent()) {
|
||||||
ctx.tellNext(msg, TbRelationTypes.FAILURE);
|
ctx.tellNext(msg, TbRelationTypes.FAILURE);
|
||||||
} else {
|
} else {
|
||||||
@ -113,7 +114,9 @@ public class CalculateDeltaNode implements TbNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
if (useCache) {
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListenableFuture<ValueWithTs> fetchLatestValue(EntityId entityId) {
|
private ListenableFuture<ValueWithTs> fetchLatestValue(EntityId entityId) {
|
||||||
@ -132,33 +135,30 @@ public class CalculateDeltaNode implements TbNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ValueWithTs extractValue(TsKvEntry kvEntry) {
|
private ValueWithTs extractValue(TsKvEntry kvEntry) {
|
||||||
|
if (kvEntry == null || kvEntry.getValue() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
double result = 0.0;
|
double result = 0.0;
|
||||||
long ts = 0;
|
long ts = kvEntry.getTs();
|
||||||
if (kvEntry != null) {
|
switch (kvEntry.getDataType()) {
|
||||||
ts = kvEntry.getTs();
|
case LONG:
|
||||||
switch (kvEntry.getDataType()) {
|
result = kvEntry.getLongValue().get();
|
||||||
case LONG:
|
break;
|
||||||
result = kvEntry.getLongValue().get();
|
case DOUBLE:
|
||||||
break;
|
result = kvEntry.getDoubleValue().get();
|
||||||
case DOUBLE:
|
break;
|
||||||
result = kvEntry.getDoubleValue().get();
|
case STRING:
|
||||||
break;
|
try {
|
||||||
case BOOLEAN:
|
result = Double.parseDouble(kvEntry.getStrValue().get());
|
||||||
result = kvEntry.getBooleanValue().get() ? 1 : 0;
|
} catch (NumberFormatException e) {
|
||||||
break;
|
throw new IllegalArgumentException("Calculation failed. Unable to parse value [" + kvEntry.getStrValue().get() + "]" +
|
||||||
case STRING:
|
" of telemetry [" + kvEntry.getKey() + "] to Double");
|
||||||
String str = kvEntry.getStrValue().orElse(null);
|
}
|
||||||
try {
|
break;
|
||||||
if (str == null) {
|
case BOOLEAN:
|
||||||
return null;
|
throw new IllegalArgumentException("Calculation failed. Boolean values are not supported!");
|
||||||
}
|
case JSON:
|
||||||
result = Double.parseDouble(str);
|
throw new IllegalArgumentException("Calculation failed. JSON values are not supported!");
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new IllegalArgumentException("Calculation failed. Unable to parse value [" + str + "]" +
|
|
||||||
" of telemetry [" + kvEntry.getKey() + "] to Double");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return new ValueWithTs(ts, result);
|
return new ValueWithTs(ts, result);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,8 +32,8 @@ public class CalculateDeltaNodeConfiguration implements NodeConfiguration<Calcul
|
|||||||
@Override
|
@Override
|
||||||
public CalculateDeltaNodeConfiguration defaultConfiguration() {
|
public CalculateDeltaNodeConfiguration defaultConfiguration() {
|
||||||
CalculateDeltaNodeConfiguration configuration = new CalculateDeltaNodeConfiguration();
|
CalculateDeltaNodeConfiguration configuration = new CalculateDeltaNodeConfiguration();
|
||||||
configuration.setInputValueKey("value");
|
configuration.setInputValueKey("pulseCounter");
|
||||||
configuration.setOutputValueKey("valueDelta");
|
configuration.setOutputValueKey("delta");
|
||||||
configuration.setUseCache(true);
|
configuration.setUseCache(true);
|
||||||
configuration.setAddPeriodBetweenMsgs(false);
|
configuration.setAddPeriodBetweenMsgs(false);
|
||||||
configuration.setPeriodValueKey("periodInMs");
|
configuration.setPeriodValueKey("periodInMs");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user