diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java index a2dc9b50f4..b69719f1a0 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java @@ -485,7 +485,6 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM private void initState(CalculatedFieldState state, CalculatedFieldCtx ctx) { state.setCtx(ctx, actorCtx); - state.init(false); if (ctx.getCfType() == CalculatedFieldType.GEOFENCING && ctx.isCfHasRelationPathQuerySource()) { GeofencingCalculatedFieldState geofencingState = (GeofencingCalculatedFieldState) state; @@ -494,6 +493,7 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM Map arguments = fetchArguments(ctx); state.update(arguments, ctx); + state.init(false); state.checkStateSize(new CalculatedFieldEntityCtxId(tenantId, ctx.getCfId(), entityId), ctx.getMaxStateSize()); states.put(ctx.getCfId(), state); diff --git a/application/src/test/java/org/thingsboard/server/cf/AlarmRulesTest.java b/application/src/test/java/org/thingsboard/server/cf/AlarmRulesTest.java index cf94940e07..3a1446fb46 100644 --- a/application/src/test/java/org/thingsboard/server/cf/AlarmRulesTest.java +++ b/application/src/test/java/org/thingsboard/server/cf/AlarmRulesTest.java @@ -402,6 +402,54 @@ public class AlarmRulesTest extends AbstractControllerTest { }); } + @Test + public void testChangeDurationConditionFromStaticToDynamic() throws Exception { + Argument temperatureArgument = new Argument(); + temperatureArgument.setRefEntityKey(new ReferencedEntityKey("temperature", ArgumentType.TS_LATEST, null)); + temperatureArgument.setDefaultValue("0"); + Map arguments = new HashMap<>(Map.of( + "temperature", temperatureArgument + )); + + long staticDurationMs = 5000L; + Map createRules = Map.of( + AlarmSeverity.CRITICAL, new Condition("return temperature >= 50;", null, staticDurationMs) + ); + + CalculatedField calculatedField = createAlarmCf(deviceId, "High Temperature Alarm", + arguments, createRules, null); + + // post telemetry to trigger condition, so that firstEventTs > 0 in AlarmRuleState + postTelemetry(deviceId, "{\"temperature\":50}"); + Thread.sleep(1000); + + // update CF: add attribute argument and switch duration from static to dynamic + AlarmCalculatedFieldConfiguration configuration = + (AlarmCalculatedFieldConfiguration) calculatedField.getConfiguration(); + + Argument durationArgument = new Argument(); + durationArgument.setRefEntityKey(new ReferencedEntityKey("durationThreshold", + ArgumentType.ATTRIBUTE, AttributeScope.SERVER_SCOPE)); + durationArgument.setDefaultValue("-1"); + configuration.getArguments().put("durationThreshold", durationArgument); + + DurationAlarmCondition durationCondition = (DurationAlarmCondition) + configuration.getCreateRules().get(AlarmSeverity.CRITICAL).getCondition(); + durationCondition.setValue(new AlarmConditionValue<>(null, "durationThreshold")); + + calculatedField = saveCalculatedField(calculatedField); + + long dynamicDurationMs = 3000L; + postAttributes(deviceId, AttributeScope.SERVER_SCOPE, + "{\"durationThreshold\":" + dynamicDurationMs + "}"); + + checkAlarmResult(calculatedField, alarmResult -> { + assertThat(alarmResult.isCreated()).isTrue(); + assertThat(alarmResult.getAlarm().getSeverity()).isEqualTo(AlarmSeverity.CRITICAL); + assertThat(alarmResult.getAlarm().getStatus()).isEqualTo(AlarmStatus.ACTIVE_UNACK); + }); + } + @Test public void testCreateAlarm_currentOwnerArgument() throws Exception { Argument temperatureArgument = new Argument();