Commit 1daf5a44b5683a35b065f568e28498e414f95111
Committed by
Andrew Shvayka
1 parent
9531e891
alarm state improvements (added details to alarm from device profile details pattern)
Showing
1 changed file
with
47 additions
and
6 deletions
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java
@@ -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())) { |