Search in sources :

Example 46 with RuleChain

use of org.thingsboard.server.common.data.rule.RuleChain in project thingsboard by thingsboard.

the class DefaultTbRuleChainService method updateRelatedRuleChains.

@Override
public List<RuleChain> updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result) {
    Set<RuleChainId> ruleChainIds = new HashSet<>();
    log.debug("[{}][{}] Going to update links in related rule chains", tenantId, ruleChainId);
    if (result.getUpdatedRuleNodes() == null || result.getUpdatedRuleNodes().isEmpty()) {
        return Collections.emptyList();
    }
    Set<String> oldLabels = new HashSet<>();
    Set<String> newLabels = new HashSet<>();
    Set<String> confusedLabels = new HashSet<>();
    Map<String, String> updatedLabels = new HashMap<>();
    for (RuleNodeUpdateResult update : result.getUpdatedRuleNodes()) {
        var oldNode = update.getOldRuleNode();
        var newNode = update.getNewRuleNode();
        if (isOutputRuleNode(newNode)) {
            try {
                oldLabels.add(oldNode.getName());
                newLabels.add(newNode.getName());
                if (!oldNode.getName().equals(newNode.getName())) {
                    String oldLabel = oldNode.getName();
                    String newLabel = newNode.getName();
                    if (updatedLabels.containsKey(oldLabel) && !updatedLabels.get(oldLabel).equals(newLabel)) {
                        confusedLabels.add(oldLabel);
                        log.warn("[{}][{}] Can't automatically rename the label from [{}] to [{}] due to conflict [{}]", tenantId, ruleChainId, oldLabel, newLabel, updatedLabels.get(oldLabel));
                    } else {
                        updatedLabels.put(oldLabel, newLabel);
                    }
                }
            } catch (Exception e) {
                log.warn("[{}][{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, newNode.getId(), e);
            }
        }
    }
    // Remove all output labels that are renamed to two or more different labels, since we don't which new label to use;
    confusedLabels.forEach(updatedLabels::remove);
    // Remove all output labels that are renamed but still present in the rule chain;
    newLabels.forEach(updatedLabels::remove);
    if (!oldLabels.equals(newLabels)) {
        ruleChainIds.addAll(updateRelatedRuleChains(tenantId, ruleChainId, updatedLabels));
    }
    return ruleChainIds.stream().map(id -> ruleChainService.findRuleChainById(tenantId, id)).collect(Collectors.toList());
}
Also used : RequiredArgsConstructor(lombok.RequiredArgsConstructor) JacksonUtil(org.thingsboard.common.util.JacksonUtil) TbRuleChainInputNode(org.thingsboard.rule.engine.flow.TbRuleChainInputNode) RuleChainMetaData(org.thingsboard.server.common.data.rule.RuleChainMetaData) HashMap(java.util.HashMap) RuleNodeId(org.thingsboard.server.common.data.id.RuleNodeId) TenantId(org.thingsboard.server.common.data.id.TenantId) RuleChainUpdateResult(org.thingsboard.server.common.data.rule.RuleChainUpdateResult) RuleChainService(org.thingsboard.server.dao.rule.RuleChainService) TreeSet(java.util.TreeSet) EntityRelation(org.thingsboard.server.common.data.relation.EntityRelation) RelationService(org.thingsboard.server.dao.relation.RelationService) HashSet(java.util.HashSet) RuleNodeUpdateResult(org.thingsboard.server.common.data.rule.RuleNodeUpdateResult) TbCoreComponent(org.thingsboard.server.queue.util.TbCoreComponent) Service(org.springframework.stereotype.Service) Map(java.util.Map) TbRuleChainInputNodeConfiguration(org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration) RuleNode(org.thingsboard.server.common.data.rule.RuleNode) Set(java.util.Set) Collectors(java.util.stream.Collectors) TbRuleChainOutputNode(org.thingsboard.rule.engine.flow.TbRuleChainOutputNode) RuleChainOutputLabelsUsage(org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage) Slf4j(lombok.extern.slf4j.Slf4j) List(java.util.List) RuleChain(org.thingsboard.server.common.data.rule.RuleChain) RuleChainId(org.thingsboard.server.common.data.id.RuleChainId) Comparator(java.util.Comparator) Collections(java.util.Collections) RuleNodeUpdateResult(org.thingsboard.server.common.data.rule.RuleNodeUpdateResult) HashMap(java.util.HashMap) RuleChainId(org.thingsboard.server.common.data.id.RuleChainId) HashSet(java.util.HashSet)

Example 47 with RuleChain

use of org.thingsboard.server.common.data.rule.RuleChain in project thingsboard by thingsboard.

the class AbstractRuleEngineFlowIntegrationTest method testTwoRuleChainsWithTwoRules.

@Test
public void testTwoRuleChainsWithTwoRules() throws Exception {
    // Creating Rule Chain
    RuleChain rootRuleChain = new RuleChain();
    rootRuleChain.setName("Root Rule Chain");
    rootRuleChain.setTenantId(savedTenant.getId());
    rootRuleChain.setRoot(true);
    rootRuleChain.setDebugMode(true);
    rootRuleChain = saveRuleChain(rootRuleChain);
    Assert.assertNull(rootRuleChain.getFirstRuleNodeId());
    // Creating Rule Chain
    RuleChain secondaryRuleChain = new RuleChain();
    secondaryRuleChain.setName("Secondary Rule Chain");
    secondaryRuleChain.setTenantId(savedTenant.getId());
    secondaryRuleChain.setRoot(false);
    secondaryRuleChain.setDebugMode(true);
    secondaryRuleChain = saveRuleChain(secondaryRuleChain);
    Assert.assertNull(secondaryRuleChain.getFirstRuleNodeId());
    RuleChainMetaData rootMetaData = new RuleChainMetaData();
    rootMetaData.setRuleChainId(rootRuleChain.getId());
    RuleNode ruleNode1 = new RuleNode();
    ruleNode1.setName("Simple Rule Node 1");
    ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName());
    ruleNode1.setDebugMode(true);
    TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration();
    configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1"));
    ruleNode1.setConfiguration(mapper.valueToTree(configuration1));
    RuleNode ruleNode12 = new RuleNode();
    ruleNode12.setName("Simple Rule Node 1");
    ruleNode12.setType(org.thingsboard.rule.engine.flow.TbRuleChainInputNode.class.getName());
    ruleNode12.setDebugMode(true);
    TbRuleChainInputNodeConfiguration configuration12 = new TbRuleChainInputNodeConfiguration();
    configuration12.setRuleChainId(secondaryRuleChain.getId().getId().toString());
    ruleNode12.setConfiguration(mapper.valueToTree(configuration12));
    rootMetaData.setNodes(Arrays.asList(ruleNode1, ruleNode12));
    rootMetaData.setFirstNodeIndex(0);
    NodeConnectionInfo connection = new NodeConnectionInfo();
    connection.setFromIndex(0);
    connection.setToIndex(1);
    connection.setType("Success");
    rootMetaData.setConnections(Collections.singletonList(connection));
    rootMetaData = saveRuleChainMetaData(rootMetaData);
    Assert.assertNotNull(rootMetaData);
    rootRuleChain = getRuleChain(rootRuleChain.getId());
    Assert.assertNotNull(rootRuleChain.getFirstRuleNodeId());
    RuleChainMetaData secondaryMetaData = new RuleChainMetaData();
    secondaryMetaData.setRuleChainId(secondaryRuleChain.getId());
    RuleNode ruleNode2 = new RuleNode();
    ruleNode2.setName("Simple Rule Node 2");
    ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName());
    ruleNode2.setDebugMode(true);
    TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration();
    configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2"));
    ruleNode2.setConfiguration(mapper.valueToTree(configuration2));
    secondaryMetaData.setNodes(Collections.singletonList(ruleNode2));
    secondaryMetaData.setFirstNodeIndex(0);
    secondaryMetaData = saveRuleChainMetaData(secondaryMetaData);
    Assert.assertNotNull(secondaryMetaData);
    // Saving the device
    Device device = new Device();
    device.setName("My device");
    device.setType("default");
    device = doPost("/api/device", device, Device.class);
    attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE, Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey1", "serverAttributeValue1"), System.currentTimeMillis()))).get();
    attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE, Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey2", "serverAttributeValue2"), System.currentTimeMillis()))).get();
    TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class);
    Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true);
    TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback);
    QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null);
    // Pushing Message to the system
    actorSystem.tell(qMsg);
    Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess();
    PageData<Event> eventsPage = getDebugEvents(savedTenant.getId(), rootRuleChain.getFirstRuleNodeId(), 1000);
    List<Event> events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
    Assert.assertEquals(2, events.size());
    Event inEvent = events.stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.IN)).findFirst().get();
    Assert.assertEquals(rootRuleChain.getFirstRuleNodeId(), inEvent.getEntityId());
    Assert.assertEquals(device.getId().getId().toString(), inEvent.getBody().get("entityId").asText());
    Event outEvent = events.stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.OUT)).findFirst().get();
    Assert.assertEquals(rootRuleChain.getFirstRuleNodeId(), outEvent.getEntityId());
    Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText());
    Assert.assertEquals("serverAttributeValue1", getMetadata(outEvent).get("ss_serverAttributeKey1").asText());
    RuleChain finalRuleChain = rootRuleChain;
    RuleNode lastRuleNode = secondaryMetaData.getNodes().stream().filter(node -> !node.getId().equals(finalRuleChain.getFirstRuleNodeId())).findFirst().get();
    eventsPage = getDebugEvents(savedTenant.getId(), lastRuleNode.getId(), 1000);
    events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
    Assert.assertEquals(2, events.size());
    inEvent = events.stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.IN)).findFirst().get();
    Assert.assertEquals(lastRuleNode.getId(), inEvent.getEntityId());
    Assert.assertEquals(device.getId().getId().toString(), inEvent.getBody().get("entityId").asText());
    outEvent = events.stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.OUT)).findFirst().get();
    Assert.assertEquals(lastRuleNode.getId(), outEvent.getEntityId());
    Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText());
    Assert.assertEquals("serverAttributeValue1", getMetadata(outEvent).get("ss_serverAttributeKey1").asText());
    Assert.assertEquals("serverAttributeValue2", getMetadata(outEvent).get("ss_serverAttributeKey2").asText());
}
Also used : Event(org.thingsboard.server.common.data.Event) Arrays(java.util.Arrays) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) TbMsg(org.thingsboard.server.common.msg.TbMsg) Device(org.thingsboard.server.common.data.Device) RuleChainMetaData(org.thingsboard.server.common.data.rule.RuleChainMetaData) Autowired(org.springframework.beans.factory.annotation.Autowired) Tenant(org.thingsboard.server.common.data.Tenant) Mockito.spy(org.mockito.Mockito.spy) TbMsgMetaData(org.thingsboard.server.common.msg.TbMsgMetaData) Answer(org.mockito.stubbing.Answer) User(org.thingsboard.server.common.data.User) MockMvcResultMatchers.status(org.springframework.test.web.servlet.result.MockMvcResultMatchers.status) ActorSystemContext(org.thingsboard.server.actors.ActorSystemContext) QueueToRuleEngineMsg(org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg) After(org.junit.After) TbRuleChainInputNodeConfiguration(org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration) AbstractRuleEngineControllerTest(org.thingsboard.server.controller.AbstractRuleEngineControllerTest) AttributesService(org.thingsboard.server.dao.attributes.AttributesService) Before(org.junit.Before) TbMsgCallback(org.thingsboard.server.common.msg.queue.TbMsgCallback) DataConstants(org.thingsboard.server.common.data.DataConstants) RuleNode(org.thingsboard.server.common.data.rule.RuleNode) TbGetAttributesNodeConfiguration(org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration) ReflectionTestUtils(org.springframework.test.util.ReflectionTestUtils) Test(org.junit.Test) BaseAttributeKvEntry(org.thingsboard.server.common.data.kv.BaseAttributeKvEntry) Authority(org.thingsboard.server.common.data.security.Authority) Collectors(java.util.stream.Collectors) Mockito(org.mockito.Mockito) Slf4j(lombok.extern.slf4j.Slf4j) EventService(org.thingsboard.server.dao.event.EventService) List(java.util.List) PageData(org.thingsboard.server.common.data.page.PageData) RuleChain(org.thingsboard.server.common.data.rule.RuleChain) Assert(org.junit.Assert) NodeConnectionInfo(org.thingsboard.server.common.data.rule.NodeConnectionInfo) Collections(java.util.Collections) StringDataEntry(org.thingsboard.server.common.data.kv.StringDataEntry) QueueToRuleEngineMsg(org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg) Device(org.thingsboard.server.common.data.Device) RuleNode(org.thingsboard.server.common.data.rule.RuleNode) TbMsgMetaData(org.thingsboard.server.common.msg.TbMsgMetaData) TbGetAttributesNodeConfiguration(org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration) NodeConnectionInfo(org.thingsboard.server.common.data.rule.NodeConnectionInfo) RuleChain(org.thingsboard.server.common.data.rule.RuleChain) StringDataEntry(org.thingsboard.server.common.data.kv.StringDataEntry) RuleChainMetaData(org.thingsboard.server.common.data.rule.RuleChainMetaData) TbRuleChainInputNodeConfiguration(org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration) BaseAttributeKvEntry(org.thingsboard.server.common.data.kv.BaseAttributeKvEntry) Event(org.thingsboard.server.common.data.Event) TbMsgCallback(org.thingsboard.server.common.msg.queue.TbMsgCallback) TbMsg(org.thingsboard.server.common.msg.TbMsg) AbstractRuleEngineControllerTest(org.thingsboard.server.controller.AbstractRuleEngineControllerTest) Test(org.junit.Test)

