Merge branch 'fix/device-profile' of https://github.com/YevhenBondarenko/thingsboard
This commit is contained in:
commit
1104c4e8f6
@ -232,15 +232,7 @@ class AlarmRuleState {
|
|||||||
if (specType.equals(AlarmConditionSpecType.REPEATING)) {
|
if (specType.equals(AlarmConditionSpecType.REPEATING)) {
|
||||||
RepeatingAlarmConditionSpec repeating = (RepeatingAlarmConditionSpec) spec;
|
RepeatingAlarmConditionSpec repeating = (RepeatingAlarmConditionSpec) spec;
|
||||||
|
|
||||||
repeatingTimes = repeating.getPredicate().getDefaultValue();
|
repeatingTimes = resolveDynamicValue(data, repeating.getPredicate());
|
||||||
|
|
||||||
if (repeating.getPredicate().getDynamicValue() != null &&
|
|
||||||
repeating.getPredicate().getDynamicValue().getSourceAttribute() != null) {
|
|
||||||
EntityKeyValue repeatingKeyValue = getDynamicPredicateValue(data, repeating.getPredicate().getDynamicValue());
|
|
||||||
if (repeatingKeyValue != null) {
|
|
||||||
repeatingTimes = repeatingKeyValue.getLngValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return repeatingTimes;
|
return repeatingTimes;
|
||||||
}
|
}
|
||||||
@ -253,20 +245,31 @@ class AlarmRuleState {
|
|||||||
DurationAlarmConditionSpec duration = (DurationAlarmConditionSpec) spec;
|
DurationAlarmConditionSpec duration = (DurationAlarmConditionSpec) spec;
|
||||||
TimeUnit timeUnit = duration.getUnit();
|
TimeUnit timeUnit = duration.getUnit();
|
||||||
|
|
||||||
durationTimeInMs = timeUnit.toMillis(duration.getPredicate().getDefaultValue());
|
durationTimeInMs = timeUnit.toMillis(resolveDynamicValue(data, duration.getPredicate()));
|
||||||
|
|
||||||
if (duration.getPredicate().getDynamicValue() != null &&
|
|
||||||
duration.getPredicate().getDynamicValue().getSourceAttribute() != null) {
|
|
||||||
EntityKeyValue durationKeyValue = getDynamicPredicateValue(data, duration.getPredicate().getDynamicValue());
|
|
||||||
if (durationKeyValue != null) {
|
|
||||||
durationTimeInMs = timeUnit.toMillis(durationKeyValue.getLngValue());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return durationTimeInMs;
|
return durationTimeInMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Long resolveDynamicValue(DataSnapshot data, FilterPredicateValue<? extends Number> predicate) {
|
||||||
|
DynamicValue<?> dynamicValue = predicate.getDynamicValue();
|
||||||
|
Long defaultValue = predicate.getDefaultValue().longValue();
|
||||||
|
if (dynamicValue == null || dynamicValue.getSourceAttribute() == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityKeyValue keyValue = getDynamicPredicateValue(data, dynamicValue);
|
||||||
|
if (keyValue == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var longValue = getLongValue(keyValue);
|
||||||
|
if (longValue == null) {
|
||||||
|
String sourceAttribute = dynamicValue.getSourceAttribute();
|
||||||
|
throw new NumericParseException(String.format("could not parse attribute [%s: %s] from source!", sourceAttribute, getStrValue(keyValue)));
|
||||||
|
}
|
||||||
|
return longValue;
|
||||||
|
}
|
||||||
|
|
||||||
public AlarmEvalResult eval(long ts, DataSnapshot dataSnapshot) {
|
public AlarmEvalResult eval(long ts, DataSnapshot dataSnapshot) {
|
||||||
switch (spec.getType()) {
|
switch (spec.getType()) {
|
||||||
case SIMPLE:
|
case SIMPLE:
|
||||||
@ -545,4 +548,28 @@ class AlarmRuleState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Long getLongValue(EntityKeyValue ekv) {
|
||||||
|
switch (ekv.getDataType()) {
|
||||||
|
case LONG:
|
||||||
|
return ekv.getLngValue();
|
||||||
|
case DOUBLE:
|
||||||
|
return ekv.getDblValue() != null ? ekv.getDblValue().longValue() : null;
|
||||||
|
case BOOLEAN:
|
||||||
|
return ekv.getBoolValue() != null ? (ekv.getBoolValue() ? 1 : 0L) : null;
|
||||||
|
case STRING:
|
||||||
|
try {
|
||||||
|
return Long.parseLong(ekv.getStrValue());
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
case JSON:
|
||||||
|
try {
|
||||||
|
return Long.parseLong(ekv.getJsonValue());
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,7 @@ import java.util.function.BiFunction;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
class AlarmState {
|
class AlarmState {
|
||||||
|
|
||||||
|
public static final String ERROR_MSG = "Failed to process alarm state for Device [%s]: %s";
|
||||||
private final ProfileState deviceProfile;
|
private final ProfileState deviceProfile;
|
||||||
private final EntityId originator;
|
private final EntityId originator;
|
||||||
private DeviceProfileAlarm alarmDefinition;
|
private DeviceProfileAlarm alarmDefinition;
|
||||||
@ -75,12 +76,20 @@ class AlarmState {
|
|||||||
lastMsgMetaData = msg.getMetaData();
|
lastMsgMetaData = msg.getMetaData();
|
||||||
lastMsgQueueName = msg.getQueueName();
|
lastMsgQueueName = msg.getQueueName();
|
||||||
this.dataSnapshot = data;
|
this.dataSnapshot = data;
|
||||||
|
try {
|
||||||
return createOrClearAlarms(ctx, msg, data, update, AlarmRuleState::eval);
|
return createOrClearAlarms(ctx, msg, data, update, AlarmRuleState::eval);
|
||||||
|
} catch (NumericParseException e) {
|
||||||
|
throw new RuntimeException(String.format(ERROR_MSG, originator.getId().toString(), e.getMessage()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean process(TbContext ctx, long ts) throws ExecutionException, InterruptedException {
|
public boolean process(TbContext ctx, long ts) throws ExecutionException, InterruptedException {
|
||||||
initCurrentAlarm(ctx);
|
initCurrentAlarm(ctx);
|
||||||
|
try {
|
||||||
return createOrClearAlarms(ctx, null, ts, null, (alarmState, tsParam) -> alarmState.eval(tsParam, dataSnapshot));
|
return createOrClearAlarms(ctx, null, ts, null, (alarmState, tsParam) -> alarmState.eval(tsParam, dataSnapshot));
|
||||||
|
} catch (NumericParseException e) {
|
||||||
|
throw new RuntimeException(String.format(ERROR_MSG, originator.getId().toString(), e.getMessage()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> boolean createOrClearAlarms(TbContext ctx, TbMsg msg, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) {
|
public <T> boolean createOrClearAlarms(TbContext ctx, TbMsg msg, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) {
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2022 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 class NumericParseException extends RuntimeException {
|
||||||
|
public NumericParseException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user