diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java index df6bcf9f58..7a26faa8f4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java @@ -15,6 +15,10 @@ */ package org.thingsboard.rule.engine.metadata; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.apache.commons.collections.CollectionUtils; @@ -40,11 +44,18 @@ import static org.thingsboard.server.common.data.DataConstants.SHARED_SCOPE; public abstract class TbAbstractGetAttributesNode implements TbNode { + private static ObjectMapper mapper = new ObjectMapper(); + + private static final String VALUE = "value"; + private static final String TS = "ts"; + protected C config; @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { this.config = loadGetAttributesNodeConfig(configuration); + mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false); + mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); } protected abstract C loadGetAttributesNodeConfig(TbNodeConfiguration configuration) throws TbNodeException; @@ -61,6 +72,11 @@ public abstract class TbAbstractGetAttributesNode findEntityIdAsync(TbContext ctx, TbMsg msg); + private void safePutAttributes(TbContext ctx, TbMsg msg, T entityId) { if (entityId == null || entityId.isNullUid()) { ctx.tellNext(msg, FAILURE); @@ -106,15 +122,22 @@ public abstract class TbAbstractGetAttributesNode> latest = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), entityId, keys); return Futures.transform(latest, l -> { l.forEach(r -> { + boolean getLatestValueWithTs = BooleanUtils.toBooleanDefaultIfNull(this.config.isGetLatestValueWithTs(), false); if (BooleanUtils.toBooleanDefaultIfNull(this.config.isTellFailureIfAbsent(), true)) { - if (r.getValue() != null) { - msg.getMetaData().putValue(r.getKey(), r.getValueAsString()); - } else { + if (r.getValue() == null) { throw new RuntimeException("[" + r.getKey() + "] telemetry value is not present in the DB!"); + } else if (getLatestValueWithTs) { + putValueWithTs(msg, r); + } else { + msg.getMetaData().putValue(r.getKey(), r.getValueAsString()); } } else { if (r.getValue() != null) { - msg.getMetaData().putValue(r.getKey(), r.getValueAsString()); + if (getLatestValueWithTs) { + putValueWithTs(msg, r); + } else { + msg.getMetaData().putValue(r.getKey(), r.getValueAsString()); + } } } }); @@ -122,10 +145,23 @@ public abstract class TbAbstractGetAttributesNode findEntityIdAsync(TbContext ctx, TbMsg msg); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java index 2b47b5264a..a9a5c47ba0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java @@ -34,6 +34,7 @@ public class TbGetAttributesNodeConfiguration implements NodeConfiguration latestTsKeyNames; private boolean tellFailureIfAbsent; + private boolean getLatestValueWithTs; @Override public TbGetAttributesNodeConfiguration defaultConfiguration() { @@ -43,6 +44,7 @@ public class TbGetAttributesNodeConfiguration implements NodeConfiguration