Example 48 with RuleChain

use of org.thingsboard.server.common.data.rule.RuleChain in project thingsboard by thingsboard.

the class EdgeController method saveEdge.

@ApiOperation(value = "Create Or Update Edge (saveEdge)", notes = "Create or update the Edge. When creating edge, platform generates Edge Id as " + UUID_WIKI_LINK + "The newly created edge id will be present in the response. " + "Specify existing Edge id to update the edge. " + "Referencing non-existing Edge Id will cause 'Not Found' error." + "\n\nEdge name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the edge names and non-unique 'label' field for user-friendly visualization purposes." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge", method = RequestMethod.POST)
@ResponseBody
public Edge saveEdge(@ApiParam(value = "A JSON value representing the edge.", required = true) @RequestBody Edge edge) throws ThingsboardException {
    try {
        TenantId tenantId = getCurrentUser().getTenantId();
        edge.setTenantId(tenantId);
        boolean created = edge.getId() == null;
        RuleChain edgeTemplateRootRuleChain = null;
        if (created) {
            edgeTemplateRootRuleChain = ruleChainService.getEdgeTemplateRootRuleChain(tenantId);
            if (edgeTemplateRootRuleChain == null) {
                throw new DataValidationException("Root edge rule chain is not available!");
            }
        }
        Operation operation = created ? Operation.CREATE : Operation.WRITE;
        accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edge.getId(), edge);
        Edge savedEdge = checkNotNull(edgeService.saveEdge(edge));
        onEdgeCreatedOrUpdated(tenantId, savedEdge, edgeTemplateRootRuleChain, !created, getCurrentUser());
        return savedEdge;
    } catch (Exception e) {
        logEntityAction(emptyId(EntityType.EDGE), edge, null, edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
        throw handleException(e);
    }
}
Also used : TenantId(org.thingsboard.server.common.data.id.TenantId) DataValidationException(org.thingsboard.server.dao.exception.DataValidationException) RuleChain(org.thingsboard.server.common.data.rule.RuleChain) ApiOperation(io.swagger.annotations.ApiOperation) Operation(org.thingsboard.server.service.security.permission.Operation) Edge(org.thingsboard.server.common.data.edge.Edge) IncorrectParameterException(org.thingsboard.server.dao.exception.IncorrectParameterException) DataValidationException(org.thingsboard.server.dao.exception.DataValidationException) ThingsboardException(org.thingsboard.server.common.data.exception.ThingsboardException) IOException(java.io.IOException) ApiOperation(io.swagger.annotations.ApiOperation) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize) RequestMapping(org.springframework.web.bind.annotation.RequestMapping) ResponseBody(org.springframework.web.bind.annotation.ResponseBody)

