Browse Source

Alarm Result State

pull/3592/head
Andrii Shvaika 6 years ago
parent
commit
51ac96d010
  1. 22
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmEvalResult.java
  2. 30
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java
  3. 38
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java
  4. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java

22
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmEvalResult.java

@ -0,0 +1,22 @@
/**
* 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.rule.engine.profile;
public enum AlarmEvalResult {
FALSE, NOT_YET_TRUE, TRUE;
}

30
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java

@ -123,17 +123,17 @@ class AlarmRuleState {
}
}
public boolean eval(DataSnapshot data) {
public AlarmEvalResult eval(DataSnapshot data) {
boolean active = isActive(data.getTs());
switch (spec.getType()) {
case SIMPLE:
return active && eval(alarmRule.getCondition(), data);
return (active && eval(alarmRule.getCondition(), data)) ? AlarmEvalResult.TRUE : AlarmEvalResult.FALSE;
case DURATION:
return evalDuration(data, active);
case REPEATING:
return evalRepeating(data, active);
default:
return false;
return AlarmEvalResult.FALSE;
}
}
@ -203,17 +203,17 @@ class AlarmRuleState {
}
}
private boolean evalRepeating(DataSnapshot data, boolean active) {
private AlarmEvalResult evalRepeating(DataSnapshot data, boolean active) {
if (active && eval(alarmRule.getCondition(), data)) {
state.setEventCount(state.getEventCount() + 1);
updateFlag = true;
return state.getEventCount() >= requiredRepeats;
return state.getEventCount() >= requiredRepeats ? AlarmEvalResult.TRUE : AlarmEvalResult.NOT_YET_TRUE;
} else {
return false;
return AlarmEvalResult.FALSE;
}
}
private boolean evalDuration(DataSnapshot data, boolean active) {
private AlarmEvalResult evalDuration(DataSnapshot data, boolean active) {
if (active && eval(alarmRule.getCondition(), data)) {
if (state.getLastEventTs() > 0) {
if (data.getTs() > state.getLastEventTs()) {
@ -226,24 +226,28 @@ class AlarmRuleState {
state.setDuration(0L);
updateFlag = true;
}
return state.getDuration() > requiredDurationInMs;
return state.getDuration() > requiredDurationInMs ? AlarmEvalResult.TRUE : AlarmEvalResult.NOT_YET_TRUE;
} else {
return false;
return AlarmEvalResult.FALSE;
}
}
public boolean eval(long ts) {
public AlarmEvalResult eval(long ts) {
switch (spec.getType()) {
case SIMPLE:
case REPEATING:
return false;
return AlarmEvalResult.NOT_YET_TRUE;
case DURATION:
if (requiredDurationInMs > 0 && state.getLastEventTs() > 0 && ts > state.getLastEventTs()) {
long duration = state.getDuration() + (ts - state.getLastEventTs());
return duration > requiredDurationInMs && isActive(ts);
if (isActive(ts)) {
return duration > requiredDurationInMs ? AlarmEvalResult.TRUE : AlarmEvalResult.NOT_YET_TRUE;
} else {
return AlarmEvalResult.FALSE;
}
}
default:
return false;
return AlarmEvalResult.FALSE;
}
}

38
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java

@ -72,7 +72,7 @@ class AlarmState {
return createOrClearAlarms(ctx, ts, null, AlarmRuleState::eval);
}
public <T> boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, Boolean> evalFunction) {
public <T> boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) {
boolean stateUpdate = false;
AlarmSeverity resultSeverity = null;
log.debug("[{}] processing update: {}", alarmDefinition.getId(), data);
@ -81,22 +81,28 @@ class AlarmState {
log.debug("[{}][{}] Update is not valid for current rule state", alarmDefinition.getId(), state.getSeverity());
continue;
}
boolean evalResult = evalFunction.apply(state, data);
AlarmEvalResult evalResult = evalFunction.apply(state, data);
stateUpdate |= state.checkUpdate();
if (evalResult) {
if (AlarmEvalResult.TRUE.equals(evalResult)) {
resultSeverity = state.getSeverity();
break;
} else if (AlarmEvalResult.FALSE.equals(evalResult)) {
state.clear();
stateUpdate |= state.checkUpdate();
}
}
if (resultSeverity != null) {
pushMsg(ctx, calculateAlarmResult(ctx, resultSeverity));
TbAlarmResult result = calculateAlarmResult(ctx, resultSeverity);
if (result != null) {
pushMsg(ctx, result);
}
} else if (currentAlarm != null && clearState != null) {
if (!validateUpdate(update, clearState)) {
log.debug("[{}] Update is not valid for current clear state", alarmDefinition.getId());
return stateUpdate;
}
Boolean evalResult = evalFunction.apply(clearState, data);
if (evalResult) {
AlarmEvalResult evalResult = evalFunction.apply(clearState, data);
if (AlarmEvalResult.TRUE.equals(evalResult)) {
stateUpdate |= clearState.checkUpdate();
for (AlarmRuleState state : createRulesSortedBySeverityDesc) {
state.clear();
@ -105,6 +111,9 @@ class AlarmState {
ctx.getAlarmService().clearAlarm(ctx.getTenantId(), currentAlarm.getId(), JacksonUtil.OBJECT_MAPPER.createObjectNode(), System.currentTimeMillis());
pushMsg(ctx, new TbAlarmResult(false, false, true, currentAlarm));
currentAlarm = null;
} else if (AlarmEvalResult.FALSE.equals(evalResult)) {
clearState.clear();
stateUpdate |= clearState.checkUpdate();
}
}
return stateUpdate;
@ -183,13 +192,18 @@ class AlarmState {
// Maybe we should fetch alarm every time?
currentAlarm.setEndTs(System.currentTimeMillis());
AlarmSeverity oldSeverity = currentAlarm.getSeverity();
if (!oldSeverity.equals(severity)) {
currentAlarm.setSeverity(severity);
currentAlarm = ctx.getAlarmService().createOrUpdateAlarm(currentAlarm);
return new TbAlarmResult(false, false, true, false, currentAlarm);
// Skip update if severity is decreased.
if (severity.ordinal() <= oldSeverity.ordinal()) {
if (!oldSeverity.equals(severity)) {
currentAlarm.setSeverity(severity);
currentAlarm = ctx.getAlarmService().createOrUpdateAlarm(currentAlarm);
return new TbAlarmResult(false, false, true, false, currentAlarm);
} else {
currentAlarm = ctx.getAlarmService().createOrUpdateAlarm(currentAlarm);
return new TbAlarmResult(false, true, false, false, currentAlarm);
}
} else {
currentAlarm = ctx.getAlarmService().createOrUpdateAlarm(currentAlarm);
return new TbAlarmResult(false, true, false, false, currentAlarm);
return null;
}
} else {
currentAlarm = new Alarm();

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java

@ -167,14 +167,14 @@ public class TbDeviceProfileNode implements TbNode {
protected void updateProfile(TbContext ctx, DeviceProfileId deviceProfileId) throws ExecutionException, InterruptedException {
DeviceProfile deviceProfile = cache.get(ctx.getTenantId(), deviceProfileId);
if (deviceProfile != null) {
log.info("[{}] Received device profile update notification: {}", ctx.getSelfId(), deviceProfile);
log.debug("[{}] Received device profile update notification: {}", ctx.getSelfId(), deviceProfile);
for (DeviceState state : deviceStates.values()) {
if (deviceProfile.getId().equals(state.getProfileId())) {
state.updateProfile(ctx, deviceProfile);
}
}
} else {
log.info("[{}] Received stale profile update notification: [{}]", ctx.getSelfId(), deviceProfileId);
log.debug("[{}] Received stale profile update notification: [{}]", ctx.getSelfId(), deviceProfileId);
}
}

Loading…
Cancel
Save