Browse Source

Update rule node doc links

pull/14114/head
Dmytro Skarzhynets 4 months ago
parent
commit
14efeecdc3
No known key found for this signature in database GPG Key ID: 2B51652F224037DF
  1. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAssignToCustomerNode.java
  2. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java
  3. 35
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java
  4. 21
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java
  5. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java
  6. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java
  7. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeviceStateNode.java
  8. 16
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java
  9. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java
  10. 7
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java
  11. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbUnassignFromCustomerNode.java
  12. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/ai/TbAiNode.java
  13. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/lambda/TbAwsLambdaNode.java
  14. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java
  15. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java
  16. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java
  17. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java
  18. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java
  19. 8
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToCloudNode.java
  20. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java
  21. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java
  22. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNode.java
  23. 8
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java
  24. 9
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java
  25. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java
  26. 12
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java
  27. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java
  28. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java
  29. 14
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java
  30. 10
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java
  31. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java
  32. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbAckNode.java
  33. 7
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java
  34. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java
  35. 9
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java
  36. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java
  37. 14
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNode.java
  38. 10
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java
  39. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java
  40. 22
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java
  41. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java
  42. 7
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java
  43. 12
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java
  44. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java
  45. 12
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java
  46. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java
  47. 9
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java
  48. 9
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java
  49. 12
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java
  50. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java
  51. 12
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java
  52. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java
  53. 9
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java
  54. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java
  55. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java
  56. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java
  57. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbSlackNode.java
  58. 7
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java
  59. 35
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java
  60. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java
  61. 8
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbSendRestApiCallReplyNode.java
  62. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNode.java
  63. 11
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java
  64. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNode.java
  65. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbCalculatedFieldsNode.java
  66. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java
  67. 9
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNode.java
  68. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java
  69. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java
  70. 10
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNode.java
  71. 12
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNode.java
  72. 21
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java
  73. 10
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java
  74. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java
  75. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java
  76. 9
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/GpsGeofencingActionTestCase.java
  77. 145
      ui-ngx/src/app/shared/models/constants.ts
  78. 7
      ui-ngx/src/app/shared/models/rule-node.models.ts

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAssignToCustomerNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.action;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -32,7 +31,6 @@ import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "assign to customer",
@ -42,7 +40,8 @@ import org.thingsboard.server.common.msg.TbMsg;
"Rule node will create a new customer if it doesn't exist, and 'Create new customer if it doesn't exist' enabled.",
configDirective = "tbActionNodeAssignToCustomerConfig",
icon = "add_circle",
version = 1
version = 1,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/assign-to-customer/"
)
public class TbAssignToCustomerNode extends TbAbstractCustomerActionNode<TbAssignToCustomerNodeConfiguration> {

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.action;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -31,7 +30,6 @@ import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "clear alarm", relationTypes = {"Cleared", "False"},
@ -44,7 +42,8 @@ import org.thingsboard.server.common.msg.TbMsg;
"Message payload can be accessed via <code>msg</code> property. For example <code>'temperature = ' + msg.temperature ;</code>. " +
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
configDirective = "tbActionNodeClearAlarmConfig",
icon = "notifications_off"
icon = "notifications_off",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/clear-alarm/"
)
public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfiguration> {
@ -79,4 +78,5 @@ public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfig
}
}, ctx.getDbCallbackExecutor());
}
}

35
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java