Example 49 with RuleChain

use of org.thingsboard.server.common.data.rule.RuleChain in project thingsboard by thingsboard.

the class EdgeServiceImpl method assignDefaultRuleChainsToEdge.

@Override
public void assignDefaultRuleChainsToEdge(TenantId tenantId, EdgeId edgeId) {
    log.trace("Executing assignDefaultRuleChainsToEdge, tenantId [{}], edgeId [{}]", tenantId, edgeId);
    PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
    PageData<RuleChain> pageData;
    do {
        pageData = ruleChainService.findAutoAssignToEdgeRuleChainsByTenantId(tenantId, pageLink);
        if (pageData.getData().size() > 0) {
            for (RuleChain ruleChain : pageData.getData()) {
                ruleChainService.assignRuleChainToEdge(tenantId, ruleChain.getId(), edgeId);
            }
        }
        if (pageData.hasNext()) {
            pageLink = pageLink.nextPageLink();
        }
    } while (pageData.hasNext());
}
Also used : RuleChain(org.thingsboard.server.common.data.rule.RuleChain) PageLink(org.thingsboard.server.common.data.page.PageLink) Validator.validatePageLink(org.thingsboard.server.dao.service.Validator.validatePageLink)

Example 50 with RuleChain

use of org.thingsboard.server.common.data.rule.RuleChain in project thingsboard by thingsboard.

