Showing
17 changed files
with
450 additions
and
39 deletions
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.common.data.device.profile; | 16 | package org.thingsboard.server.common.data.device.profile; |
17 | 17 | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
18 | import lombok.Data; | 19 | import lombok.Data; |
19 | import org.thingsboard.server.common.data.query.KeyFilter; | 20 | import org.thingsboard.server.common.data.query.KeyFilter; |
20 | 21 | ||
@@ -22,10 +23,10 @@ import java.util.List; | @@ -22,10 +23,10 @@ import java.util.List; | ||
22 | import java.util.concurrent.TimeUnit; | 23 | import java.util.concurrent.TimeUnit; |
23 | 24 | ||
24 | @Data | 25 | @Data |
26 | +@JsonIgnoreProperties(ignoreUnknown = true) | ||
25 | public class AlarmCondition { | 27 | public class AlarmCondition { |
26 | 28 | ||
27 | private List<KeyFilter> condition; | 29 | private List<KeyFilter> condition; |
28 | - private TimeUnit durationUnit; | ||
29 | - private long durationValue; | 30 | + private AlarmConditionSpec spec; |
30 | 31 | ||
31 | } | 32 | } |
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmConditionSpec.java
0 → 100644
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
19 | +import com.fasterxml.jackson.annotation.JsonSubTypes; | ||
20 | +import com.fasterxml.jackson.annotation.JsonTypeInfo; | ||
21 | + | ||
22 | +@JsonIgnoreProperties(ignoreUnknown = true) | ||
23 | +@JsonTypeInfo( | ||
24 | + use = JsonTypeInfo.Id.NAME, | ||
25 | + include = JsonTypeInfo.As.PROPERTY, | ||
26 | + property = "type") | ||
27 | +@JsonSubTypes({ | ||
28 | + @JsonSubTypes.Type(value = SimpleAlarmConditionSpec.class, name = "SIMPLE"), | ||
29 | + @JsonSubTypes.Type(value = DurationAlarmConditionSpec.class, name = "DURATION"), | ||
30 | + @JsonSubTypes.Type(value = RepeatingAlarmConditionSpec.class, name = "REPEATING")}) | ||
31 | +public interface AlarmConditionSpec { | ||
32 | + | ||
33 | + AlarmConditionSpecType getType(); | ||
34 | + | ||
35 | +} |
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +public enum AlarmConditionSpecType { | ||
19 | + | ||
20 | + SIMPLE, | ||
21 | + DURATION, | ||
22 | + REPEATING | ||
23 | + | ||
24 | +} |
@@ -21,6 +21,7 @@ import lombok.Data; | @@ -21,6 +21,7 @@ import lombok.Data; | ||
21 | public class AlarmRule { | 21 | public class AlarmRule { |
22 | 22 | ||
23 | private AlarmCondition condition; | 23 | private AlarmCondition condition; |
24 | + private AlarmSchedule schedule; | ||
24 | // Advanced | 25 | // Advanced |
25 | private String alarmDetails; | 26 | private String alarmDetails; |
26 | 27 |
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmSchedule.java
0 → 100644
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
19 | +import com.fasterxml.jackson.annotation.JsonSubTypes; | ||
20 | +import com.fasterxml.jackson.annotation.JsonTypeInfo; | ||
21 | + | ||
22 | +@JsonIgnoreProperties(ignoreUnknown = true) | ||
23 | +@JsonTypeInfo( | ||
24 | + use = JsonTypeInfo.Id.NAME, | ||
25 | + include = JsonTypeInfo.As.PROPERTY, | ||
26 | + property = "type") | ||
27 | +@JsonSubTypes({ | ||
28 | + @JsonSubTypes.Type(value = SimpleAlarmConditionSpec.class, name = "ANY_TIME"), | ||
29 | + @JsonSubTypes.Type(value = DurationAlarmConditionSpec.class, name = "SPECIFIC_TIME"), | ||
30 | + @JsonSubTypes.Type(value = RepeatingAlarmConditionSpec.class, name = "CUSTOM")}) | ||
31 | +public interface AlarmSchedule { | ||
32 | + | ||
33 | + AlarmScheduleType getType(); | ||
34 | + | ||
35 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmScheduleType.java
0 → 100644
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +public enum AlarmScheduleType { | ||
19 | + | ||
20 | + ANY_TIME, | ||
21 | + SPECIFIC_TIME, | ||
22 | + CUSTOM | ||
23 | + | ||
24 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AnyTimeSchedule.java
0 → 100644
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +public class AnyTimeSchedule implements AlarmSchedule { | ||
19 | + | ||
20 | + @Override | ||
21 | + public AlarmScheduleType getType() { | ||
22 | + return AlarmScheduleType.ANY_TIME; | ||
23 | + } | ||
24 | + | ||
25 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CustomTimeSchedule.java
0 → 100644
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | + | ||
20 | +import java.util.List; | ||
21 | + | ||
22 | +@Data | ||
23 | +public class CustomTimeSchedule implements AlarmSchedule { | ||
24 | + | ||
25 | + private String timezone; | ||
26 | + private List<CustomTimeScheduleItem> items; | ||
27 | + | ||
28 | + @Override | ||
29 | + public AlarmScheduleType getType() { | ||
30 | + return AlarmScheduleType.CUSTOM; | ||
31 | + } | ||
32 | + | ||
33 | +} |
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | + | ||
20 | +import java.util.List; | ||
21 | + | ||
22 | +@Data | ||
23 | +public class CustomTimeScheduleItem { | ||
24 | + | ||
25 | + private boolean enabled; | ||
26 | + private Integer dayOfWeek; | ||
27 | + private long startsOn; | ||
28 | + private long endsOn; | ||
29 | + | ||
30 | +} |
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | + | ||
20 | +import java.util.concurrent.TimeUnit; | ||
21 | + | ||
22 | +@Data | ||
23 | +public class DurationAlarmConditionSpec implements AlarmConditionSpec { | ||
24 | + | ||
25 | + private TimeUnit unit; | ||
26 | + private long value; | ||
27 | + | ||
28 | + @Override | ||
29 | + public AlarmConditionSpecType getType() { | ||
30 | + return AlarmConditionSpecType.SIMPLE; | ||
31 | + } | ||
32 | +} |
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | + | ||
20 | +import java.util.concurrent.TimeUnit; | ||
21 | + | ||
22 | +@Data | ||
23 | +public class RepeatingAlarmConditionSpec implements AlarmConditionSpec { | ||
24 | + | ||
25 | + private int count; | ||
26 | + | ||
27 | + @Override | ||
28 | + public AlarmConditionSpecType getType() { | ||
29 | + return AlarmConditionSpecType.SIMPLE; | ||
30 | + } | ||
31 | +} |
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | + | ||
20 | +@Data | ||
21 | +public class SimpleAlarmConditionSpec implements AlarmConditionSpec { | ||
22 | + @Override | ||
23 | + public AlarmConditionSpecType getType() { | ||
24 | + return AlarmConditionSpecType.SIMPLE; | ||
25 | + } | ||
26 | +} |
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.server.common.data.device.profile; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | + | ||
20 | +import java.util.List; | ||
21 | + | ||
22 | +@Data | ||
23 | +public class SpecificTimeSchedule implements AlarmSchedule { | ||
24 | + | ||
25 | + private String timezone; | ||
26 | + private List<Integer> daysOfWeek; | ||
27 | + private long startsOn; | ||
28 | + private long endsOn; | ||
29 | + | ||
30 | + @Override | ||
31 | + public AlarmScheduleType getType() { | ||
32 | + return AlarmScheduleType.SPECIFIC_TIME; | ||
33 | + } | ||
34 | + | ||
35 | +} |
@@ -19,7 +19,11 @@ import lombok.Data; | @@ -19,7 +19,11 @@ import lombok.Data; | ||
19 | import org.thingsboard.rule.engine.profile.state.PersistedAlarmRuleState; | 19 | import org.thingsboard.rule.engine.profile.state.PersistedAlarmRuleState; |
20 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; | 20 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
21 | import org.thingsboard.server.common.data.device.profile.AlarmCondition; | 21 | import org.thingsboard.server.common.data.device.profile.AlarmCondition; |
22 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionSpec; | ||
22 | import org.thingsboard.server.common.data.device.profile.AlarmRule; | 23 | import org.thingsboard.server.common.data.device.profile.AlarmRule; |
24 | +import org.thingsboard.server.common.data.device.profile.DurationAlarmConditionSpec; | ||
25 | +import org.thingsboard.server.common.data.device.profile.RepeatingAlarmConditionSpec; | ||
26 | +import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec; | ||
23 | import org.thingsboard.server.common.data.query.BooleanFilterPredicate; | 27 | import org.thingsboard.server.common.data.query.BooleanFilterPredicate; |
24 | import org.thingsboard.server.common.data.query.ComplexFilterPredicate; | 28 | import org.thingsboard.server.common.data.query.ComplexFilterPredicate; |
25 | import org.thingsboard.server.common.data.query.KeyFilter; | 29 | import org.thingsboard.server.common.data.query.KeyFilter; |
@@ -32,7 +36,9 @@ public class AlarmRuleState { | @@ -32,7 +36,9 @@ public class AlarmRuleState { | ||
32 | 36 | ||
33 | private final AlarmSeverity severity; | 37 | private final AlarmSeverity severity; |
34 | private final AlarmRule alarmRule; | 38 | private final AlarmRule alarmRule; |
39 | + private final AlarmConditionSpec spec; | ||
35 | private final long requiredDurationInMs; | 40 | private final long requiredDurationInMs; |
41 | + private final long requiredRepeats; | ||
36 | private PersistedAlarmRuleState state; | 42 | private PersistedAlarmRuleState state; |
37 | private boolean updateFlag; | 43 | private boolean updateFlag; |
38 | 44 | ||
@@ -42,13 +48,31 @@ public class AlarmRuleState { | @@ -42,13 +48,31 @@ public class AlarmRuleState { | ||
42 | if (state != null) { | 48 | if (state != null) { |
43 | this.state = state; | 49 | this.state = state; |
44 | } else { | 50 | } else { |
45 | - this.state = new PersistedAlarmRuleState(0L, 0L); | 51 | + this.state = new PersistedAlarmRuleState(0L, 0L, 0L); |
46 | } | 52 | } |
47 | - if (alarmRule.getCondition().getDurationValue() > 0) { | ||
48 | - requiredDurationInMs = alarmRule.getCondition().getDurationUnit().toMillis(alarmRule.getCondition().getDurationValue()); | ||
49 | - } else { | ||
50 | - requiredDurationInMs = 0; | 53 | + this.spec = getSpec(alarmRule); |
54 | + long requiredDurationInMs = 0; | ||
55 | + long requiredRepeats = 0; | ||
56 | + switch (spec.getType()) { | ||
57 | + case DURATION: | ||
58 | + DurationAlarmConditionSpec duration = (DurationAlarmConditionSpec) spec; | ||
59 | + requiredDurationInMs = duration.getUnit().toMillis(duration.getValue()); | ||
60 | + break; | ||
61 | + case REPEATING: | ||
62 | + RepeatingAlarmConditionSpec repeating = (RepeatingAlarmConditionSpec) spec; | ||
63 | + requiredRepeats = repeating.getCount(); | ||
64 | + break; | ||
51 | } | 65 | } |
66 | + this.requiredDurationInMs = requiredDurationInMs; | ||
67 | + this.requiredRepeats = requiredRepeats; | ||
68 | + } | ||
69 | + | ||
70 | + public AlarmConditionSpec getSpec(AlarmRule alarmRule) { | ||
71 | + AlarmConditionSpec spec = alarmRule.getCondition().getSpec(); | ||
72 | + if (spec == null) { | ||
73 | + spec = new SimpleAlarmConditionSpec(); | ||
74 | + } | ||
75 | + return spec; | ||
52 | } | 76 | } |
53 | 77 | ||
54 | public boolean checkUpdate() { | 78 | public boolean checkUpdate() { |
@@ -61,38 +85,70 @@ public class AlarmRuleState { | @@ -61,38 +85,70 @@ public class AlarmRuleState { | ||
61 | } | 85 | } |
62 | 86 | ||
63 | public boolean eval(DeviceDataSnapshot data) { | 87 | public boolean eval(DeviceDataSnapshot data) { |
64 | - if (requiredDurationInMs > 0) { | ||
65 | - boolean eval = eval(alarmRule.getCondition(), data); | ||
66 | - if (eval) { | ||
67 | - if (state.getLastEventTs() > 0) { | ||
68 | - if (data.getTs() > state.getLastEventTs()) { | ||
69 | - state.setDuration(state.getDuration() + (data.getTs() - state.getLastEventTs())); | ||
70 | - state.setLastEventTs(data.getTs()); | ||
71 | - updateFlag = true; | ||
72 | - } | ||
73 | - } else { | 88 | + switch (spec.getType()) { |
89 | + case SIMPLE: | ||
90 | + return eval(alarmRule.getCondition(), data); | ||
91 | + case DURATION: | ||
92 | + return evalDuration(data); | ||
93 | + case REPEATING: | ||
94 | + return evalRepeating(data); | ||
95 | + default: | ||
96 | + return false; | ||
97 | + } | ||
98 | + } | ||
99 | + | ||
100 | + private boolean evalRepeating(DeviceDataSnapshot data) { | ||
101 | + boolean eval = eval(alarmRule.getCondition(), data); | ||
102 | + if (eval) { | ||
103 | + state.setEventCount(state.getEventCount() + 1); | ||
104 | + updateFlag = true; | ||
105 | + return state.getEventCount() > requiredRepeats; | ||
106 | + } else { | ||
107 | + if (state.getEventCount() > 0) { | ||
108 | + state.setEventCount(0L); | ||
109 | + updateFlag = true; | ||
110 | + } | ||
111 | + return false; | ||
112 | + } | ||
113 | + } | ||
114 | + | ||
115 | + private boolean evalDuration(DeviceDataSnapshot data) { | ||
116 | + boolean eval = eval(alarmRule.getCondition(), data); | ||
117 | + if (eval) { | ||
118 | + if (state.getLastEventTs() > 0) { | ||
119 | + if (data.getTs() > state.getLastEventTs()) { | ||
120 | + state.setDuration(state.getDuration() + (data.getTs() - state.getLastEventTs())); | ||
74 | state.setLastEventTs(data.getTs()); | 121 | state.setLastEventTs(data.getTs()); |
75 | - state.setDuration(0L); | ||
76 | updateFlag = true; | 122 | updateFlag = true; |
77 | } | 123 | } |
78 | - return state.getDuration() > requiredDurationInMs; | ||
79 | } else { | 124 | } else { |
80 | - state.setLastEventTs(0L); | 125 | + state.setLastEventTs(data.getTs()); |
81 | state.setDuration(0L); | 126 | state.setDuration(0L); |
82 | updateFlag = true; | 127 | updateFlag = true; |
83 | - return false; | ||
84 | } | 128 | } |
129 | + return state.getDuration() > requiredDurationInMs; | ||
85 | } else { | 130 | } else { |
86 | - return eval(alarmRule.getCondition(), data); | 131 | + if (state.getLastEventTs() > 0 || state.getDuration() > 0) { |
132 | + state.setLastEventTs(0L); | ||
133 | + state.setDuration(0L); | ||
134 | + updateFlag = true; | ||
135 | + } | ||
136 | + return false; | ||
87 | } | 137 | } |
88 | } | 138 | } |
89 | 139 | ||
90 | public boolean eval(long ts) { | 140 | public boolean eval(long ts) { |
91 | - if (requiredDurationInMs > 0 && state.getLastEventTs() > 0 && ts > state.getLastEventTs()) { | ||
92 | - long duration = state.getDuration() + (ts - state.getLastEventTs()); | ||
93 | - return duration > requiredDurationInMs; | ||
94 | - } else { | ||
95 | - return false; | 141 | + switch (spec.getType()) { |
142 | + case SIMPLE: | ||
143 | + case REPEATING: | ||
144 | + return false; | ||
145 | + case DURATION: | ||
146 | + if (requiredDurationInMs > 0 && state.getLastEventTs() > 0 && ts > state.getLastEventTs()) { | ||
147 | + long duration = state.getDuration() + (ts - state.getLastEventTs()); | ||
148 | + return duration > requiredDurationInMs; | ||
149 | + } | ||
150 | + default: | ||
151 | + return false; | ||
96 | } | 152 | } |
97 | } | 153 | } |
98 | 154 | ||
@@ -144,7 +200,6 @@ public class AlarmRuleState { | @@ -144,7 +200,6 @@ public class AlarmRuleState { | ||
144 | } | 200 | } |
145 | } | 201 | } |
146 | 202 | ||
147 | - | ||
148 | private boolean evalBoolPredicate(EntityKeyValue ekv, BooleanFilterPredicate predicate) { | 203 | private boolean evalBoolPredicate(EntityKeyValue ekv, BooleanFilterPredicate predicate) { |
149 | Boolean value; | 204 | Boolean value; |
150 | switch (ekv.getDataType()) { | 205 | switch (ekv.getDataType()) { |
@@ -62,18 +62,22 @@ class DeviceState { | @@ -62,18 +62,22 @@ class DeviceState { | ||
62 | private DeviceDataSnapshot latestValues; | 62 | private DeviceDataSnapshot latestValues; |
63 | private final ConcurrentMap<String, DeviceProfileAlarmState> alarmStates = new ConcurrentHashMap<>(); | 63 | private final ConcurrentMap<String, DeviceProfileAlarmState> alarmStates = new ConcurrentHashMap<>(); |
64 | 64 | ||
65 | - public DeviceState(TbContext ctx, TbDeviceProfileNodeConfiguration config, DeviceId deviceId, DeviceProfileState deviceProfile) { | 65 | + public DeviceState(TbContext ctx, TbDeviceProfileNodeConfiguration config, DeviceId deviceId, DeviceProfileState deviceProfile, RuleNodeState state) { |
66 | this.persistState = config.isPersistAlarmRulesState(); | 66 | this.persistState = config.isPersistAlarmRulesState(); |
67 | this.deviceId = deviceId; | 67 | this.deviceId = deviceId; |
68 | this.deviceProfile = deviceProfile; | 68 | this.deviceProfile = deviceProfile; |
69 | if (config.isPersistAlarmRulesState()) { | 69 | if (config.isPersistAlarmRulesState()) { |
70 | - state = ctx.findRuleNodeStateForEntity(deviceId); | ||
71 | if (state != null) { | 70 | if (state != null) { |
72 | - pds = JacksonUtil.fromString(state.getStateData(), PersistedDeviceState.class); | 71 | + this.state = state; |
73 | } else { | 72 | } else { |
74 | - state = new RuleNodeState(); | ||
75 | - state.setRuleNodeId(ctx.getSelfId()); | ||
76 | - state.setEntityId(deviceId); | 73 | + this.state = ctx.findRuleNodeStateForEntity(deviceId); |
74 | + } | ||
75 | + if (this.state != null) { | ||
76 | + pds = JacksonUtil.fromString(this.state.getStateData(), PersistedDeviceState.class); | ||
77 | + } else { | ||
78 | + this.state = new RuleNodeState(); | ||
79 | + this.state.setRuleNodeId(ctx.getSelfId()); | ||
80 | + this.state.setEntityId(deviceId); | ||
77 | pds = new PersistedDeviceState(); | 81 | pds = new PersistedDeviceState(); |
78 | pds.setAlarmStates(new HashMap<>()); | 82 | pds.setAlarmStates(new HashMap<>()); |
79 | } | 83 | } |
@@ -30,6 +30,8 @@ import org.thingsboard.server.common.data.DeviceProfile; | @@ -30,6 +30,8 @@ import org.thingsboard.server.common.data.DeviceProfile; | ||
30 | import org.thingsboard.server.common.data.EntityType; | 30 | import org.thingsboard.server.common.data.EntityType; |
31 | import org.thingsboard.server.common.data.id.DeviceId; | 31 | import org.thingsboard.server.common.data.id.DeviceId; |
32 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 32 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
33 | +import org.thingsboard.server.common.data.page.PageData; | ||
34 | +import org.thingsboard.server.common.data.page.PageLink; | ||
33 | import org.thingsboard.server.common.data.plugin.ComponentType; | 35 | import org.thingsboard.server.common.data.plugin.ComponentType; |
34 | import org.thingsboard.server.common.data.rule.RuleNodeState; | 36 | import org.thingsboard.server.common.data.rule.RuleNodeState; |
35 | import org.thingsboard.server.common.msg.TbMsg; | 37 | import org.thingsboard.server.common.msg.TbMsg; |
@@ -65,11 +67,28 @@ public class TbDeviceProfileNode implements TbNode { | @@ -65,11 +67,28 @@ public class TbDeviceProfileNode implements TbNode { | ||
65 | this.config = TbNodeUtils.convert(configuration, TbDeviceProfileNodeConfiguration.class); | 67 | this.config = TbNodeUtils.convert(configuration, TbDeviceProfileNodeConfiguration.class); |
66 | this.cache = ctx.getDeviceProfileCache(); | 68 | this.cache = ctx.getDeviceProfileCache(); |
67 | scheduleAlarmHarvesting(ctx); | 69 | scheduleAlarmHarvesting(ctx); |
68 | - //TODO: launch a process of fetching the alarm rule states from the database; | 70 | + if (config.isFetchAlarmRulesStateOnStart()) { |
71 | + PageLink pageLink = new PageLink(1024); | ||
72 | + while (true) { | ||
73 | + PageData<RuleNodeState> states = ctx.findRuleNodeStates(pageLink); | ||
74 | + if (!states.getData().isEmpty()) { | ||
75 | + for (RuleNodeState rns : states.getData()) { | ||
76 | + if (rns.getEntityId().getEntityType().equals(EntityType.DEVICE) && ctx.isLocalEntity(rns.getEntityId())) { | ||
77 | + getOrCreateDeviceState(ctx, new DeviceId(rns.getEntityId().getId()), rns); | ||
78 | + } | ||
79 | + } | ||
80 | + } | ||
81 | + if (!states.hasNext()) { | ||
82 | + break; | ||
83 | + } else { | ||
84 | + pageLink = pageLink.nextPageLink(); | ||
85 | + } | ||
86 | + } | ||
87 | + } | ||
69 | } | 88 | } |
70 | 89 | ||
71 | /** | 90 | /** |
72 | - * 2. Dynamic values evaluation; | 91 | + * TODO: Dynamic values evaluation; |
73 | */ | 92 | */ |
74 | @Override | 93 | @Override |
75 | public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { | 94 | public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { |
@@ -85,7 +104,7 @@ public class TbDeviceProfileNode implements TbNode { | @@ -85,7 +104,7 @@ public class TbDeviceProfileNode implements TbNode { | ||
85 | } else if (msg.getType().equals(DataConstants.ENTITY_DELETED)) { | 104 | } else if (msg.getType().equals(DataConstants.ENTITY_DELETED)) { |
86 | deviceStates.remove(deviceId); | 105 | deviceStates.remove(deviceId); |
87 | } else { | 106 | } else { |
88 | - DeviceState deviceState = getOrCreateDeviceState(ctx, deviceId); | 107 | + DeviceState deviceState = getOrCreateDeviceState(ctx, deviceId, null); |
89 | if (deviceState != null) { | 108 | if (deviceState != null) { |
90 | deviceState.process(ctx, msg); | 109 | deviceState.process(ctx, msg); |
91 | } else { | 110 | } else { |
@@ -124,12 +143,12 @@ public class TbDeviceProfileNode implements TbNode { | @@ -124,12 +143,12 @@ public class TbDeviceProfileNode implements TbNode { | ||
124 | deviceStates.clear(); | 143 | deviceStates.clear(); |
125 | } | 144 | } |
126 | 145 | ||
127 | - protected DeviceState getOrCreateDeviceState(TbContext ctx, DeviceId deviceId) { | 146 | + protected DeviceState getOrCreateDeviceState(TbContext ctx, DeviceId deviceId, RuleNodeState rns) { |
128 | DeviceState deviceState = deviceStates.get(deviceId); | 147 | DeviceState deviceState = deviceStates.get(deviceId); |
129 | if (deviceState == null) { | 148 | if (deviceState == null) { |
130 | DeviceProfile deviceProfile = cache.get(ctx.getTenantId(), deviceId); | 149 | DeviceProfile deviceProfile = cache.get(ctx.getTenantId(), deviceId); |
131 | if (deviceProfile != null) { | 150 | if (deviceProfile != null) { |
132 | - deviceState = new DeviceState(ctx, config, deviceId, new DeviceProfileState(deviceProfile)); | 151 | + deviceState = new DeviceState(ctx, config, deviceId, new DeviceProfileState(deviceProfile), rns); |
133 | deviceStates.put(deviceId, deviceState); | 152 | deviceStates.put(deviceId, deviceState); |
134 | } | 153 | } |
135 | } | 154 | } |