Method to create default rule chain for device profile
This commit is contained in:
parent
e353ab3c81
commit
4a3b28d331
@ -0,0 +1,135 @@
|
|||||||
|
{
|
||||||
|
"ruleChain": {
|
||||||
|
"additionalInfo": {
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"name": "Device Profile Rule Chain Template",
|
||||||
|
"firstRuleNodeId": null,
|
||||||
|
"root": false,
|
||||||
|
"debugMode": false,
|
||||||
|
"configuration": null
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"firstNodeIndex": 6,
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"additionalInfo": {
|
||||||
|
"layoutX": 822,
|
||||||
|
"layoutY": 294
|
||||||
|
},
|
||||||
|
"type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode",
|
||||||
|
"name": "Save Timeseries",
|
||||||
|
"debugMode": false,
|
||||||
|
"configuration": {
|
||||||
|
"defaultTTL": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"additionalInfo": {
|
||||||
|
"layoutX": 824,
|
||||||
|
"layoutY": 221
|
||||||
|
},
|
||||||
|
"type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode",
|
||||||
|
"name": "Save Client Attributes",
|
||||||
|
"debugMode": false,
|
||||||
|
"configuration": {
|
||||||
|
"scope": "CLIENT_SCOPE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"additionalInfo": {
|
||||||
|
"layoutX": 494,
|
||||||
|
"layoutY": 309
|
||||||
|
},
|
||||||
|
"type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode",
|
||||||
|
"name": "Message Type Switch",
|
||||||
|
"debugMode": false,
|
||||||
|
"configuration": {
|
||||||
|
"version": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"additionalInfo": {
|
||||||
|
"layoutX": 824,
|
||||||
|
"layoutY": 383
|
||||||
|
},
|
||||||
|
"type": "org.thingsboard.rule.engine.action.TbLogNode",
|
||||||
|
"name": "Log RPC from Device",
|
||||||
|
"debugMode": false,
|
||||||
|
"configuration": {
|
||||||
|
"jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"additionalInfo": {
|
||||||
|
"layoutX": 823,
|
||||||
|
"layoutY": 444
|
||||||
|
},
|
||||||
|
"type": "org.thingsboard.rule.engine.action.TbLogNode",
|
||||||
|
"name": "Log Other",
|
||||||
|
"debugMode": false,
|
||||||
|
"configuration": {
|
||||||
|
"jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"additionalInfo": {
|
||||||
|
"layoutX": 822,
|
||||||
|
"layoutY": 507
|
||||||
|
},
|
||||||
|
"type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode",
|
||||||
|
"name": "RPC Call Request",
|
||||||
|
"debugMode": false,
|
||||||
|
"configuration": {
|
||||||
|
"timeoutInSeconds": 60
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"additionalInfo": {
|
||||||
|
"description": "",
|
||||||
|
"layoutX": 209,
|
||||||
|
"layoutY": 307
|
||||||
|
},
|
||||||
|
"type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode",
|
||||||
|
"name": "Device Profile Node",
|
||||||
|
"debugMode": false,
|
||||||
|
"configuration": {
|
||||||
|
"version": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": [
|
||||||
|
{
|
||||||
|
"fromIndex": 2,
|
||||||
|
"toIndex": 4,
|
||||||
|
"type": "Other"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fromIndex": 2,
|
||||||
|
"toIndex": 1,
|
||||||
|
"type": "Post attributes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fromIndex": 2,
|
||||||
|
"toIndex": 0,
|
||||||
|
"type": "Post telemetry"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fromIndex": 2,
|
||||||
|
"toIndex": 3,
|
||||||
|
"type": "RPC Request from Device"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fromIndex": 2,
|
||||||
|
"toIndex": 5,
|
||||||
|
"type": "RPC Request to Device"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fromIndex": 6,
|
||||||
|
"toIndex": 2,
|
||||||
|
"type": "Success"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ruleChainConnections": null
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -47,6 +47,7 @@ import org.thingsboard.server.common.data.id.TenantId;
|
|||||||
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.plugin.ComponentLifecycleEvent;
|
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
|
||||||
|
import org.thingsboard.server.common.data.rule.DefaultRuleChainCreateRequest;
|
||||||
import org.thingsboard.server.common.data.rule.RuleChain;
|
import org.thingsboard.server.common.data.rule.RuleChain;
|
||||||
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
|
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
|
||||||
import org.thingsboard.server.common.data.rule.RuleNode;
|
import org.thingsboard.server.common.data.rule.RuleNode;
|
||||||
@ -55,6 +56,7 @@ import org.thingsboard.server.common.msg.TbMsgDataType;
|
|||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
import org.thingsboard.server.dao.event.EventService;
|
import org.thingsboard.server.dao.event.EventService;
|
||||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||||
|
import org.thingsboard.server.service.install.InstallScripts;
|
||||||
import org.thingsboard.server.service.script.JsInvokeService;
|
import org.thingsboard.server.service.script.JsInvokeService;
|
||||||
import org.thingsboard.server.service.script.RuleNodeJsScriptEngine;
|
import org.thingsboard.server.service.script.RuleNodeJsScriptEngine;
|
||||||
import org.thingsboard.server.service.security.permission.Operation;
|
import org.thingsboard.server.service.security.permission.Operation;
|
||||||
@ -77,6 +79,9 @@ public class RuleChainController extends BaseController {
|
|||||||
|
|
||||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private InstallScripts installScripts;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private EventService eventService;
|
private EventService eventService;
|
||||||
|
|
||||||
@ -146,6 +151,27 @@ public class RuleChainController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
|
||||||
|
@RequestMapping(value = "/ruleChain/device/default", method = RequestMethod.POST)
|
||||||
|
@ResponseBody
|
||||||
|
public RuleChain saveRuleChain(@RequestBody DefaultRuleChainCreateRequest request) throws ThingsboardException {
|
||||||
|
try {
|
||||||
|
checkNotNull(request);
|
||||||
|
checkNotNull(request.getName());
|
||||||
|
|
||||||
|
RuleChain savedRuleChain = installScripts.createDefaultRuleChain(getCurrentUser().getTenantId(), request.getName());
|
||||||
|
|
||||||
|
logEntityAction(savedRuleChain.getId(), savedRuleChain, null, ActionType.ADDED, null);
|
||||||
|
|
||||||
|
return savedRuleChain;
|
||||||
|
} catch (Exception e) {
|
||||||
|
RuleChain ruleChain = new RuleChain();
|
||||||
|
ruleChain.setName(request.getName());
|
||||||
|
logEntityAction(emptyId(EntityType.RULE_CHAIN), ruleChain, null, ActionType.ADDED, e);
|
||||||
|
throw handleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
|
||||||
@RequestMapping(value = "/ruleChain/{ruleChainId}/root", method = RequestMethod.POST)
|
@RequestMapping(value = "/ruleChain/{ruleChainId}/root", method = RequestMethod.POST)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
|
|||||||
@ -57,6 +57,7 @@ public class InstallScripts {
|
|||||||
public static final String JSON_DIR = "json";
|
public static final String JSON_DIR = "json";
|
||||||
public static final String SYSTEM_DIR = "system";
|
public static final String SYSTEM_DIR = "system";
|
||||||
public static final String TENANT_DIR = "tenant";
|
public static final String TENANT_DIR = "tenant";
|
||||||
|
public static final String DEVICE_PROFILE_DIR = "device_profile";
|
||||||
public static final String DEMO_DIR = "demo";
|
public static final String DEMO_DIR = "demo";
|
||||||
public static final String RULE_CHAINS_DIR = "rule_chains";
|
public static final String RULE_CHAINS_DIR = "rule_chains";
|
||||||
public static final String WIDGET_BUNDLES_DIR = "widget_bundles";
|
public static final String WIDGET_BUNDLES_DIR = "widget_bundles";
|
||||||
@ -83,6 +84,10 @@ public class InstallScripts {
|
|||||||
return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR);
|
return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Path getDeviceProfileDefaultRuleChainTemplateFilePath() {
|
||||||
|
return Paths.get(getDataDir(), JSON_DIR, DEVICE_PROFILE_DIR, "rule_chain_template.json");
|
||||||
|
}
|
||||||
|
|
||||||
public String getDataDir() {
|
public String getDataDir() {
|
||||||
if (!StringUtils.isEmpty(dataDir)) {
|
if (!StringUtils.isEmpty(dataDir)) {
|
||||||
if (!Paths.get(this.dataDir).toFile().isDirectory()) {
|
if (!Paths.get(this.dataDir).toFile().isDirectory()) {
|
||||||
@ -110,15 +115,7 @@ public class InstallScripts {
|
|||||||
dirStream.forEach(
|
dirStream.forEach(
|
||||||
path -> {
|
path -> {
|
||||||
try {
|
try {
|
||||||
JsonNode ruleChainJson = objectMapper.readTree(path.toFile());
|
createRuleChainFromFile(tenantId, path, null);
|
||||||
RuleChain ruleChain = objectMapper.treeToValue(ruleChainJson.get("ruleChain"), RuleChain.class);
|
|
||||||
RuleChainMetaData ruleChainMetaData = objectMapper.treeToValue(ruleChainJson.get("metadata"), RuleChainMetaData.class);
|
|
||||||
|
|
||||||
ruleChain.setTenantId(tenantId);
|
|
||||||
ruleChain = ruleChainService.saveRuleChain(ruleChain);
|
|
||||||
|
|
||||||
ruleChainMetaData.setRuleChainId(ruleChain.getId());
|
|
||||||
ruleChainService.saveRuleChainMetaData(new TenantId(EntityId.NULL_UUID), ruleChainMetaData);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Unable to load rule chain from json: [{}]", path.toString());
|
log.error("Unable to load rule chain from json: [{}]", path.toString());
|
||||||
throw new RuntimeException("Unable to load rule chain from json", e);
|
throw new RuntimeException("Unable to load rule chain from json", e);
|
||||||
@ -128,6 +125,28 @@ public class InstallScripts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RuleChain createDefaultRuleChain(TenantId tenantId, String ruleChainName) throws IOException {
|
||||||
|
return createRuleChainFromFile(tenantId, getDeviceProfileDefaultRuleChainTemplateFilePath(), ruleChainName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RuleChain createRuleChainFromFile(TenantId tenantId, Path templateFilePath, String newRuleChainName) throws IOException {
|
||||||
|
JsonNode ruleChainJson = objectMapper.readTree(templateFilePath.toFile());
|
||||||
|
RuleChain ruleChain = objectMapper.treeToValue(ruleChainJson.get("ruleChain"), RuleChain.class);
|
||||||
|
RuleChainMetaData ruleChainMetaData = objectMapper.treeToValue(ruleChainJson.get("metadata"), RuleChainMetaData.class);
|
||||||
|
|
||||||
|
ruleChain.setTenantId(tenantId);
|
||||||
|
if (!StringUtils.isEmpty(newRuleChainName)) {
|
||||||
|
ruleChain.setName(newRuleChainName);
|
||||||
|
}
|
||||||
|
ruleChain = ruleChainService.saveRuleChain(ruleChain);
|
||||||
|
|
||||||
|
ruleChainMetaData.setRuleChainId(ruleChain.getId());
|
||||||
|
ruleChainService.saveRuleChainMetaData(new TenantId(EntityId.NULL_UUID), ruleChainMetaData);
|
||||||
|
|
||||||
|
return ruleChain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void loadSystemWidgets() throws Exception {
|
public void loadSystemWidgets() throws Exception {
|
||||||
Path widgetBundlesDir = Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, WIDGET_BUNDLES_DIR);
|
Path widgetBundlesDir = Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, WIDGET_BUNDLES_DIR);
|
||||||
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(JSON_EXT))) {
|
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(JSON_EXT))) {
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2020 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.common.data.rule;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Slf4j
|
||||||
|
public class DefaultRuleChainCreateRequest implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 5600333716030561537L;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.TbContext;
|
|||||||
import org.thingsboard.server.common.data.DataConstants;
|
import org.thingsboard.server.common.data.DataConstants;
|
||||||
import org.thingsboard.server.common.data.alarm.Alarm;
|
import org.thingsboard.server.common.data.alarm.Alarm;
|
||||||
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
|
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
|
||||||
|
import org.thingsboard.server.common.data.alarm.AlarmStatus;
|
||||||
import org.thingsboard.server.common.data.device.profile.AlarmCondition;
|
import org.thingsboard.server.common.data.device.profile.AlarmCondition;
|
||||||
import org.thingsboard.server.common.data.device.profile.AlarmRule;
|
import org.thingsboard.server.common.data.device.profile.AlarmRule;
|
||||||
import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
|
import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
|
||||||
@ -34,11 +35,13 @@ import org.thingsboard.server.common.data.query.NumericFilterPredicate;
|
|||||||
import org.thingsboard.server.common.data.query.StringFilterPredicate;
|
import org.thingsboard.server.common.data.query.StringFilterPredicate;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
|
import org.thingsboard.server.dao.alarm.AlarmService;
|
||||||
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
|
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
class DeviceProfileAlarmState {
|
class DeviceProfileAlarmState {
|
||||||
@ -47,6 +50,7 @@ class DeviceProfileAlarmState {
|
|||||||
private final DeviceProfileAlarm alarmDefinition;
|
private final DeviceProfileAlarm alarmDefinition;
|
||||||
private volatile Map<AlarmSeverity, AlarmRule> createRulesSortedBySeverityDesc;
|
private volatile Map<AlarmSeverity, AlarmRule> createRulesSortedBySeverityDesc;
|
||||||
private volatile Alarm currentAlarm;
|
private volatile Alarm currentAlarm;
|
||||||
|
private volatile boolean initialFetchDone;
|
||||||
|
|
||||||
public DeviceProfileAlarmState(EntityId originator, DeviceProfileAlarm alarmDefinition) {
|
public DeviceProfileAlarmState(EntityId originator, DeviceProfileAlarm alarmDefinition) {
|
||||||
this.originator = originator;
|
this.originator = originator;
|
||||||
@ -55,7 +59,15 @@ class DeviceProfileAlarmState {
|
|||||||
this.createRulesSortedBySeverityDesc.putAll(alarmDefinition.getCreateRules());
|
this.createRulesSortedBySeverityDesc.putAll(alarmDefinition.getCreateRules());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void process(TbContext ctx, TbMsg msg, DeviceDataSnapshot data) {
|
public void process(TbContext ctx, TbMsg msg, DeviceDataSnapshot data) throws ExecutionException, InterruptedException {
|
||||||
|
if (!initialFetchDone) {
|
||||||
|
Alarm alarm = ctx.getAlarmService().findLatestByOriginatorAndType(ctx.getTenantId(), originator, alarmDefinition.getAlarmType()).get();
|
||||||
|
if (alarm != null && !alarm.getStatus().isCleared()) {
|
||||||
|
currentAlarm = alarm;
|
||||||
|
}
|
||||||
|
initialFetchDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
AlarmSeverity resultSeverity = null;
|
AlarmSeverity resultSeverity = null;
|
||||||
for (Map.Entry<AlarmSeverity, AlarmRule> kv : createRulesSortedBySeverityDesc.entrySet()) {
|
for (Map.Entry<AlarmSeverity, AlarmRule> kv : createRulesSortedBySeverityDesc.entrySet()) {
|
||||||
AlarmRule alarmRule = kv.getValue();
|
AlarmRule alarmRule = kv.getValue();
|
||||||
@ -69,6 +81,7 @@ class DeviceProfileAlarmState {
|
|||||||
} else if (currentAlarm != null) {
|
} else if (currentAlarm != null) {
|
||||||
AlarmRule clearRule = alarmDefinition.getClearRule();
|
AlarmRule clearRule = alarmDefinition.getClearRule();
|
||||||
if (eval(clearRule.getCondition(), data)) {
|
if (eval(clearRule.getCondition(), data)) {
|
||||||
|
ctx.getAlarmService().clearAlarm(ctx.getTenantId(), currentAlarm.getId(), JacksonUtil.OBJECT_MAPPER.createObjectNode(), System.currentTimeMillis());
|
||||||
pushMsg(ctx, new TbAlarmResult(false, false, true, currentAlarm), msg);
|
pushMsg(ctx, new TbAlarmResult(false, false, true, currentAlarm), msg);
|
||||||
currentAlarm = null;
|
currentAlarm = null;
|
||||||
}
|
}
|
||||||
@ -112,6 +125,8 @@ class DeviceProfileAlarmState {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
currentAlarm = new Alarm();
|
currentAlarm = new Alarm();
|
||||||
|
currentAlarm.setType(alarmDefinition.getAlarmType());
|
||||||
|
currentAlarm.setStatus(AlarmStatus.ACTIVE_UNACK);
|
||||||
currentAlarm.setSeverity(severity);
|
currentAlarm.setSeverity(severity);
|
||||||
currentAlarm.setStartTs(System.currentTimeMillis());
|
currentAlarm.setStartTs(System.currentTimeMillis());
|
||||||
currentAlarm.setEndTs(currentAlarm.getStartTs());
|
currentAlarm.setEndTs(currentAlarm.getStartTs());
|
||||||
|
|||||||
@ -62,15 +62,17 @@ class DeviceState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processTelemetry(TbContext ctx, TbMsg msg) {
|
private void processTelemetry(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException {
|
||||||
Map<Long, List<KvEntry>> tsKvMap = JsonConverter.convertToSortedTelemetry(new JsonParser().parse(msg.getData()), TbMsgTimeseriesNode.getTs(msg));
|
Map<Long, List<KvEntry>> tsKvMap = JsonConverter.convertToSortedTelemetry(new JsonParser().parse(msg.getData()), TbMsgTimeseriesNode.getTs(msg));
|
||||||
tsKvMap.forEach((ts, data) -> {
|
for (Map.Entry<Long, List<KvEntry>> entry : tsKvMap.entrySet()) {
|
||||||
|
Long ts = entry.getKey();
|
||||||
|
List<KvEntry> data = entry.getValue();
|
||||||
latestValues = merge(latestValues, ts, data);
|
latestValues = merge(latestValues, ts, data);
|
||||||
for (DeviceProfileAlarm alarm : deviceProfile.getAlarmSettings()) {
|
for (DeviceProfileAlarm alarm : deviceProfile.getAlarmSettings()) {
|
||||||
DeviceProfileAlarmState alarmState = alarmStates.computeIfAbsent(alarm.getId(), a -> new DeviceProfileAlarmState(msg.getOriginator(), alarm));
|
DeviceProfileAlarmState alarmState = alarmStates.computeIfAbsent(alarm.getId(), a -> new DeviceProfileAlarmState(msg.getOriginator(), alarm));
|
||||||
alarmState.process(ctx, msg, latestValues);
|
alarmState.process(ctx, msg, latestValues);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
ctx.tellSuccess(msg);
|
ctx.tellSuccess(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,9 +142,11 @@ class DeviceState {
|
|||||||
if (!latestTsKeys.isEmpty()) {
|
if (!latestTsKeys.isEmpty()) {
|
||||||
List<TsKvEntry> data = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), originator, latestTsKeys).get();
|
List<TsKvEntry> data = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), originator, latestTsKeys).get();
|
||||||
for (TsKvEntry entry : data) {
|
for (TsKvEntry entry : data) {
|
||||||
|
if (entry.getValue() != null) {
|
||||||
result.putValue(new EntityKey(EntityKeyType.TIME_SERIES, entry.getKey()), toEntityValue(entry));
|
result.putValue(new EntityKey(EntityKeyType.TIME_SERIES, entry.getKey()), toEntityValue(entry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!clientAttributeKeys.isEmpty()) {
|
if (!clientAttributeKeys.isEmpty()) {
|
||||||
addToSnapshot(result, commonAttributeKeys,
|
addToSnapshot(result, commonAttributeKeys,
|
||||||
ctx.getAttributesService().find(ctx.getTenantId(), originator, DataConstants.CLIENT_SCOPE, clientAttributeKeys).get());
|
ctx.getAttributesService().find(ctx.getTenantId(), originator, DataConstants.CLIENT_SCOPE, clientAttributeKeys).get());
|
||||||
@ -161,6 +165,7 @@ class DeviceState {
|
|||||||
|
|
||||||
private void addToSnapshot(DeviceDataSnapshot snapshot, Set<String> commonAttributeKeys, List<AttributeKvEntry> data) {
|
private void addToSnapshot(DeviceDataSnapshot snapshot, Set<String> commonAttributeKeys, List<AttributeKvEntry> data) {
|
||||||
for (AttributeKvEntry entry : data) {
|
for (AttributeKvEntry entry : data) {
|
||||||
|
if (entry.getValue() != null) {
|
||||||
EntityKeyValue value = toEntityValue(entry);
|
EntityKeyValue value = toEntityValue(entry);
|
||||||
snapshot.putValue(new EntityKey(EntityKeyType.CLIENT_ATTRIBUTE, entry.getKey()), value);
|
snapshot.putValue(new EntityKey(EntityKeyType.CLIENT_ATTRIBUTE, entry.getKey()), value);
|
||||||
if (commonAttributeKeys.contains(entry.getKey())) {
|
if (commonAttributeKeys.contains(entry.getKey())) {
|
||||||
@ -168,6 +173,7 @@ class DeviceState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private EntityKeyValue toEntityValue(KvEntry entry) {
|
private EntityKeyValue toEntityValue(KvEntry entry) {
|
||||||
switch (entry.getDataType()) {
|
switch (entry.getDataType()) {
|
||||||
|
|||||||
@ -137,6 +137,7 @@ public class TbDeviceProfileNodeTest {
|
|||||||
alarmRule.setCondition(alarmCondition);
|
alarmRule.setCondition(alarmCondition);
|
||||||
DeviceProfileAlarm dpa = new DeviceProfileAlarm();
|
DeviceProfileAlarm dpa = new DeviceProfileAlarm();
|
||||||
dpa.setId("highTemperatureAlarmID");
|
dpa.setId("highTemperatureAlarmID");
|
||||||
|
dpa.setAlarmType("highTemperatureAlarm");
|
||||||
dpa.setCreateRules(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule));
|
dpa.setCreateRules(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule));
|
||||||
deviceProfileData.setAlarms(Collections.singletonList(dpa));
|
deviceProfileData.setAlarms(Collections.singletonList(dpa));
|
||||||
deviceProfile.setProfileData(deviceProfileData);
|
deviceProfile.setProfileData(deviceProfileData);
|
||||||
@ -144,6 +145,7 @@ public class TbDeviceProfileNodeTest {
|
|||||||
Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile);
|
Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile);
|
||||||
Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature")))
|
Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature")))
|
||||||
.thenReturn(Futures.immediateFuture(Collections.emptyList()));
|
.thenReturn(Futures.immediateFuture(Collections.emptyList()));
|
||||||
|
Mockito.when(alarmService.findLatestByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")).thenReturn(Futures.immediateFuture(null));
|
||||||
Mockito.when(alarmService.createOrUpdateAlarm(Mockito.any())).thenAnswer(AdditionalAnswers.returnsFirstArg());
|
Mockito.when(alarmService.createOrUpdateAlarm(Mockito.any())).thenAnswer(AdditionalAnswers.returnsFirstArg());
|
||||||
|
|
||||||
TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "");
|
TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user