From 1278339e611537be6b4a929fa4d00e69b74f12c2 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 5 Oct 2020 15:09:57 +0300 Subject: [PATCH] DeviceProfileRuleNode --- .../data/device/profile/AlarmCondition.java | 5 +- .../device/profile/AlarmConditionSpec.java | 35 ++++++ .../profile/AlarmConditionSpecType.java | 24 ++++ .../common/data/device/profile/AlarmRule.java | 1 + .../data/device/profile/AlarmSchedule.java | 35 ++++++ .../device/profile/AlarmScheduleType.java | 24 ++++ .../data/device/profile/AnyTimeSchedule.java | 25 ++++ .../device/profile/CustomTimeSchedule.java | 33 ++++++ .../profile/CustomTimeScheduleItem.java | 30 +++++ .../profile/DurationAlarmConditionSpec.java | 32 ++++++ .../profile/RepeatingAlarmConditionSpec.java | 31 +++++ .../profile/SimpleAlarmConditionSpec.java | 26 +++++ .../device/profile/SpecificTimeSchedule.java | 35 ++++++ .../rule/engine/profile/AlarmRuleState.java | 107 +++++++++++++----- .../rule/engine/profile/DeviceState.java | 16 ++- .../engine/profile/TbDeviceProfileNode.java | 29 ++++- .../state/PersistedAlarmRuleState.java | 1 + 17 files changed, 450 insertions(+), 39 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpecType.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmScheduleType.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AnyTimeSchedule.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CustomTimeSchedule.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CustomTimeScheduleItem.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DurationAlarmConditionSpec.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/RepeatingAlarmConditionSpec.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SimpleAlarmConditionSpec.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SpecificTimeSchedule.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmCondition.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmCondition.java index f0e51903b5..32db0f730f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmCondition.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmCondition.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data.device.profile; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import org.thingsboard.server.common.data.query.KeyFilter; @@ -22,10 +23,10 @@ import java.util.List; import java.util.concurrent.TimeUnit; @Data +@JsonIgnoreProperties(ignoreUnknown = true) public class AlarmCondition { private List condition; - private TimeUnit durationUnit; - private long durationValue; + private AlarmConditionSpec spec; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java new file mode 100644 index 0000000000..8c3e841707 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java @@ -0,0 +1,35 @@ +/** + * 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.server.common.data.device.profile; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "type") +@JsonSubTypes({ + @JsonSubTypes.Type(value = SimpleAlarmConditionSpec.class, name = "SIMPLE"), + @JsonSubTypes.Type(value = DurationAlarmConditionSpec.class, name = "DURATION"), + @JsonSubTypes.Type(value = RepeatingAlarmConditionSpec.class, name = "REPEATING")}) +public interface AlarmConditionSpec { + + AlarmConditionSpecType getType(); + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpecType.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpecType.java new file mode 100644 index 0000000000..11ea8e6347 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpecType.java @@ -0,0 +1,24 @@ +/** + * 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.server.common.data.device.profile; + +public enum AlarmConditionSpecType { + + SIMPLE, + DURATION, + REPEATING + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmRule.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmRule.java index afdf8abfc5..cf830ab8de 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmRule.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmRule.java @@ -21,6 +21,7 @@ import lombok.Data; public class AlarmRule { private AlarmCondition condition; + private AlarmSchedule schedule; // Advanced private String alarmDetails; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java new file mode 100644 index 0000000000..33eb7e9b0a --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java @@ -0,0 +1,35 @@ +/** + * 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.server.common.data.device.profile; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "type") +@JsonSubTypes({ + @JsonSubTypes.Type(value = SimpleAlarmConditionSpec.class, name = "ANY_TIME"), + @JsonSubTypes.Type(value = DurationAlarmConditionSpec.class, name = "SPECIFIC_TIME"), + @JsonSubTypes.Type(value = RepeatingAlarmConditionSpec.class, name = "CUSTOM")}) +public interface AlarmSchedule { + + AlarmScheduleType getType(); + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmScheduleType.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmScheduleType.java new file mode 100644 index 0000000000..e72502a954 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmScheduleType.java @@ -0,0 +1,24 @@ +/** + * 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.server.common.data.device.profile; + +public enum AlarmScheduleType { + + ANY_TIME, + SPECIFIC_TIME, + CUSTOM + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AnyTimeSchedule.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AnyTimeSchedule.java new file mode 100644 index 0000000000..fb7e10bc22 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AnyTimeSchedule.java @@ -0,0 +1,25 @@ +/** + * 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.server.common.data.device.profile; + +public class AnyTimeSchedule implements AlarmSchedule { + + @Override + public AlarmScheduleType getType() { + return AlarmScheduleType.ANY_TIME; + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CustomTimeSchedule.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CustomTimeSchedule.java new file mode 100644 index 0000000000..7d41a72f46 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CustomTimeSchedule.java @@ -0,0 +1,33 @@ +/** + * 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.server.common.data.device.profile; + +import lombok.Data; + +import java.util.List; + +@Data +public class CustomTimeSchedule implements AlarmSchedule { + + private String timezone; + private List items; + + @Override + public AlarmScheduleType getType() { + return AlarmScheduleType.CUSTOM; + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CustomTimeScheduleItem.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CustomTimeScheduleItem.java new file mode 100644 index 0000000000..b38ec32fc9 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CustomTimeScheduleItem.java @@ -0,0 +1,30 @@ +/** + * 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.server.common.data.device.profile; + +import lombok.Data; + +import java.util.List; + +@Data +public class CustomTimeScheduleItem { + + private boolean enabled; + private Integer dayOfWeek; + private long startsOn; + private long endsOn; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DurationAlarmConditionSpec.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DurationAlarmConditionSpec.java new file mode 100644 index 0000000000..c6d54ca3ad --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DurationAlarmConditionSpec.java @@ -0,0 +1,32 @@ +/** + * 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.server.common.data.device.profile; + +import lombok.Data; + +import java.util.concurrent.TimeUnit; + +@Data +public class DurationAlarmConditionSpec implements AlarmConditionSpec { + + private TimeUnit unit; + private long value; + + @Override + public AlarmConditionSpecType getType() { + return AlarmConditionSpecType.SIMPLE; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/RepeatingAlarmConditionSpec.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/RepeatingAlarmConditionSpec.java new file mode 100644 index 0000000000..808c673cb9 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/RepeatingAlarmConditionSpec.java @@ -0,0 +1,31 @@ +/** + * 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.server.common.data.device.profile; + +import lombok.Data; + +import java.util.concurrent.TimeUnit; + +@Data +public class RepeatingAlarmConditionSpec implements AlarmConditionSpec { + + private int count; + + @Override + public AlarmConditionSpecType getType() { + return AlarmConditionSpecType.SIMPLE; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SimpleAlarmConditionSpec.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SimpleAlarmConditionSpec.java new file mode 100644 index 0000000000..e96d5dda29 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SimpleAlarmConditionSpec.java @@ -0,0 +1,26 @@ +/** + * 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.server.common.data.device.profile; + +import lombok.Data; + +@Data +public class SimpleAlarmConditionSpec implements AlarmConditionSpec { + @Override + public AlarmConditionSpecType getType() { + return AlarmConditionSpecType.SIMPLE; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SpecificTimeSchedule.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SpecificTimeSchedule.java new file mode 100644 index 0000000000..35d5c03057 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SpecificTimeSchedule.java @@ -0,0 +1,35 @@ +/** + * 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.server.common.data.device.profile; + +import lombok.Data; + +import java.util.List; + +@Data +public class SpecificTimeSchedule implements AlarmSchedule { + + private String timezone; + private List daysOfWeek; + private long startsOn; + private long endsOn; + + @Override + public AlarmScheduleType getType() { + return AlarmScheduleType.SPECIFIC_TIME; + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java index 0f1349791b..bd921ac931 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java @@ -19,7 +19,11 @@ import lombok.Data; import org.thingsboard.rule.engine.profile.state.PersistedAlarmRuleState; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.device.profile.AlarmCondition; +import org.thingsboard.server.common.data.device.profile.AlarmConditionSpec; import org.thingsboard.server.common.data.device.profile.AlarmRule; +import org.thingsboard.server.common.data.device.profile.DurationAlarmConditionSpec; +import org.thingsboard.server.common.data.device.profile.RepeatingAlarmConditionSpec; +import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec; import org.thingsboard.server.common.data.query.BooleanFilterPredicate; import org.thingsboard.server.common.data.query.ComplexFilterPredicate; import org.thingsboard.server.common.data.query.KeyFilter; @@ -32,7 +36,9 @@ public class AlarmRuleState { private final AlarmSeverity severity; private final AlarmRule alarmRule; + private final AlarmConditionSpec spec; private final long requiredDurationInMs; + private final long requiredRepeats; private PersistedAlarmRuleState state; private boolean updateFlag; @@ -42,13 +48,31 @@ public class AlarmRuleState { if (state != null) { this.state = state; } else { - this.state = new PersistedAlarmRuleState(0L, 0L); + this.state = new PersistedAlarmRuleState(0L, 0L, 0L); } - if (alarmRule.getCondition().getDurationValue() > 0) { - requiredDurationInMs = alarmRule.getCondition().getDurationUnit().toMillis(alarmRule.getCondition().getDurationValue()); - } else { - requiredDurationInMs = 0; + this.spec = getSpec(alarmRule); + long requiredDurationInMs = 0; + long requiredRepeats = 0; + switch (spec.getType()) { + case DURATION: + DurationAlarmConditionSpec duration = (DurationAlarmConditionSpec) spec; + requiredDurationInMs = duration.getUnit().toMillis(duration.getValue()); + break; + case REPEATING: + RepeatingAlarmConditionSpec repeating = (RepeatingAlarmConditionSpec) spec; + requiredRepeats = repeating.getCount(); + break; } + this.requiredDurationInMs = requiredDurationInMs; + this.requiredRepeats = requiredRepeats; + } + + public AlarmConditionSpec getSpec(AlarmRule alarmRule) { + AlarmConditionSpec spec = alarmRule.getCondition().getSpec(); + if (spec == null) { + spec = new SimpleAlarmConditionSpec(); + } + return spec; } public boolean checkUpdate() { @@ -61,38 +85,70 @@ public class AlarmRuleState { } public boolean eval(DeviceDataSnapshot data) { - if (requiredDurationInMs > 0) { - boolean eval = eval(alarmRule.getCondition(), data); - if (eval) { - if (state.getLastEventTs() > 0) { - if (data.getTs() > state.getLastEventTs()) { - state.setDuration(state.getDuration() + (data.getTs() - state.getLastEventTs())); - state.setLastEventTs(data.getTs()); - updateFlag = true; - } - } else { + switch (spec.getType()) { + case SIMPLE: + return eval(alarmRule.getCondition(), data); + case DURATION: + return evalDuration(data); + case REPEATING: + return evalRepeating(data); + default: + return false; + } + } + + private boolean evalRepeating(DeviceDataSnapshot data) { + boolean eval = eval(alarmRule.getCondition(), data); + if (eval) { + state.setEventCount(state.getEventCount() + 1); + updateFlag = true; + return state.getEventCount() > requiredRepeats; + } else { + if (state.getEventCount() > 0) { + state.setEventCount(0L); + updateFlag = true; + } + return false; + } + } + + private boolean evalDuration(DeviceDataSnapshot data) { + boolean eval = eval(alarmRule.getCondition(), data); + if (eval) { + if (state.getLastEventTs() > 0) { + if (data.getTs() > state.getLastEventTs()) { + state.setDuration(state.getDuration() + (data.getTs() - state.getLastEventTs())); state.setLastEventTs(data.getTs()); - state.setDuration(0L); updateFlag = true; } - return state.getDuration() > requiredDurationInMs; } else { - state.setLastEventTs(0L); + state.setLastEventTs(data.getTs()); state.setDuration(0L); updateFlag = true; - return false; } + return state.getDuration() > requiredDurationInMs; } else { - return eval(alarmRule.getCondition(), data); + if (state.getLastEventTs() > 0 || state.getDuration() > 0) { + state.setLastEventTs(0L); + state.setDuration(0L); + updateFlag = true; + } + return false; } } public boolean eval(long ts) { - if (requiredDurationInMs > 0 && state.getLastEventTs() > 0 && ts > state.getLastEventTs()) { - long duration = state.getDuration() + (ts - state.getLastEventTs()); - return duration > requiredDurationInMs; - } else { - return false; + switch (spec.getType()) { + case SIMPLE: + case REPEATING: + return false; + case DURATION: + if (requiredDurationInMs > 0 && state.getLastEventTs() > 0 && ts > state.getLastEventTs()) { + long duration = state.getDuration() + (ts - state.getLastEventTs()); + return duration > requiredDurationInMs; + } + default: + return false; } } @@ -144,7 +200,6 @@ public class AlarmRuleState { } } - private boolean evalBoolPredicate(EntityKeyValue ekv, BooleanFilterPredicate predicate) { Boolean value; switch (ekv.getDataType()) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java index 6ac3e2e14a..2086b1af71 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java @@ -62,18 +62,22 @@ class DeviceState { private DeviceDataSnapshot latestValues; private final ConcurrentMap alarmStates = new ConcurrentHashMap<>(); - public DeviceState(TbContext ctx, TbDeviceProfileNodeConfiguration config, DeviceId deviceId, DeviceProfileState deviceProfile) { + public DeviceState(TbContext ctx, TbDeviceProfileNodeConfiguration config, DeviceId deviceId, DeviceProfileState deviceProfile, RuleNodeState state) { this.persistState = config.isPersistAlarmRulesState(); this.deviceId = deviceId; this.deviceProfile = deviceProfile; if (config.isPersistAlarmRulesState()) { - state = ctx.findRuleNodeStateForEntity(deviceId); if (state != null) { - pds = JacksonUtil.fromString(state.getStateData(), PersistedDeviceState.class); + this.state = state; } else { - state = new RuleNodeState(); - state.setRuleNodeId(ctx.getSelfId()); - state.setEntityId(deviceId); + this.state = ctx.findRuleNodeStateForEntity(deviceId); + } + if (this.state != null) { + pds = JacksonUtil.fromString(this.state.getStateData(), PersistedDeviceState.class); + } else { + this.state = new RuleNodeState(); + this.state.setRuleNodeId(ctx.getSelfId()); + this.state.setEntityId(deviceId); pds = new PersistedDeviceState(); pds.setAlarmStates(new HashMap<>()); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java index ce01b3c103..97ec088f10 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java @@ -30,6 +30,8 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.rule.RuleNodeState; import org.thingsboard.server.common.msg.TbMsg; @@ -65,11 +67,28 @@ public class TbDeviceProfileNode implements TbNode { this.config = TbNodeUtils.convert(configuration, TbDeviceProfileNodeConfiguration.class); this.cache = ctx.getDeviceProfileCache(); scheduleAlarmHarvesting(ctx); - //TODO: launch a process of fetching the alarm rule states from the database; + if (config.isFetchAlarmRulesStateOnStart()) { + PageLink pageLink = new PageLink(1024); + while (true) { + PageData states = ctx.findRuleNodeStates(pageLink); + if (!states.getData().isEmpty()) { + for (RuleNodeState rns : states.getData()) { + if (rns.getEntityId().getEntityType().equals(EntityType.DEVICE) && ctx.isLocalEntity(rns.getEntityId())) { + getOrCreateDeviceState(ctx, new DeviceId(rns.getEntityId().getId()), rns); + } + } + } + if (!states.hasNext()) { + break; + } else { + pageLink = pageLink.nextPageLink(); + } + } + } } /** - * 2. Dynamic values evaluation; + * TODO: Dynamic values evaluation; */ @Override public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { @@ -85,7 +104,7 @@ public class TbDeviceProfileNode implements TbNode { } else if (msg.getType().equals(DataConstants.ENTITY_DELETED)) { deviceStates.remove(deviceId); } else { - DeviceState deviceState = getOrCreateDeviceState(ctx, deviceId); + DeviceState deviceState = getOrCreateDeviceState(ctx, deviceId, null); if (deviceState != null) { deviceState.process(ctx, msg); } else { @@ -124,12 +143,12 @@ public class TbDeviceProfileNode implements TbNode { deviceStates.clear(); } - protected DeviceState getOrCreateDeviceState(TbContext ctx, DeviceId deviceId) { + protected DeviceState getOrCreateDeviceState(TbContext ctx, DeviceId deviceId, RuleNodeState rns) { DeviceState deviceState = deviceStates.get(deviceId); if (deviceState == null) { DeviceProfile deviceProfile = cache.get(ctx.getTenantId(), deviceId); if (deviceProfile != null) { - deviceState = new DeviceState(ctx, config, deviceId, new DeviceProfileState(deviceProfile)); + deviceState = new DeviceState(ctx, config, deviceId, new DeviceProfileState(deviceProfile), rns); deviceStates.put(deviceId, deviceState); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/state/PersistedAlarmRuleState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/state/PersistedAlarmRuleState.java index c097d91f38..57bc424874 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/state/PersistedAlarmRuleState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/state/PersistedAlarmRuleState.java @@ -26,5 +26,6 @@ public class PersistedAlarmRuleState { private long lastEventTs; private long duration; + private long eventCount; }