Commit 3cd964327a2686f6f2f6db4b8cccdd67b20a10dc
Committed by
Andrew Shvayka
1 parent
72374979
Constant filters for device profile
Showing
12 changed files
with
414 additions
and
181 deletions
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
... | ... | @@ -36,6 +36,9 @@ import org.thingsboard.server.common.data.TenantProfile; |
36 | 36 | import org.thingsboard.server.common.data.User; |
37 | 37 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
38 | 38 | import org.thingsboard.server.common.data.device.profile.AlarmCondition; |
39 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; | |
40 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; | |
41 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; | |
39 | 42 | import org.thingsboard.server.common.data.device.profile.AlarmRule; |
40 | 43 | import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; |
41 | 44 | import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; |
... | ... | @@ -290,16 +293,16 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
290 | 293 | AlarmCondition temperatureCondition = new AlarmCondition(); |
291 | 294 | temperatureCondition.setSpec(new SimpleAlarmConditionSpec()); |
292 | 295 | |
293 | - KeyFilter temperatureAlarmFlagAttributeFilter = new KeyFilter(); | |
294 | - temperatureAlarmFlagAttributeFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperatureAlarmFlag")); | |
296 | + AlarmConditionFilter temperatureAlarmFlagAttributeFilter = new AlarmConditionFilter(); | |
297 | + temperatureAlarmFlagAttributeFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.ATTRIBUTE, "temperatureAlarmFlag")); | |
295 | 298 | temperatureAlarmFlagAttributeFilter.setValueType(EntityKeyValueType.BOOLEAN); |
296 | 299 | BooleanFilterPredicate temperatureAlarmFlagAttributePredicate = new BooleanFilterPredicate(); |
297 | 300 | temperatureAlarmFlagAttributePredicate.setOperation(BooleanFilterPredicate.BooleanOperation.EQUAL); |
298 | 301 | temperatureAlarmFlagAttributePredicate.setValue(new FilterPredicateValue<>(Boolean.TRUE)); |
299 | 302 | temperatureAlarmFlagAttributeFilter.setPredicate(temperatureAlarmFlagAttributePredicate); |
300 | 303 | |
301 | - KeyFilter temperatureTimeseriesFilter = new KeyFilter(); | |
302 | - temperatureTimeseriesFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")); | |
304 | + AlarmConditionFilter temperatureTimeseriesFilter = new AlarmConditionFilter(); | |
305 | + temperatureTimeseriesFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
303 | 306 | temperatureTimeseriesFilter.setValueType(EntityKeyValueType.NUMERIC); |
304 | 307 | NumericFilterPredicate temperatureTimeseriesFilterPredicate = new NumericFilterPredicate(); |
305 | 308 | temperatureTimeseriesFilterPredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); |
... | ... | @@ -317,8 +320,8 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
317 | 320 | AlarmCondition clearTemperatureCondition = new AlarmCondition(); |
318 | 321 | clearTemperatureCondition.setSpec(new SimpleAlarmConditionSpec()); |
319 | 322 | |
320 | - KeyFilter clearTemperatureTimeseriesFilter = new KeyFilter(); | |
321 | - clearTemperatureTimeseriesFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")); | |
323 | + AlarmConditionFilter clearTemperatureTimeseriesFilter = new AlarmConditionFilter(); | |
324 | + clearTemperatureTimeseriesFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
322 | 325 | clearTemperatureTimeseriesFilter.setValueType(EntityKeyValueType.NUMERIC); |
323 | 326 | NumericFilterPredicate clearTemperatureTimeseriesFilterPredicate = new NumericFilterPredicate(); |
324 | 327 | clearTemperatureTimeseriesFilterPredicate.setOperation(NumericFilterPredicate.NumericOperation.LESS_OR_EQUAL); |
... | ... | @@ -340,16 +343,16 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
340 | 343 | AlarmCondition humidityCondition = new AlarmCondition(); |
341 | 344 | humidityCondition.setSpec(new SimpleAlarmConditionSpec()); |
342 | 345 | |
343 | - KeyFilter humidityAlarmFlagAttributeFilter = new KeyFilter(); | |
344 | - humidityAlarmFlagAttributeFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "humidityAlarmFlag")); | |
346 | + AlarmConditionFilter humidityAlarmFlagAttributeFilter = new AlarmConditionFilter(); | |
347 | + humidityAlarmFlagAttributeFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.ATTRIBUTE, "humidityAlarmFlag")); | |
345 | 348 | humidityAlarmFlagAttributeFilter.setValueType(EntityKeyValueType.BOOLEAN); |
346 | 349 | BooleanFilterPredicate humidityAlarmFlagAttributePredicate = new BooleanFilterPredicate(); |
347 | 350 | humidityAlarmFlagAttributePredicate.setOperation(BooleanFilterPredicate.BooleanOperation.EQUAL); |
348 | 351 | humidityAlarmFlagAttributePredicate.setValue(new FilterPredicateValue<>(Boolean.TRUE)); |
349 | 352 | humidityAlarmFlagAttributeFilter.setPredicate(humidityAlarmFlagAttributePredicate); |
350 | 353 | |
351 | - KeyFilter humidityTimeseriesFilter = new KeyFilter(); | |
352 | - humidityTimeseriesFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "humidity")); | |
354 | + AlarmConditionFilter humidityTimeseriesFilter = new AlarmConditionFilter(); | |
355 | + humidityTimeseriesFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "humidity")); | |
353 | 356 | humidityTimeseriesFilter.setValueType(EntityKeyValueType.NUMERIC); |
354 | 357 | NumericFilterPredicate humidityTimeseriesFilterPredicate = new NumericFilterPredicate(); |
355 | 358 | humidityTimeseriesFilterPredicate.setOperation(NumericFilterPredicate.NumericOperation.LESS); |
... | ... | @@ -368,8 +371,8 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
368 | 371 | AlarmCondition clearHumidityCondition = new AlarmCondition(); |
369 | 372 | clearHumidityCondition.setSpec(new SimpleAlarmConditionSpec()); |
370 | 373 | |
371 | - KeyFilter clearHumidityTimeseriesFilter = new KeyFilter(); | |
372 | - clearHumidityTimeseriesFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "humidity")); | |
374 | + AlarmConditionFilter clearHumidityTimeseriesFilter = new AlarmConditionFilter(); | |
375 | + clearHumidityTimeseriesFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "humidity")); | |
373 | 376 | clearHumidityTimeseriesFilter.setValueType(EntityKeyValueType.NUMERIC); |
374 | 377 | NumericFilterPredicate clearHumidityTimeseriesFilterPredicate = new NumericFilterPredicate(); |
375 | 378 | clearHumidityTimeseriesFilterPredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER_OR_EQUAL); | ... | ... |
... | ... | @@ -26,7 +26,7 @@ import java.util.concurrent.TimeUnit; |
26 | 26 | @JsonIgnoreProperties(ignoreUnknown = true) |
27 | 27 | public class AlarmCondition { |
28 | 28 | |
29 | - private List<KeyFilter> condition; | |
29 | + private List<AlarmConditionFilter> condition; | |
30 | 30 | private AlarmConditionSpec spec; |
31 | 31 | |
32 | 32 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 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 | +import org.thingsboard.server.common.data.query.EntityKeyValueType; | |
20 | +import org.thingsboard.server.common.data.query.KeyFilterPredicate; | |
21 | + | |
22 | +@Data | |
23 | +public class AlarmConditionFilter { | |
24 | + | |
25 | + private AlarmConditionFilterKey key; | |
26 | + private EntityKeyValueType valueType; | |
27 | + private Object value; | |
28 | + private KeyFilterPredicate predicate; | |
29 | + | |
30 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 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 AlarmConditionFilterKey { | |
22 | + | |
23 | + private final AlarmConditionKeyType type; | |
24 | + private final String key; | |
25 | + | |
26 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 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 AlarmConditionKeyType { | |
19 | + ATTRIBUTE, | |
20 | + TIME_SERIES, | |
21 | + ENTITY_FIELD, | |
22 | + CONSTANT | |
23 | +} | ... | ... |
... | ... | @@ -16,9 +16,13 @@ |
16 | 16 | package org.thingsboard.rule.engine.profile; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | +import lombok.extern.slf4j.Slf4j; | |
19 | 20 | import org.thingsboard.rule.engine.profile.state.PersistedAlarmRuleState; |
20 | 21 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
21 | 22 | import org.thingsboard.server.common.data.device.profile.AlarmCondition; |
23 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; | |
24 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; | |
25 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; | |
22 | 26 | import org.thingsboard.server.common.data.device.profile.AlarmConditionSpec; |
23 | 27 | import org.thingsboard.server.common.data.device.profile.AlarmRule; |
24 | 28 | import org.thingsboard.server.common.data.device.profile.CustomTimeSchedule; |
... | ... | @@ -45,6 +49,7 @@ import java.util.Set; |
45 | 49 | import java.util.function.Function; |
46 | 50 | |
47 | 51 | @Data |
52 | +@Slf4j | |
48 | 53 | class AlarmRuleState { |
49 | 54 | |
50 | 55 | private final AlarmSeverity severity; |
... | ... | @@ -52,12 +57,12 @@ class AlarmRuleState { |
52 | 57 | private final AlarmConditionSpec spec; |
53 | 58 | private final long requiredDurationInMs; |
54 | 59 | private final long requiredRepeats; |
55 | - private final Set<EntityKey> entityKeys; | |
60 | + private final Set<AlarmConditionFilterKey> entityKeys; | |
56 | 61 | private PersistedAlarmRuleState state; |
57 | 62 | private boolean updateFlag; |
58 | 63 | private final DynamicPredicateValueCtx dynamicPredicateValueCtx; |
59 | 64 | |
60 | - AlarmRuleState(AlarmSeverity severity, AlarmRule alarmRule, Set<EntityKey> entityKeys, PersistedAlarmRuleState state, DynamicPredicateValueCtx dynamicPredicateValueCtx) { | |
65 | + AlarmRuleState(AlarmSeverity severity, AlarmRule alarmRule, Set<AlarmConditionFilterKey> entityKeys, PersistedAlarmRuleState state, DynamicPredicateValueCtx dynamicPredicateValueCtx) { | |
61 | 66 | this.severity = severity; |
62 | 67 | this.alarmRule = alarmRule; |
63 | 68 | this.entityKeys = entityKeys; |
... | ... | @@ -84,8 +89,8 @@ class AlarmRuleState { |
84 | 89 | this.dynamicPredicateValueCtx = dynamicPredicateValueCtx; |
85 | 90 | } |
86 | 91 | |
87 | - public boolean validateTsUpdate(Set<EntityKey> changedKeys) { | |
88 | - for (EntityKey key : changedKeys) { | |
92 | + public boolean validateTsUpdate(Set<AlarmConditionFilterKey> changedKeys) { | |
93 | + for (AlarmConditionFilterKey key : changedKeys) { | |
89 | 94 | if (entityKeys.contains(key)) { |
90 | 95 | return true; |
91 | 96 | } |
... | ... | @@ -93,18 +98,14 @@ class AlarmRuleState { |
93 | 98 | return false; |
94 | 99 | } |
95 | 100 | |
96 | - public boolean validateAttrUpdate(Set<EntityKey> changedKeys) { | |
101 | + public boolean validateAttrUpdate(Set<AlarmConditionFilterKey> changedKeys) { | |
97 | 102 | //If the attribute was updated, but no new telemetry arrived - we ignore this until new telemetry is there. |
98 | - for (EntityKey key : entityKeys) { | |
99 | - if (key.getType().equals(EntityKeyType.TIME_SERIES)) { | |
103 | + for (AlarmConditionFilterKey key : entityKeys) { | |
104 | + if (key.getType().equals(AlarmConditionKeyType.TIME_SERIES)) { | |
100 | 105 | return false; |
101 | 106 | } |
102 | 107 | } |
103 | - for (EntityKey key : changedKeys) { | |
104 | - EntityKeyType keyType = key.getType(); | |
105 | - if (EntityKeyType.CLIENT_ATTRIBUTE.equals(keyType) || EntityKeyType.SERVER_ATTRIBUTE.equals(keyType) || EntityKeyType.SHARED_ATTRIBUTE.equals(keyType)) { | |
106 | - key = new EntityKey(EntityKeyType.ATTRIBUTE, key.getKey()); | |
107 | - } | |
108 | + for (AlarmConditionFilterKey key : changedKeys) { | |
108 | 109 | if (entityKeys.contains(key)) { |
109 | 110 | return true; |
110 | 111 | } |
... | ... | @@ -259,16 +260,46 @@ class AlarmRuleState { |
259 | 260 | |
260 | 261 | private boolean eval(AlarmCondition condition, DataSnapshot data) { |
261 | 262 | boolean eval = true; |
262 | - for (KeyFilter keyFilter : condition.getCondition()) { | |
263 | - EntityKeyValue value = data.getValue(keyFilter.getKey()); | |
263 | + for (var filter : condition.getCondition()) { | |
264 | + EntityKeyValue value; | |
265 | + if (filter.getKey().getType().equals(AlarmConditionKeyType.CONSTANT)) { | |
266 | + try { | |
267 | + value = getConstantValue(filter); | |
268 | + } catch (RuntimeException e) { | |
269 | + log.warn("Failed to parse constant value from filter: {}", filter, e); | |
270 | + value = null; | |
271 | + } | |
272 | + } else { | |
273 | + value = data.getValue(filter.getKey()); | |
274 | + } | |
264 | 275 | if (value == null) { |
265 | 276 | return false; |
266 | 277 | } |
267 | - eval = eval && eval(data, value, keyFilter.getPredicate()); | |
278 | + eval = eval && eval(data, value, filter.getPredicate()); | |
268 | 279 | } |
269 | 280 | return eval; |
270 | 281 | } |
271 | 282 | |
283 | + private EntityKeyValue getConstantValue(AlarmConditionFilter filter) { | |
284 | + EntityKeyValue value = new EntityKeyValue(); | |
285 | + String valueStr = filter.getValue().toString(); | |
286 | + switch (filter.getValueType()) { | |
287 | + case STRING: | |
288 | + value.setStrValue(valueStr); | |
289 | + break; | |
290 | + case DATE_TIME: | |
291 | + value.setLngValue(Long.valueOf(valueStr)); | |
292 | + break; | |
293 | + case NUMERIC: | |
294 | + value.setDblValue(Double.valueOf(valueStr)); | |
295 | + break; | |
296 | + case BOOLEAN: | |
297 | + value.setBoolValue(Boolean.valueOf(valueStr)); | |
298 | + break; | |
299 | + } | |
300 | + return value; | |
301 | + } | |
302 | + | |
272 | 303 | private boolean eval(DataSnapshot data, EntityKeyValue value, KeyFilterPredicate predicate) { |
273 | 304 | switch (predicate.getType()) { |
274 | 305 | case STRING: |
... | ... | @@ -389,23 +420,14 @@ class AlarmRuleState { |
389 | 420 | if (value.getDynamicValue() != null) { |
390 | 421 | switch (value.getDynamicValue().getSourceType()) { |
391 | 422 | case CURRENT_DEVICE: |
392 | - ekv = data.getValue(new EntityKey(EntityKeyType.ATTRIBUTE, value.getDynamicValue().getSourceAttribute())); | |
393 | - if (ekv == null) { | |
394 | - ekv = data.getValue(new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, value.getDynamicValue().getSourceAttribute())); | |
395 | - if (ekv == null) { | |
396 | - ekv = data.getValue(new EntityKey(EntityKeyType.SHARED_ATTRIBUTE, value.getDynamicValue().getSourceAttribute())); | |
397 | - if (ekv == null) { | |
398 | - ekv = data.getValue(new EntityKey(EntityKeyType.CLIENT_ATTRIBUTE, value.getDynamicValue().getSourceAttribute())); | |
399 | - } | |
400 | - } | |
401 | - } | |
402 | - if(ekv != null || !value.getDynamicValue().isInherit()) { | |
423 | + ekv = data.getValue(new AlarmConditionFilterKey(AlarmConditionKeyType.ATTRIBUTE, value.getDynamicValue().getSourceAttribute())); | |
424 | + if (ekv != null || !value.getDynamicValue().isInherit()) { | |
403 | 425 | break; |
404 | 426 | } |
405 | 427 | case CURRENT_CUSTOMER: |
406 | 428 | ekv = dynamicPredicateValueCtx.getCustomerValue(value.getDynamicValue().getSourceAttribute()); |
407 | - if(ekv != null || !value.getDynamicValue().isInherit()) { | |
408 | - break; | |
429 | + if (ekv != null || !value.getDynamicValue().isInherit()) { | |
430 | + break; | |
409 | 431 | } |
410 | 432 | case CURRENT_TENANT: |
411 | 433 | ekv = dynamicPredicateValueCtx.getTenantValue(value.getDynamicValue().getSourceAttribute()); | ... | ... |
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java
... | ... | @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.Tenant; |
29 | 29 | import org.thingsboard.server.common.data.alarm.Alarm; |
30 | 30 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
31 | 31 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
32 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; | |
32 | 33 | import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; |
33 | 34 | import org.thingsboard.server.common.data.id.CustomerId; |
34 | 35 | import org.thingsboard.server.common.data.id.EntityId; |
... | ... | @@ -138,9 +139,9 @@ class AlarmState { |
138 | 139 | public boolean validateUpdate(SnapshotUpdate update, AlarmRuleState state) { |
139 | 140 | if (update != null) { |
140 | 141 | //Check that the update type and that keys match. |
141 | - if (update.getType().equals(EntityKeyType.TIME_SERIES)) { | |
142 | + if (update.getType().equals(AlarmConditionKeyType.TIME_SERIES)) { | |
142 | 143 | return state.validateTsUpdate(update.getKeys()); |
143 | - } else if (update.getType().equals(EntityKeyType.ATTRIBUTE)) { | |
144 | + } else if (update.getType().equals(AlarmConditionKeyType.ATTRIBUTE)) { | |
144 | 145 | return state.validateAttrUpdate(update.getKeys()); |
145 | 146 | } |
146 | 147 | } |
... | ... | @@ -252,7 +253,7 @@ class AlarmState { |
252 | 253 | String alarmDetailsStr = ruleState.getAlarmRule().getAlarmDetails(); |
253 | 254 | |
254 | 255 | if (StringUtils.isNotEmpty(alarmDetailsStr)) { |
255 | - for (KeyFilter keyFilter : ruleState.getAlarmRule().getCondition().getCondition()) { | |
256 | + for (var keyFilter : ruleState.getAlarmRule().getCondition().getCondition()) { | |
256 | 257 | EntityKeyValue entityKeyValue = dataSnapshot.getValue(keyFilter.getKey()); |
257 | 258 | alarmDetailsStr = alarmDetailsStr.replaceAll(String.format("\\$\\{%s}", keyFilter.getKey().getKey()), getValueAsString(entityKeyValue)); |
258 | 259 | } | ... | ... |
... | ... | @@ -17,6 +17,8 @@ package org.thingsboard.rule.engine.profile; |
17 | 17 | |
18 | 18 | import lombok.Getter; |
19 | 19 | import lombok.Setter; |
20 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; | |
21 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; | |
20 | 22 | import org.thingsboard.server.common.data.query.EntityKey; |
21 | 23 | import org.thingsboard.server.common.data.query.EntityKeyType; |
22 | 24 | |
... | ... | @@ -30,55 +32,42 @@ class DataSnapshot { |
30 | 32 | @Getter |
31 | 33 | @Setter |
32 | 34 | private long ts; |
33 | - private final Set<EntityKey> keys; | |
34 | - private final Map<EntityKey, EntityKeyValue> values = new ConcurrentHashMap<>(); | |
35 | + private final Set<AlarmConditionFilterKey> keys; | |
36 | + private final Map<AlarmConditionFilterKey, EntityKeyValue> values = new ConcurrentHashMap<>(); | |
35 | 37 | |
36 | - DataSnapshot(Set<EntityKey> entityKeysToFetch) { | |
38 | + DataSnapshot(Set<AlarmConditionFilterKey> entityKeysToFetch) { | |
37 | 39 | this.keys = entityKeysToFetch; |
38 | 40 | } |
39 | 41 | |
40 | - void removeValue(EntityKey key) { | |
41 | - switch (key.getType()) { | |
42 | - case ATTRIBUTE: | |
43 | - values.remove(key); | |
44 | - values.remove(getAttrKey(key, EntityKeyType.CLIENT_ATTRIBUTE)); | |
45 | - values.remove(getAttrKey(key, EntityKeyType.SHARED_ATTRIBUTE)); | |
46 | - values.remove(getAttrKey(key, EntityKeyType.SERVER_ATTRIBUTE)); | |
47 | - break; | |
48 | - case CLIENT_ATTRIBUTE: | |
49 | - case SHARED_ATTRIBUTE: | |
50 | - case SERVER_ATTRIBUTE: | |
51 | - values.remove(key); | |
52 | - values.remove(getAttrKey(key, EntityKeyType.ATTRIBUTE)); | |
53 | - break; | |
54 | - default: | |
55 | - values.remove(key); | |
56 | - } | |
42 | + static AlarmConditionFilterKey toConditionKey(EntityKey key) { | |
43 | + return new AlarmConditionFilterKey(toConditionKeyType(key.getType()), key.getKey()); | |
57 | 44 | } |
58 | 45 | |
59 | - boolean putValue(EntityKey key, long newTs, EntityKeyValue value) { | |
60 | - boolean updateOfTs = ts != newTs; | |
61 | - boolean result = false; | |
62 | - switch (key.getType()) { | |
46 | + static AlarmConditionKeyType toConditionKeyType(EntityKeyType keyType) { | |
47 | + switch (keyType) { | |
63 | 48 | case ATTRIBUTE: |
64 | - result |= putIfKeyExists(key, value, updateOfTs); | |
65 | - result |= putIfKeyExists(getAttrKey(key, EntityKeyType.CLIENT_ATTRIBUTE), value, updateOfTs); | |
66 | - result |= putIfKeyExists(getAttrKey(key, EntityKeyType.SHARED_ATTRIBUTE), value, updateOfTs); | |
67 | - result |= putIfKeyExists(getAttrKey(key, EntityKeyType.SERVER_ATTRIBUTE), value, updateOfTs); | |
68 | - break; | |
69 | - case CLIENT_ATTRIBUTE: | |
70 | - case SHARED_ATTRIBUTE: | |
71 | 49 | case SERVER_ATTRIBUTE: |
72 | - result |= putIfKeyExists(key, value, updateOfTs); | |
73 | - result |= putIfKeyExists(getAttrKey(key, EntityKeyType.ATTRIBUTE), value, updateOfTs); | |
74 | - break; | |
50 | + case SHARED_ATTRIBUTE: | |
51 | + case CLIENT_ATTRIBUTE: | |
52 | + return AlarmConditionKeyType.ATTRIBUTE; | |
53 | + case TIME_SERIES: | |
54 | + return AlarmConditionKeyType.TIME_SERIES; | |
55 | + case ENTITY_FIELD: | |
56 | + return AlarmConditionKeyType.ENTITY_FIELD; | |
75 | 57 | default: |
76 | - result |= putIfKeyExists(key, value, updateOfTs); | |
58 | + throw new RuntimeException("Not supported entity key: " + keyType.name()); | |
77 | 59 | } |
78 | - return result; | |
79 | 60 | } |
80 | 61 | |
81 | - private boolean putIfKeyExists(EntityKey key, EntityKeyValue value, boolean updateOfTs) { | |
62 | + void removeValue(EntityKey key) { | |
63 | + values.remove(toConditionKey(key)); | |
64 | + } | |
65 | + | |
66 | + boolean putValue(AlarmConditionFilterKey key, long newTs, EntityKeyValue value) { | |
67 | + return putIfKeyExists(key, value, ts != newTs); | |
68 | + } | |
69 | + | |
70 | + private boolean putIfKeyExists(AlarmConditionFilterKey key, EntityKeyValue value, boolean updateOfTs) { | |
82 | 71 | if (keys.contains(key)) { |
83 | 72 | EntityKeyValue oldValue = values.put(key, value); |
84 | 73 | if (updateOfTs) { |
... | ... | @@ -91,25 +80,7 @@ class DataSnapshot { |
91 | 80 | } |
92 | 81 | } |
93 | 82 | |
94 | - EntityKeyValue getValue(EntityKey key) { | |
95 | - if (EntityKeyType.ATTRIBUTE.equals(key.getType())) { | |
96 | - EntityKeyValue value = values.get(key); | |
97 | - if (value == null) { | |
98 | - value = values.get(getAttrKey(key, EntityKeyType.CLIENT_ATTRIBUTE)); | |
99 | - if (value == null) { | |
100 | - value = values.get(getAttrKey(key, EntityKeyType.SHARED_ATTRIBUTE)); | |
101 | - if (value == null) { | |
102 | - value = values.get(getAttrKey(key, EntityKeyType.SERVER_ATTRIBUTE)); | |
103 | - } | |
104 | - } | |
105 | - } | |
106 | - return value; | |
107 | - } else { | |
108 | - return values.get(key); | |
109 | - } | |
110 | - } | |
111 | - | |
112 | - private EntityKey getAttrKey(EntityKey key, EntityKeyType clientAttribute) { | |
113 | - return new EntityKey(clientAttribute, key.getKey()); | |
83 | + EntityKeyValue getValue(AlarmConditionFilterKey key) { | |
84 | + return values.get(key); | |
114 | 85 | } |
115 | 86 | } | ... | ... |
... | ... | @@ -26,6 +26,8 @@ import org.thingsboard.server.common.data.DataConstants; |
26 | 26 | import org.thingsboard.server.common.data.Device; |
27 | 27 | import org.thingsboard.server.common.data.DeviceProfile; |
28 | 28 | import org.thingsboard.server.common.data.alarm.Alarm; |
29 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; | |
30 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; | |
29 | 31 | import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; |
30 | 32 | import org.thingsboard.server.common.data.id.DeviceId; |
31 | 33 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
... | ... | @@ -97,10 +99,10 @@ class DeviceState { |
97 | 99 | } |
98 | 100 | |
99 | 101 | public void updateProfile(TbContext ctx, DeviceProfile deviceProfile) throws ExecutionException, InterruptedException { |
100 | - Set<EntityKey> oldKeys = this.deviceProfile.getEntityKeys(); | |
102 | + Set<AlarmConditionFilterKey> oldKeys = this.deviceProfile.getEntityKeys(); | |
101 | 103 | this.deviceProfile.updateDeviceProfile(deviceProfile); |
102 | 104 | if (latestValues != null) { |
103 | - Set<EntityKey> keysToFetch = new HashSet<>(this.deviceProfile.getEntityKeys()); | |
105 | + Set<AlarmConditionFilterKey> keysToFetch = new HashSet<>(this.deviceProfile.getEntityKeys()); | |
104 | 106 | keysToFetch.removeAll(oldKeys); |
105 | 107 | if (!keysToFetch.isEmpty()) { |
106 | 108 | addEntityKeysToSnapshot(ctx, deviceId, keysToFetch, latestValues); |
... | ... | @@ -260,29 +262,29 @@ class DeviceState { |
260 | 262 | } |
261 | 263 | |
262 | 264 | private SnapshotUpdate merge(DataSnapshot latestValues, Long newTs, List<KvEntry> data) { |
263 | - Set<EntityKey> keys = new HashSet<>(); | |
265 | + Set<AlarmConditionFilterKey> keys = new HashSet<>(); | |
264 | 266 | for (KvEntry entry : data) { |
265 | - EntityKey entityKey = new EntityKey(EntityKeyType.TIME_SERIES, entry.getKey()); | |
267 | + AlarmConditionFilterKey entityKey = new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, entry.getKey()); | |
266 | 268 | if (latestValues.putValue(entityKey, newTs, toEntityValue(entry))) { |
267 | 269 | keys.add(entityKey); |
268 | 270 | } |
269 | 271 | } |
270 | 272 | latestValues.setTs(newTs); |
271 | - return new SnapshotUpdate(EntityKeyType.TIME_SERIES, keys); | |
273 | + return new SnapshotUpdate(AlarmConditionKeyType.TIME_SERIES, keys); | |
272 | 274 | } |
273 | 275 | |
274 | 276 | private SnapshotUpdate merge(DataSnapshot latestValues, Set<AttributeKvEntry> attributes, String scope) { |
275 | 277 | long newTs = 0; |
276 | - Set<EntityKey> keys = new HashSet<>(); | |
278 | + Set<AlarmConditionFilterKey> keys = new HashSet<>(); | |
277 | 279 | for (AttributeKvEntry entry : attributes) { |
278 | 280 | newTs = Math.max(newTs, entry.getLastUpdateTs()); |
279 | - EntityKey entityKey = new EntityKey(getKeyTypeFromScope(scope), entry.getKey()); | |
281 | + AlarmConditionFilterKey entityKey = new AlarmConditionFilterKey(AlarmConditionKeyType.ATTRIBUTE, entry.getKey()); | |
280 | 282 | if (latestValues.putValue(entityKey, newTs, toEntityValue(entry))) { |
281 | 283 | keys.add(entityKey); |
282 | 284 | } |
283 | 285 | } |
284 | 286 | latestValues.setTs(newTs); |
285 | - return new SnapshotUpdate(EntityKeyType.ATTRIBUTE, keys); | |
287 | + return new SnapshotUpdate(AlarmConditionKeyType.ATTRIBUTE, keys); | |
286 | 288 | } |
287 | 289 | |
288 | 290 | private static EntityKeyType getKeyTypeFromScope(String scope) { |
... | ... | @@ -298,37 +300,22 @@ class DeviceState { |
298 | 300 | } |
299 | 301 | |
300 | 302 | private DataSnapshot fetchLatestValues(TbContext ctx, EntityId originator) throws ExecutionException, InterruptedException { |
301 | - Set<EntityKey> entityKeysToFetch = deviceProfile.getEntityKeys(); | |
303 | + Set<AlarmConditionFilterKey> entityKeysToFetch = deviceProfile.getEntityKeys(); | |
302 | 304 | DataSnapshot result = new DataSnapshot(entityKeysToFetch); |
303 | 305 | addEntityKeysToSnapshot(ctx, originator, entityKeysToFetch, result); |
304 | 306 | return result; |
305 | 307 | } |
306 | 308 | |
307 | - private void addEntityKeysToSnapshot(TbContext ctx, EntityId originator, Set<EntityKey> entityKeysToFetch, DataSnapshot result) throws InterruptedException, ExecutionException { | |
308 | - Set<String> serverAttributeKeys = new HashSet<>(); | |
309 | - Set<String> clientAttributeKeys = new HashSet<>(); | |
310 | - Set<String> sharedAttributeKeys = new HashSet<>(); | |
311 | - Set<String> commonAttributeKeys = new HashSet<>(); | |
309 | + private void addEntityKeysToSnapshot(TbContext ctx, EntityId originator, Set<AlarmConditionFilterKey> entityKeysToFetch, DataSnapshot result) throws InterruptedException, ExecutionException { | |
310 | + Set<String> attributeKeys = new HashSet<>(); | |
312 | 311 | Set<String> latestTsKeys = new HashSet<>(); |
313 | 312 | |
314 | 313 | Device device = null; |
315 | - for (EntityKey entityKey : entityKeysToFetch) { | |
314 | + for (AlarmConditionFilterKey entityKey : entityKeysToFetch) { | |
316 | 315 | String key = entityKey.getKey(); |
317 | 316 | switch (entityKey.getType()) { |
318 | - case SERVER_ATTRIBUTE: | |
319 | - serverAttributeKeys.add(key); | |
320 | - break; | |
321 | - case CLIENT_ATTRIBUTE: | |
322 | - clientAttributeKeys.add(key); | |
323 | - break; | |
324 | - case SHARED_ATTRIBUTE: | |
325 | - sharedAttributeKeys.add(key); | |
326 | - break; | |
327 | 317 | case ATTRIBUTE: |
328 | - serverAttributeKeys.add(key); | |
329 | - clientAttributeKeys.add(key); | |
330 | - sharedAttributeKeys.add(key); | |
331 | - commonAttributeKeys.add(key); | |
318 | + attributeKeys.add(key); | |
332 | 319 | break; |
333 | 320 | case TIME_SERIES: |
334 | 321 | latestTsKeys.add(key); |
... | ... | @@ -361,32 +348,22 @@ class DeviceState { |
361 | 348 | List<TsKvEntry> data = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), originator, latestTsKeys).get(); |
362 | 349 | for (TsKvEntry entry : data) { |
363 | 350 | if (entry.getValue() != null) { |
364 | - result.putValue(new EntityKey(EntityKeyType.TIME_SERIES, entry.getKey()), entry.getTs(), toEntityValue(entry)); | |
351 | + result.putValue(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, entry.getKey()), entry.getTs(), toEntityValue(entry)); | |
365 | 352 | } |
366 | 353 | } |
367 | 354 | } |
368 | - if (!clientAttributeKeys.isEmpty()) { | |
369 | - addToSnapshot(result, commonAttributeKeys, | |
370 | - ctx.getAttributesService().find(ctx.getTenantId(), originator, DataConstants.CLIENT_SCOPE, clientAttributeKeys).get()); | |
371 | - } | |
372 | - if (!sharedAttributeKeys.isEmpty()) { | |
373 | - addToSnapshot(result, commonAttributeKeys, | |
374 | - ctx.getAttributesService().find(ctx.getTenantId(), originator, DataConstants.SHARED_SCOPE, sharedAttributeKeys).get()); | |
375 | - } | |
376 | - if (!serverAttributeKeys.isEmpty()) { | |
377 | - addToSnapshot(result, commonAttributeKeys, | |
378 | - ctx.getAttributesService().find(ctx.getTenantId(), originator, DataConstants.SERVER_SCOPE, serverAttributeKeys).get()); | |
355 | + if (!attributeKeys.isEmpty()) { | |
356 | + addToSnapshot(result, ctx.getAttributesService().find(ctx.getTenantId(), originator, DataConstants.CLIENT_SCOPE, attributeKeys).get()); | |
357 | + addToSnapshot(result, ctx.getAttributesService().find(ctx.getTenantId(), originator, DataConstants.SHARED_SCOPE, attributeKeys).get()); | |
358 | + addToSnapshot(result, ctx.getAttributesService().find(ctx.getTenantId(), originator, DataConstants.SERVER_SCOPE, attributeKeys).get()); | |
379 | 359 | } |
380 | 360 | } |
381 | 361 | |
382 | - private void addToSnapshot(DataSnapshot snapshot, Set<String> commonAttributeKeys, List<AttributeKvEntry> data) { | |
362 | + private void addToSnapshot(DataSnapshot snapshot, List<AttributeKvEntry> data) { | |
383 | 363 | for (AttributeKvEntry entry : data) { |
384 | 364 | if (entry.getValue() != null) { |
385 | 365 | EntityKeyValue value = toEntityValue(entry); |
386 | - snapshot.putValue(new EntityKey(EntityKeyType.CLIENT_ATTRIBUTE, entry.getKey()), entry.getLastUpdateTs(), value); | |
387 | - if (commonAttributeKeys.contains(entry.getKey())) { | |
388 | - snapshot.putValue(new EntityKey(EntityKeyType.ATTRIBUTE, entry.getKey()), entry.getLastUpdateTs(), value); | |
389 | - } | |
366 | + snapshot.putValue(new AlarmConditionFilterKey(AlarmConditionKeyType.ATTRIBUTE, entry.getKey()), entry.getLastUpdateTs(), value); | |
390 | 367 | } |
391 | 368 | } |
392 | 369 | } | ... | ... |
... | ... | @@ -19,6 +19,9 @@ import lombok.AccessLevel; |
19 | 19 | import lombok.Getter; |
20 | 20 | import org.thingsboard.server.common.data.DeviceProfile; |
21 | 21 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
22 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; | |
23 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; | |
24 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; | |
22 | 25 | import org.thingsboard.server.common.data.device.profile.AlarmRule; |
23 | 26 | import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; |
24 | 27 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
... | ... | @@ -50,10 +53,10 @@ class ProfileState { |
50 | 53 | @Getter(AccessLevel.PACKAGE) |
51 | 54 | private final List<DeviceProfileAlarm> alarmSettings = new CopyOnWriteArrayList<>(); |
52 | 55 | @Getter(AccessLevel.PACKAGE) |
53 | - private final Set<EntityKey> entityKeys = ConcurrentHashMap.newKeySet(); | |
56 | + private final Set<AlarmConditionFilterKey> entityKeys = ConcurrentHashMap.newKeySet(); | |
54 | 57 | |
55 | - private final Map<String, Map<AlarmSeverity, Set<EntityKey>>> alarmCreateKeys = new HashMap<>(); | |
56 | - private final Map<String, Set<EntityKey>> alarmClearKeys = new HashMap<>(); | |
58 | + private final Map<String, Map<AlarmSeverity, Set<AlarmConditionFilterKey>>> alarmCreateKeys = new HashMap<>(); | |
59 | + private final Map<String, Set<AlarmConditionFilterKey>> alarmClearKeys = new HashMap<>(); | |
57 | 60 | |
58 | 61 | ProfileState(DeviceProfile deviceProfile) { |
59 | 62 | updateDeviceProfile(deviceProfile); |
... | ... | @@ -68,18 +71,18 @@ class ProfileState { |
68 | 71 | if (deviceProfile.getProfileData().getAlarms() != null) { |
69 | 72 | alarmSettings.addAll(deviceProfile.getProfileData().getAlarms()); |
70 | 73 | for (DeviceProfileAlarm alarm : deviceProfile.getProfileData().getAlarms()) { |
71 | - Map<AlarmSeverity, Set<EntityKey>> createAlarmKeys = alarmCreateKeys.computeIfAbsent(alarm.getId(), id -> new HashMap<>()); | |
74 | + Map<AlarmSeverity, Set<AlarmConditionFilterKey>> createAlarmKeys = alarmCreateKeys.computeIfAbsent(alarm.getId(), id -> new HashMap<>()); | |
72 | 75 | alarm.getCreateRules().forEach(((severity, alarmRule) -> { |
73 | - Set<EntityKey> ruleKeys = createAlarmKeys.computeIfAbsent(severity, id -> new HashSet<>()); | |
74 | - for (KeyFilter keyFilter : alarmRule.getCondition().getCondition()) { | |
76 | + var ruleKeys = createAlarmKeys.computeIfAbsent(severity, id -> new HashSet<>()); | |
77 | + for (var keyFilter : alarmRule.getCondition().getCondition()) { | |
75 | 78 | entityKeys.add(keyFilter.getKey()); |
76 | 79 | ruleKeys.add(keyFilter.getKey()); |
77 | 80 | addDynamicValuesRecursively(keyFilter.getPredicate(), entityKeys, ruleKeys); |
78 | 81 | } |
79 | 82 | })); |
80 | 83 | if (alarm.getClearRule() != null) { |
81 | - Set<EntityKey> clearAlarmKeys = alarmClearKeys.computeIfAbsent(alarm.getId(), id -> new HashSet<>()); | |
82 | - for (KeyFilter keyFilter : alarm.getClearRule().getCondition().getCondition()) { | |
84 | + var clearAlarmKeys = alarmClearKeys.computeIfAbsent(alarm.getId(), id -> new HashSet<>()); | |
85 | + for (var keyFilter : alarm.getClearRule().getCondition().getCondition()) { | |
83 | 86 | entityKeys.add(keyFilter.getKey()); |
84 | 87 | clearAlarmKeys.add(keyFilter.getKey()); |
85 | 88 | addDynamicValuesRecursively(keyFilter.getPredicate(), entityKeys, clearAlarmKeys); |
... | ... | @@ -89,7 +92,7 @@ class ProfileState { |
89 | 92 | } |
90 | 93 | } |
91 | 94 | |
92 | - private void addDynamicValuesRecursively(KeyFilterPredicate predicate, Set<EntityKey> entityKeys, Set<EntityKey> ruleKeys) { | |
95 | + private void addDynamicValuesRecursively(KeyFilterPredicate predicate, Set<AlarmConditionFilterKey> entityKeys, Set<AlarmConditionFilterKey> ruleKeys) { | |
93 | 96 | switch (predicate.getType()) { |
94 | 97 | case STRING: |
95 | 98 | case NUMERIC: |
... | ... | @@ -98,7 +101,7 @@ class ProfileState { |
98 | 101 | if (value != null && (value.getSourceType() == DynamicValueSourceType.CURRENT_TENANT || |
99 | 102 | value.getSourceType() == DynamicValueSourceType.CURRENT_CUSTOMER || |
100 | 103 | value.getSourceType() == DynamicValueSourceType.CURRENT_DEVICE)) { |
101 | - EntityKey entityKey = new EntityKey(EntityKeyType.ATTRIBUTE, value.getSourceAttribute()); | |
104 | + AlarmConditionFilterKey entityKey = new AlarmConditionFilterKey(AlarmConditionKeyType.ATTRIBUTE, value.getSourceAttribute()); | |
102 | 105 | entityKeys.add(entityKey); |
103 | 106 | ruleKeys.add(entityKey); |
104 | 107 | } |
... | ... | @@ -115,12 +118,12 @@ class ProfileState { |
115 | 118 | return deviceProfile.getId(); |
116 | 119 | } |
117 | 120 | |
118 | - Set<EntityKey> getCreateAlarmKeys(String id, AlarmSeverity severity) { | |
119 | - Map<AlarmSeverity, Set<EntityKey>> sKeys = alarmCreateKeys.get(id); | |
121 | + Set<AlarmConditionFilterKey> getCreateAlarmKeys(String id, AlarmSeverity severity) { | |
122 | + Map<AlarmSeverity, Set<AlarmConditionFilterKey>> sKeys = alarmCreateKeys.get(id); | |
120 | 123 | if (sKeys == null) { |
121 | 124 | return Collections.emptySet(); |
122 | 125 | } else { |
123 | - Set<EntityKey> keys = sKeys.get(severity); | |
126 | + Set<AlarmConditionFilterKey> keys = sKeys.get(severity); | |
124 | 127 | if (keys == null) { |
125 | 128 | return Collections.emptySet(); |
126 | 129 | } else { |
... | ... | @@ -129,8 +132,8 @@ class ProfileState { |
129 | 132 | } |
130 | 133 | } |
131 | 134 | |
132 | - Set<EntityKey> getClearAlarmKeys(String id) { | |
133 | - Set<EntityKey> keys = alarmClearKeys.get(id); | |
135 | + Set<AlarmConditionFilterKey> getClearAlarmKeys(String id) { | |
136 | + Set<AlarmConditionFilterKey> keys = alarmClearKeys.get(id); | |
134 | 137 | if (keys == null) { |
135 | 138 | return Collections.emptySet(); |
136 | 139 | } else { | ... | ... |
... | ... | @@ -16,6 +16,8 @@ |
16 | 16 | package org.thingsboard.rule.engine.profile; |
17 | 17 | |
18 | 18 | import lombok.Getter; |
19 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; | |
20 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; | |
19 | 21 | import org.thingsboard.server.common.data.query.EntityKey; |
20 | 22 | import org.thingsboard.server.common.data.query.EntityKeyType; |
21 | 23 | |
... | ... | @@ -24,11 +26,11 @@ import java.util.Set; |
24 | 26 | class SnapshotUpdate { |
25 | 27 | |
26 | 28 | @Getter |
27 | - private final EntityKeyType type; | |
29 | + private final AlarmConditionKeyType type; | |
28 | 30 | @Getter |
29 | - private final Set<EntityKey> keys; | |
31 | + private final Set<AlarmConditionFilterKey> keys; | |
30 | 32 | |
31 | - SnapshotUpdate(EntityKeyType type, Set<EntityKey> keys) { | |
33 | + SnapshotUpdate(AlarmConditionKeyType type, Set<AlarmConditionFilterKey> keys) { | |
32 | 34 | this.type = type; |
33 | 35 | this.keys = keys; |
34 | 36 | } | ... | ... |
... | ... | @@ -36,6 +36,9 @@ import org.thingsboard.server.common.data.DeviceProfile; |
36 | 36 | import org.thingsboard.server.common.data.EntityType; |
37 | 37 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
38 | 38 | import org.thingsboard.server.common.data.device.profile.AlarmCondition; |
39 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; | |
40 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; | |
41 | +import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; | |
39 | 42 | import org.thingsboard.server.common.data.device.profile.AlarmRule; |
40 | 43 | import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; |
41 | 44 | import org.thingsboard.server.common.data.device.profile.DeviceProfileData; |
... | ... | @@ -44,6 +47,7 @@ import org.thingsboard.server.common.data.id.DeviceId; |
44 | 47 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
45 | 48 | import org.thingsboard.server.common.data.id.TenantId; |
46 | 49 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
50 | +import org.thingsboard.server.common.data.query.BooleanFilterPredicate; | |
47 | 51 | import org.thingsboard.server.common.data.query.DynamicValue; |
48 | 52 | import org.thingsboard.server.common.data.query.DynamicValueSourceType; |
49 | 53 | import org.thingsboard.server.common.data.query.EntityKey; |
... | ... | @@ -62,6 +66,7 @@ import org.thingsboard.server.dao.model.sql.AttributeKvCompositeKey; |
62 | 66 | import org.thingsboard.server.dao.model.sql.AttributeKvEntity; |
63 | 67 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
64 | 68 | |
69 | +import java.util.Arrays; | |
65 | 70 | import java.util.Collections; |
66 | 71 | import java.util.List; |
67 | 72 | import java.util.Optional; |
... | ... | @@ -69,6 +74,7 @@ import java.util.TreeMap; |
69 | 74 | import java.util.UUID; |
70 | 75 | |
71 | 76 | import static org.mockito.ArgumentMatchers.eq; |
77 | +import static org.mockito.Mockito.mock; | |
72 | 78 | import static org.mockito.Mockito.verify; |
73 | 79 | |
74 | 80 | @RunWith(MockitoJUnitRunner.class) |
... | ... | @@ -141,8 +147,8 @@ public class TbDeviceProfileNodeTest { |
141 | 147 | DeviceProfile deviceProfile = new DeviceProfile(); |
142 | 148 | DeviceProfileData deviceProfileData = new DeviceProfileData(); |
143 | 149 | |
144 | - KeyFilter highTempFilter = new KeyFilter(); | |
145 | - highTempFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")); | |
150 | + AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); | |
151 | + highTempFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
146 | 152 | highTempFilter.setValueType(EntityKeyValueType.NUMERIC); |
147 | 153 | NumericFilterPredicate highTemperaturePredicate = new NumericFilterPredicate(); |
148 | 154 | highTemperaturePredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); |
... | ... | @@ -157,8 +163,8 @@ public class TbDeviceProfileNodeTest { |
157 | 163 | dpa.setAlarmType("highTemperatureAlarm"); |
158 | 164 | dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); |
159 | 165 | |
160 | - KeyFilter lowTempFilter = new KeyFilter(); | |
161 | - lowTempFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")); | |
166 | + AlarmConditionFilter lowTempFilter = new AlarmConditionFilter(); | |
167 | + lowTempFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
162 | 168 | lowTempFilter.setValueType(EntityKeyValueType.NUMERIC); |
163 | 169 | NumericFilterPredicate lowTemperaturePredicate = new NumericFilterPredicate(); |
164 | 170 | lowTemperaturePredicate.setOperation(NumericFilterPredicate.NumericOperation.LESS); |
... | ... | @@ -204,6 +210,175 @@ public class TbDeviceProfileNodeTest { |
204 | 210 | } |
205 | 211 | |
206 | 212 | @Test |
213 | + public void testConstantKeyFilterSimple() throws Exception { | |
214 | + init(); | |
215 | + | |
216 | + DeviceProfile deviceProfile = new DeviceProfile(); | |
217 | + deviceProfile.setId(deviceProfileId); | |
218 | + DeviceProfileData deviceProfileData = new DeviceProfileData(); | |
219 | + | |
220 | + Device device = new Device(); | |
221 | + device.setId(deviceId); | |
222 | + device.setCustomerId(customerId); | |
223 | + | |
224 | + AttributeKvCompositeKey compositeKey = new AttributeKvCompositeKey( | |
225 | + EntityType.TENANT, deviceId.getId(), "SERVER_SCOPE", "alarmEnabled" | |
226 | + ); | |
227 | + | |
228 | + AttributeKvEntity attributeKvEntity = new AttributeKvEntity(); | |
229 | + attributeKvEntity.setId(compositeKey); | |
230 | + attributeKvEntity.setBooleanValue(Boolean.TRUE); | |
231 | + attributeKvEntity.setLastUpdateTs(System.currentTimeMillis()); | |
232 | + | |
233 | + AttributeKvEntry entry = attributeKvEntity.toData(); | |
234 | + ListenableFuture<List<AttributeKvEntry>> attrListListenableFuture = Futures.immediateFuture(Collections.singletonList(entry)); | |
235 | + | |
236 | + AlarmConditionFilter alarmEnabledFilter = new AlarmConditionFilter(); | |
237 | + alarmEnabledFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.CONSTANT, "alarmEnabled")); | |
238 | + alarmEnabledFilter.setValue(Boolean.TRUE); | |
239 | + alarmEnabledFilter.setValueType(EntityKeyValueType.BOOLEAN); | |
240 | + BooleanFilterPredicate alarmEnabledPredicate = new BooleanFilterPredicate(); | |
241 | + alarmEnabledPredicate.setOperation(BooleanFilterPredicate.BooleanOperation.EQUAL); | |
242 | + alarmEnabledPredicate.setValue(new FilterPredicateValue<>( | |
243 | + Boolean.FALSE, | |
244 | + null, | |
245 | + new DynamicValue<>(DynamicValueSourceType.CURRENT_DEVICE, "alarmEnabled") | |
246 | + )); | |
247 | + alarmEnabledFilter.setPredicate(alarmEnabledPredicate); | |
248 | + | |
249 | + AlarmConditionFilter temperatureFilter = new AlarmConditionFilter(); | |
250 | + temperatureFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
251 | + temperatureFilter.setValueType(EntityKeyValueType.NUMERIC); | |
252 | + NumericFilterPredicate temperaturePredicate = new NumericFilterPredicate(); | |
253 | + temperaturePredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); | |
254 | + temperaturePredicate.setValue(new FilterPredicateValue<>(20.0, null, null)); | |
255 | + temperatureFilter.setPredicate(temperaturePredicate); | |
256 | + | |
257 | + AlarmCondition alarmCondition = new AlarmCondition(); | |
258 | + alarmCondition.setCondition(Arrays.asList(alarmEnabledFilter, temperatureFilter)); | |
259 | + AlarmRule alarmRule = new AlarmRule(); | |
260 | + alarmRule.setCondition(alarmCondition); | |
261 | + DeviceProfileAlarm dpa = new DeviceProfileAlarm(); | |
262 | + dpa.setId("alarmEnabledAlarmID"); | |
263 | + dpa.setAlarmType("alarmEnabledAlarm"); | |
264 | + dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); | |
265 | + | |
266 | + deviceProfileData.setAlarms(Collections.singletonList(dpa)); | |
267 | + deviceProfile.setProfileData(deviceProfileData); | |
268 | + | |
269 | + Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); | |
270 | + Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) | |
271 | + .thenReturn(Futures.immediateFuture(Collections.emptyList())); | |
272 | + Mockito.when(alarmService.findLatestByOriginatorAndType(tenantId, deviceId, "alarmEnabledAlarm")) | |
273 | + .thenReturn(Futures.immediateFuture(null)); | |
274 | + Mockito.when(alarmService.createOrUpdateAlarm(Mockito.any())).thenAnswer(AdditionalAnswers.returnsFirstArg()); | |
275 | + Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); | |
276 | + Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) | |
277 | + .thenReturn(attrListListenableFuture); | |
278 | + | |
279 | + TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); | |
280 | + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())) | |
281 | + .thenReturn(theMsg); | |
282 | + | |
283 | + ObjectNode data = mapper.createObjectNode(); | |
284 | + data.put("temperature", 21); | |
285 | + TbMsg msg = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), | |
286 | + TbMsgDataType.JSON, mapper.writeValueAsString(data), null, null); | |
287 | + | |
288 | + node.onMsg(ctx, msg); | |
289 | + verify(ctx).tellSuccess(msg); | |
290 | + verify(ctx).tellNext(theMsg, "Alarm Created"); | |
291 | + verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); | |
292 | + } | |
293 | + | |
294 | + @Test | |
295 | + public void testConstantKeyFilterInherited() throws Exception { | |
296 | + init(); | |
297 | + | |
298 | + DeviceProfile deviceProfile = new DeviceProfile(); | |
299 | + deviceProfile.setId(deviceProfileId); | |
300 | + DeviceProfileData deviceProfileData = new DeviceProfileData(); | |
301 | + | |
302 | + Device device = new Device(); | |
303 | + device.setId(deviceId); | |
304 | + device.setCustomerId(customerId); | |
305 | + | |
306 | + AttributeKvCompositeKey compositeKey = new AttributeKvCompositeKey( | |
307 | + EntityType.TENANT, tenantId.getId(), "SERVER_SCOPE", "alarmEnabled" | |
308 | + ); | |
309 | + | |
310 | + AttributeKvEntity attributeKvEntity = new AttributeKvEntity(); | |
311 | + attributeKvEntity.setId(compositeKey); | |
312 | + attributeKvEntity.setBooleanValue(Boolean.TRUE); | |
313 | + attributeKvEntity.setLastUpdateTs(System.currentTimeMillis()); | |
314 | + | |
315 | + AttributeKvEntry entry = attributeKvEntity.toData(); | |
316 | + ListenableFuture<Optional<AttributeKvEntry>> attrListListenableFuture = Futures.immediateFuture(Optional.of(entry)); | |
317 | + | |
318 | + AlarmConditionFilter alarmEnabledFilter = new AlarmConditionFilter(); | |
319 | + alarmEnabledFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.CONSTANT, "alarmEnabled")); | |
320 | + alarmEnabledFilter.setValue(Boolean.TRUE); | |
321 | + alarmEnabledFilter.setValueType(EntityKeyValueType.BOOLEAN); | |
322 | + BooleanFilterPredicate alarmEnabledPredicate = new BooleanFilterPredicate(); | |
323 | + alarmEnabledPredicate.setOperation(BooleanFilterPredicate.BooleanOperation.EQUAL); | |
324 | + alarmEnabledPredicate.setValue(new FilterPredicateValue<>( | |
325 | + Boolean.FALSE, | |
326 | + null, | |
327 | + new DynamicValue<>(DynamicValueSourceType.CURRENT_DEVICE, "alarmEnabled", true) | |
328 | + )); | |
329 | + alarmEnabledFilter.setPredicate(alarmEnabledPredicate); | |
330 | + | |
331 | + AlarmConditionFilter temperatureFilter = new AlarmConditionFilter(); | |
332 | + temperatureFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
333 | + temperatureFilter.setValueType(EntityKeyValueType.NUMERIC); | |
334 | + NumericFilterPredicate temperaturePredicate = new NumericFilterPredicate(); | |
335 | + temperaturePredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); | |
336 | + temperaturePredicate.setValue(new FilterPredicateValue<>(20.0, null, null)); | |
337 | + temperatureFilter.setPredicate(temperaturePredicate); | |
338 | + | |
339 | + AlarmCondition alarmCondition = new AlarmCondition(); | |
340 | + alarmCondition.setCondition(Arrays.asList(alarmEnabledFilter, temperatureFilter)); | |
341 | + AlarmRule alarmRule = new AlarmRule(); | |
342 | + alarmRule.setCondition(alarmCondition); | |
343 | + DeviceProfileAlarm dpa = new DeviceProfileAlarm(); | |
344 | + dpa.setId("alarmEnabledAlarmID"); | |
345 | + dpa.setAlarmType("alarmEnabledAlarm"); | |
346 | + dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); | |
347 | + | |
348 | + deviceProfileData.setAlarms(Collections.singletonList(dpa)); | |
349 | + deviceProfile.setProfileData(deviceProfileData); | |
350 | + | |
351 | + Mockito.when(deviceService.findDeviceById(tenantId, deviceId)).thenReturn(device); | |
352 | + Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); | |
353 | + Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) | |
354 | + .thenReturn(Futures.immediateFuture(Collections.emptyList())); | |
355 | + Mockito.when(alarmService.findLatestByOriginatorAndType(tenantId, deviceId, "alarmEnabledAlarm")) | |
356 | + .thenReturn(Futures.immediateFuture(null)); | |
357 | + Mockito.when(alarmService.createOrUpdateAlarm(Mockito.any())).thenAnswer(AdditionalAnswers.returnsFirstArg()); | |
358 | + Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); | |
359 | + Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) | |
360 | + .thenReturn(Futures.immediateFuture(Collections.emptyList())); | |
361 | + Mockito.when(attributesService.find(eq(tenantId), eq(customerId), Mockito.anyString(), Mockito.anyString())) | |
362 | + .thenReturn(Futures.immediateFuture(Optional.empty())); | |
363 | + Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), Mockito.anyString(), Mockito.anyString())) | |
364 | + .thenReturn(attrListListenableFuture); | |
365 | + | |
366 | + TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); | |
367 | + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())) | |
368 | + .thenReturn(theMsg); | |
369 | + | |
370 | + ObjectNode data = mapper.createObjectNode(); | |
371 | + data.put("temperature", 21); | |
372 | + TbMsg msg = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), | |
373 | + TbMsgDataType.JSON, mapper.writeValueAsString(data), null, null); | |
374 | + | |
375 | + node.onMsg(ctx, msg); | |
376 | + verify(ctx).tellSuccess(msg); | |
377 | + verify(ctx).tellNext(theMsg, "Alarm Created"); | |
378 | + verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); | |
379 | + } | |
380 | + | |
381 | + @Test | |
207 | 382 | public void testCurrentDeviceAttributeForDynamicValue() throws Exception { |
208 | 383 | init(); |
209 | 384 | |
... | ... | @@ -228,8 +403,8 @@ public class TbDeviceProfileNodeTest { |
228 | 403 | ListenableFuture<List<AttributeKvEntry>> listListenableFutureWithLess = |
229 | 404 | Futures.immediateFuture(Collections.singletonList(entry)); |
230 | 405 | |
231 | - KeyFilter highTempFilter = new KeyFilter(); | |
232 | - highTempFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")); | |
406 | + AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); | |
407 | + highTempFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
233 | 408 | highTempFilter.setValueType(EntityKeyValueType.NUMERIC); |
234 | 409 | NumericFilterPredicate highTemperaturePredicate = new NumericFilterPredicate(); |
235 | 410 | highTemperaturePredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); |
... | ... | @@ -303,8 +478,8 @@ public class TbDeviceProfileNodeTest { |
303 | 478 | ListenableFuture<Optional<AttributeKvEntry>> optionalListenableFutureWithLess = |
304 | 479 | Futures.immediateFuture(Optional.of(entry)); |
305 | 480 | |
306 | - KeyFilter lowTempFilter = new KeyFilter(); | |
307 | - lowTempFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")); | |
481 | + AlarmConditionFilter lowTempFilter = new AlarmConditionFilter(); | |
482 | + lowTempFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
308 | 483 | lowTempFilter.setValueType(EntityKeyValueType.NUMERIC); |
309 | 484 | NumericFilterPredicate lowTempPredicate = new NumericFilterPredicate(); |
310 | 485 | lowTempPredicate.setOperation(NumericFilterPredicate.NumericOperation.LESS); |
... | ... | @@ -382,8 +557,8 @@ public class TbDeviceProfileNodeTest { |
382 | 557 | ListenableFuture<Optional<AttributeKvEntry>> optionalListenableFutureWithLess = |
383 | 558 | Futures.immediateFuture(Optional.of(entry)); |
384 | 559 | |
385 | - KeyFilter lowTempFilter = new KeyFilter(); | |
386 | - lowTempFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")); | |
560 | + AlarmConditionFilter lowTempFilter = new AlarmConditionFilter(); | |
561 | + lowTempFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
387 | 562 | lowTempFilter.setValueType(EntityKeyValueType.NUMERIC); |
388 | 563 | NumericFilterPredicate lowTempPredicate = new NumericFilterPredicate(); |
389 | 564 | lowTempPredicate.setOperation(NumericFilterPredicate.NumericOperation.LESS); |
... | ... | @@ -416,7 +591,7 @@ public class TbDeviceProfileNodeTest { |
416 | 591 | Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); |
417 | 592 | Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) |
418 | 593 | .thenReturn(listListenableFutureWithLess); |
419 | - Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(DataConstants.SERVER_SCOPE), Mockito.anyString())) | |
594 | + Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(DataConstants.SERVER_SCOPE), Mockito.anyString())) | |
420 | 595 | .thenReturn(optionalListenableFutureWithLess); |
421 | 596 | |
422 | 597 | TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); |
... | ... | @@ -454,8 +629,8 @@ public class TbDeviceProfileNodeTest { |
454 | 629 | ListenableFuture<List<AttributeKvEntry>> listListenableFutureWithLess = |
455 | 630 | Futures.immediateFuture(Collections.singletonList(entry)); |
456 | 631 | |
457 | - KeyFilter lowTempFilter = new KeyFilter(); | |
458 | - lowTempFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")); | |
632 | + AlarmConditionFilter lowTempFilter = new AlarmConditionFilter(); | |
633 | + lowTempFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
459 | 634 | lowTempFilter.setValueType(EntityKeyValueType.NUMERIC); |
460 | 635 | NumericFilterPredicate lowTempPredicate = new NumericFilterPredicate(); |
461 | 636 | lowTempPredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); |
... | ... | @@ -502,9 +677,9 @@ public class TbDeviceProfileNodeTest { |
502 | 677 | verify(ctx).tellSuccess(msg); |
503 | 678 | verify(ctx).tellNext(theMsg, "Alarm Created"); |
504 | 679 | verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); |
505 | - | |
506 | 680 | } |
507 | 681 | |
682 | + | |
508 | 683 | @Test |
509 | 684 | public void testCustomerInheritModeForDynamicValues() throws Exception { |
510 | 685 | init(); |
... | ... | @@ -527,8 +702,8 @@ public class TbDeviceProfileNodeTest { |
527 | 702 | ListenableFuture<Optional<AttributeKvEntry>> optionalListenableFutureWithLess = |
528 | 703 | Futures.immediateFuture(Optional.of(entry)); |
529 | 704 | |
530 | - KeyFilter lowTempFilter = new KeyFilter(); | |
531 | - lowTempFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")); | |
705 | + AlarmConditionFilter lowTempFilter = new AlarmConditionFilter(); | |
706 | + lowTempFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); | |
532 | 707 | lowTempFilter.setValueType(EntityKeyValueType.NUMERIC); |
533 | 708 | NumericFilterPredicate lowTempPredicate = new NumericFilterPredicate(); |
534 | 709 | lowTempPredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); |
... | ... | @@ -561,7 +736,7 @@ public class TbDeviceProfileNodeTest { |
561 | 736 | Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); |
562 | 737 | Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) |
563 | 738 | .thenReturn(listListenableFutureWithLess); |
564 | - Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(DataConstants.SERVER_SCOPE), Mockito.anyString())) | |
739 | + Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(DataConstants.SERVER_SCOPE), Mockito.anyString())) | |
565 | 740 | .thenReturn(optionalListenableFutureWithLess); |
566 | 741 | |
567 | 742 | TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); | ... | ... |