@ -21,7 +21,7 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import jakarta.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.thingsboard.common.util.DonAsynchron;
import org.thingsboard.rule.engine.api.AttributesDeleteRequest;
import org.thingsboard.rule.engine.api.AttributesSaveRequest;
@ -30,8 +30,6 @@ import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.adaptor.JsonConverter;
import org.thingsboard.server.common.data.AttributeScope;
import org.thingsboard.server.common.data.DataConstants;
@ -53,7 +51,6 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST;
import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCESS;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "copy to view",
@ -63,16 +60,13 @@ import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCES
"Copy will be done only for attributes that are between start and end dates and according to attribute keys configuration. \n" +
"Changes message originator to related entity view and produces new messages according to count of updated entity views",
configDirective = "tbNodeEmptyConfig",
icon = "content_copy"
icon = "content_copy",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/copy-to-view/"
)
public class TbCopyAttributesToEntityViewNode implements TbNode {
EmptyNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
}
public void init(TbContext ctx, TbNodeConfiguration configuration) {}
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
@ -138,14 +132,14 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
}
private FutureCallback<Void> getFutureCallback(TbContext ctx, TbMsg msg, EntityView entityView) {
return new FutureCallback<Void>() {
return new FutureCallback<>() {
@Override
public void onSuccess(@Nullable Void result) {
transformAndTellNext(ctx, msg, entityView);
}
@Override
public void onFailure(Throwable t) {
public void onFailure(@NonNull Throwable t) {
ctx.tellFailure(msg, t);
}
};
@ -157,18 +151,11 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
private boolean attributeContainsInEntityView(AttributeScope scope, String attrKey, EntityView entityView) {
AttributesEntityView attributesEntityView = entityView.getKeys().getAttributes();
List<String> keys = null;
switch (scope) {
case CLIENT_SCOPE:
keys = attributesEntityView.getCs();
break;
case SERVER_SCOPE:
keys = attributesEntityView.getSs();
break;
case SHARED_SCOPE:
keys = attributesEntityView.getSh();
break;
}
List<String> keys = switch (scope) {
case CLIENT_SCOPE -> attributesEntityView.getCs();
case SERVER_SCOPE -> attributesEntityView.getSs();
case SHARED_SCOPE -> attributesEntityView.getSh();
};
return CollectionsUtil.contains(keys, attrKey);
}

21
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java

@ -19,7 +19,6 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.EnumUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
@ -39,7 +38,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.io.IOException;
import java.util.List;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "create alarm", relationTypes = {"Created", "Updated", "False"},
@ -52,7 +50,8 @@ import java.util.List;
"Message payload can be accessed via <code>msg</code> property. For example <code>'temperature = ' + msg.temperature ;</code>. " +
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
configDirective = "tbActionNodeCreateAlarmConfig",
icon = "notifications_active"
icon = "notifications_active",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/create-alarm/"
)
public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConfiguration> {
@ -62,10 +61,10 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConf
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
super.init(ctx, configuration);
if (!this.config.isDynamicSeverity()) {
this.notDynamicAlarmSeverity = EnumUtils.getEnum(AlarmSeverity.class, this.config.getSeverity());
if (this.notDynamicAlarmSeverity == null) {
throw new TbNodeException("Incorrect Alarm Severity value: " + this.config.getSeverity(), true);
if (!config.isDynamicSeverity()) {
notDynamicAlarmSeverity = EnumUtils.getEnum(AlarmSeverity.class, config.getSeverity());
if (notDynamicAlarmSeverity == null) {
throw new TbNodeException("Incorrect Alarm Severity value: " + config.getSeverity(), true);
}
}
}
@ -83,7 +82,7 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConf
final Alarm msgAlarm;
if (!config.isUseMessageAlarmData()) {
alarmType = TbNodeUtils.processPattern(this.config.getAlarmType(), msg);
alarmType = TbNodeUtils.processPattern(config.getAlarmType(), msg);
msgAlarm = null;
} else {
try {
@ -180,11 +179,11 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConf
.originator(msg.getOriginator())
.cleared(false)
.acknowledged(false)
.severity(this.config.isDynamicSeverity() ? processAlarmSeverity(msg) : notDynamicAlarmSeverity)
.severity(config.isDynamicSeverity() ? processAlarmSeverity(msg) : notDynamicAlarmSeverity)
.propagate(config.isPropagate())
.propagateToOwner(config.isPropagateToOwner())
.propagateToTenant(config.isPropagateToTenant())
.type(TbNodeUtils.processPattern(this.config.getAlarmType(), msg))
.type(TbNodeUtils.processPattern(config.getAlarmType(), msg))
.propagateRelationTypes(relationTypes)
.startTs(ts)
.endTs(ts)
@ -193,7 +192,7 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConf
}
private AlarmSeverity processAlarmSeverity(TbMsg msg) {
AlarmSeverity severity = EnumUtils.getEnum(AlarmSeverity.class, TbNodeUtils.processPattern(this.config.getSeverity(), msg));
AlarmSeverity severity = EnumUtils.getEnum(AlarmSeverity.class, TbNodeUtils.processPattern(config.getSeverity(), msg));
if (severity == null) {
throw new RuntimeException("Used incorrect pattern or Alarm Severity not included in message");
}

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.action;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -33,7 +32,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import static org.thingsboard.common.util.DonAsynchron.withCallback;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "create relation",
@ -63,7 +61,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"Output connections: <code>Success</code> - if the relation already exists or successfully created, otherwise <code>Failure</code>.",
configDirective = "tbActionNodeCreateRelationConfig",
icon = "add_circle",
version = 1
version = 1,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/create-relation/"
)
public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateRelationNodeConfiguration> {

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.action;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -32,8 +31,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import static org.thingsboard.common.util.DonAsynchron.withCallback;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "delete relation",
@ -55,7 +52,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"Output connections: <code>Success</code> - If the relation(s) successfully deleted, otherwise <code>Failure</code>.",
configDirective = "tbActionNodeDeleteRelationConfig",
icon = "remove_circle",
version = 1
version = 1,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/delete-relation/"
)
public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> {

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeviceStateNode.java

@ -58,7 +58,8 @@ import java.util.Set;
"This node is particularly useful when device isn't using transports to receive data, such as when fetching data from external API or computing new data within the rule chain.",
configClazz = TbDeviceStateNodeConfiguration.class,
relationTypes = {TbNodeConnectionType.SUCCESS, TbNodeConnectionType.FAILURE, "Rate limited"},
configDirective = "tbActionNodeDeviceStateConfig"
configDirective = "tbActionNodeDeviceStateConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/device-state/"
)
public class TbDeviceStateNode implements TbNode {

16
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java

@ -19,6 +19,7 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
@ -44,19 +45,19 @@ import java.util.Objects;
"Message payload can be accessed via <code>msg</code> property. For example <code>'temperature = ' + msg.temperature ;</code>. " +
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
configDirective = "tbActionNodeLogConfig",
icon = "menu"
icon = "menu",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/log/"
)
public class TbLogNode implements TbNode {
private TbLogNodeConfiguration config;
private ScriptEngine scriptEngine;
private boolean standard;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbLogNodeConfiguration.class);
this.standard = isStandard(config);
this.scriptEngine = this.standard ? null : createScriptEngine(ctx, config);
var config = TbNodeUtils.convert(configuration, TbLogNodeConfiguration.class);
standard = isStandard(config);
scriptEngine = standard ? null : createScriptEngine(ctx, config);
}
ScriptEngine createScriptEngine(TbContext ctx, TbLogNodeConfiguration config) {
@ -75,7 +76,7 @@ public class TbLogNode implements TbNode {
return;
}
Futures.addCallback(scriptEngine.executeToStringAsync(msg), new FutureCallback<String>() {
Futures.addCallback(scriptEngine.executeToStringAsync(msg), new FutureCallback<>() {
@Override
public void onSuccess(@Nullable String result) {
log.info(result);
@ -83,7 +84,7 @@ public class TbLogNode implements TbNode {
}
@Override
public void onFailure(Throwable t) {
public void onFailure(@NonNull Throwable t) {
ctx.tellFailure(msg, t);
}
}, MoreExecutors.directExecutor()); //usually js responses runs on js callback executor
@ -120,4 +121,5 @@ public class TbLogNode implements TbNode {
scriptEngine.destroy();
}
}
}

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java

@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.action;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
@ -34,7 +33,6 @@ import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "message count",
@ -42,7 +40,8 @@ import java.util.concurrent.atomic.AtomicLong;
nodeDescription = "Count incoming messages",
nodeDetails = "Count incoming messages for specified interval and produces POST_TELEMETRY_REQUEST msg with messages count",
icon = "functions",
configDirective = "tbActionNodeMsgCountConfig"
configDirective = "tbActionNodeMsgCountConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/message-count/"
)
public class TbMsgCountNode implements TbNode {
@ -59,7 +58,6 @@ public class TbMsgCountNode implements TbNode {
this.delay = TimeUnit.SECONDS.toMillis(config.getInterval());
this.telemetryPrefix = config.getTelemetryPrefix();
scheduleTickMsg(ctx, null);
}
@Override

7
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java

@ -57,7 +57,8 @@ import java.util.concurrent.atomic.AtomicInteger;
import static org.thingsboard.common.util.DonAsynchron.withCallback;
@Slf4j
@RuleNode(type = ComponentType.ACTION,
@RuleNode(
type = ComponentType.ACTION,
name = "save to custom table",
configClazz = TbSaveToCustomCassandraTableNodeConfiguration.class,
version = 1,
@ -71,7 +72,9 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
" otherwise, the message will be routed via <b>success</b> chain.",
configDirective = "tbActionNodeCustomTableConfig",
icon = "file_upload",
ruleChainTypes = RuleChainType.CORE)
ruleChainTypes = RuleChainType.CORE,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/save-to-custom-table/"
)
public class TbSaveToCustomCassandraTableNode implements TbNode {
private static final String TABLE_PREFIX = "cs_tb_";

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbUnassignFromCustomerNode.java

@ -44,7 +44,8 @@ import org.thingsboard.server.common.msg.TbMsg;
"Other entities can be assigned only to one customer, so specified customer title in the configuration will be ignored if the originator isn't a dashboard.",
configDirective = "tbActionNodeUnAssignToCustomerConfig",
icon = "remove_circle",
version = 1
version = 1,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/unassign-from-customer/"
)
public class TbUnassignFromCustomerNode extends TbAbstractCustomerActionNode<TbUnassignFromCustomerNodeConfiguration> {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/ai/TbAiNode.java

@ -92,8 +92,8 @@ import static org.thingsboard.server.dao.service.ConstraintValidator.validateFie
configClazz = TbAiNodeConfiguration.class,
configDirective = "tbExternalNodeAiConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDkiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OSA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0zOC42MzExIDE3LjA3OTVDNDAuMTcwNSAxNy4wNzk2IDQxLjY1MTggMTcuNjg3MiA0Mi43NDc4IDE4Ljc3NjNDNDMuODQ0OCAxOS44NjYzIDQ0LjQ2NTkgMjEuMzUwMSA0NC40NjU5IDIyLjkwMjlWMzUuNDY1MkM0NC40NjU5IDM2LjM1MDkgNDQuMzU2NyAzNy4wNzY5IDQ0LjA5NzMgMzcuNzUxN0M0My44NDE0IDM4LjQxNjcgNDMuNDY1MSAzOC45NjE0IDQzLjA0NDggMzkuNTAyOEM0Mi40NjY3IDQwLjI0NzIgNDEuNjU2MyA0MC42ODU5IDQwLjg5MTkgNDAuOTM4OEM0MC4xMjExIDQxLjE5MzcgMzkuMzE0MyA0MS4yODg1IDM4LjYzMTEgNDEuMjg4NUgzMS4wMjU5TDIzLjM4MTIgNDUuODQ2NEMyMy4wNDMxIDQ2LjA0NzggMjIuNjI0MSA0Ni4wNTA3IDIyLjI4MzkgNDUuODUyOUMyMS45NDM3IDQ1LjY1NDcgMjEuNzMzOCA0NS4yODU5IDIxLjczMzcgNDQuODg3MlY0MS4yODg1SDE5LjY2NjNDMTguMTI2OSA0MS4yODg0IDE2LjY0NTUgNDAuNjgwOSAxNS41NDk2IDM5LjU5MThDMTQuNDUyNyAzOC41MDE5IDEzLjgzMTUgMzcuMDE3OSAxMy44MzE1IDM1LjQ2NTJWMjIuOTAyOUMxMy44MzE1IDIyLjMyMDIgMTMuOTE4NSAyMS43NDY4IDE0LjA4NTggMjEuMjAwN0wxNi4yODg5IDIxLjgxMDFMMTcuMjA5OSAyNS4yNTAyQzE3Ljk0MTYgMjcuOTg0NSAyMS43NTYyIDI3Ljk4NDQgMjIuNDg4IDI1LjI1MDJMMjMuNDA3OSAyMS44MTAxTDI2Ljc5MTcgMjAuODc0OUMyOC41NzkxIDIwLjM4MDUgMjkuMTc3IDE4LjUwMjYgMjguNTg4OCAxNy4wNzk1SDM4LjYzMTFaTTIyLjU4NDIgMzEuNTM5NUMyMS45OCAzMS41Mzk3IDIxLjQ5MDEgMzIuMDM3NiAyMS40OTAxIDMyLjY1MTlDMjEuNDkwMiAzMy4yNjYgMjEuOTgwMSAzMy43NjQgMjIuNTg0MiAzMy43NjQySDM0LjYxOTFDMzUuMjIzMyAzMy43NjQyIDM1LjcxMzEgMzMuMjY2MSAzNS43MTMyIDMyLjY1MTlDMzUuNzEzMiAzMi4wMzc1IDM1LjIyMzQgMzEuNTM5NSAzNC42MTkxIDMxLjUzOTVIMjIuNTg0MlpNMjQuNzcyMyAyNC44NjU3QzI0LjE2ODIgMjQuODY1OCAyMy42NzgzIDI1LjM2MzggMjMuNjc4MyAyNS45NzhDMjMuNjc4NCAyNi41OTIyIDI0LjE2ODMgMjcuMDkwMiAyNC43NzIzIDI3LjA5MDNIMzcuOTAxNEMzOC41MDU1IDI3LjA5MDMgMzguOTk1MyAyNi41OTIyIDM4Ljk5NTQgMjUuOTc4QzM4Ljk5NTQgMjUuMzYzNyAzOC41MDU2IDI0Ljg2NTcgMzcuOTAxNCAyNC44NjU3SDI0Ljc3MjNaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjc2Ii8+CjxwYXRoIGQ9Ik0xOC43ODkxIDExLjI5NzVDMTkuMDY5MSAxMC4xODA4IDIwLjYyOTkgMTAuMTgwOCAyMC45MDk5IDExLjI5NzVMMjEuOTE0MyAxNS4zMDM2QzIyLjAxMTYgMTUuNjkxOCAyMi4zMDY1IDE1Ljk5NzggMjIuNjg2NyAxNi4xMDNMMjYuMzYxMSAxNy4xMTg3QzI3LjQzNyAxNy40MTYyIDI3LjQzNyAxOC45Njc2IDI2LjM2MTEgMTkuMjY1MUwyMi42NzYxIDIwLjI4NEMyMi4zMDE4IDIwLjM4NzQgMjIuMDA4NyAyMC42ODQ1IDIxLjkwNjggMjEuMDY1TDIwLjkwNDYgMjQuODEyNUMyMC42MTE3IDI1LjkwNTggMTkuMDg2MSAyNS45MDU5IDE4Ljc5MzMgMjQuODEyNUwxNy43OTExIDIxLjA2NUMxNy42ODkzIDIwLjY4NDcgMTcuMzk3IDIwLjM4NzUgMTcuMDIyOSAyMC4yODRMMTMuMzM2OCAxOS4yNjUxQzEyLjI2MTQgMTguOTY3MyAxMi4yNjE1IDE3LjQxNjUgMTMuMzM2OCAxNy4xMTg3TDE3LjAxMTIgMTYuMTAzQzE3LjM5MTYgMTUuOTk3OCAxNy42ODc0IDE1LjY5MTkgMTcuNzg0NyAxNS4zMDM2TDE4Ljc4OTEgMTEuMjk3NVoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuNzYiLz4KPHBhdGggZD0iTTEwLjAzNDMgNy4wMjQyNUMxMC4zMDY4IDUuODk0NDQgMTEuODg2OCA1Ljg5NDQ0IDEyLjE1OTQgNy4wMjQyNUwxMi42OTg5IDkuMjYyOThDMTIuNzkyNyA5LjY1MTc0IDEzLjA4NTEgOS45NTg4NyAxMy40NjQgMTAuMDY3OUwxNS41NzczIDEwLjY3NTFDMTYuNjM5MyAxMC45ODAzIDE2LjYzOTMgMTIuNTEwOSAxNS41NzczIDEyLjgxNjFMMTMuNDUzMyAxMy40MjY1QzEzLjA4MDIgMTMuNTMzOCAxMi43OTA4IDEzLjgzMzkgMTIuNjkyNSAxNC4yMTUxTDEyLjE1NTEgMTYuMzA0QzExLjg3IDE3LjQxMTYgMTAuMzIzNiAxNy40MTE2IDEwLjAzODUgMTYuMzA0TDkuNTAwMDMgMTQuMjE1MUM5LjQwMTczIDEzLjgzMzkgOS4xMTIzNSAxMy41MzM3IDguNzM5MyAxMy40MjY1TDYuNjE1MjQgMTIuODE2MUM1LjU1Mzc4IDEyLjUxMDYgNS41NTM2NCAxMC45ODA0IDYuNjE1MjQgMTAuNjc1MUw4LjcyODYyIDEwLjA2NzlDOS4xMDc2IDkuOTU4OTggOS4zOTk3OCA5LjY1MTg0IDkuNDkzNjIgOS4yNjI5OEwxMC4wMzQzIDcuMDI0MjVaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjc2Ii8+CjxwYXRoIGQ9Ik0yNS45MDI4IDYuNzMzMTNDMjYuMTg3OCA1LjYyNTQxIDI3LjczNDMgNS42MjU0MSAyOC4wMTkzIDYuNzMzMTNMMjguMjAzMSA3LjQ0Njc5QzI4LjMwMyA3LjgzNDMxIDI4LjYwMDEgOC4xMzcwNSAyOC45ODA5IDguMjM5NzVMMjkuNTM0NCA4LjM4OTY1QzMwLjYxOTIgOC42ODIxMiAzMC42MTkzIDEwLjI0NjkgMjkuNTM0NCAxMC41MzkzTDI4Ljk2OTIgMTAuNjkxNEMyOC41OTQ0IDEwLjc5MjUgMjguMjk5OSAxMS4wODgzIDI4LjE5NTYgMTEuNDY4TDI4LjAxNTEgMTIuMTI4NUMyNy43MTc0IDEzLjIxMjggMjYuMjA0NyAxMy4yMTI4IDI1LjkwNyAxMi4xMjg1TDI1LjcyNTQgMTEuNDY4QzI1LjYyMTEgMTEuMDg4MiAyNS4zMjY4IDEwLjc5MjQgMjQuOTUxOCAxMC42OTE0TDI0LjM4NzcgMTAuNTM5M0MyMy4zMDI2IDEwLjI0NyAyMy4zMDI2IDguNjgxOTggMjQuMzg3NyA4LjM4OTY1TDI0Ljk0MDEgOC4yMzk3NUMyNS4zMjExIDguMTM3MDkgMjUuNjE5MSA3LjgzNDQ2IDI1LjcxOSA3LjQ0Njc5TDI1LjkwMjggNi43MzMxM1oiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuNzYiLz4KPC9zdmc+Cg==",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/external-nodes/#ai-request-node",
ruleChainTypes = RuleChainType.CORE
ruleChainTypes = RuleChainType.CORE,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/ai-request/"
)
public final class TbAiNode extends TbAbstractExternalNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/lambda/TbAwsLambdaNode.java

@ -54,7 +54,8 @@ import static org.thingsboard.server.dao.service.ConstraintValidator.validateFie
"The node uses a pre-configured client and specified function to run.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbExternalNodeLambdaConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/aws-lambda/"
)
public class TbAwsLambdaNode extends TbAbstractExternalNode {
@ -156,4 +157,5 @@ public class TbAwsLambdaNode extends TbAbstractExternalNode {
}
}
}
}

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java

@ -47,7 +47,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"(<code>messageId</code>, <code>requestId</code>) in the Message Metadata from the AWS SNS. " +
"For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.",
configDirective = "tbExternalNodeSnsConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/aws-sns/"
)
public class TbSnsNode extends TbAbstractExternalNode {
@ -125,4 +126,5 @@ public class TbSnsNode extends TbAbstractExternalNode {
}
}
}
}

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java

@ -53,7 +53,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
", <code>sequenceNumber</code>) in the Message Metadata from the AWS SQS." +
" For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.",
configDirective = "tbExternalNodeSqsConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/aws-sqs/"
)
public class TbSqsNode extends TbAbstractExternalNode {
@ -156,4 +157,5 @@ public class TbSqsNode extends TbAbstractExternalNode {
}
}
}
}

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java

