Commit 1daf5a44b5683a35b065f568e28498e414f95111

Authored by YevhenBondarenko
Committed by Andrew Shvayka
1 parent 9531e891

alarm state improvements (added details to alarm from device profile details pattern)

@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.rule.engine.profile; 16 package org.thingsboard.rule.engine.profile;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 import lombok.Data; 20 import lombok.Data;
20 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
21 import org.thingsboard.rule.engine.action.TbAlarmResult; 22 import org.thingsboard.rule.engine.action.TbAlarmResult;
@@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; @@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus;
29 import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; 30 import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
30 import org.thingsboard.server.common.data.id.EntityId; 31 import org.thingsboard.server.common.data.id.EntityId;
31 import org.thingsboard.server.common.data.query.EntityKeyType; 32 import org.thingsboard.server.common.data.query.EntityKeyType;
  33 +import org.thingsboard.server.common.data.query.KeyFilter;
32 import org.thingsboard.server.common.msg.TbMsg; 34 import org.thingsboard.server.common.msg.TbMsg;
33 import org.thingsboard.server.common.msg.TbMsgMetaData; 35 import org.thingsboard.server.common.msg.TbMsgMetaData;
34 import org.thingsboard.server.common.msg.queue.ServiceQueue; 36 import org.thingsboard.server.common.msg.queue.ServiceQueue;
@@ -74,7 +76,7 @@ class AlarmState { @@ -74,7 +76,7 @@ class AlarmState {
74 76
75 public <T> boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) { 77 public <T> boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) {
76 boolean stateUpdate = false; 78 boolean stateUpdate = false;
77 - AlarmSeverity resultSeverity = null; 79 + AlarmRuleState resultState = null;
78 log.debug("[{}] processing update: {}", alarmDefinition.getId(), data); 80 log.debug("[{}] processing update: {}", alarmDefinition.getId(), data);
79 for (AlarmRuleState state : createRulesSortedBySeverityDesc) { 81 for (AlarmRuleState state : createRulesSortedBySeverityDesc) {
80 if (!validateUpdate(update, state)) { 82 if (!validateUpdate(update, state)) {
@@ -84,15 +86,15 @@ class AlarmState { @@ -84,15 +86,15 @@ class AlarmState {
84 AlarmEvalResult evalResult = evalFunction.apply(state, data); 86 AlarmEvalResult evalResult = evalFunction.apply(state, data);
85 stateUpdate |= state.checkUpdate(); 87 stateUpdate |= state.checkUpdate();
86 if (AlarmEvalResult.TRUE.equals(evalResult)) { 88 if (AlarmEvalResult.TRUE.equals(evalResult)) {
87 - resultSeverity = state.getSeverity(); 89 + resultState = state;
88 break; 90 break;
89 } else if (AlarmEvalResult.FALSE.equals(evalResult)) { 91 } else if (AlarmEvalResult.FALSE.equals(evalResult)) {
90 state.clear(); 92 state.clear();
91 stateUpdate |= state.checkUpdate(); 93 stateUpdate |= state.checkUpdate();
92 } 94 }
93 } 95 }
94 - if (resultSeverity != null) {  
95 - TbAlarmResult result = calculateAlarmResult(ctx, resultSeverity); 96 + if (resultState != null) {
  97 + TbAlarmResult result = calculateAlarmResult(ctx, resultState, data);
96 if (result != null) { 98 if (result != null) {
97 pushMsg(ctx, result); 99 pushMsg(ctx, result);
98 } 100 }
@@ -187,7 +189,8 @@ class AlarmState { @@ -187,7 +189,8 @@ class AlarmState {
187 } 189 }
188 } 190 }
189 191
190 - private TbAlarmResult calculateAlarmResult(TbContext ctx, AlarmSeverity severity) { 192 + private <T> TbAlarmResult calculateAlarmResult(TbContext ctx, AlarmRuleState ruleState, T data) {
  193 + AlarmSeverity severity = ruleState.getSeverity();
191 if (currentAlarm != null) { 194 if (currentAlarm != null) {
192 // TODO: In some extremely rare cases, we might miss the event of alarm clear (If one use in-mem queue and restarted the server) or (if one manipulated the rule chain). 195 // TODO: In some extremely rare cases, we might miss the event of alarm clear (If one use in-mem queue and restarted the server) or (if one manipulated the rule chain).
193 // Maybe we should fetch alarm every time? 196 // Maybe we should fetch alarm every time?
@@ -213,7 +216,7 @@ class AlarmState { @@ -213,7 +216,7 @@ class AlarmState {
213 currentAlarm.setSeverity(severity); 216 currentAlarm.setSeverity(severity);
214 currentAlarm.setStartTs(System.currentTimeMillis()); 217 currentAlarm.setStartTs(System.currentTimeMillis());
215 currentAlarm.setEndTs(currentAlarm.getStartTs()); 218 currentAlarm.setEndTs(currentAlarm.getStartTs());
216 - currentAlarm.setDetails(JacksonUtil.OBJECT_MAPPER.createObjectNode()); 219 + currentAlarm.setDetails(createDetails(ruleState, (DataSnapshot) data));
217 currentAlarm.setOriginator(originator); 220 currentAlarm.setOriginator(originator);
218 currentAlarm.setTenantId(ctx.getTenantId()); 221 currentAlarm.setTenantId(ctx.getTenantId());
219 currentAlarm.setPropagate(alarmDefinition.isPropagate()); 222 currentAlarm.setPropagate(alarmDefinition.isPropagate());
@@ -226,6 +229,44 @@ class AlarmState { @@ -226,6 +229,44 @@ class AlarmState {
226 } 229 }
227 } 230 }
228 231
  232 + private <T> JsonNode createDetails(AlarmRuleState ruleState, DataSnapshot dataSnapshot) {
  233 + ObjectNode details = JacksonUtil.OBJECT_MAPPER.createObjectNode();
  234 + String alarmDetails = ruleState.getAlarmRule().getAlarmDetails();
  235 +
  236 + if (alarmDetails != null) {
  237 + for (KeyFilter keyFilter : ruleState.getAlarmRule().getCondition().getCondition()) {
  238 + EntityKeyValue entityKeyValue = dataSnapshot.getValue(keyFilter.getKey());
  239 + alarmDetails = alarmDetails.replaceAll(String.format("\\$\\{%s}", keyFilter.getKey().getKey()), getValueAsString(entityKeyValue));
  240 + }
  241 +
  242 + details.put("data", alarmDetails);
  243 + }
  244 +
  245 + return details;
  246 + }
  247 +
  248 + private static String getValueAsString(EntityKeyValue entityKeyValue) {
  249 + Object result = null;
  250 + switch (entityKeyValue.getDataType()) {
  251 + case STRING:
  252 + result = entityKeyValue.getStrValue();
  253 + break;
  254 + case JSON:
  255 + result = entityKeyValue.getJsonValue();
  256 + break;
  257 + case LONG:
  258 + result = String.valueOf(entityKeyValue.getLngValue());
  259 + break;
  260 + case DOUBLE:
  261 + result = String.valueOf(entityKeyValue.getDblValue());
  262 + break;
  263 + case BOOLEAN:
  264 + result = String.valueOf(entityKeyValue.getBoolValue());
  265 + break;
  266 + }
  267 + return String.valueOf(result);
  268 + }
  269 +
229 public boolean processAlarmClear(TbContext ctx, Alarm alarmNf) { 270 public boolean processAlarmClear(TbContext ctx, Alarm alarmNf) {
230 boolean updated = false; 271 boolean updated = false;
231 if (currentAlarm != null && currentAlarm.getId().equals(alarmNf.getId())) { 272 if (currentAlarm != null && currentAlarm.getId().equals(alarmNf.getId())) {