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(
 | 
			
		||||
                    new File(targetDir + "docker-compose.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-test-extras.yml" : "docker-compose.postgres-test-extras.yml")),
 | 
			
		||||
                    new File(targetDir + "docker-compose.postgres.volumes.yml"),
 | 
			
		||||
@ -162,6 +163,7 @@ public class ContainerTestSuite {
 | 
			
		||||
                    .withEnv(queueEnv)
 | 
			
		||||
                    .withEnv("LOAD_BALANCER_NAME", "")
 | 
			
		||||
                    .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-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))
 | 
			
		||||
 | 
			
		||||
@ -48,4 +48,13 @@ public class TestProperties {
 | 
			
		||||
        }
 | 
			
		||||
        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.DeviceProfile;
 | 
			
		||||
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.alarm.Alarm;
 | 
			
		||||
import org.thingsboard.server.common.data.asset.Asset;
 | 
			
		||||
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.AssetId;
 | 
			
		||||
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.EntityViewId;
 | 
			
		||||
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.page.PageData;
 | 
			
		||||
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.RelationTypeGroup;
 | 
			
		||||
import org.thingsboard.server.common.data.rule.RuleChain;
 | 
			
		||||
@ -527,4 +531,41 @@ public class TestRestClient {
 | 
			
		||||
                .then()
 | 
			
		||||
                .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