@ -63,9 +63,9 @@ import static org.thingsboard.server.common.data.DataConstants.QUEUE_NAME;
nodeDetails = "Generates messages with configurable period. Javascript function used for message generation.",
inEnabled = false,
configDirective = "tbActionNodeGeneratorConfig",
icon = "repeat"
icon = "repeat",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/generator/"
)
public class TbMsgGeneratorNode implements TbNode {
private static final Set<EntityType> supportedEntityTypes = EnumSet.of(EntityType.DEVICE, EntityType.ASSET, EntityType.ENTITY_VIEW,

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java

@ -46,6 +46,7 @@ import java.util.concurrent.TimeUnit;
import static org.thingsboard.server.common.data.DataConstants.QUEUE_NAME;
@Slf4j
@RuleNode(
type = ComponentType.TRANSFORMATION,
name = "deduplication",
@ -59,9 +60,9 @@ import static org.thingsboard.server.common.data.DataConstants.QUEUE_NAME;
"<li><strong>ALL</strong> - return all messages as a single JSON array message. " +
"Where each element represents object with <strong><i>msg</i></strong> and <strong><i>metadata</i></strong> inner properties.</li></ul>",
icon = "content_copy",
configDirective = "tbTransformationNodeDeduplicationConfig"
configDirective = "tbTransformationNodeDeduplicationConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/transformation/deduplication/"
)
@Slf4j
public class TbMsgDeduplicationNode implements TbNode {
public static final long TB_MSG_DEDUPLICATION_RETRY_DELAY = 10L;

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.rule.engine.delay;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -34,7 +33,6 @@ import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "delay (deprecated)",
@ -45,7 +43,8 @@ import java.util.concurrent.TimeUnit;
"Deprecated because the acknowledged message still stays in memory (to be delayed) and this " +
"does not guarantee that message will be processed even if the \"retry failures and timeouts\" processing strategy will be chosen.",
icon = "pause",
configDirective = "tbActionNodeMsgDelayConfig"
configDirective = "tbActionNodeMsgDelayConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/delay/"
)
public class TbMsgDelayNode implements TbNode {
@ -109,4 +108,5 @@ public class TbMsgDelayNode implements TbNode {
public void destroy() {
pendingMsgs.clear();
}
}

8
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToCloudNode.java

@ -16,7 +16,6 @@
package org.thingsboard.rule.engine.edge;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.server.common.data.EntityType;
@ -28,7 +27,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.UUID;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "push to cloud",
@ -48,7 +46,8 @@ import java.util.UUID;
"In case successful storage cloud event to database message will be routed via <b>Success</b> route.",
configDirective = "tbActionNodePushToCloudConfig",
icon = "cloud_upload",
ruleChainTypes = RuleChainType.EDGE
ruleChainTypes = RuleChainType.EDGE,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/push-to-cloud/"
)
public class TbMsgPushToCloudNode extends AbstractTbMsgPushNode<TbMsgPushToCloudNodeConfiguration, Object, Object> {
@ -80,7 +79,6 @@ public class TbMsgPushToCloudNode extends AbstractTbMsgPushNode<TbMsgPushToCloud
}
@Override
void processMsg(TbContext ctx, TbMsg msg) {
}
void processMsg(TbContext ctx, TbMsg msg) {}
}

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java

@ -20,6 +20,7 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -63,7 +64,8 @@ import static org.thingsboard.server.dao.edge.BaseRelatedEdgesService.RELATED_ED
"In case successful storage edge event to database message will be routed via <b>Success</b> route.",
configDirective = "tbActionNodePushToEdgeConfig",
icon = "cloud_download",
ruleChainTypes = RuleChainType.CORE
ruleChainTypes = RuleChainType.CORE,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/push-to-edge/"
)
public class TbMsgPushToEdgeNode extends AbstractTbMsgPushNode<TbMsgPushToEdgeNodeConfiguration, EdgeEvent, EdgeEventType> {
@ -113,7 +115,7 @@ public class TbMsgPushToEdgeNode extends AbstractTbMsgPushNode<TbMsgPushToEdgeNo
}
@Override
public void onFailure(Throwable t) {
public void onFailure(@NonNull Throwable t) {
ctx.tellFailure(msg, t);
}
};

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.rule.engine.filter;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -26,7 +25,6 @@ import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "asset profile switch",
@ -36,7 +34,9 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
nodeDescription = "Route incoming messages based on the name of the asset profile",
nodeDetails = "Route incoming messages based on the name of the asset profile. The asset profile name is case-sensitive.<br><br>" +
"Output connections: <i>Asset profile name</i> or <code>Failure</code>",
configDirective = "tbNodeEmptyConfig")
configDirective = "tbNodeEmptyConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/asset-profile-switch/"
)
public class TbAssetTypeSwitchNode extends TbAbstractTypeSwitchNode {
@Override

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNode.java

@ -43,7 +43,9 @@ import java.util.Objects;
nodeDescription = "Checks alarm status.",
nodeDetails = "Checks the alarm status to match one of the specified statuses.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>.",
configDirective = "tbFilterNodeCheckAlarmStatusConfig")
configDirective = "tbFilterNodeCheckAlarmStatusConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/alarm-status-filter/"
)
public class TbCheckAlarmStatusNode implements TbNode {
private TbCheckAlarmStatusNodeConfig config;

8
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java

@ -16,7 +16,6 @@
package org.thingsboard.rule.engine.filter;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
@ -30,7 +29,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.List;
import java.util.Map;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "check fields presence",
@ -40,7 +38,9 @@ import java.util.Map;
nodeDetails = "By default, the rule node checks that all specified fields are present. " +
"Uncheck the 'Check that all selected fields are present' if the presence of at least one field is sufficient.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
configDirective = "tbFilterNodeCheckMessageConfig")
configDirective = "tbFilterNodeCheckMessageConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/check-fields-presence/"
)
public class TbCheckMessageNode implements TbNode {
private static final Gson gson = new Gson();
@ -127,4 +127,4 @@ public class TbCheckMessageNode implements TbNode {
return (Map<String, String>) gson.fromJson(msg.getData(), Map.class);
}
}
}

9
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java

@ -19,7 +19,6 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
@ -41,10 +40,6 @@ import java.util.List;
import static org.thingsboard.common.util.DonAsynchron.withCallback;
/**
* Created by ashvayka on 19.01.18.
*/
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "check relation presence",
@ -56,7 +51,9 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"Otherwise, the rule node checks the presence of a relation to any entity. " +
"In both cases, relation lookup is based on configured direction and type.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
configDirective = "tbFilterNodeCheckRelationConfig")
configDirective = "tbFilterNodeCheckRelationConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/check-relation-presence/"
)
public class TbCheckRelationNode implements TbNode {
private TbCheckRelationNodeConfiguration config;

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.rule.engine.filter;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -26,7 +25,6 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "device profile switch",
@ -36,7 +34,9 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
nodeDescription = "Route incoming messages based on the name of the device profile",
nodeDetails = "Route incoming messages based on the name of the device profile. The device profile name is case-sensitive<br><br>" +
"Output connections: <i>Device profile name</i> or <code>Failure</code>",
configDirective = "tbNodeEmptyConfig")
configDirective = "tbNodeEmptyConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/device-profile-switch/"
)
public class TbDeviceTypeSwitchNode extends TbAbstractTypeSwitchNode {
@Override

12
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.rule.engine.filter;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.ScriptEngine;
import org.thingsboard.rule.engine.api.TbContext;
@ -30,7 +29,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import static org.thingsboard.common.util.DonAsynchron.withCallback;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "script",
@ -44,18 +42,17 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
"Message type can be accessed via <code>msgType</code> property.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
configDirective = "tbFilterNodeScriptConfig"
configDirective = "tbFilterNodeScriptConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/script/"
)
public class TbJsFilterNode implements TbNode {
private TbJsFilterNodeConfiguration config;
private ScriptEngine scriptEngine;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbJsFilterNodeConfiguration.class);
scriptEngine = ctx.createScriptEngine(config.getScriptLang(),
ScriptLanguage.TBEL.equals(config.getScriptLang()) ? config.getTbelScript() : config.getJsScript());
var config = TbNodeUtils.convert(configuration, TbJsFilterNodeConfiguration.class);
scriptEngine = ctx.createScriptEngine(config.getScriptLang(), ScriptLanguage.TBEL.equals(config.getScriptLang()) ? config.getTbelScript() : config.getJsScript());
}
@Override
@ -75,4 +72,5 @@ public class TbJsFilterNode implements TbNode {
scriptEngine.destroy();
}
}
}

13
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.filter;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.ScriptEngine;
@ -33,7 +32,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.Set;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "switch", customRelations = true,
@ -46,17 +44,17 @@ import java.util.Set;
"Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
"Message type can be accessed via <code>msgType</code> property.<br><br>" +
"Output connections: <i>Custom connection(s) defined by switch node</i> or <code>Failure</code>",
configDirective = "tbFilterNodeSwitchConfig")
configDirective = "tbFilterNodeSwitchConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/switch/"
)
public class TbJsSwitchNode implements TbNode {
private TbJsSwitchNodeConfiguration config;
private ScriptEngine scriptEngine;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbJsSwitchNodeConfiguration.class);
this.scriptEngine = ctx.createScriptEngine(config.getScriptLang(),
ScriptLanguage.TBEL.equals(config.getScriptLang()) ? config.getTbelScript() : config.getJsScript());
var config = TbNodeUtils.convert(configuration, TbJsSwitchNodeConfiguration.class);
scriptEngine = ctx.createScriptEngine(config.getScriptLang(), ScriptLanguage.TBEL.equals(config.getScriptLang()) ? config.getTbelScript() : config.getJsScript());
}
@Override
@ -84,4 +82,5 @@ public class TbJsSwitchNode implements TbNode {
scriptEngine.destroy();
}
}
}

13
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.rule.engine.filter;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
@ -26,10 +25,6 @@ import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
/**
* Created by ashvayka on 19.01.18.
*/
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "message type filter",
@ -38,14 +33,16 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDescription = "Filter incoming messages by Message Type",
nodeDetails = "If incoming message type is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
configDirective = "tbFilterNodeMessageTypeConfig")
configDirective = "tbFilterNodeMessageTypeConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/message-type-filter/"
)
public class TbMsgTypeFilterNode implements TbNode {
TbMsgTypeFilterNodeConfiguration config;
private TbMsgTypeFilterNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbMsgTypeFilterNodeConfiguration.class);
config = TbNodeUtils.convert(configuration, TbMsgTypeFilterNodeConfiguration.class);
}
@Override

14
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java

@ -15,18 +15,14 @@
*/
package org.thingsboard.rule.engine.filter;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "message type switch",
@ -36,15 +32,13 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b>" +
" etc. via corresponding chain, otherwise <b>Other</b> chain is used.<br><br>" +
"Output connections: <i>Message type connection</i>, <code>Other</code> - if message type is custom or <code>Failure</code>",
configDirective = "tbNodeEmptyConfig")
configDirective = "tbNodeEmptyConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/message-type-switch/"
)
public class TbMsgTypeSwitchNode implements TbNode {
EmptyNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
}
public void init(TbContext ctx, TbNodeConfiguration configuration) {}
@Override
public void onMsg(TbContext ctx, TbMsg msg) {

10
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.rule.engine.filter;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
@ -27,7 +26,6 @@ import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "entity type filter",
@ -36,14 +34,16 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDescription = "Filter incoming messages by the type of message originator entity",
nodeDetails = "Checks that the entity type of the incoming message originator matches one of the values specified in the filter.<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
configDirective = "tbFilterNodeOriginatorTypeConfig")
configDirective = "tbFilterNodeOriginatorTypeConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/entity-type-filter/"
)
public class TbOriginatorTypeFilterNode implements TbNode {
TbOriginatorTypeFilterNodeConfiguration config;
private TbOriginatorTypeFilterNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbOriginatorTypeFilterNodeConfiguration.class);
config = TbNodeUtils.convert(configuration, TbOriginatorTypeFilterNodeConfiguration.class);
}
@Override

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java

