added test for singleton mqtt node
This commit is contained in:
parent
1e2c7f9579
commit
65a8b0a34c
@ -107,6 +107,7 @@ public class ContainerTestSuite {
|
|||||||
List<File> composeFiles = new ArrayList<>(Arrays.asList(
|
List<File> composeFiles = new ArrayList<>(Arrays.asList(
|
||||||
new File(targetDir + "docker-compose.yml"),
|
new File(targetDir + "docker-compose.yml"),
|
||||||
new File(targetDir + "docker-compose.volumes.yml"),
|
new File(targetDir + "docker-compose.volumes.yml"),
|
||||||
|
new File(targetDir + "docker-compose.mosquitto.yml"),
|
||||||
new File(targetDir + (IS_HYBRID_MODE ? "docker-compose.hybrid.yml" : "docker-compose.postgres.yml")),
|
new File(targetDir + (IS_HYBRID_MODE ? "docker-compose.hybrid.yml" : "docker-compose.postgres.yml")),
|
||||||
new File(targetDir + (IS_HYBRID_MODE ? "docker-compose.hybrid-test-extras.yml" : "docker-compose.postgres-test-extras.yml")),
|
new File(targetDir + (IS_HYBRID_MODE ? "docker-compose.hybrid-test-extras.yml" : "docker-compose.postgres-test-extras.yml")),
|
||||||
new File(targetDir + "docker-compose.postgres.volumes.yml"),
|
new File(targetDir + "docker-compose.postgres.volumes.yml"),
|
||||||
@ -162,6 +163,7 @@ public class ContainerTestSuite {
|
|||||||
.withEnv(queueEnv)
|
.withEnv(queueEnv)
|
||||||
.withEnv("LOAD_BALANCER_NAME", "")
|
.withEnv("LOAD_BALANCER_NAME", "")
|
||||||
.withExposedService("haproxy", 80, Wait.forHttp("/swagger-ui.html").withStartupTimeout(CONTAINER_STARTUP_TIMEOUT))
|
.withExposedService("haproxy", 80, Wait.forHttp("/swagger-ui.html").withStartupTimeout(CONTAINER_STARTUP_TIMEOUT))
|
||||||
|
.withExposedService("broker", 1883)
|
||||||
.waitingFor("tb-core1", Wait.forLogMessage(TB_CORE_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT))
|
.waitingFor("tb-core1", Wait.forLogMessage(TB_CORE_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT))
|
||||||
.waitingFor("tb-core2", Wait.forLogMessage(TB_CORE_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT))
|
.waitingFor("tb-core2", Wait.forLogMessage(TB_CORE_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT))
|
||||||
.waitingFor("tb-http-transport1", Wait.forLogMessage(TRANSPORTS_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT))
|
.waitingFor("tb-http-transport1", Wait.forLogMessage(TRANSPORTS_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT))
|
||||||
|
|||||||
@ -48,4 +48,13 @@ public class TestProperties {
|
|||||||
}
|
}
|
||||||
return System.getProperty("tb.wsUrl", "ws://localhost:8080");
|
return System.getProperty("tb.wsUrl", "ws://localhost:8080");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getMqttBrokerUrl() {
|
||||||
|
if (instance.isActive()) {
|
||||||
|
String host = instance.getTestContainer().getServiceHost("broker", 1883);
|
||||||
|
Integer port = instance.getTestContainer().getServicePort("broker", 1883);
|
||||||
|
return "tcp://" + host + ":" + port;
|
||||||
|
}
|
||||||
|
return System.getProperty("mqtt.broker", "tcp://localhost:1883");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,10 +31,12 @@ import org.thingsboard.server.common.data.Dashboard;
|
|||||||
import org.thingsboard.server.common.data.Device;
|
import org.thingsboard.server.common.data.Device;
|
||||||
import org.thingsboard.server.common.data.DeviceProfile;
|
import org.thingsboard.server.common.data.DeviceProfile;
|
||||||
import org.thingsboard.server.common.data.EntityView;
|
import org.thingsboard.server.common.data.EntityView;
|
||||||
|
import org.thingsboard.server.common.data.EventInfo;
|
||||||
import org.thingsboard.server.common.data.User;
|
import org.thingsboard.server.common.data.User;
|
||||||
import org.thingsboard.server.common.data.alarm.Alarm;
|
import org.thingsboard.server.common.data.alarm.Alarm;
|
||||||
import org.thingsboard.server.common.data.asset.Asset;
|
import org.thingsboard.server.common.data.asset.Asset;
|
||||||
import org.thingsboard.server.common.data.asset.AssetProfile;
|
import org.thingsboard.server.common.data.asset.AssetProfile;
|
||||||
|
import org.thingsboard.server.common.data.event.EventType;
|
||||||
import org.thingsboard.server.common.data.id.AlarmId;
|
import org.thingsboard.server.common.data.id.AlarmId;
|
||||||
import org.thingsboard.server.common.data.id.AssetId;
|
import org.thingsboard.server.common.data.id.AssetId;
|
||||||
import org.thingsboard.server.common.data.id.AssetProfileId;
|
import org.thingsboard.server.common.data.id.AssetProfileId;
|
||||||
@ -45,9 +47,11 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
|
|||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
import org.thingsboard.server.common.data.id.EntityViewId;
|
import org.thingsboard.server.common.data.id.EntityViewId;
|
||||||
import org.thingsboard.server.common.data.id.RuleChainId;
|
import org.thingsboard.server.common.data.id.RuleChainId;
|
||||||
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.id.UserId;
|
import org.thingsboard.server.common.data.id.UserId;
|
||||||
import org.thingsboard.server.common.data.page.PageData;
|
import org.thingsboard.server.common.data.page.PageData;
|
||||||
import org.thingsboard.server.common.data.page.PageLink;
|
import org.thingsboard.server.common.data.page.PageLink;
|
||||||
|
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||||
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
||||||
import org.thingsboard.server.common.data.rule.RuleChain;
|
import org.thingsboard.server.common.data.rule.RuleChain;
|
||||||
@ -527,4 +531,41 @@ public class TestRestClient {
|
|||||||
.then()
|
.then()
|
||||||
.statusCode(HTTP_OK);
|
.statusCode(HTTP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PageData<EventInfo> getEvents(EntityId entityId, EventType eventType, TenantId tenantId, TimePageLink pageLink) {
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put("entityType", entityId.getEntityType().name());
|
||||||
|
params.put("entityId", entityId.getId().toString());
|
||||||
|
params.put("eventType", eventType.name());
|
||||||
|
params.put("tenantId", tenantId.getId().toString());
|
||||||
|
addTimePageLinkToParam(params, pageLink);
|
||||||
|
|
||||||
|
return given().spec(requestSpec)
|
||||||
|
.get("/api/events/{entityType}/{entityId}/{eventType}?tenantId={tenantId}&" + getTimeUrlParams(pageLink), params)
|
||||||
|
.then()
|
||||||
|
.statusCode(HTTP_OK)
|
||||||
|
.extract()
|
||||||
|
.as(new TypeRef<>() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTimePageLinkToParam(Map<String, String> params, TimePageLink pageLink) {
|
||||||
|
this.addPageLinkToParam(params, pageLink);
|
||||||
|
if (pageLink.getStartTime() != null) {
|
||||||
|
params.put("startTime", String.valueOf(pageLink.getStartTime()));
|
||||||
|
}
|
||||||
|
if (pageLink.getEndTime() != null) {
|
||||||
|
params.put("endTime", String.valueOf(pageLink.getEndTime()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTimeUrlParams(TimePageLink pageLink) {
|
||||||
|
String urlParams = getUrlParams(pageLink);
|
||||||
|
if (pageLink.getStartTime() != null) {
|
||||||
|
urlParams += "&startTime={startTime}";
|
||||||
|
}
|
||||||
|
if (pageLink.getEndTime() != null) {
|
||||||
|
urlParams += "&endTime={endTime}";
|
||||||
|
}
|
||||||
|
return urlParams;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,204 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2023 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.msa.rule.node;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.awaitility.Awaitility;
|
||||||
|
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||||
|
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||||
|
import org.testng.annotations.AfterMethod;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
|
import org.thingsboard.server.common.data.Device;
|
||||||
|
import org.thingsboard.server.common.data.EventInfo;
|
||||||
|
import org.thingsboard.server.common.data.StringUtils;
|
||||||
|
import org.thingsboard.server.common.data.event.EventType;
|
||||||
|
import org.thingsboard.server.common.data.id.RuleChainId;
|
||||||
|
import org.thingsboard.server.common.data.page.PageData;
|
||||||
|
import org.thingsboard.server.common.data.page.PageLink;
|
||||||
|
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||||
|
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
|
||||||
|
import org.thingsboard.server.common.data.rule.RuleChain;
|
||||||
|
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
|
||||||
|
import org.thingsboard.server.common.data.rule.RuleNode;
|
||||||
|
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||||
|
import org.thingsboard.server.msa.AbstractContainerTest;
|
||||||
|
import org.thingsboard.server.msa.DisableUIListeners;
|
||||||
|
import org.thingsboard.server.msa.TestProperties;
|
||||||
|
import org.thingsboard.server.msa.WsClient;
|
||||||
|
import org.thingsboard.server.msa.mapper.WsTelemetryResponse;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.testng.Assert.fail;
|
||||||
|
import static org.thingsboard.server.msa.prototypes.DevicePrototypes.defaultDevicePrototype;
|
||||||
|
|
||||||
|
@DisableUIListeners
|
||||||
|
@Slf4j
|
||||||
|
public class MqttNodeTest extends AbstractContainerTest {
|
||||||
|
|
||||||
|
private static final String TOPIC = "tb/mqtt/device";
|
||||||
|
|
||||||
|
private Device device;
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
public void setUp() {
|
||||||
|
testRestClient.login("tenant@thingsboard.org", "tenant");
|
||||||
|
device = testRestClient.postDevice("", defaultDevicePrototype("mqtt_"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterMethod
|
||||||
|
public void tearDown() {
|
||||||
|
testRestClient.deleteDeviceIfExists(device.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void telemetryUpload() throws Exception {
|
||||||
|
RuleChainId defaultRuleChainId = getDefaultRuleChainId();
|
||||||
|
|
||||||
|
createRootRuleChainWithTestNode("MqttRuleNodeTestMetadata.json", "org.thingsboard.rule.engine.mqtt.TbMqttNode", 2);
|
||||||
|
|
||||||
|
DeviceCredentials deviceCredentials = testRestClient.getDeviceCredentialsByDeviceId(device.getId());
|
||||||
|
|
||||||
|
WsClient wsClient = subscribeToWebSocket(device.getId(), "LATEST_TELEMETRY", CmdsType.TS_SUB_CMDS);
|
||||||
|
|
||||||
|
MqttMessageListener messageListener = new MqttMessageListener();
|
||||||
|
MqttClient responseClient = new MqttClient(TestProperties.getMqttBrokerUrl(), StringUtils.randomAlphanumeric(10), new MemoryPersistence());
|
||||||
|
responseClient.connect();
|
||||||
|
responseClient.subscribe(TOPIC, messageListener);
|
||||||
|
|
||||||
|
MqttClient mqttClient = new MqttClient("tcp://localhost:1883", StringUtils.randomAlphanumeric(10), new MemoryPersistence());
|
||||||
|
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
|
||||||
|
mqttConnectOptions.setUserName(deviceCredentials.getCredentialsId());
|
||||||
|
mqttClient.connect(mqttConnectOptions);
|
||||||
|
mqttClient.publish("v1/devices/me/telemetry", new MqttMessage(createPayload().toString().getBytes()));
|
||||||
|
|
||||||
|
WsTelemetryResponse actualLatestTelemetry = wsClient.getLastMessage();
|
||||||
|
log.info("Received telemetry: {}", actualLatestTelemetry);
|
||||||
|
wsClient.closeBlocking();
|
||||||
|
|
||||||
|
assertThat(actualLatestTelemetry.getData()).hasSize(4);
|
||||||
|
assertThat(actualLatestTelemetry.getLatestValues().keySet()).containsOnlyOnceElementsOf(Arrays.asList("booleanKey", "stringKey", "doubleKey", "longKey"));
|
||||||
|
|
||||||
|
assertThat(actualLatestTelemetry.getDataValuesByKey("booleanKey").get(1)).isEqualTo(Boolean.TRUE.toString());
|
||||||
|
assertThat(actualLatestTelemetry.getDataValuesByKey("stringKey").get(1)).isEqualTo("value1");
|
||||||
|
assertThat(actualLatestTelemetry.getDataValuesByKey("doubleKey").get(1)).isEqualTo(Double.toString(42.0));
|
||||||
|
assertThat(actualLatestTelemetry.getDataValuesByKey("longKey").get(1)).isEqualTo(Long.toString(73));
|
||||||
|
|
||||||
|
Awaitility
|
||||||
|
.await()
|
||||||
|
.alias("Get integration events")
|
||||||
|
.atMost(10, TimeUnit.SECONDS)
|
||||||
|
.until(() -> messageListener.getEvents().size() > 0);
|
||||||
|
|
||||||
|
BlockingQueue<MqttEvent> events = messageListener.getEvents();
|
||||||
|
JsonNode actual = JacksonUtil.toJsonNode(Objects.requireNonNull(events.poll()).message);
|
||||||
|
|
||||||
|
assertThat(actual.get("stringKey").asText()).isEqualTo("value1");
|
||||||
|
assertThat(actual.get("booleanKey").asBoolean()).isEqualTo(Boolean.TRUE);
|
||||||
|
assertThat(actual.get("doubleKey").asDouble()).isEqualTo(42.0);
|
||||||
|
assertThat(actual.get("longKey").asLong()).isEqualTo(73);
|
||||||
|
|
||||||
|
testRestClient.setRootRuleChain(defaultRuleChainId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
private class MqttMessageListener implements IMqttMessageListener {
|
||||||
|
private final BlockingQueue<MqttEvent> events;
|
||||||
|
|
||||||
|
private MqttMessageListener() {
|
||||||
|
events = new ArrayBlockingQueue<>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageArrived(String s, MqttMessage mqttMessage) {
|
||||||
|
log.info("MQTT message [{}], topic [{}]", mqttMessage.toString(), s);
|
||||||
|
events.add(new MqttEvent(s, mqttMessage.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockingQueue<MqttEvent> getEvents() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
private class MqttEvent {
|
||||||
|
private final String topic;
|
||||||
|
private final String message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RuleChainId getDefaultRuleChainId() {
|
||||||
|
PageData<RuleChain> ruleChains = testRestClient.getRuleChains(new PageLink(40, 0));
|
||||||
|
|
||||||
|
Optional<RuleChain> defaultRuleChain = ruleChains.getData()
|
||||||
|
.stream()
|
||||||
|
.filter(RuleChain::isRoot)
|
||||||
|
.findFirst();
|
||||||
|
if (!defaultRuleChain.isPresent()) {
|
||||||
|
fail("Root rule chain wasn't found");
|
||||||
|
}
|
||||||
|
return defaultRuleChain.get().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RuleChainId createRootRuleChainWithTestNode(String ruleChainMetadataFile, String ruleNodeType, int eventsCount) throws Exception {
|
||||||
|
RuleChain newRuleChain = new RuleChain();
|
||||||
|
newRuleChain.setName("testRuleChain");
|
||||||
|
RuleChain ruleChain = testRestClient.postRuleChain(newRuleChain);
|
||||||
|
|
||||||
|
JsonNode configuration = JacksonUtil.OBJECT_MAPPER.readTree(this.getClass().getClassLoader().getResourceAsStream(ruleChainMetadataFile));
|
||||||
|
RuleChainMetaData ruleChainMetaData = new RuleChainMetaData();
|
||||||
|
ruleChainMetaData.setRuleChainId(ruleChain.getId());
|
||||||
|
ruleChainMetaData.setFirstNodeIndex(configuration.get("firstNodeIndex").asInt());
|
||||||
|
ruleChainMetaData.setNodes(Arrays.asList(JacksonUtil.OBJECT_MAPPER.treeToValue(configuration.get("nodes"), RuleNode[].class)));
|
||||||
|
ruleChainMetaData.setConnections(Arrays.asList(JacksonUtil.OBJECT_MAPPER.treeToValue(configuration.get("connections"), NodeConnectionInfo[].class)));
|
||||||
|
|
||||||
|
ruleChainMetaData = testRestClient.postRuleChainMetadata(ruleChainMetaData);
|
||||||
|
|
||||||
|
testRestClient.setRootRuleChain(ruleChain.getId());
|
||||||
|
|
||||||
|
RuleNode node = ruleChainMetaData.getNodes().stream().filter(ruleNode -> ruleNode.getType().equals(ruleNodeType)).findFirst().get();
|
||||||
|
|
||||||
|
Awaitility
|
||||||
|
.await()
|
||||||
|
.alias("Get events from rule chain")
|
||||||
|
.atMost(10, TimeUnit.SECONDS)
|
||||||
|
.until(() -> {
|
||||||
|
PageData<EventInfo> events = testRestClient.getEvents(node.getId(), EventType.LC_EVENT, ruleChain.getTenantId(), new TimePageLink(1024));
|
||||||
|
List<EventInfo> eventInfos = events.getData().stream().filter(eventInfo ->
|
||||||
|
"STARTED".equals(eventInfo.getBody().get("event").asText()) &&
|
||||||
|
"true".equals(eventInfo.getBody().get("success").asText()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return eventInfos.size() == eventsCount;
|
||||||
|
});
|
||||||
|
|
||||||
|
return ruleChain.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"firstNodeIndex": 2,
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"additionalInfo": {
|
||||||
|
"description": "",
|
||||||
|
"layoutX": 626,
|
||||||
|
"layoutY": 152
|
||||||
|
},
|
||||||
|
"type": "org.thingsboard.rule.engine.mqtt.TbMqttNode",
|
||||||
|
"name": "test mqtt",
|
||||||
|
"debugMode": true,
|
||||||
|
"singletonMode": true,
|
||||||
|
"queueName": "HighPriority",
|
||||||
|
"configurationVersion": 0,
|
||||||
|
"configuration": {
|
||||||
|
"topicPattern": "tb/mqtt/device",
|
||||||
|
"host": "broker",
|
||||||
|
"port": 1883,
|
||||||
|
"connectTimeoutSec": 10,
|
||||||
|
"clientId": null,
|
||||||
|
"cleanSession": true,
|
||||||
|
"retainedMessage": false,
|
||||||
|
"ssl": false,
|
||||||
|
"credentials": {
|
||||||
|
"type": "anonymous"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"externalId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"additionalInfo": {
|
||||||
|
"description": "",
|
||||||
|
"layoutX": 949,
|
||||||
|
"layoutY": 153
|
||||||
|
},
|
||||||
|
"type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode",
|
||||||
|
"name": "save timeseries",
|
||||||
|
"debugMode": true,
|
||||||
|
"singletonMode": false,
|
||||||
|
"configurationVersion": 0,
|
||||||
|
"configuration": {
|
||||||
|
"defaultTTL": 0,
|
||||||
|
"skipLatestPersistence": false,
|
||||||
|
"useServerTs": false
|
||||||
|
},
|
||||||
|
"externalId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"additionalInfo": {
|
||||||
|
"description": "",
|
||||||
|
"layoutX": 305,
|
||||||
|
"layoutY": 151
|
||||||
|
},
|
||||||
|
"type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode",
|
||||||
|
"name": "swatch",
|
||||||
|
"debugMode": false,
|
||||||
|
"singletonMode": false,
|
||||||
|
"configurationVersion": 0,
|
||||||
|
"configuration": {
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"externalId": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": [
|
||||||
|
{
|
||||||
|
"fromIndex": 0,
|
||||||
|
"toIndex": 1,
|
||||||
|
"type": "Success"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fromIndex": 2,
|
||||||
|
"toIndex": 0,
|
||||||
|
"type": "Post telemetry"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ruleChainConnections": null
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
#
|
||||||
|
# Copyright © 2016-2023 The Thingsboard Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
version: '3.0'
|
||||||
|
services:
|
||||||
|
broker:
|
||||||
|
image: eclipse-mosquitto
|
||||||
|
volumes:
|
||||||
|
- ./mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf
|
||||||
|
ports:
|
||||||
|
- "1883"
|
||||||
|
restart: always
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
#
|
||||||
|
# Copyright © 2016-2023 The Thingsboard Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
listener 1883
|
||||||
|
allow_anonymous true
|
||||||
Loading…
x
Reference in New Issue
Block a user