Commit fc0d47a89cf54ac479815c6cedff4a63fca7d52b

Authored by 芯火源
1 parent 89167b44

feat: 场景联动显示告警详情

@@ -175,4 +175,17 @@ public interface FastIotConstants { @@ -175,4 +175,17 @@ public interface FastIotConstants {
175 /**RPC单项双向*/ 175 /**RPC单项双向*/
176 public static String ONEWAY = "oneway"; 176 public static String ONEWAY = "oneway";
177 } 177 }
  178 + class Alarm{
  179 +
  180 + /**遥测指标标识符*/
  181 + public static String KEY = "key";
  182 + /**遥测指标值*/
  183 + public static String VALUE = "value";
  184 + /**触发器逻辑关系*/
  185 + public static String PREDICATE = "logic";
  186 + /**触发器*/
  187 + public static String TRIGGER = "trigger";
  188 + /**执行条件*/
  189 + public static String CONDITION = "condition";
  190 + }
178 } 191 }
@@ -89,24 +89,27 @@ class ReactState { @@ -89,24 +89,27 @@ class ReactState {
89 * 89 *
90 * @param ctx 90 * @param ctx
91 * @param msg 设备推送的遥测数据 91 * @param msg 设备推送的遥测数据
  92 + * @param prefixId 运算规则ID,例如:触发器、执行条件
92 * @param deviceId 遥测数据的来源设备的TB设备ID 93 * @param deviceId 遥测数据的来源设备的TB设备ID
93 * @throws ExecutionException 94 * @throws ExecutionException
94 * @throws InterruptedException 95 * @throws InterruptedException
95 */ 96 */
96 - public void process(TbContext ctx, TbMsg msg, String prefixId,String deviceId) 97 + public void process(TbContext ctx, TbMsg msg, String prefixId, String deviceId)
97 throws ExecutionException, InterruptedException { 98 throws ExecutionException, InterruptedException {
98 99
99 - StringBuilder detail = new StringBuilder(); 100 + /** 场景联动告警详情 */
  101 + ObjectNode detail = JacksonUtil.newObjectNode();
100 if (actions == null) { 102 if (actions == null) {
101 ctx.tellSuccess(msg); 103 ctx.tellSuccess(msg);
102 } 104 }
103 105
  106 + /** 1、单个触发器内只要有1个设备满足条件即为true 2、多个触发器只要有1个触发器满足条件即为true */
104 AtomicBoolean triggerMatched = new AtomicBoolean(true); 107 AtomicBoolean triggerMatched = new AtomicBoolean(true);
105 Optional.ofNullable(triggers) 108 Optional.ofNullable(triggers)
106 .ifPresent( 109 .ifPresent(
107 - t -> { 110 + all -> {
108 triggerMatched.set(false); 111 triggerMatched.set(false);
109 - t.forEach( 112 + all.forEach(
110 trigger -> { 113 trigger -> {
111 ScopeEnum entityType = trigger.getEntityType(); 114 ScopeEnum entityType = trigger.getEntityType();
112 List<String> trifggerDevices = trigger.getEntityId(); 115 List<String> trifggerDevices = trigger.getEntityId();
@@ -119,24 +122,30 @@ class ReactState { @@ -119,24 +122,30 @@ class ReactState {
119 triggerMatched.set( 122 triggerMatched.set(
120 trifggerDevices.stream() 123 trifggerDevices.stream()
121 .anyMatch( 124 .anyMatch(
122 - id -> { 125 + devId -> {
123 TriggerState triggerState = 126 TriggerState triggerState =
124 - getOrCreateTriggerState(trigger, tkProjectId, id); 127 + getOrCreateTriggerState(trigger, tkProjectId, devId);
125 if (triggerState == null) { 128 if (triggerState == null) {
126 return false; 129 return false;
127 } 130 }
128 try { 131 try {
129 boolean fresh = false; 132 boolean fresh = false;
130 - if(trigger.getId().equals(prefixId)&&msg.getOriginator().getId().toString().equals(id)){  
131 - fresh=true; 133 + if (trigger.getId().equals(prefixId)
  134 + && msg.getOriginator().getId().toString().equals(devId)) {
  135 + fresh = true;
132 } 136 }
133 - boolean result = triggerState.process(ctx, msg,fresh);  
134 - log.error(String.format("触发器【%s】刷新【%s】结果【%s】触发器设备【%s】数据设备【%s】数据内容【%s】",trigger.getId(),fresh,result,id,msg.getOriginator(),msg.getData()));  
135 - if (result) {  
136 - detail.append(  
137 - triggerState.getAlarmDetails() == null  
138 - ? ""  
139 - : triggerState.getAlarmDetails()); 137 + ObjectNode result = triggerState.process(ctx, msg, fresh);
  138 + log.error(
  139 + String.format(
  140 + "触发器【%s】刷新【%s】结果【%s】触发器设备【%s】数据设备【%s】数据内容【%s】",
  141 + trigger.getId(),
  142 + fresh,
  143 + result,
  144 + devId,
  145 + msg.getOriginator(),
  146 + msg.getData()));
  147 + if (!result.isEmpty()) {
  148 + detail.set(FastIotConstants.Alarm.TRIGGER,result);
140 return true; 149 return true;
141 } else if (currentAlarms.containsKey(deviceId)) { 150 } else if (currentAlarms.containsKey(deviceId)) {
142 // 清除设备告警 151 // 清除设备告警
@@ -155,51 +164,65 @@ class ReactState { @@ -155,51 +164,65 @@ class ReactState {
155 }); 164 });
156 }); 165 });
157 166
158 - /** 执行条件的所有设备都满足才为true */ 167 + /** 1、单个执行条件内全部设备满足条件才为true 2、多个执行条件全部执行条件满足条件才为true */
159 AtomicBoolean conditionMatched = new AtomicBoolean(true); 168 AtomicBoolean conditionMatched = new AtomicBoolean(true);
160 Optional.ofNullable(conditions) 169 Optional.ofNullable(conditions)
161 - .ifPresent(  
162 - t -> {  
163 - t.forEach(  
164 - condition -> {  
165 - ScopeEnum entityType = condition.getEntityType();  
166 - List<String> conditionDevices = condition.getEntityId();  
167 - String tkProjectId = condition.getDeviceProfileId();  
168 - if (ScopeEnum.ALL.equals(entityType)) {  
169 - conditionDevices =  
170 - ytDeviceService.findTbDeviceIdsByDeviceProfileId(  
171 - tkProjectId, condition.getTenantId());  
172 - }  
173 - conditionMatched.set(  
174 - !conditionDevices.stream()  
175 - .anyMatch(  
176 - id -> {  
177 - TriggerState conditionState =  
178 - getOrCreateConditionState(condition, tkProjectId, id);  
179 - try {  
180 - boolean fresh = false;  
181 - if(msg.getOriginator().getId().toString().equals(id)){  
182 - fresh=true;  
183 - }  
184 - boolean result = conditionState.process(ctx, msg,fresh);  
185 - log.warn(String.format("执行器【%s】刷新【%s】结果【%s】执行器设备【%s】数据设备【%s】数据内容【%s】",condition.getId(),fresh,result,id,msg.getOriginator(),msg.getData()));  
186 - return !result;  
187 - } catch (ExecutionException e) {  
188 - throw new RuntimeException(e);  
189 - } catch (InterruptedException e) {  
190 - throw new RuntimeException(e);  
191 - }  
192 - }));  
193 - });  
194 - }); 170 + .ifPresent(
  171 + all -> {
  172 + conditionMatched.set(
  173 + all.stream()
  174 + .allMatch(
  175 + condition -> {
  176 + ScopeEnum entityType = condition.getEntityType();
  177 + List<String> conditionDevices = condition.getEntityId();
  178 + String tkProjectId = condition.getDeviceProfileId();
  179 + if (ScopeEnum.ALL.equals(entityType)) {
  180 + conditionDevices =
  181 + ytDeviceService.findTbDeviceIdsByDeviceProfileId(
  182 + tkProjectId, condition.getTenantId());
  183 + }
  184 +
  185 + return conditionDevices.stream()
  186 + .allMatch(
  187 + devId -> {
  188 + TriggerState conditionState =
  189 + getOrCreateConditionState(condition, tkProjectId, devId);
  190 + try {
  191 + boolean fresh = false;
  192 + if (msg.getOriginator().getId().toString().equals(devId)) {
  193 + fresh = true;
  194 + }
  195 + ObjectNode result = conditionState.process(ctx, msg, fresh);
  196 + log.warn(
  197 + String.format(
  198 + "执行器【%s】刷新【%s】结果【%s】执行器设备【%s】数据设备【%s】数据内容【%s】",
  199 + condition.getId(),
  200 + fresh,
  201 + result,
  202 + devId,
  203 + msg.getOriginator(),
  204 + msg.getData()));
  205 + if (!result.isEmpty()) {
  206 + detail.set(FastIotConstants.Alarm.CONDITION,result);
  207 + return true;
  208 + }
  209 + } catch (ExecutionException e) {
  210 + throw new RuntimeException(e);
  211 + } catch (InterruptedException e) {
  212 + throw new RuntimeException(e);
  213 + }
  214 + return false;
  215 + });
  216 + }));
  217 + });
195 218
196 if (triggerMatched.get() && conditionMatched.get()) { 219 if (triggerMatched.get() && conditionMatched.get()) {
197 - log.error(String.format("设备【%s】的消息内容【%s】触发动作",deviceId,msg.getData())); 220 + log.error(String.format("设备【%s】的消息内容【%s】触发动作", deviceId, msg.getData()));
198 for (TkDoActionEntity item : actions) { 221 for (TkDoActionEntity item : actions) {
199 if (ActionTypeEnum.MSG_NOTIFY.equals(item.getOutTarget())) { 222 if (ActionTypeEnum.MSG_NOTIFY.equals(item.getOutTarget())) {
200 - noticeMsg(ctx, msg, item, deviceId, detail.toString(), msg.getTs()); 223 + noticeMsg(ctx, msg, item, deviceId, detail, msg.getTs());
201 } else { 224 } else {
202 - pushMsg(ctx, msg, item, detail.toString()); 225 + pushMsg(ctx, msg, item);
203 } 226 }
204 } 227 }
205 } else { 228 } else {
@@ -226,7 +249,7 @@ class ReactState { @@ -226,7 +249,7 @@ class ReactState {
226 || (trigger.getEntityType().equals(ScopeEnum.ALL) 249 || (trigger.getEntityType().equals(ScopeEnum.ALL)
227 && trigger.getDeviceProfileId().equals(profileId))) { 250 && trigger.getDeviceProfileId().equals(profileId))) {
228 TriggerState state = createTriggerState(deviceId, trigger.getTriggerCondition()); 251 TriggerState state = createTriggerState(deviceId, trigger.getTriggerCondition());
229 - log.error(String.format("新建设备【%s】的触发器",deviceId)); 252 + log.error(String.format("新建设备【%s】的触发器", deviceId));
230 triggerState.put(cacheKey, state); 253 triggerState.put(cacheKey, state);
231 return state; 254 return state;
232 } 255 }
@@ -290,12 +313,12 @@ class ReactState { @@ -290,12 +313,12 @@ class ReactState {
290 for (AlarmConditionFilter filter : rule.getCondition().getCondition()) { 313 for (AlarmConditionFilter filter : rule.getCondition().getCondition()) {
291 filterKeys.add(filter.getKey()); 314 filterKeys.add(filter.getKey());
292 } 315 }
293 - TriggerState state = new TriggerState(deviceId, rule, filterKeys, rule.getAlarmDetails(), null); 316 + TriggerState state = new TriggerState(deviceId, rule, filterKeys, null);
294 317
295 return state; 318 return state;
296 } 319 }
297 320
298 - private void pushMsg(TbContext ctx, TbMsg msg, TkDoActionEntity action, String detail) { 321 + private void pushMsg(TbContext ctx, TbMsg msg, TkDoActionEntity action) {
299 switch (action.getOutTarget()) { 322 switch (action.getOutTarget()) {
300 case DEVICE_OUT: 323 case DEVICE_OUT:
301 List<String> rpcDevices = action.getDeviceId(); 324 List<String> rpcDevices = action.getDeviceId();
@@ -354,7 +377,7 @@ class ReactState { @@ -354,7 +377,7 @@ class ReactState {
354 TbMsg msg, 377 TbMsg msg,
355 TkDoActionEntity action, 378 TkDoActionEntity action,
356 String deviceId, 379 String deviceId,
357 - String detailStr, 380 + ObjectNode detail,
358 long startTs) { 381 long startTs) {
359 382
360 DeviceId entityId = new DeviceId(UUID.fromString(deviceId)); 383 DeviceId entityId = new DeviceId(UUID.fromString(deviceId));
@@ -370,12 +393,7 @@ class ReactState { @@ -370,12 +393,7 @@ class ReactState {
370 } 393 }
371 currentAlarm.setStartTs(startTs); 394 currentAlarm.setStartTs(startTs);
372 currentAlarm.setEndTs(currentAlarm.getStartTs()); 395 currentAlarm.setEndTs(currentAlarm.getStartTs());
373 - ObjectNode detailData = JacksonUtil.newObjectNode();  
374 - if (StringUtils.isNotEmpty(detailStr)) {  
375 - detailData.put("msg", detailStr);  
376 - }  
377 - detailData.put("data", JacksonUtil.toJsonNode(msg.getData()));  
378 - currentAlarm.setDetails(detailData); 396 + currentAlarm.setDetails(detail);
379 currentAlarm.setOriginator(entityId); 397 currentAlarm.setOriginator(entityId);
380 currentAlarm.setTenantId(ctx.getTenantId()); 398 currentAlarm.setTenantId(ctx.getTenantId());
381 currentAlarm.setPropagate(false); 399 currentAlarm.setPropagate(false);
@@ -393,7 +411,7 @@ class ReactState { @@ -393,7 +411,7 @@ class ReactState {
393 411
394 AlarmInfoDTO formData = new AlarmInfoDTO(); 412 AlarmInfoDTO formData = new AlarmInfoDTO();
395 formData.setDeviceName(msg.getMetaData().getData().get("deviceName")); 413 formData.setDeviceName(msg.getMetaData().getData().get("deviceName"));
396 - formData.setDetails(JacksonUtil.toString(detailData)); 414 + formData.setDetails(JacksonUtil.toString(detail));
397 formData.setType(currentAlarm.getType()); 415 formData.setType(currentAlarm.getType());
398 formData.setCreateTs(currentAlarm.getCreatedTime()); 416 formData.setCreateTs(currentAlarm.getCreatedTime());
399 formData.setStartTs(currentAlarm.getStartTs()); 417 formData.setStartTs(currentAlarm.getStartTs());
@@ -408,16 +426,19 @@ class ReactState { @@ -408,16 +426,19 @@ class ReactState {
408 private void clearAlarm(TbContext ctx, TbMsg msg, String deviceId, String key) 426 private void clearAlarm(TbContext ctx, TbMsg msg, String deviceId, String key)
409 throws ExecutionException, InterruptedException { 427 throws ExecutionException, InterruptedException {
410 TriggerState clearState = getOrCreateClearState(deviceId, key); 428 TriggerState clearState = getOrCreateClearState(deviceId, key);
411 - if (clearState != null && clearState.process(ctx, msg,true)) {  
412 - ctx.getAlarmService()  
413 - .clearAlarmForResult(  
414 - ctx.getTenantId(),  
415 - currentAlarms.get(deviceId).getId(),  
416 - null,  
417 - System.currentTimeMillis());  
418 - ytDeviceService.freshAlarmStatus(new DeviceId(UUID.fromString(deviceId)), 0);  
419 - alarmMsg(ctx, msg, currentAlarms.get(deviceId), "Alarm Cleared");  
420 - currentAlarms.remove(deviceId); 429 + if(clearState !=null){
  430 + ObjectNode clearResult = clearState.process(ctx, msg, true);
  431 + if(!clearResult.isEmpty()){
  432 + ctx.getAlarmService()
  433 + .clearAlarmForResult(
  434 + ctx.getTenantId(),
  435 + currentAlarms.get(deviceId).getId(),
  436 + clearResult,
  437 + System.currentTimeMillis());
  438 + ytDeviceService.freshAlarmStatus(new DeviceId(UUID.fromString(deviceId)), 0);
  439 + alarmMsg(ctx, msg, currentAlarms.get(deviceId), "Alarm Cleared");
  440 + currentAlarms.remove(deviceId);
  441 + }
421 } 442 }
422 } 443 }
423 444
@@ -13,6 +13,7 @@ @@ -13,6 +13,7 @@
13 */ 13 */
14 package org.thingsboard.rule.engine.yunteng.scene; 14 package org.thingsboard.rule.engine.yunteng.scene;
15 15
  16 +import com.fasterxml.jackson.databind.node.ObjectNode;
16 import com.google.gson.JsonParser; 17 import com.google.gson.JsonParser;
17 import java.util.*; 18 import java.util.*;
18 import java.util.concurrent.ExecutionException; 19 import java.util.concurrent.ExecutionException;
@@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.id.DeviceId; @@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
32 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 33 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
33 import org.thingsboard.server.common.data.kv.KvEntry; 34 import org.thingsboard.server.common.data.kv.KvEntry;
34 import org.thingsboard.server.common.data.kv.TsKvEntry; 35 import org.thingsboard.server.common.data.kv.TsKvEntry;
  36 +import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil;
35 import org.thingsboard.server.common.msg.TbMsg; 37 import org.thingsboard.server.common.msg.TbMsg;
36 import org.thingsboard.server.common.msg.TbMsgMetaData; 38 import org.thingsboard.server.common.msg.TbMsgMetaData;
37 import org.thingsboard.server.common.msg.session.SessionMsgType; 39 import org.thingsboard.server.common.msg.session.SessionMsgType;
@@ -50,18 +52,14 @@ class TriggerState { @@ -50,18 +52,14 @@ class TriggerState {
50 private final DynamicPredicateValueCtx dynamicPredicateValueCtx; 52 private final DynamicPredicateValueCtx dynamicPredicateValueCtx;
51 private DataSnapshot latestValues; 53 private DataSnapshot latestValues;
52 54
  55 + /**触发器的遥测指标*/
53 private final Set<AlarmConditionFilterKey> entityKeys; 56 private final Set<AlarmConditionFilterKey> entityKeys;
54 - private final String alarmDetails;  
55 57
56 - @Getter  
57 - /** 触发条件执行结果 */  
58 - private boolean ruleMatched = false;  
59 58
60 TriggerState( 59 TriggerState(
61 String originator, 60 String originator,
62 AlarmRule rule, 61 AlarmRule rule,
63 Set<AlarmConditionFilterKey> filterKeys, 62 Set<AlarmConditionFilterKey> filterKeys,
64 - String alarmDetails,  
65 DynamicPredicateValueCtx dynamicPredicateValueCtx) { 63 DynamicPredicateValueCtx dynamicPredicateValueCtx) {
66 64
67 this.originator = originator; 65 this.originator = originator;
@@ -70,12 +68,12 @@ class TriggerState { @@ -70,12 +68,12 @@ class TriggerState {
70 new TriggerRuleState( 68 new TriggerRuleState(
71 rule.getCondition(), filterKeys, new PersistedAlarmRuleState(), rule.getSchedule()); 69 rule.getCondition(), filterKeys, new PersistedAlarmRuleState(), rule.getSchedule());
72 this.entityKeys = filterKeys; 70 this.entityKeys = filterKeys;
73 - this.alarmDetails = alarmDetails;  
74 } 71 }
75 72
76 - public boolean process(TbContext ctx, TbMsg msg,boolean needFresh) throws ExecutionException, InterruptedException { 73 + public ObjectNode process(TbContext ctx, TbMsg msg, boolean needFresh)
  74 + throws ExecutionException, InterruptedException {
77 if (!needFresh) { 75 if (!needFresh) {
78 - return ruleMatched; 76 + return ruleState.getDetailInform();
79 } 77 }
80 if (latestValues == null) { 78 if (latestValues == null) {
81 latestValues = fetchLatestValues(ctx, originator); 79 latestValues = fetchLatestValues(ctx, originator);
@@ -89,35 +87,33 @@ class TriggerState { @@ -89,35 +87,33 @@ class TriggerState {
89 } 87 }
90 88
91 if (update != null && update.hasUpdate()) { 89 if (update != null && update.hasUpdate()) {
92 - ruleMatched = createOrClearAlarms(ctx, msg, latestValues, update, TriggerRuleState::eval);  
93 - return ruleMatched; 90 + return createOrClearAlarms(ctx, msg, latestValues, update, TriggerRuleState::eval);
94 } 91 }
95 - return false; 92 + return JacksonUtil.newObjectNode();
96 } 93 }
97 94
98 - public boolean process(TbContext ctx, long ts) throws ExecutionException, InterruptedException { 95 + public ObjectNode process(TbContext ctx, long ts) throws ExecutionException, InterruptedException {
99 return createOrClearAlarms( 96 return createOrClearAlarms(
100 ctx, null, ts, null, (alarmState, tsParam) -> alarmState.eval(tsParam, latestValues)); 97 ctx, null, ts, null, (alarmState, tsParam) -> alarmState.eval(tsParam, latestValues));
101 } 98 }
102 99
103 - public <T> boolean createOrClearAlarms( 100 + public <T> ObjectNode createOrClearAlarms(
104 TbContext ctx, 101 TbContext ctx,
105 TbMsg msg, 102 TbMsg msg,
106 T data, 103 T data,
107 SnapshotUpdate update, 104 SnapshotUpdate update,
108 BiFunction<TriggerRuleState, T, AlarmEvalResult> evalFunction) { 105 BiFunction<TriggerRuleState, T, AlarmEvalResult> evalFunction) {
109 - boolean stateUpdate = false;  
110 if (!validateUpdate(update, ruleState)) { 106 if (!validateUpdate(update, ruleState)) {
111 - return false; 107 + return JacksonUtil.newObjectNode();
112 } 108 }
  109 +// ruleState.getCondition().
113 AlarmEvalResult evalResult = evalFunction.apply(ruleState, data); 110 AlarmEvalResult evalResult = evalFunction.apply(ruleState, data);
114 if (AlarmEvalResult.TRUE.equals(evalResult)) { 111 if (AlarmEvalResult.TRUE.equals(evalResult)) {
115 - stateUpdate = true;  
116 - clearAlarmState(stateUpdate, ruleState); 112 + clearAlarmState(true, ruleState);
117 } else if (AlarmEvalResult.FALSE.equals(evalResult)) { 113 } else if (AlarmEvalResult.FALSE.equals(evalResult)) {
118 - clearAlarmState(stateUpdate, ruleState); 114 + clearAlarmState(false, ruleState);
119 } 115 }
120 - return stateUpdate; 116 + return ruleState.getDetailInform();
121 } 117 }
122 118
123 public boolean clearAlarmState(boolean stateUpdate, TriggerRuleState state) { 119 public boolean clearAlarmState(boolean stateUpdate, TriggerRuleState state) {
@@ -128,6 +124,12 @@ class TriggerState { @@ -128,6 +124,12 @@ class TriggerState {
128 return stateUpdate; 124 return stateUpdate;
129 } 125 }
130 126
  127 + /**
  128 + * 快照中有更新的遥测指标是否包含在触发器中
  129 + * @param update 遥测数据的快照
  130 + * @param state 触发器状态
  131 + * @return
  132 + */
131 public boolean validateUpdate(SnapshotUpdate update, TriggerRuleState state) { 133 public boolean validateUpdate(SnapshotUpdate update, TriggerRuleState state) {
132 if (update != null) { 134 if (update != null) {
133 // Check that the update type and that keys match. 135 // Check that the update type and that keys match.
@@ -3,7 +3,9 @@ @@ -3,7 +3,9 @@
3 */ 3 */
4 package org.thingsboard.rule.engine.yunteng.utils; 4 package org.thingsboard.rule.engine.yunteng.utils;
5 5
  6 +import com.fasterxml.jackson.databind.node.ObjectNode;
6 import lombok.Data; 7 import lombok.Data;
  8 +import lombok.Getter;
7 import lombok.extern.slf4j.Slf4j; 9 import lombok.extern.slf4j.Slf4j;
8 import org.thingsboard.rule.engine.profile.AlarmEvalResult; 10 import org.thingsboard.rule.engine.profile.AlarmEvalResult;
9 import org.thingsboard.rule.engine.profile.DataSnapshot; 11 import org.thingsboard.rule.engine.profile.DataSnapshot;
@@ -12,6 +14,8 @@ import org.thingsboard.rule.engine.profile.EntityKeyValue; @@ -12,6 +14,8 @@ import org.thingsboard.rule.engine.profile.EntityKeyValue;
12 import org.thingsboard.rule.engine.profile.state.PersistedAlarmRuleState; 14 import org.thingsboard.rule.engine.profile.state.PersistedAlarmRuleState;
13 import org.thingsboard.server.common.data.device.profile.*; 15 import org.thingsboard.server.common.data.device.profile.*;
14 import org.thingsboard.server.common.data.query.*; 16 import org.thingsboard.server.common.data.query.*;
  17 +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
  18 +import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil;
15 import org.thingsboard.server.common.msg.tools.SchedulerUtils; 19 import org.thingsboard.server.common.msg.tools.SchedulerUtils;
16 20
17 import java.time.Instant; 21 import java.time.Instant;
@@ -33,6 +37,8 @@ public class TriggerRuleState { @@ -33,6 +37,8 @@ public class TriggerRuleState {
33 private final DynamicPredicateValueCtx dynamicPredicateValueCtx =null; 37 private final DynamicPredicateValueCtx dynamicPredicateValueCtx =null;
34 38
35 39
  40 + /**告警触发详情*/
  41 + private ObjectNode detailInform = null;
36 42
37 43
38 44
@@ -46,6 +52,7 @@ public class TriggerRuleState { @@ -46,6 +52,7 @@ public class TriggerRuleState {
46 this.state = new PersistedAlarmRuleState(0L, 0L, 0L); 52 this.state = new PersistedAlarmRuleState(0L, 0L, 0L);
47 } 53 }
48 this.spec = getSpec(condition); 54 this.spec = getSpec(condition);
  55 + this.detailInform = JacksonUtil.newObjectNode();
49 } 56 }
50 57
51 58
@@ -279,7 +286,11 @@ public class TriggerRuleState { @@ -279,7 +286,11 @@ public class TriggerRuleState {
279 if (value == null) { 286 if (value == null) {
280 return false; 287 return false;
281 } 288 }
  289 + detailInform.put(FastIotConstants.Alarm.KEY,filter.getKey().getKey());
282 eval = eval && eval(data, value, filter.getPredicate(), filter); 290 eval = eval && eval(data, value, filter.getPredicate(), filter);
  291 + if(!eval){
  292 + detailInform.removeAll();
  293 + }
283 } 294 }
284 return eval; 295 return eval;
285 } 296 }
@@ -320,6 +331,8 @@ public class TriggerRuleState { @@ -320,6 +331,8 @@ public class TriggerRuleState {
320 } 331 }
321 332
322 private boolean evalComplexPredicate(DataSnapshot data, EntityKeyValue ekv, ComplexFilterPredicate predicate, AlarmConditionFilter filter) { 333 private boolean evalComplexPredicate(DataSnapshot data, EntityKeyValue ekv, ComplexFilterPredicate predicate, AlarmConditionFilter filter) {
  334 + detailInform.put(FastIotConstants.Alarm.VALUE,ekv.getDataType().toString());
  335 + detailInform.put(FastIotConstants.Alarm.PREDICATE,predicate.getOperation().toString());
323 switch (predicate.getOperation()) { 336 switch (predicate.getOperation()) {
324 case OR: 337 case OR:
325 for (KeyFilterPredicate kfp : predicate.getPredicates()) { 338 for (KeyFilterPredicate kfp : predicate.getPredicates()) {
@@ -349,6 +362,8 @@ public class TriggerRuleState { @@ -349,6 +362,8 @@ public class TriggerRuleState {
349 if (predicateValue == null) { 362 if (predicateValue == null) {
350 return false; 363 return false;
351 } 364 }
  365 + detailInform.put(FastIotConstants.Alarm.VALUE,predicateValue);
  366 + detailInform.put(FastIotConstants.Alarm.PREDICATE,predicate.getOperation().toString());
352 switch (predicate.getOperation()) { 367 switch (predicate.getOperation()) {
353 case EQUAL: 368 case EQUAL:
354 return val.equals(predicateValue); 369 return val.equals(predicateValue);
@@ -368,6 +383,8 @@ public class TriggerRuleState { @@ -368,6 +383,8 @@ public class TriggerRuleState {
368 if (predicateValue == null) { 383 if (predicateValue == null) {
369 return false; 384 return false;
370 } 385 }
  386 + detailInform.put(FastIotConstants.Alarm.VALUE,predicateValue);
  387 + detailInform.put(FastIotConstants.Alarm.PREDICATE,predicate.getOperation().toString());
371 switch (predicate.getOperation()) { 388 switch (predicate.getOperation()) {
372 case NOT_EQUAL: 389 case NOT_EQUAL:
373 return !val.equals(predicateValue); 390 return !val.equals(predicateValue);
@@ -399,6 +416,8 @@ public class TriggerRuleState { @@ -399,6 +416,8 @@ public class TriggerRuleState {
399 val = val.toLowerCase(); 416 val = val.toLowerCase();
400 predicateValue = predicateValue.toLowerCase(); 417 predicateValue = predicateValue.toLowerCase();
401 } 418 }
  419 + detailInform.put(FastIotConstants.Alarm.VALUE,predicateValue);
  420 + detailInform.put(FastIotConstants.Alarm.PREDICATE,predicate.getOperation().toString());
402 switch (predicate.getOperation()) { 421 switch (predicate.getOperation()) {
403 case CONTAINS: 422 case CONTAINS:
404 return val.contains(predicateValue); 423 return val.contains(predicateValue);