@ -15,14 +15,12 @@
*/
package org.thingsboard.rule.engine.filter;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "entity type switch",
@ -31,7 +29,9 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
nodeDescription = "Route incoming messages by Message Originator Type",
nodeDetails = "Routes messages to chain according to the entity type ('Device', 'Asset', etc.).<br><br>" +
"Output connections: <i>Message originator type</i> or <code>Failure</code>",
configDirective = "tbNodeEmptyConfig")
configDirective = "tbNodeEmptyConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/entity-type-switch/"
)
public class TbOriginatorTypeSwitchNode extends TbAbstractTypeSwitchNode {
@Override

13
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbAckNode.java

@ -15,34 +15,27 @@
*/
package org.thingsboard.rule.engine.flow;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(
type = ComponentType.FLOW,
name = "acknowledge",
configClazz = EmptyNodeConfiguration.class,
nodeDescription = "Acknowledges the incoming message",
nodeDetails = "After acknowledgement, the message is pushed to related rule nodes. Useful if you don't care what happens to this message next.",
configDirective = "tbNodeEmptyConfig"
configDirective = "tbNodeEmptyConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/flow/acknowledge/"
)
public class TbAckNode implements TbNode {
EmptyNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
}
public void init(TbContext ctx, TbNodeConfiguration configuration) {}
@Override
public void onMsg(TbContext ctx, TbMsg msg) {

7
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java

@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.flow;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -31,7 +30,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import static org.thingsboard.server.common.data.DataConstants.QUEUE_NAME;
@Slf4j
@RuleNode(
type = ComponentType.FLOW,
name = "checkpoint",
@ -40,7 +38,8 @@ import static org.thingsboard.server.common.data.DataConstants.QUEUE_NAME;
hasQueueName = true,
nodeDescription = "transfers the message to another queue",
nodeDetails = "After successful transfer incoming message is automatically acknowledged. Queue name is configurable.",
configDirective = "tbNodeEmptyConfig"
configDirective = "tbNodeEmptyConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/flow/checkpoint/"
)
public class TbCheckpointNode implements TbNode {
@ -48,7 +47,7 @@ public class TbCheckpointNode implements TbNode {
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.queueName = ctx.getQueueName();
queueName = ctx.getQueueName();
}
@Override

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java

@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.flow;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
@ -34,7 +33,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.Optional;
import java.util.UUID;
@Slf4j
@RuleNode(
type = ComponentType.FLOW,
name = "rule chain",
@ -49,7 +47,8 @@ import java.util.UUID;
configDirective = "tbFlowNodeRuleChainInputConfig",
relationTypes = {},
ruleChainNode = true,
customRelations = true
customRelations = true,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/flow/rule-chain/"
)
public class TbRuleChainInputNode implements TbNode {
@ -106,4 +105,5 @@ public class TbRuleChainInputNode implements TbNode {
default -> null;
});
}
}

9
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java

@ -15,17 +15,14 @@
*/
package org.thingsboard.rule.engine.flow;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(
type = ComponentType.FLOW,
name = "output",
@ -35,13 +32,13 @@ import org.thingsboard.server.common.msg.TbMsg;
"The output is forwarded to the caller rule chain, as an output of the corresponding \"input\" rule node. " +
"The output rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ",
configDirective = "tbFlowNodeRuleChainOutputConfig",
outEnabled = false
outEnabled = false,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/flow/output/"
)
public class TbRuleChainOutputNode implements TbNode {
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
}
public void init(TbContext ctx, TbNodeConfiguration configuration) {}
@Override
public void onMsg(TbContext ctx, TbMsg msg) {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java

@ -53,7 +53,8 @@ import java.util.concurrent.TimeUnit;
"(<code>messageId</code> in the Message Metadata from the GCP PubSub. " +
"<b>messageId</b> field can be accessed with <code>metadata.messageId</code>.",
configDirective = "tbExternalNodePubSubConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo="
iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo=",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/gcp-pubsub/"
)
public class TbPubSubNode extends TbAbstractExternalNode {
@ -155,4 +156,5 @@ public class TbPubSubNode extends TbAbstractExternalNode {
.setExecutorProvider(FixedExecutorProvider.create(ctx.getPubSubRuleNodeExecutorProvider().getExecutor()))
.build();
}
}

14
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNode.java

@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeException;
@ -34,10 +33,10 @@ import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.common.msg.TbMsg;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@ -47,10 +46,6 @@ import static org.thingsboard.rule.engine.util.GpsGeofencingEvents.INSIDE;
import static org.thingsboard.rule.engine.util.GpsGeofencingEvents.LEFT;
import static org.thingsboard.rule.engine.util.GpsGeofencingEvents.OUTSIDE;
/**
* Created by ashvayka on 19.01.18.
*/
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "gps geofencing events",
@ -66,12 +61,13 @@ import static org.thingsboard.rule.engine.util.GpsGeofencingEvents.OUTSIDE;
"If the presence monitoring strategy <b>\"On each message\"</b> is selected, sends messages via rule node connection type <code>Inside</code> or <code>Outside</code> every time the geofencing condition is satisfied. " +
"<br><br>" +
"Output connections: <code>Entered</code>, <code>Left</code>, <code>Inside</code>, <code>Outside</code>, <code>Success</code>",
configDirective = "tbActionNodeGpsGeofencingConfig"
configDirective = "tbActionNodeGpsGeofencingConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/gps-geofencing-events/"
)
public class TbGpsGeofencingActionNode extends AbstractGeofencingNode<TbGpsGeofencingActionNodeConfiguration> {
private static final String REPORT_PRESENCE_STATUS_ON_EACH_MESSAGE = "reportPresenceStatusOnEachMessage";
private final Map<EntityId, EntityGeofencingState> entityStates = new HashMap<>();
private final ConcurrentMap<EntityId, EntityGeofencingState> entityStates = new ConcurrentHashMap<>();
private final Gson gson = new Gson();
@Override

10
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.rule.engine.geo;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeException;
@ -23,10 +22,6 @@ import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
/**
* Created by ashvayka on 19.01.18.
*/
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "gps geofencing filter",
@ -60,7 +55,9 @@ import org.thingsboard.server.common.msg.TbMsg;
"</br></br>" +
"Available radius units: METER, KILOMETER, FOOT, MILE, NAUTICAL_MILE;<br><br>" +
"Output connections: <code>True</code>, <code>False</code>, <code>Failure</code>",
configDirective = "tbFilterNodeGpsGeofencingConfig")
configDirective = "tbFilterNodeGpsGeofencingConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/filter/gps-geofencing-filter/"
)
public class TbGpsGeofencingFilterNode extends AbstractGeofencingNode<TbGpsGeofencingFilterNodeConfiguration> {
@Override
@ -72,4 +69,5 @@ public class TbGpsGeofencingFilterNode extends AbstractGeofencingNode<TbGpsGeofe
protected Class<TbGpsGeofencingFilterNodeConfiguration> getConfigClazz() {
return TbGpsGeofencingFilterNodeConfiguration.class;
}
}

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java

@ -58,7 +58,8 @@ import java.util.Properties;
"Outbound message will contain response fields (<code>offset</code>, <code>partition</code>, <code>topic</code>)" +
" from the Kafka in the Message Metadata. For example <b>partition</b> field can be accessed with <code>metadata.partition</code>.",
configDirective = "tbExternalNodeKafkaConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg=="
iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg==",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/kafka/"
)
public class TbKafkaNode extends TbAbstractExternalNode {

22
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java

@ -16,7 +16,6 @@
package org.thingsboard.rule.engine.mail;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -34,7 +33,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RuleNode(
type = ComponentType.TRANSFORMATION,
name = "to email",
@ -43,7 +41,8 @@ import java.util.Map;
nodeDetails = "Transforms message to email message. If transformation completed successfully output message type will be set to <code>SEND_EMAIL</code>.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbTransformationNodeToEmailConfig",
icon = "email"
icon = "email",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/transformation/to-email/"
)
public class TbMsgToEmailNode implements TbNode {
@ -55,20 +54,15 @@ public class TbMsgToEmailNode implements TbNode {
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbMsgToEmailNodeConfiguration.class);
this.dynamicMailBodyType = DYNAMIC.equals(this.config.getMailBodyType());
}
config = TbNodeUtils.convert(configuration, TbMsgToEmailNodeConfiguration.class);
dynamicMailBodyType = DYNAMIC.equals(config.getMailBodyType());
}
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
try {
TbEmail email = convert(msg);
TbMsg emailMsg = buildEmailMsg(ctx, msg, email);
ctx.tellNext(emailMsg, TbNodeConnectionType.SUCCESS);
} catch (Exception ex) {
log.warn("Can not convert message to email " + ex.getMessage());
ctx.tellFailure(msg, ex);
}
TbEmail email = convert(msg);
TbMsg emailMsg = buildEmailMsg(ctx, msg, email);
ctx.tellNext(emailMsg, TbNodeConnectionType.SUCCESS);
}
private TbMsg buildEmailMsg(TbContext ctx, TbMsg msg, TbEmail email) {

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java

@ -45,7 +45,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
" where created using <code>to Email</code> transformation Node, please connect this Node " +
"with <code>to Email</code> Node using <code>Successful</code> chain.",
configDirective = "tbExternalNodeSendEmailConfig",
icon = "send"
icon = "send",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/send-email/"
)
public class TbSendEmailNode extends TbAbstractExternalNode {
@ -91,7 +92,7 @@ public class TbSendEmailNode extends TbAbstractExternalNode {
}
}
private TbEmail getEmail(TbMsg msg) throws IOException {
private TbEmail getEmail(TbMsg msg) {
TbEmail email = JacksonUtil.fromString(msg.getData(), TbEmail.class);
if (StringUtils.isBlank(email.getTo())) {
throw new IllegalStateException("Email destination can not be blank [" + email.getTo() + "]");
@ -141,4 +142,5 @@ public class TbSendEmailNode extends TbAbstractExternalNode {
}
return javaMailProperties;
}
}

7
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java

@ -20,7 +20,6 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import lombok.extern.slf4j.Slf4j;
import net.objecthunter.exp4j.Expression;
import net.objecthunter.exp4j.ExpressionBuilder;
import org.springframework.util.ConcurrentReferenceHashMap;
@ -56,8 +55,6 @@ import java.util.stream.Collectors;
import static org.thingsboard.common.util.ExpressionFunctionsUtil.userDefinedFunctions;
import static org.thingsboard.rule.engine.math.TbMathArgumentType.CONSTANT;
@SuppressWarnings("UnstableApiUsage")
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "math function",
@ -78,8 +75,8 @@ import static org.thingsboard.rule.engine.math.TbMathArgumentType.CONSTANT;
"The execution is synchronized in scope of message originator (e.g. device) and server node. " +
"If you have rule nodes in different rule chains, they will process messages from the same originator synchronously in the scope of the server node.",
configDirective = "tbActionNodeMathFunctionConfig",
icon = "calculate"
icon = "calculate",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/math-function/"
)
public class TbMathNode implements TbNode {

12
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java

@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
@ -43,8 +42,8 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
@Slf4j
@RuleNode(type = ComponentType.ENRICHMENT,
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "calculate delta",
version = 1,
relationTypes = {TbNodeConnectionType.SUCCESS, TbNodeConnectionType.FAILURE, TbNodeConnectionType.OTHER},
@ -53,7 +52,9 @@ import java.util.Map;
"and current value for this key from the incoming message",
nodeDetails = "Useful for metering use cases, when you need to calculate consumption based on pulse counter reading.<br><br>" +
"Output connections: <code>Success</code>, <code>Other</code> or <code>Failure</code>.",
configDirective = "tbEnrichmentNodeCalculateDeltaConfig")
configDirective = "tbEnrichmentNodeCalculateDeltaConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/calculate-delta/"
)
public class CalculateDeltaNode implements TbNode {
private Map<EntityId, ValueWithTs> cache;
@ -189,7 +190,6 @@ public class CalculateDeltaNode implements TbNode {
return fetchLatestValueAsync(ctx, originator);
}
private record ValueWithTs(long ts, double value) {
}
private record ValueWithTs(long ts, double value) {}
}

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java

