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 16 package org.thingsboard.rule.engine.profile;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 20 import lombok.Data;
20 21 import lombok.extern.slf4j.Slf4j;
21 22 import org.thingsboard.rule.engine.action.TbAlarmResult;
... ... @@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus;
29 30 import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
30 31 import org.thingsboard.server.common.data.id.EntityId;
31 32 import org.thingsboard.server.common.data.query.EntityKeyType;
  33 +import org.thingsboard.server.common.data.query.KeyFilter;
32 34 import org.thingsboard.server.common.msg.TbMsg;
33 35 import org.thingsboard.server.common.msg.TbMsgMetaData;
34 36 import org.thingsboard.server.common.msg.queue.ServiceQueue;
... ... @@ -74,7 +76,7 @@ class AlarmState {
74 76
75 77 public <T> boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) {
76 78 boolean stateUpdate = false;
77   - AlarmSeverity resultSeverity = null;
  79 + AlarmRuleState resultState = null;
78 80 log.debug("[{}] processing update: {}", alarmDefinition.getId(), data);
79 81 for (AlarmRuleState state : createRulesSortedBySeverityDesc) {
80 82 if (!validateUpdate(update, state)) {
... ... @@ -84,15 +86,15 @@ class AlarmState {
84 86 AlarmEvalResult evalResult = evalFunction.apply(state, data);
85 87 stateUpdate |= state.checkUpdate();
86 88 if (AlarmEvalResult.TRUE.equals(evalResult)) {
87   - resultSeverity = state.getSeverity();
  89 + resultState = state;
88 90 break;
89 91 } else if (AlarmEvalResult.FALSE.equals(evalResult)) {
90 92 state.clear();
91 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 98 if (result != null) {
97 99 pushMsg(ctx, result);
98 100 }
... ... @@ -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 194 if (currentAlarm != null) {
192 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 196 // Maybe we should fetch alarm every time?
... ... @@ -213,7 +216,7 @@ class AlarmState {
213 216 currentAlarm.setSeverity(severity);
214 217 currentAlarm.setStartTs(System.currentTimeMillis());
215 218 currentAlarm.setEndTs(currentAlarm.getStartTs());
216   - currentAlarm.setDetails(JacksonUtil.OBJECT_MAPPER.createObjectNode());
  219 + currentAlarm.setDetails(createDetails(ruleState, (DataSnapshot) data));
217 220 currentAlarm.setOriginator(originator);
218 221 currentAlarm.setTenantId(ctx.getTenantId());
219 222 currentAlarm.setPropagate(alarmDefinition.isPropagate());
... ... @@ -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 270 public boolean processAlarmClear(TbContext ctx, Alarm alarmNf) {
230 271 boolean updated = false;
231 272 if (currentAlarm != null && currentAlarm.getId().equals(alarmNf.getId())) {
... ...