Commit 51ac96d0102bb299cf86bb1ccb272aadeb03dfa5

Authored by Andrii Shvaika
1 parent 7a34e2a3

Alarm Result State

  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.profile;
  17 +
  18 +public enum AlarmEvalResult {
  19 +
  20 + FALSE, NOT_YET_TRUE, TRUE;
  21 +
  22 +}
... ...
... ... @@ -123,17 +123,17 @@ class AlarmRuleState {
123 123 }
124 124 }
125 125
126   - public boolean eval(DataSnapshot data) {
  126 + public AlarmEvalResult eval(DataSnapshot data) {
127 127 boolean active = isActive(data.getTs());
128 128 switch (spec.getType()) {
129 129 case SIMPLE:
130   - return active && eval(alarmRule.getCondition(), data);
  130 + return (active && eval(alarmRule.getCondition(), data)) ? AlarmEvalResult.TRUE : AlarmEvalResult.FALSE;
131 131 case DURATION:
132 132 return evalDuration(data, active);
133 133 case REPEATING:
134 134 return evalRepeating(data, active);
135 135 default:
136   - return false;
  136 + return AlarmEvalResult.FALSE;
137 137 }
138 138 }
139 139
... ... @@ -203,17 +203,17 @@ class AlarmRuleState {
203 203 }
204 204 }
205 205
206   - private boolean evalRepeating(DataSnapshot data, boolean active) {
  206 + private AlarmEvalResult evalRepeating(DataSnapshot data, boolean active) {
207 207 if (active && eval(alarmRule.getCondition(), data)) {
208 208 state.setEventCount(state.getEventCount() + 1);
209 209 updateFlag = true;
210   - return state.getEventCount() >= requiredRepeats;
  210 + return state.getEventCount() >= requiredRepeats ? AlarmEvalResult.TRUE : AlarmEvalResult.NOT_YET_TRUE;
211 211 } else {
212   - return false;
  212 + return AlarmEvalResult.FALSE;
213 213 }
214 214 }
215 215
216   - private boolean evalDuration(DataSnapshot data, boolean active) {
  216 + private AlarmEvalResult evalDuration(DataSnapshot data, boolean active) {
217 217 if (active && eval(alarmRule.getCondition(), data)) {
218 218 if (state.getLastEventTs() > 0) {
219 219 if (data.getTs() > state.getLastEventTs()) {
... ... @@ -226,24 +226,28 @@ class AlarmRuleState {
226 226 state.setDuration(0L);
227 227 updateFlag = true;
228 228 }
229   - return state.getDuration() > requiredDurationInMs;
  229 + return state.getDuration() > requiredDurationInMs ? AlarmEvalResult.TRUE : AlarmEvalResult.NOT_YET_TRUE;
230 230 } else {
231   - return false;
  231 + return AlarmEvalResult.FALSE;
232 232 }
233 233 }
234 234
235   - public boolean eval(long ts) {
  235 + public AlarmEvalResult eval(long ts) {
236 236 switch (spec.getType()) {
237 237 case SIMPLE:
238 238 case REPEATING:
239   - return false;
  239 + return AlarmEvalResult.NOT_YET_TRUE;
240 240 case DURATION:
241 241 if (requiredDurationInMs > 0 && state.getLastEventTs() > 0 && ts > state.getLastEventTs()) {
242 242 long duration = state.getDuration() + (ts - state.getLastEventTs());
243   - return duration > requiredDurationInMs && isActive(ts);
  243 + if (isActive(ts)) {
  244 + return duration > requiredDurationInMs ? AlarmEvalResult.TRUE : AlarmEvalResult.NOT_YET_TRUE;
  245 + } else {
  246 + return AlarmEvalResult.FALSE;
  247 + }
244 248 }
245 249 default:
246   - return false;
  250 + return AlarmEvalResult.FALSE;
247 251 }
248 252 }
249 253
... ...
... ... @@ -72,7 +72,7 @@ class AlarmState {
72 72 return createOrClearAlarms(ctx, ts, null, AlarmRuleState::eval);
73 73 }
74 74
75   - public <T> boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, Boolean> evalFunction) {
  75 + public <T> boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) {
76 76 boolean stateUpdate = false;
77 77 AlarmSeverity resultSeverity = null;
78 78 log.debug("[{}] processing update: {}", alarmDefinition.getId(), data);
... ... @@ -81,22 +81,28 @@ class AlarmState {
81 81 log.debug("[{}][{}] Update is not valid for current rule state", alarmDefinition.getId(), state.getSeverity());
82 82 continue;
83 83 }
84   - boolean evalResult = evalFunction.apply(state, data);
  84 + AlarmEvalResult evalResult = evalFunction.apply(state, data);
85 85 stateUpdate |= state.checkUpdate();
86   - if (evalResult) {
  86 + if (AlarmEvalResult.TRUE.equals(evalResult)) {
87 87 resultSeverity = state.getSeverity();
88 88 break;
  89 + } else if (AlarmEvalResult.FALSE.equals(evalResult)) {
  90 + state.clear();
  91 + stateUpdate |= state.checkUpdate();
89 92 }
90 93 }
91 94 if (resultSeverity != null) {
92   - pushMsg(ctx, calculateAlarmResult(ctx, resultSeverity));
  95 + TbAlarmResult result = calculateAlarmResult(ctx, resultSeverity);
  96 + if (result != null) {
  97 + pushMsg(ctx, result);
  98 + }
93 99 } else if (currentAlarm != null && clearState != null) {
94 100 if (!validateUpdate(update, clearState)) {
95 101 log.debug("[{}] Update is not valid for current clear state", alarmDefinition.getId());
96 102 return stateUpdate;
97 103 }
98   - Boolean evalResult = evalFunction.apply(clearState, data);
99   - if (evalResult) {
  104 + AlarmEvalResult evalResult = evalFunction.apply(clearState, data);
  105 + if (AlarmEvalResult.TRUE.equals(evalResult)) {
100 106 stateUpdate |= clearState.checkUpdate();
101 107 for (AlarmRuleState state : createRulesSortedBySeverityDesc) {
102 108 state.clear();
... ... @@ -105,6 +111,9 @@ class AlarmState {
105 111 ctx.getAlarmService().clearAlarm(ctx.getTenantId(), currentAlarm.getId(), JacksonUtil.OBJECT_MAPPER.createObjectNode(), System.currentTimeMillis());
106 112 pushMsg(ctx, new TbAlarmResult(false, false, true, currentAlarm));
107 113 currentAlarm = null;
  114 + } else if (AlarmEvalResult.FALSE.equals(evalResult)) {
  115 + clearState.clear();
  116 + stateUpdate |= clearState.checkUpdate();
108 117 }
109 118 }
110 119 return stateUpdate;
... ... @@ -183,13 +192,18 @@ class AlarmState {
183 192 // Maybe we should fetch alarm every time?
184 193 currentAlarm.setEndTs(System.currentTimeMillis());
185 194 AlarmSeverity oldSeverity = currentAlarm.getSeverity();
186   - if (!oldSeverity.equals(severity)) {
187   - currentAlarm.setSeverity(severity);
188   - currentAlarm = ctx.getAlarmService().createOrUpdateAlarm(currentAlarm);
189   - return new TbAlarmResult(false, false, true, false, currentAlarm);
  195 + // Skip update if severity is decreased.
  196 + if (severity.ordinal() <= oldSeverity.ordinal()) {
  197 + if (!oldSeverity.equals(severity)) {
  198 + currentAlarm.setSeverity(severity);
  199 + currentAlarm = ctx.getAlarmService().createOrUpdateAlarm(currentAlarm);
  200 + return new TbAlarmResult(false, false, true, false, currentAlarm);
  201 + } else {
  202 + currentAlarm = ctx.getAlarmService().createOrUpdateAlarm(currentAlarm);
  203 + return new TbAlarmResult(false, true, false, false, currentAlarm);
  204 + }
190 205 } else {
191   - currentAlarm = ctx.getAlarmService().createOrUpdateAlarm(currentAlarm);
192   - return new TbAlarmResult(false, true, false, false, currentAlarm);
  206 + return null;
193 207 }
194 208 } else {
195 209 currentAlarm = new Alarm();
... ...
... ... @@ -167,14 +167,14 @@ public class TbDeviceProfileNode implements TbNode {
167 167 protected void updateProfile(TbContext ctx, DeviceProfileId deviceProfileId) throws ExecutionException, InterruptedException {
168 168 DeviceProfile deviceProfile = cache.get(ctx.getTenantId(), deviceProfileId);
169 169 if (deviceProfile != null) {
170   - log.info("[{}] Received device profile update notification: {}", ctx.getSelfId(), deviceProfile);
  170 + log.debug("[{}] Received device profile update notification: {}", ctx.getSelfId(), deviceProfile);
171 171 for (DeviceState state : deviceStates.values()) {
172 172 if (deviceProfile.getId().equals(state.getProfileId())) {
173 173 state.updateProfile(ctx, deviceProfile);
174 174 }
175 175 }
176 176 } else {
177   - log.info("[{}] Received stale profile update notification: [{}]", ctx.getSelfId(), deviceProfileId);
  177 + log.debug("[{}] Received stale profile update notification: [{}]", ctx.getSelfId(), deviceProfileId);
178 178 }
179 179 }
180 180
... ...