@ -16,7 +16,6 @@
package org.thingsboard.rule.engine.metadata;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -33,7 +32,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.concurrent.ExecutionException;
@Slf4j
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "fetch device credentials",
@ -45,7 +43,9 @@ import java.util.concurrent.ExecutionException;
"Useful when you need to fetch device credentials and use them for further message processing. " +
"For example, use device credentials to interact with external systems.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbEnrichmentNodeFetchDeviceCredentialsConfig")
configDirective = "tbEnrichmentNodeFetchDeviceCredentialsConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/fetch-device-credentials/"
)
public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo<TbFetchDeviceCredentialsNodeConfiguration> {
private static final String CREDENTIALS = "credentials";

12
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.metadata;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -30,11 +29,8 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.common.msg.TbMsg;
/**
* Created by ashvayka on 19.01.18.
*/
@Slf4j
@RuleNode(type = ComponentType.ENRICHMENT,
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "originator attributes",
configClazz = TbGetAttributesNodeConfiguration.class,
version = 1,
@ -43,7 +39,9 @@ import org.thingsboard.server.common.msg.TbMsg;
"that are not included in the incoming message to use them for further message processing. " +
"For example to filter messages based on the threshold value stored in the attributes.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbEnrichmentNodeOriginatorAttributesConfig")
configDirective = "tbEnrichmentNodeOriginatorAttributesConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/originator-attributes/"
)
public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttributesNodeConfiguration, EntityId> {
@Override

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.metadata;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -30,7 +29,6 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.util.TbPair;
@Slf4j
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "customer attributes",
@ -41,7 +39,9 @@ import org.thingsboard.server.common.data.util.TbPair;
"that is stored as customer attributes or telemetry data and used for dynamic message filtering, transformation, " +
"or actions such as alarm creation if the threshold is exceeded.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbEnrichmentNodeCustomerAttributesConfig")
configDirective = "tbEnrichmentNodeCustomerAttributesConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/customer-attributes/"
)
public class TbGetCustomerAttributeNode extends TbAbstractGetEntityDataNode<CustomerId> {
private static final String CUSTOMER_NOT_FOUND_MESSAGE = "Failed to find customer for entity with id: %s and type: %s";

9
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.metadata;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -41,8 +40,8 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.NoSuchElementException;
@Slf4j
@RuleNode(type = ComponentType.ENRICHMENT,
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "customer details",
configClazz = TbGetCustomerDetailsNodeConfiguration.class,
version = 1,
@ -50,7 +49,9 @@ import java.util.NoSuchElementException;
nodeDetails = "Useful in multi-customer solutions where we need dynamically use customer contact information " +
"such as email, phone, address, etc., for notifications via email, SMS, and other notification providers.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbEnrichmentNodeEntityDetailsConfig")
configDirective = "tbEnrichmentNodeEntityDetailsConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/customer-details/"
)
public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetCustomerDetailsNodeConfiguration, CustomerId> {
private static final String CUSTOMER_PREFIX = "customer_";

9
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.metadata;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -31,8 +30,8 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(type = ComponentType.ENRICHMENT,
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "related device attributes",
configClazz = TbGetDeviceAttrNodeConfiguration.class,
version = 1,
@ -42,7 +41,9 @@ import org.thingsboard.server.common.msg.TbMsg;
"Useful when you need to retrieve attributes and/or latest telemetry values from device that has a relation " +
"to the message originator and use them for further message processing.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbEnrichmentNodeDeviceAttributesConfig")
configDirective = "tbEnrichmentNodeDeviceAttributesConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/related-device-attributes/"
)
public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDeviceAttrNodeConfiguration, DeviceId> {
private static final String RELATED_DEVICE_NOT_FOUND_MESSAGE = "Failed to find related device to message originator using relation query specified in the configuration!";

12
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java

@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.metadata;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -31,11 +30,8 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.concurrent.ExecutionException;
/**
* Created by ashvayka on 19.01.18.
*/
@Slf4j
@RuleNode(type = ComponentType.ENRICHMENT,
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "originator fields",
configClazz = TbGetOriginatorFieldsConfiguration.class,
version = 1,
@ -43,7 +39,9 @@ import java.util.concurrent.ExecutionException;
nodeDetails = "Fetches fields values specified in the mapping. If specified field is not part of originator fields it will be ignored. " +
"Useful when you need to retrieve originator fields and use them for further message processing.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbEnrichmentNodeOriginatorFieldsConfig")
configDirective = "tbEnrichmentNodeOriginatorFieldsConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/originator-fields/"
)
public class TbGetOriginatorFieldsNode extends TbAbstractGetMappedDataNode<EntityId, TbGetOriginatorFieldsConfiguration> {
protected final static String DATA_MAPPING_PROPERTY_NAME = "dataMapping";

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.metadata;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -31,7 +30,6 @@ import org.thingsboard.server.common.data.util.TbPair;
import java.util.Arrays;
@Slf4j
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "related entity data",
@ -42,7 +40,9 @@ import java.util.Arrays;
"If multiple related entities are found, only first entity is used for message enrichment, other entities are discarded. " +
"Useful when you need to retrieve data from an entity that has a relation to the message originator and use them for further message processing.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbEnrichmentNodeRelatedAttributesConfig")
configDirective = "tbEnrichmentNodeRelatedAttributesConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/related-entity-data/"
)
public class TbGetRelatedAttributeNode extends TbAbstractGetEntityDataNode<EntityId> {
private static final String RELATED_ENTITY_NOT_FOUND_MESSAGE = "Failed to find related entity to message originator using relation query specified in the configuration!";

12
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java

@ -21,7 +21,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.thingsboard.common.util.DonAsynchron;
import org.thingsboard.common.util.JacksonUtil;
@ -45,11 +44,8 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* Created by mshvayka on 04.09.18.
*/
@Slf4j
@RuleNode(type = ComponentType.ENRICHMENT,
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "originator telemetry",
configClazz = TbGetTelemetryNodeConfiguration.class,
version = 2,
@ -58,7 +54,9 @@ import java.util.stream.Collectors;
"instead of fetching just the latest telemetry or if you need to get the closest telemetry to the fetch interval start or end. " +
"Also, this node can be used for telemetry aggregation within configured fetch interval.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase")
configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/originator-telemetry/"
)
public class TbGetTelemetryNode implements TbNode {
private TbGetTelemetryNodeConfiguration config;

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.metadata;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -29,7 +28,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.util.TbPair;
@Slf4j
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "tenant attributes",
@ -39,7 +37,9 @@ import org.thingsboard.server.common.data.util.TbPair;
nodeDetails = "Useful when you need to retrieve some common configuration or threshold set " +
"that is stored as tenant attributes or telemetry data and use it for further message processing.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbEnrichmentNodeTenantAttributesConfig")
configDirective = "tbEnrichmentNodeTenantAttributesConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/tenant-attributes/"
)
public class TbGetTenantAttributeNode extends TbAbstractGetEntityDataNode<TenantId> {
@Override

9
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java

@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.metadata;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -30,8 +29,8 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(type = ComponentType.ENRICHMENT,
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "tenant details",
configClazz = TbGetTenantDetailsNodeConfiguration.class,
version = 1,
@ -39,7 +38,9 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDetails = "Useful when we need to retrieve contact information from your tenant " +
"such as email, phone, address, etc., for notifications via email, SMS, and other notification providers.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbEnrichmentNodeEntityDetailsConfig")
configDirective = "tbEnrichmentNodeEntityDetailsConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/enrichment/tenant-details/"
)
public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetTenantDetailsNodeConfiguration, TenantId> {
private static final String TENANT_PREFIX = "tenant_";

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java

@ -22,7 +22,6 @@ import io.netty.handler.codec.mqtt.MqttQoS;
import io.netty.handler.codec.mqtt.MqttVersion;
import io.netty.handler.ssl.SslContext;
import io.netty.util.concurrent.Promise;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.mqtt.MqttClient;
import org.thingsboard.mqtt.MqttClientConfig;
@ -49,7 +48,6 @@ import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@Slf4j
@RuleNode(
type = ComponentType.EXTERNAL,
name = "mqtt",
@ -59,7 +57,8 @@ import java.util.concurrent.TimeoutException;
nodeDescription = "Publish messages to the MQTT broker",
nodeDetails = "Will publish message payload to the MQTT broker with QoS <b>AT_LEAST_ONCE</b>.",
configDirective = "tbExternalNodeMqttConfig",
icon = "call_split"
icon = "call_split",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/mqtt/"
)
public class TbMqttNode extends TbAbstractExternalNode {

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java

@ -19,7 +19,6 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.annotations.VisibleForTesting;
import io.netty.handler.codec.mqtt.MqttVersion;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.AzureIotHubUtil;
import org.thingsboard.mqtt.MqttClient;
import org.thingsboard.mqtt.MqttClientConfig;
@ -39,7 +38,6 @@ import org.thingsboard.server.common.data.util.TbPair;
import java.time.Clock;
@Slf4j
@RuleNode(
type = ComponentType.EXTERNAL,
name = "azure iot hub",
@ -48,7 +46,8 @@ import java.time.Clock;
clusteringMode = ComponentClusteringMode.SINGLETON,
nodeDescription = "Publish messages to the Azure IoT Hub",
nodeDetails = "Will publish message payload to the Azure IoT Hub with QoS <b>AT_LEAST_ONCE</b>.",
configDirective = "tbExternalNodeAzureIotHubConfig"
configDirective = "tbExternalNodeAzureIotHubConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/azure-iot-hub/"
)
public class TbAzureIotHubNode extends TbMqttNode {

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java

@ -42,7 +42,8 @@ import java.util.concurrent.ExecutionException;
nodeDescription = "Sends notification to targets using the template",
nodeDetails = "Will send notification to the specified targets using the template",
configDirective = "tbExternalNodeNotificationConfig",
icon = "notifications"
icon = "notifications",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/send-notification/"
)
public class TbNotificationNode extends TbAbstractExternalNode {
@ -51,7 +52,7 @@ public class TbNotificationNode extends TbAbstractExternalNode {
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
super.init(ctx);
this.config = TbNodeUtils.convert(configuration, TbNotificationNodeConfiguration.class);
config = TbNodeUtils.convert(configuration, TbNotificationNodeConfiguration.class);
}
@Override

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbSlackNode.java

@ -34,7 +34,8 @@ import java.util.concurrent.ExecutionException;
nodeDescription = "Send message via Slack",
nodeDetails = "Sends message to a Slack channel or user",
configDirective = "tbExternalNodeSlackConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTYsMTVBMiwyIDAgMCwxIDQsMTdBMiwyIDAgMCwxIDIsMTVBMiwyIDAgMCwxIDQsMTNINlYxNU03LDE1QTIsMiAwIDAsMSA5LDEzQTIsMiAwIDAsMSAxMSwxNVYyMEEyLDIgMCAwLDEgOSwyMkEyLDIgMCAwLDEgNywyMFYxNU05LDdBMiwyIDAgMCwxIDcsNUEyLDIgMCAwLDEgOSwzQTIsMiAwIDAsMSAxMSw1VjdIOU05LDhBMiwyIDAgMCwxIDExLDEwQTIsMiAwIDAsMSA5LDEySDRBMiwyIDAgMCwxIDIsMTBBMiwyIDAgMCwxIDQsOEg5TTE3LDEwQTIsMiAwIDAsMSAxOSw4QTIsMiAwIDAsMSAyMSwxMEEyLDIgMCAwLDEgMTksMTJIMTdWMTBNMTYsMTBBMiwyIDAgMCwxIDE0LDEyQTIsMiAwIDAsMSAxMiwxMFY1QTIsMiAwIDAsMSAxNCwzQTIsMiAwIDAsMSAxNiw1VjEwTTE0LDE4QTIsMiAwIDAsMSAxNiwyMEEyLDIgMCAwLDEgMTQsMjJBMiwyIDAgMCwxIDEyLDIwVjE4SDE0TTE0LDE3QTIsMiAwIDAsMSAxMiwxNUEyLDIgMCAwLDEgMTQsMTNIMTlBMiwyIDAgMCwxIDIxLDE1QTIsMiAwIDAsMSAxOSwxN0gxNFoiIC8+PC9zdmc+"
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTYsMTVBMiwyIDAgMCwxIDQsMTdBMiwyIDAgMCwxIDIsMTVBMiwyIDAgMCwxIDQsMTNINlYxNU03LDE1QTIsMiAwIDAsMSA5LDEzQTIsMiAwIDAsMSAxMSwxNVYyMEEyLDIgMCAwLDEgOSwyMkEyLDIgMCAwLDEgNywyMFYxNU05LDdBMiwyIDAgMCwxIDcsNUEyLDIgMCAwLDEgOSwzQTIsMiAwIDAsMSAxMSw1VjdIOU05LDhBMiwyIDAgMCwxIDExLDEwQTIsMiAwIDAsMSA5LDEySDRBMiwyIDAgMCwxIDIsMTBBMiwyIDAgMCwxIDQsOEg5TTE3LDEwQTIsMiAwIDAsMSAxOSw4QTIsMiAwIDAsMSAyMSwxMEEyLDIgMCAwLDEgMTksMTJIMTdWMTBNMTYsMTBBMiwyIDAgMCwxIDE0LDEyQTIsMiAwIDAsMSAxMiwxMFY1QTIsMiAwIDAsMSAxNCwzQTIsMiAwIDAsMSAxNiw1VjEwTTE0LDE4QTIsMiAwIDAsMSAxNiwyMEEyLDIgMCAwLDEgMTQsMjJBMiwyIDAgMCwxIDEyLDIwVjE4SDE0TTE0LDE3QTIsMiAwIDAsMSAxMiwxNUEyLDIgMCAwLDEgMTQsMTNIMTlBMiwyIDAgMCwxIDIxLDE1QTIsMiAwIDAsMSAxOSwxN0gxNFoiIC8+PC9zdmc+",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/send-to-slack/"
)
public class TbSlackNode extends TbAbstractExternalNode {
@ -43,7 +44,7 @@ public class TbSlackNode extends TbAbstractExternalNode {
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
super.init(ctx);
this.config = TbNodeUtils.convert(configuration, TbSlackNodeConfiguration.class);
config = TbNodeUtils.convert(configuration, TbSlackNodeConfiguration.class);
}
@Override

7
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java

@ -59,7 +59,8 @@ import java.util.concurrent.TimeUnit;
nodeDescription = "Process device messages based on device profile settings",
nodeDetails = "Create and clear alarms based on alarm rules defined in device profile. The output relation type is either " +
"'Alarm Created', 'Alarm Updated', 'Alarm Severity Updated' and 'Alarm Cleared' or simply 'Success' if no alarms were affected.",
configDirective = "tbActionNodeDeviceProfileConfig"
configDirective = "tbActionNodeDeviceProfileConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/device-profile/"
)
public class TbDeviceProfileNode implements TbNode {
@ -137,7 +138,7 @@ public class TbDeviceProfileNode implements TbNode {
if (deviceState != null) {
deviceState.process(ctx, msg);
} else {
log.info("Device was not found! Most probably device [" + deviceId + "] has been removed from the database. Acknowledging msg.");
log.info("Device was not found! Most probably device [{}] has been removed from the database. Acknowledging msg.", deviceId);
ctx.ack(msg);
}
}
@ -160,7 +161,7 @@ public class TbDeviceProfileNode implements TbNode {
deviceStates.clear();
}
protected DeviceState getOrCreateDeviceState(TbContext ctx, DeviceId deviceId, RuleNodeState rns, boolean printNewlyAddedDeviceStates) {
private DeviceState getOrCreateDeviceState(TbContext ctx, DeviceId deviceId, RuleNodeState rns, boolean printNewlyAddedDeviceStates) {
DeviceState deviceState = deviceStates.get(deviceId);
if (deviceState == null) {
DeviceProfile deviceProfile = cache.get(ctx.getTenantId(), deviceId);

35
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java

@ -46,7 +46,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
nodeDescription = "Publish messages to the RabbitMQ",
nodeDetails = "Will publish message payload to RabbitMQ queue.",
configDirective = "tbExternalNodeRabbitMqConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4="
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4=",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/rabbitmq/"
)
public class TbRabbitMqNode extends TbAbstractExternalNode {
@ -99,10 +100,10 @@ public class TbRabbitMqNode extends TbAbstractExternalNode {
}
private ListenableFuture<TbMsg> publishMessageAsync(TbContext ctx, TbMsg msg) {
return ctx.getExternalCallExecutor().executeAsync(() -> publishMessage(ctx, msg));
return ctx.getExternalCallExecutor().executeAsync(() -> publishMessage(msg));
}
private TbMsg publishMessage(TbContext ctx, TbMsg msg) throws Exception {
private TbMsg publishMessage(TbMsg msg) throws Exception {
String exchangeName = "";
if (!StringUtils.isEmpty(this.config.getExchangeNamePattern())) {
exchangeName = TbNodeUtils.processPattern(this.config.getExchangeNamePattern(), msg);
@ -143,23 +144,15 @@ public class TbRabbitMqNode extends TbAbstractExternalNode {
}
static AMQP.BasicProperties convert(String name) throws TbNodeException {
switch (name) {
case "BASIC":
return MessageProperties.BASIC;
case "TEXT_PLAIN":
return MessageProperties.TEXT_PLAIN;
case "MINIMAL_BASIC":
return MessageProperties.MINIMAL_BASIC;
case "MINIMAL_PERSISTENT_BASIC":
return MessageProperties.MINIMAL_PERSISTENT_BASIC;
case "PERSISTENT_BASIC":
return MessageProperties.PERSISTENT_BASIC;
case "PERSISTENT_TEXT_PLAIN":
return MessageProperties.PERSISTENT_TEXT_PLAIN;
default:
throw new TbNodeException("Undefined message properties type '" + name +
"'! Only " + supportedPropertiesStr + " message properties types are supported!");
}
return switch (name) {
case "BASIC" -> MessageProperties.BASIC;
case "TEXT_PLAIN" -> MessageProperties.TEXT_PLAIN;
case "MINIMAL_BASIC" -> MessageProperties.MINIMAL_BASIC;
case "MINIMAL_PERSISTENT_BASIC" -> MessageProperties.MINIMAL_PERSISTENT_BASIC;
case "PERSISTENT_BASIC" -> MessageProperties.PERSISTENT_BASIC;
case "PERSISTENT_TEXT_PLAIN" -> MessageProperties.PERSISTENT_TEXT_PLAIN;
default -> throw new TbNodeException("Undefined message properties type '" + name + "'! Only " + supportedPropertiesStr + " message properties types are supported!");
};
}
}
}

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java

@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.rest;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -30,7 +29,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.List;
@Slf4j
@RuleNode(
type = ComponentType.EXTERNAL,
name = "rest api call",
@ -46,7 +44,8 @@ import java.util.List;
"<br/><b>Note-</b> if you use system proxy properties, the next system proxy properties should be added: \"http.proxyHost\" and \"http.proxyPort\" or \"https.proxyHost\" and \"https.proxyPort\" or \"socksProxyHost\" and \"socksProxyPort\"," +
"and if your proxy with auth, the next ones should be added: \"tb.proxy.user\" and \"tb.proxy.password\" to the thingsboard.conf file.",
configDirective = "tbExternalNodeRestApiCallConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+"
iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/rest-api-call/"
)
public class TbRestApiCallNode extends TbAbstractExternalNode {

8
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbSendRestApiCallReplyNode.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.rule.engine.rest;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
@ -28,7 +27,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.UUID;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "rest call reply",
@ -36,7 +34,8 @@ import java.util.UUID;
nodeDescription = "Sends reply to REST API call to rule engine",
nodeDetails = "Expects messages with any message type. Forwards incoming message as a reply to REST API call sent to rule engine.",
configDirective = "tbActionNodeSendRestApiCallReplyConfig",
icon = "call_merge"
icon = "call_merge",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/rest-call-reply/"
)
public class TbSendRestApiCallReplyNode implements TbNode {
@ -44,7 +43,7 @@ public class TbSendRestApiCallReplyNode implements TbNode {
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbSendRestApiCallReplyNodeConfiguration.class);
config = TbNodeUtils.convert(configuration, TbSendRestApiCallReplyNodeConfiguration.class);
}
@Override
@ -62,4 +61,5 @@ public class TbSendRestApiCallReplyNode implements TbNode {
ctx.tellSuccess(msg);
}
}
}

13
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNode.java

@ -19,7 +19,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -41,7 +41,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.UUID;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "rpc call reply",
@ -49,7 +48,8 @@ import java.util.UUID;
nodeDescription = "Sends reply to RPC call from device",
nodeDetails = "Expects messages with any message type. Will forward message body to the device.",
configDirective = "tbActionNodeRpcReplyConfig",
icon = "call_merge"
icon = "call_merge",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/rpc-call-reply/"
)
public class TbSendRPCReplyNode implements TbNode {
@ -57,7 +57,7 @@ public class TbSendRPCReplyNode implements TbNode {
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbSendRpcReplyNodeConfiguration.class);
config = TbNodeUtils.convert(configuration, TbSendRpcReplyNodeConfiguration.class);
}
@Override
@ -103,7 +103,7 @@ public class TbSendRPCReplyNode implements TbNode {
body.put("requestId", requestIdStr);
body.put("response", msg.getData());
EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(ctx.getTenantId(), edgeId, EdgeEventType.DEVICE,
EdgeEventActionType.RPC_CALL, deviceId, JacksonUtil.valueToTree(body));
EdgeEventActionType.RPC_CALL, deviceId, JacksonUtil.valueToTree(body));
ListenableFuture<Void> future = ctx.getEdgeEventService().saveAsync(edgeEvent);
Futures.addCallback(future, new FutureCallback<>() {
@Override
@ -112,9 +112,10 @@ public class TbSendRPCReplyNode implements TbNode {
}
@Override
public void onFailure(Throwable t) {
public void onFailure(@NonNull Throwable t) {
ctx.tellFailure(msg, t);
}
}, ctx.getDbCallbackExecutor());
}
}

11
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java

@ -20,7 +20,6 @@ import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -41,7 +40,6 @@ import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "rpc call request",
@ -50,17 +48,18 @@ import java.util.concurrent.TimeUnit;
nodeDetails = "Expects messages with \"method\" and \"params\". Will forward response from device to next nodes." +
"If the RPC call request is originated by REST API call from user, will forward the response to user immediately.",
configDirective = "tbActionNodeRpcRequestConfig",
icon = "call_made"
icon = "call_made",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/rpc-call-request/"
)
public class TbSendRPCRequestNode implements TbNode {
private Random random = new Random();
private Gson gson = new Gson();
private final Random random = new Random();
private final Gson gson = new Gson();
private TbSendRpcRequestNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbSendRpcRequestNodeConfiguration.class);
config = TbNodeUtils.convert(configuration, TbSendRpcRequestNodeConfiguration.class);
}
@Override

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNode.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.rule.engine.sms;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
@ -28,7 +27,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import static org.thingsboard.common.util.DonAsynchron.withCallback;
@Slf4j
@RuleNode(
type = ComponentType.EXTERNAL,
name = "send sms",
@ -36,7 +34,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
nodeDescription = "Sends SMS message via SMS provider.",
nodeDetails = "Will send SMS message by populating target phone numbers and sms message fields using values derived from message metadata.",
configDirective = "tbExternalNodeSendSmsConfig",
icon = "sms"
icon = "sms",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/external/send-sms/"
)
public class TbSendSmsNode extends TbAbstractExternalNode {

13
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbCalculatedFieldsNode.java

@ -16,16 +16,13 @@
package org.thingsboard.rule.engine.telemetry;
import com.google.gson.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.AttributesSaveRequest;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.TimeseriesSaveRequest;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.adaptor.JsonConverter;
import org.thingsboard.server.common.data.AttributeScope;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
@ -41,7 +38,6 @@ import java.util.Map;
import static org.thingsboard.server.common.data.DataConstants.SCOPE;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "calculated fields",
@ -52,16 +48,13 @@ import static org.thingsboard.server.common.data.DataConstants.SCOPE;
"This rule node accepts the same messages as these nodes but allows you to trigger the processing of calculated " +
"fields independently, ensuring that derived data can be computed and utilized in real time without storing the original message in the database.",
configDirective = "tbNodeEmptyConfig",
icon = "published_with_changes"
icon = "published_with_changes",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/calculated-fields/"
)
public class TbCalculatedFieldsNode implements TbNode {
private EmptyNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
}
public void init(TbContext ctx, TbNodeConfiguration configuration) {}
@Override
public void onMsg(TbContext ctx, TbMsg msg) {

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java

@ -21,7 +21,6 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.gson.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.DonAsynchron;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.AttributesSaveRequest;
@ -56,7 +55,6 @@ import static org.thingsboard.server.common.data.DataConstants.NOTIFY_DEVICE_MET
import static org.thingsboard.server.common.data.DataConstants.SCOPE;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "save attributes",
@ -107,7 +105,8 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_R
Output connections: <code>Success</code>, <code>Failure</code>.
""",
configDirective = "tbActionNodeAttributesConfig",
icon = "file_upload"
icon = "file_upload",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/save-attributes/"
)
public class TbMsgAttributesNode implements TbNode {

9
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNode.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.rule.engine.telemetry;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.AttributesDeleteRequest;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -35,7 +34,6 @@ import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.DataConstants.NOTIFY_DEVICE_METADATA_KEY;
import static org.thingsboard.server.common.data.DataConstants.SCOPE;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "delete attributes",
@ -46,7 +44,8 @@ import static org.thingsboard.server.common.data.DataConstants.SCOPE;
" rule node will send the \"Attributes Deleted\" event to the root chain of the message originator and " +
" send the incoming message via <b>Success</b> chain, otherwise, <b>Failure</b> chain is used.",
configDirective = "tbActionNodeDeleteAttributesConfig",
icon = "remove_circle"
icon = "remove_circle",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/delete-attributes/"
)
public class TbMsgDeleteAttributesNode implements TbNode {
@ -55,8 +54,8 @@ public class TbMsgDeleteAttributesNode implements TbNode {
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbMsgDeleteAttributesNodeConfiguration.class);
this.keys = config.getKeys();
config = TbNodeUtils.convert(configuration, TbMsgDeleteAttributesNodeConfiguration.class);
keys = config.getKeys();
}
@Override

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java

@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.telemetry;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.gson.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -52,7 +51,6 @@ import static org.thingsboard.rule.engine.telemetry.settings.TimeseriesProcessin
import static org.thingsboard.rule.engine.telemetry.settings.TimeseriesProcessingSettings.WebSocketsOnly;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "save time series",
@ -103,7 +101,8 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_RE
""",
configDirective = "tbActionNodeTimeseriesConfig",
icon = "file_upload",
version = 1
version = 1,
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/action/save-timeseries/"
)
public class TbMsgTimeseriesNode implements TbNode {

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java

@ -55,7 +55,8 @@ import static org.thingsboard.rule.engine.transform.OriginatorSource.RELATED;
"'Device', 'Asset', 'Entity View', 'Edge' or 'User'.</li></ul>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbTransformationNodeChangeOriginatorConfig",
icon = "find_replace"
icon = "find_replace",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/transformation/change-originator/"
)
public class TbChangeOriginatorNode extends TbAbstractTransformNode<TbChangeOriginatorNodeConfiguration> {

10
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNode.java

@ -47,22 +47,22 @@ import java.util.stream.Collectors;
"Regular expressions can be used to define which keys-value pairs to copy. Any configured key not found in the source will be ignored.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbTransformationNodeCopyKeysConfig",
icon = "content_copy"
icon = "content_copy",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/transformation/copy-key-value-pairs/"
)
public class TbCopyKeysNode extends TbAbstractTransformNodeWithTbMsgSource {
private TbCopyKeysNodeConfiguration config;
private TbMsgSource copyFrom;
private List<Pattern> compiledKeyPatterns;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbCopyKeysNodeConfiguration.class);
this.copyFrom = config.getCopyFrom();
var config = TbNodeUtils.convert(configuration, TbCopyKeysNodeConfiguration.class);
copyFrom = config.getCopyFrom();
if (copyFrom == null) {
throw new TbNodeException("CopyFrom can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
}
this.compiledKeyPatterns = config.getKeys().stream().map(Pattern::compile).collect(Collectors.toList());
compiledKeyPatterns = config.getKeys().stream().map(Pattern::compile).collect(Collectors.toList());
}
@Override

12
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNode.java

@ -47,22 +47,22 @@ import java.util.stream.Collectors;
"keys and/or regular expressions.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbTransformationNodeDeleteKeysConfig",
icon = "remove_circle"
icon = "remove_circle",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/transformation/delete-key-value-pairs/"
)
public class TbDeleteKeysNode extends TbAbstractTransformNodeWithTbMsgSource {
private TbDeleteKeysNodeConfiguration config;
private TbMsgSource deleteFrom;
private List<Pattern> compiledKeyPatterns;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbDeleteKeysNodeConfiguration.class);
this.deleteFrom = config.getDeleteFrom();
var config = TbNodeUtils.convert(configuration, TbDeleteKeysNodeConfiguration.class);
deleteFrom = config.getDeleteFrom();
if (deleteFrom == null) {
throw new TbNodeException("DeleteFrom can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
}
this.compiledKeyPatterns = config.getKeys().stream().map(Pattern::compile).collect(Collectors.toList());
compiledKeyPatterns = config.getKeys().stream().map(Pattern::compile).collect(Collectors.toList());
}
@Override
@ -76,7 +76,7 @@ public class TbDeleteKeysNode extends TbAbstractTransformNodeWithTbMsgSource {
var mdKeysToDelete = metaDataMap.keySet()
.stream()
.filter(this::matches)
.collect(Collectors.toList());
.toList();
mdKeysToDelete.forEach(metaDataMap::remove);
metaDataCopy = new TbMsgMetaData(metaDataMap);
hasNoChanges = mdKeysToDelete.isEmpty();

21
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java

@ -19,7 +19,6 @@ import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
@ -32,7 +31,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import java.util.concurrent.ExecutionException;
@Slf4j
@RuleNode(
type = ComponentType.TRANSFORMATION,
name = "json path",
@ -41,32 +39,32 @@ import java.util.concurrent.ExecutionException;
nodeDetails = "JSONPath expression specifies a path to an element or a set of elements in a JSON structure.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
icon = "functions",
configDirective = "tbTransformationNodeJsonPathConfig"
configDirective = "tbTransformationNodeJsonPathConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/transformation/json-path/"
)
public class TbJsonPathNode implements TbNode {
private TbJsonPathNodeConfiguration config;
private Configuration configurationJsonPath;
private JsonPath jsonPath;
private String jsonPathValue;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbJsonPathNodeConfiguration.class);
this.jsonPathValue = config.getJsonPath();
if (!TbJsonPathNodeConfiguration.DEFAULT_JSON_PATH.equals(this.jsonPathValue)) {
this.configurationJsonPath = Configuration.builder()
var config = TbNodeUtils.convert(configuration, TbJsonPathNodeConfiguration.class);
jsonPathValue = config.getJsonPath();
if (!TbJsonPathNodeConfiguration.DEFAULT_JSON_PATH.equals(jsonPathValue)) {
configurationJsonPath = Configuration.builder()
.jsonProvider(new JacksonJsonNodeJsonProvider())
.build();
this.jsonPath = JsonPath.compile(config.getJsonPath());
jsonPath = JsonPath.compile(config.getJsonPath());
}
}
@Override
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
if (!TbJsonPathNodeConfiguration.DEFAULT_JSON_PATH.equals(this.jsonPathValue)) {
if (!TbJsonPathNodeConfiguration.DEFAULT_JSON_PATH.equals(jsonPathValue)) {
try {
Object jsonPathData = jsonPath.read(msg.getData(), this.configurationJsonPath);
Object jsonPathData = jsonPath.read(msg.getData(), configurationJsonPath);
ctx.tellSuccess(msg.transform()
.data(JacksonUtil.toString(jsonPathData))
.build());
@ -77,4 +75,5 @@ public class TbJsonPathNode implements TbNode {
ctx.tellSuccess(msg);
}
}
}

10
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java

@ -44,19 +44,19 @@ import java.util.concurrent.ExecutionException;
"If key to rename doesn't exist in the specified source (message or message metadata) it will be ignored.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbTransformationNodeRenameKeysConfig",
icon = "find_replace"
icon = "find_replace",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/transformation/rename-keys/"
)
public class TbRenameKeysNode extends TbAbstractTransformNodeWithTbMsgSource {
private TbRenameKeysNodeConfiguration config;
private Map<String, String> renameKeysMapping;
private TbMsgSource renameIn;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbRenameKeysNodeConfiguration.class);
this.renameIn = config.getRenameIn();
this.renameKeysMapping = config.getRenameKeysMapping();
var config = TbNodeUtils.convert(configuration, TbRenameKeysNodeConfiguration.class);
renameIn = config.getRenameIn();
renameKeysMapping = config.getRenameKeysMapping();
if (renameIn == null) {
throw new TbNodeException("RenameIn can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
}

13
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java

@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.transform;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
@ -25,7 +24,6 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@ -34,7 +32,6 @@ import org.thingsboard.server.common.msg.queue.TbMsgCallback;
import java.util.concurrent.ExecutionException;
@Slf4j
@RuleNode(
type = ComponentType.TRANSFORMATION,
name = "split array msg",
@ -44,16 +41,13 @@ import java.util.concurrent.ExecutionException;
"All outbound messages will have the same type and metadata as the original array message.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
icon = "content_copy",
configDirective = "tbNodeEmptyConfig"
configDirective = "tbNodeEmptyConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/transformation/split-array-msg/"
)
public class TbSplitArrayMsgNode implements TbNode {
private EmptyNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
}
public void init(TbContext ctx, TbNodeConfiguration configuration) {}
@Override
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
@ -89,4 +83,5 @@ public class TbSplitArrayMsgNode implements TbNode {
ctx.tellFailure(msg, new RuntimeException("Msg data is not a JSON Array!"));
}
}
}

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java