the class MqttClientTest method clientSideRpc.

@Test
public void clientSideRpc() throws Exception {
    restClient.login("tenant@thingsboard.org", "tenant");
    Device device = createDevice("mqtt_");
    DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get();
    MqttMessageListener listener = new MqttMessageListener();
    MqttClient mqttClient = getMqttClient(deviceCredentials, listener);
    mqttClient.on("v1/devices/me/rpc/request/+", listener, MqttQoS.AT_LEAST_ONCE).get();
    // Get the default rule chain id to make it root again after test finished
    RuleChainId defaultRuleChainId = getDefaultRuleChainId();
    // Create a new root rule chain
    RuleChainId ruleChainId = createRootRuleChainForRpcResponse();
    TimeUnit.SECONDS.sleep(3);
    // Send the request to the server
    JsonObject clientRequest = new JsonObject();
    clientRequest.addProperty("method", "getResponse");
    clientRequest.addProperty("params", true);
    Integer requestId = 42;
    mqttClient.publish("v1/devices/me/rpc/request/" + requestId, Unpooled.wrappedBuffer(clientRequest.toString().getBytes())).get();
    // Check the response from the server
    TimeUnit.SECONDS.sleep(1);
    MqttEvent responseFromServer = listener.getEvents().poll(1, TimeUnit.SECONDS);
    Integer responseId = Integer.valueOf(Objects.requireNonNull(responseFromServer).getTopic().substring("v1/devices/me/rpc/response/".length()));
    Assert.assertEquals(requestId, responseId);
    Assert.assertEquals("requestReceived", mapper.readTree(responseFromServer.getMessage()).get("response").asText());
    // Make the default rule chain a root again
    ResponseEntity<RuleChain> rootRuleChainResponse = restClient.getRestTemplate().postForEntity(HTTPS_URL + "/api/ruleChain/{ruleChainId}/root", null, RuleChain.class, defaultRuleChainId);
    Assert.assertTrue(rootRuleChainResponse.getStatusCode().is2xxSuccessful());
    // Delete the created rule chain
    restClient.getRestTemplate().delete(HTTPS_URL + "/api/ruleChain/{ruleChainId}", ruleChainId);
    restClient.getRestTemplate().delete(HTTPS_URL + "/api/device/" + device.getId());
}
Also used : MqttClient(org.thingsboard.mqtt.MqttClient) RuleChain(org.thingsboard.server.common.data.rule.RuleChain) Device(org.thingsboard.server.common.data.Device) RuleChainId(org.thingsboard.server.common.data.id.RuleChainId) JsonObject(com.google.gson.JsonObject) DeviceCredentials(org.thingsboard.server.common.data.security.DeviceCredentials) AbstractContainerTest(org.thingsboard.server.msa.AbstractContainerTest)

Aggregations

RuleChain (org.thingsboard.server.common.data.rule.RuleChain)67 RuleChainId (org.thingsboard.server.common.data.id.RuleChainId)26 Test (org.junit.Test)20 RuleNode (org.thingsboard.server.common.data.rule.RuleNode)19 ArrayList (java.util.ArrayList)16 ThingsboardException (org.thingsboard.server.common.data.exception.ThingsboardException)15 RuleChainMetaData (org.thingsboard.server.common.data.rule.RuleChainMetaData)14 ApiOperation (io.swagger.annotations.ApiOperation)13 PreAuthorize (org.springframework.security.access.prepost.PreAuthorize)13 Edge (org.thingsboard.server.common.data.edge.Edge)13 TenantId (org.thingsboard.server.common.data.id.TenantId)13 RequestMapping (org.springframework.web.bind.annotation.RequestMapping)12 ResponseBody (org.springframework.web.bind.annotation.ResponseBody)11 PageLink (org.thingsboard.server.common.data.page.PageLink)11 RuleNodeId (org.thingsboard.server.common.data.id.RuleNodeId)10 EntityRelation (org.thingsboard.server.common.data.relation.EntityRelation)10 DataValidationException (org.thingsboard.server.dao.exception.DataValidationException)9 EdgeId (org.thingsboard.server.common.data.id.EdgeId)8 List (java.util.List)7 Device (org.thingsboard.server.common.data.Device)7