@ -41,7 +41,8 @@ import java.util.List;
"<code>{ msg: <i style=\"color: #666;\">new payload</i>,<br/>&nbsp&nbsp&nbspmetadata: <i style=\"color: #666;\">new metadata</i>,<br/>&nbsp&nbsp&nbspmsgType: <i style=\"color: #666;\">new msgType</i> }</code><br/>" +
"All fields in resulting object are optional and will be taken from original message if not specified.<br><br>" +
"Output connections: <code>Success</code>, <code>Failure</code>.",
configDirective = "tbTransformationNodeScriptConfig"
configDirective = "tbTransformationNodeScriptConfig",
docUrl = "https://thingsboard.io/docs/user-guide/rule-engine-2-0/nodes/transformation/script/"
)
public class TbTransformMsgNode extends TbAbstractTransformNode<TbTransformMsgNodeConfiguration> {
@ -71,4 +72,5 @@ public class TbTransformMsgNode extends TbAbstractTransformNode<TbTransformMsgNo
scriptEngine.destroy();
}
}
}

9
rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/GpsGeofencingActionTestCase.java

@ -18,14 +18,14 @@ package org.thingsboard.rule.engine.geo;
import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Data
public class GpsGeofencingActionTestCase {
private EntityId entityId;
private Map<EntityId, EntityGeofencingState> entityStates;
private ConcurrentMap<EntityId, EntityGeofencingState> entityStates;
private boolean msgInside;
private boolean reportPresenceStatusOnEachMessage;
@ -33,7 +33,8 @@ public class GpsGeofencingActionTestCase {
this.entityId = entityId;
this.msgInside = msgInside;
this.reportPresenceStatusOnEachMessage = reportPresenceStatusOnEachMessage;
this.entityStates = new HashMap<>();
this.entityStates = new ConcurrentHashMap<>();
this.entityStates.put(entityId, entityGeofencingState);
}
}

145
ui-ngx/src/app/shared/models/constants.ts

@ -94,76 +94,83 @@ export const HelpLinks = {
oauth2Apple: 'https://developer.apple.com/sign-in-with-apple/get-started/',
oauth2Facebook: 'https://developers.facebook.com/docs/facebook-login/web#logindialog',
oauth2Github: 'https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app',
oauth2Google: 'https://developers.google.com/google-ads/api/docs/start',
oauth2Google: 'https://developers.google.com/identity/protocols/oauth2',
ruleEngine: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/overview/`,
ruleNodeCheckRelation: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#check-relation-filter-node`,
ruleNodeCheckExistenceFields: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#check-existence-fields-node`,
ruleNodeGpsGeofencingFilter: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#gps-geofencing-filter-node`,
ruleNodeJsFilter: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#script-filter-node`,
ruleNodeJsSwitch: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#switch-node`,
ruleNodeAssetProfileSwitch: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#asset-profile-switch`,
ruleNodeDeviceProfileSwitch: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#device-profile-switch`,
ruleNodeCheckAlarmStatus: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#check-alarm-status`,
ruleNodeMessageTypeFilter: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#message-type-filter-node`,
ruleNodeMessageTypeSwitch: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#message-type-switch-node`,
ruleNodeOriginatorTypeFilter: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#originator-type-filter-node`,
ruleNodeOriginatorTypeSwitch: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/filter-nodes/#originator-type-switch-node`,
ruleNodeOriginatorAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#originator-attributes`,
ruleNodeOriginatorFields: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#originator-fields`,
ruleNodeOriginatorTelemetry: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#originator-telemetry`,
ruleNodeCustomerAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#customer-attributes`,
ruleNodeCustomerDetails: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#customer-details`,
ruleNodeFetchDeviceCredentials: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#fetch-device-credentials`,
ruleNodeDeviceAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#device-attributes`,
ruleNodeRelatedAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#related-attributes`,
ruleNodeTenantAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#tenant-attributes`,
ruleNodeTenantDetails: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#tenant-details`,
ruleNodeChangeOriginator: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/transformation-nodes/#change-originator`,
ruleNodeTransformMsg: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/transformation-nodes/#script-transformation-node`,
ruleNodeMsgToEmail: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/transformation-nodes/#to-email-node`,
ruleNodeAssignToCustomer: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#assign-to-customer-node`,
ruleNodeUnassignFromCustomer: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#unassign-from-customer-node`,
ruleNodeCalculatedFields: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#calculated-fields-node`,
ruleNodeClearAlarm: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#clear-alarm-node`,
ruleNodeCreateAlarm: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#create-alarm-node`,
ruleNodeCopyToView: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#copy-to-view-node`,
ruleNodeCreateRelation: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#create-relation-node`,
ruleNodeDeleteRelation: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#delete-relation-node`,
ruleNodeDeviceState: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#device-state-node`,
ruleNodeMessageCount: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#message-count-node`,
ruleNodeMsgDelay: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#delay-node-deprecated`,
ruleNodeMsgGenerator: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#generator-node`,
ruleNodeGpsGeofencingEvents: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#gps-geofencing-events-node`,
ruleNodeLog: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#log-node`,
ruleNodeRpcCallReply: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#rpc-call-reply-node`,
ruleNodeRpcCallRequest: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#rpc-call-request-node`,
ruleNodeSaveAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#save-attributes-node`,
ruleNodeDeleteAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#delete-attributes-node`,
ruleNodeSaveTimeseries: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#save-timeseries-node`,
ruleNodeSaveToCustomTable: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#save-to-custom-table-node`,
ruleNodeRuleChain: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/flow-nodes/#rule-chain-node`,
ruleNodeOutputNode: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/flow-nodes/#output-node`,
ruleNodeAiRequest: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#ai-request-node`,
ruleNodeAwsLambda: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#aws-lambda-node`,
ruleNodeAwsSns: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#aws-sns-node`,
ruleNodeAwsSqs: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#aws-sqs-node`,
ruleNodeKafka: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#kafka-node`,
ruleNodeMqtt: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#mqtt-node`,
ruleNodeAzureIotHub: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#azure-iot-hub-node`,
ruleNodeRabbitMq: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#rabbitmq-node`,
ruleNodeRestApiCall: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#rest-api-call-node`,
ruleNodeSendEmail: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#send-email-node`,
ruleNodeSendSms: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#send-sms-node`,
ruleNodeMath: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#math-function-node`,
ruleNodeCalculateDelta: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#calculate-delta`,
ruleNodeRestCallReply: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#rest-call-reply-node`,
ruleNodePushToCloud: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#push-to-cloud`,
ruleNodePushToEdge: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#push-to-edge`,
ruleNodeDeviceProfile: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#device-profile-node`,
ruleNodeAcknowledge: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/flow-nodes/#acknowledge-node`,
ruleNodeCheckpoint: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/flow-nodes/#checkpoint-node`,
ruleNodeSendNotification: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#send-notification-node`,
ruleNodeSendSlack: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/external-nodes/#send-to-slack-node`,
ruleNodeCheckRelation: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/check-relation-presence/`,
ruleNodeCheckExistenceFields: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/check-fields-presence/`,
ruleNodeGpsGeofencingFilter: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/gps-geofencing-filter/`,
ruleNodeJsFilter: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/script/`,
ruleNodeJsSwitch: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/switch/`,
ruleNodeAssetProfileSwitch: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/asset-profile-switch/`,
ruleNodeDeviceProfileSwitch: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/device-profile-switch/`,
ruleNodeCheckAlarmStatus: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/alarm-status-filter/`,
ruleNodeMessageTypeFilter: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/message-type-filter/`,
ruleNodeMessageTypeSwitch: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/message-type-switch/`,
ruleNodeOriginatorTypeFilter: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/entity-type-filter/`,
ruleNodeOriginatorTypeSwitch: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/filter/entity-type-switch/`,
ruleNodeOriginatorAttributes: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/originator-attributes/`,
ruleNodeOriginatorFields: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/originator-fields/`,
ruleNodeOriginatorTelemetry: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/originator-telemetry/`,
ruleNodeCustomerAttributes: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/customer-attributes/`,
ruleNodeCustomerDetails: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/customer-details/`,
ruleNodeFetchDeviceCredentials: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/fetch-device-credentials/`,
ruleNodeDeviceAttributes: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/related-device-attributes/`,
ruleNodeRelatedAttributes: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/related-entity-data/`,
ruleNodeTenantAttributes: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/tenant-attributes/`,
ruleNodeTenantDetails: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/tenant-details/`,
ruleNodeChangeOriginator: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/transformation/change-originator/`,
ruleNodeCopyKeyValuePairs: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/transformation/copy-key-value-pairs/`,
ruleNodeDeduplication: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/transformation/deduplication/`,
ruleNodeDeleteKeyValuePairs: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/transformation/delete-key-value-pairs/`,
ruleNodeJsonPath: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/transformation/json-path/`,
ruleNodeRenameKeys: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/transformation/rename-keys/`,
ruleNodeTransformMsg: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/transformation/script/`,
ruleNodeSplitArrayMsg: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/transformation/split-array-msg/`,
ruleNodeMsgToEmail: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/transformation/to-email/`,
ruleNodeAssignToCustomer: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/assign-to-customer/`,
ruleNodeUnassignFromCustomer: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/unassign-from-customer/`,
ruleNodeCalculatedFields: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/calculated-fields/`,
ruleNodeClearAlarm: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/clear-alarm/`,
ruleNodeCreateAlarm: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/create-alarm/`,
ruleNodeCopyToView: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/copy-to-view/`,
ruleNodeCreateRelation: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/create-relation/`,
ruleNodeDeleteRelation: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/delete-relation/`,
ruleNodeDeviceState: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/device-state/`,
ruleNodeMessageCount: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/message-count/`,
ruleNodeMsgDelay: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/delay/`,
ruleNodeMsgGenerator: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/generator/`,
ruleNodeGpsGeofencingEvents: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/gps-geofencing-events/`,
ruleNodeLog: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/log/`,
ruleNodeRpcCallReply: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/rpc-call-reply/`,
ruleNodeRpcCallRequest: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/rpc-call-request/`,
ruleNodeSaveAttributes: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/save-attributes/`,
ruleNodeDeleteAttributes: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/delete-attributes/`,
ruleNodeSaveTimeseries: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/save-timeseries/`,
ruleNodeSaveToCustomTable: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/save-to-custom-table/`,
ruleNodeRuleChain: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/flow/rule-chain/`,
ruleNodeOutputNode: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/flow/output/`,
ruleNodeAiRequest: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/ai-request/`,
ruleNodeAwsLambda: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/aws-lambda/`,
ruleNodeAwsSns: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/aws-sns/`,
ruleNodeAwsSqs: `${helpBaseUrl}docs/user-guide/rule-engine-2-0/nodes/external/aws-sqs/`,
ruleNodeKafka: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/kafka/`,
ruleNodeMqtt: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/mqtt/`,
ruleNodeAzureIotHub: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/azure-iot-hub/`,
ruleNodeGcpPubSub: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/gcp-pubsub/`,
ruleNodeRabbitMq: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/rabbitmq/`,
ruleNodeRestApiCall: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/rest-api-call/`,
ruleNodeSendEmail: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/send-email/`,
ruleNodeSendSms: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/send-sms/`,
ruleNodeMath: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/math-function/`,
ruleNodeCalculateDelta: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/enrichment/calculate-delta/`,
ruleNodeRestCallReply: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/rest-call-reply/`,
ruleNodePushToCloud: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/push-to-cloud/`,
ruleNodePushToEdge: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/push-to-edge/`,
ruleNodeDeviceProfile: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/action/device-profile/`,
ruleNodeAcknowledge: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/flow/acknowledge/`,
ruleNodeCheckpoint: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/flow/checkpoint/`,
ruleNodeSendNotification: `${helpBaseUrl}/docs/user-guide/rule-engine-2-0/nodes/external/send-notification/`,
ruleNodeSendSlack: `${helpBaseUrl}docs/user-guide/rule-engine-2-0/nodes/external/send-to-slack/`,
tenants: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/tenants`,
tenantProfiles: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/tenant-profiles`,
customers: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/customers`,

7
ui-ngx/src/app/shared/models/rule-node.models.ts

@ -476,7 +476,13 @@ const ruleNodeClazzHelpLinkMap = {
'org.thingsboard.rule.engine.metadata.TbGetTenantDetailsNode': 'ruleNodeTenantDetails',
'org.thingsboard.rule.engine.metadata.CalculateDeltaNode': 'ruleNodeCalculateDelta',
'org.thingsboard.rule.engine.transform.TbChangeOriginatorNode': 'ruleNodeChangeOriginator',
'org.thingsboard.rule.engine.transform.TbCopyKeysNode': 'ruleNodeCopyKeyValuePairs',
'org.thingsboard.rule.engine.deduplication.TbMsgDeduplicationNode': 'ruleNodeDeduplication',
'org.thingsboard.rule.engine.transform.TbDeleteKeysNode': 'ruleNodeDeleteKeyValuePairs',
'org.thingsboard.rule.engine.transform.TbJsonPathNode': 'ruleNodeJsonPath',
'org.thingsboard.rule.engine.transform.TbRenameKeysNode': 'ruleNodeRenameKeys',
'org.thingsboard.rule.engine.transform.TbTransformMsgNode': 'ruleNodeTransformMsg',
'org.thingsboard.rule.engine.transform.TbSplitArrayMsgNode': 'ruleNodeSplitArrayMsg',
'org.thingsboard.rule.engine.mail.TbMsgToEmailNode': 'ruleNodeMsgToEmail',
'org.thingsboard.rule.engine.action.TbAssignToCustomerNode': 'ruleNodeAssignToCustomer',
'org.thingsboard.rule.engine.action.TbUnassignFromCustomerNode': 'ruleNodeUnassignFromCustomer',
@ -505,6 +511,7 @@ const ruleNodeClazzHelpLinkMap = {
'org.thingsboard.rule.engine.kafka.TbKafkaNode': 'ruleNodeKafka',
'org.thingsboard.rule.engine.mqtt.TbMqttNode': 'ruleNodeMqtt',
'org.thingsboard.rule.engine.mqtt.azure.TbAzureIotHubNode': 'ruleNodeAzureIotHub',
'org.thingsboard.rule.engine.gcp.pubsub.TbPubSubNode': 'ruleNodeGcpPubSub',
'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode': 'ruleNodeRabbitMq',
'org.thingsboard.rule.engine.rest.TbRestApiCallNode': 'ruleNodeRestApiCall',
'org.thingsboard.rule.engine.mail.TbSendEmailNode': 'ruleNodeSendEmail',

Loading…
Cancel
Save