Commit 059fe0b6e9005f6b9359752938d11462e94d3857

Authored by 云中非
1 parent df9ada88

refactor: 场景联动触发设备告警

@@ -424,8 +424,10 @@ public class SceneLinkageServiceImpl extends AbstractBaseService<SceneLinkageMap @@ -424,8 +424,10 @@ public class SceneLinkageServiceImpl extends AbstractBaseService<SceneLinkageMap
424 .eq(SceneLinkage::getStatus, FastIotConstants.StateValue.ENABLE) 424 .eq(SceneLinkage::getStatus, FastIotConstants.StateValue.ENABLE)
425 ); 425 );
426 Set<String> enableIds = new HashSet<>(); 426 Set<String> enableIds = new HashSet<>();
  427 + Map<String, String> sceneInform = new HashMap<>();
427 for (SceneLinkage item : runningScenes) { 428 for (SceneLinkage item : runningScenes) {
428 enableIds.add(item.getId()); 429 enableIds.add(item.getId());
  430 + sceneInform.put(item.getId(),item.getName());
429 } 431 }
430 enableIds.add(currentSceneId); 432 enableIds.add(currentSceneId);
431 if (state == FastIotConstants.StateValue.DISABLE) { 433 if (state == FastIotConstants.StateValue.DISABLE) {
@@ -488,6 +490,9 @@ public class SceneLinkageServiceImpl extends AbstractBaseService<SceneLinkageMap @@ -488,6 +490,9 @@ public class SceneLinkageServiceImpl extends AbstractBaseService<SceneLinkageMap
488 490
489 Map<String, Map> engineConfig = new HashMap<>(); 491 Map<String, Map> engineConfig = new HashMap<>();
490 engineConfig.put("scenes", matchedDevices); 492 engineConfig.put("scenes", matchedDevices);
  493 + engineConfig.put("names", sceneInform);
  494 +
  495 +
491 496
492 497
493 return JacksonUtil.convertValue(engineConfig, JsonNode.class); 498 return JacksonUtil.convertValue(engineConfig, JsonNode.class);
@@ -4,31 +4,37 @@ @@ -4,31 +4,37 @@
4 package org.thingsboard.rule.engine.yunteng.scene; 4 package org.thingsboard.rule.engine.yunteng.scene;
5 5
6 import com.fasterxml.jackson.databind.JsonNode; 6 import com.fasterxml.jackson.databind.JsonNode;
  7 +import com.fasterxml.jackson.databind.node.ObjectNode;
  8 +import com.google.common.util.concurrent.ListenableFuture;
7 import lombok.extern.slf4j.Slf4j; 9 import lombok.extern.slf4j.Slf4j;
8 import org.apache.commons.lang3.StringUtils; 10 import org.apache.commons.lang3.StringUtils;
9 import org.jetbrains.annotations.NotNull; 11 import org.jetbrains.annotations.NotNull;
  12 +import org.thingsboard.common.util.DonAsynchron;
  13 +import org.thingsboard.rule.engine.action.TbAlarmResult;
10 import org.thingsboard.rule.engine.api.TbContext; 14 import org.thingsboard.rule.engine.api.TbContext;
11 import org.thingsboard.server.common.data.DataConstants; 15 import org.thingsboard.server.common.data.DataConstants;
12 import org.thingsboard.server.common.data.alarm.Alarm; 16 import org.thingsboard.server.common.data.alarm.Alarm;
  17 +import org.thingsboard.server.common.data.alarm.AlarmStatus;
13 import org.thingsboard.server.common.data.device.profile.AlarmCondition; 18 import org.thingsboard.server.common.data.device.profile.AlarmCondition;
14 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; 19 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter;
15 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; 20 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey;
16 import org.thingsboard.server.common.data.device.profile.AlarmRule; 21 import org.thingsboard.server.common.data.device.profile.AlarmRule;
  22 +import org.thingsboard.server.common.data.id.DeviceId;
17 import org.thingsboard.server.common.data.rule.RuleNodeState; 23 import org.thingsboard.server.common.data.rule.RuleNodeState;
18 import org.thingsboard.server.common.data.yunteng.dto.ActionAlarmDTO; 24 import org.thingsboard.server.common.data.yunteng.dto.ActionAlarmDTO;
19 import org.thingsboard.server.common.data.yunteng.dto.AlarmInfoDTO; 25 import org.thingsboard.server.common.data.yunteng.dto.AlarmInfoDTO;
  26 +import org.thingsboard.server.common.data.yunteng.dto.DoActionDTO;
20 import org.thingsboard.server.common.data.yunteng.dto.TriggerDTO; 27 import org.thingsboard.server.common.data.yunteng.dto.TriggerDTO;
  28 +import org.thingsboard.server.common.data.yunteng.enums.ActionTypeEnum;
21 import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil; 29 import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil;
22 import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils; 30 import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils;
23 import org.thingsboard.server.common.msg.TbMsg; 31 import org.thingsboard.server.common.msg.TbMsg;
24 import org.thingsboard.server.common.msg.TbMsgMetaData; 32 import org.thingsboard.server.common.msg.TbMsgMetaData;
25 import org.thingsboard.server.common.msg.queue.ServiceQueue; 33 import org.thingsboard.server.common.msg.queue.ServiceQueue;
  34 +import org.thingsboard.server.dao.alarm.AlarmOperationResult;
26 import org.thingsboard.server.dao.yunteng.entities.DoAction; 35 import org.thingsboard.server.dao.yunteng.entities.DoAction;
27 import org.thingsboard.server.dao.yunteng.entities.DoCondition; 36 import org.thingsboard.server.dao.yunteng.entities.DoCondition;
28 -import org.thingsboard.server.dao.yunteng.service.DoActionService;  
29 -import org.thingsboard.server.dao.yunteng.service.DoConditionService;  
30 -import org.thingsboard.server.dao.yunteng.service.TriggerService;  
31 -import org.thingsboard.server.dao.yunteng.service.YtNoticeService; 37 +import org.thingsboard.server.dao.yunteng.service.*;
32 38
33 import java.net.InetAddress; 39 import java.net.InetAddress;
34 import java.util.*; 40 import java.util.*;
@@ -42,25 +48,38 @@ class ReactState { @@ -42,25 +48,38 @@ class ReactState {
42 * 场景联动主键 48 * 场景联动主键
43 */ 49 */
44 String reactId; 50 String reactId;
  51 + String reactName;
45 52
46 /** 53 /**
47 * 场景联动的触发器状态 54 * 场景联动的触发器状态
48 - * 键:设备主 55 + * 键:触发器ID和设备ID为
49 * 值:设备指标参与的触发器 56 * 值:设备指标参与的触发器
50 */ 57 */
51 private ConcurrentHashMap<String, TriggerState> triggerState = new ConcurrentHashMap<>(); 58 private ConcurrentHashMap<String, TriggerState> triggerState = new ConcurrentHashMap<>();
52 59
  60 + /**
  61 + * 场景联动的告警清除触发器状态
  62 + * 键:设备ID为键
  63 + * 值:设备指标参与的触发器
  64 + */
53 private ConcurrentHashMap<String, TriggerState> clearState = new ConcurrentHashMap<>(); 65 private ConcurrentHashMap<String, TriggerState> clearState = new ConcurrentHashMap<>();
  66 + /**
  67 + * 设备告警信息
  68 + * 键:设备ID为键
  69 + * 值:设备最新告警信息
  70 + */
  71 + private ConcurrentHashMap<String, Alarm> currentAlarms;
54 72
55 /** 73 /**
56 * 场景联动的执行条件状态 74 * 场景联动的执行条件状态
57 - * 键:设备主 75 + * 键:触发器ID和设备ID为
58 * 值:设备指标参与的触发器 76 * 值:设备指标参与的触发器
59 */ 77 */
60 private ConcurrentHashMap<String, TriggerState> conditionState = new ConcurrentHashMap<>(); 78 private ConcurrentHashMap<String, TriggerState> conditionState = new ConcurrentHashMap<>();
61 79
62 80
63 private final List<TriggerDTO> triggers; 81 private final List<TriggerDTO> triggers;
  82 + private DoAction alarmAction = null;
64 /** 83 /**
65 * 【场景联动的执行条件】懒加载 84 * 【场景联动的执行条件】懒加载
66 */ 85 */
@@ -70,21 +89,28 @@ class ReactState { @@ -70,21 +89,28 @@ class ReactState {
70 */ 89 */
71 private final List<DoAction> actions; 90 private final List<DoAction> actions;
72 private final YtNoticeService noticeService; 91 private final YtNoticeService noticeService;
  92 + private YtDeviceService ytDeviceService;
73 93
74 94
75 - private RuleNodeState state;  
76 -  
77 95
78 ReactState(String reactId, TbContext ctx, TbSceneReactNodeConfig config) { 96 ReactState(String reactId, TbContext ctx, TbSceneReactNodeConfig config) {
79 this.reactId = reactId; 97 this.reactId = reactId;
  98 + this.reactName = config.getNames().get(reactId);
80 TriggerService triggerService = SpringBeanUtils.getBean(TriggerService.class); 99 TriggerService triggerService = SpringBeanUtils.getBean(TriggerService.class);
81 this.triggers = triggerService.getTrigger(reactId); 100 this.triggers = triggerService.getTrigger(reactId);
82 DoConditionService conditionService = SpringBeanUtils.getBean(DoConditionService.class); 101 DoConditionService conditionService = SpringBeanUtils.getBean(DoConditionService.class);
83 this.conditions = conditionService.getConditions(reactId); 102 this.conditions = conditionService.getConditions(reactId);
84 DoActionService actionService = SpringBeanUtils.getBean(DoActionService.class); 103 DoActionService actionService = SpringBeanUtils.getBean(DoActionService.class);
85 this.actions = actionService.getActions(reactId); 104 this.actions = actionService.getActions(reactId);
  105 + for(DoAction action: actions){
  106 + /**动作中只有1个告警通知*/
  107 + if(ActionTypeEnum.MSG_NOTIFY.equals(action.getOutTarget())){
  108 + this.alarmAction = action;
  109 + break;
  110 + }
  111 + }
86 this.noticeService = SpringBeanUtils.getBean(YtNoticeService.class); 112 this.noticeService = SpringBeanUtils.getBean(YtNoticeService.class);
87 - 113 + this.ytDeviceService = SpringBeanUtils.getBean(YtDeviceService.class);
88 } 114 }
89 115
90 116
@@ -106,7 +132,12 @@ class ReactState { @@ -106,7 +132,12 @@ class ReactState {
106 matched = triggerState.process(ctx, msg); 132 matched = triggerState.process(ctx, msg);
107 if (matched) { 133 if (matched) {
108 detail.append(triggerState.getAlarmDetails()); 134 detail.append(triggerState.getAlarmDetails());
109 - break; 135 + if(this.alarmAction != null){
  136 + noticeMsg(ctx, msg, alarmAction,deviceId,triggerState.getAlarmDetails(),triggerState.getLatestValues().getTs());
  137 + }
  138 + }else if(currentAlarms.containsKey(deviceId) && this.alarmAction != null){
  139 + //清除设备告警
  140 + clearAlarm(ctx, msg, deviceId);
110 } 141 }
111 } 142 }
112 } 143 }
@@ -138,6 +169,9 @@ class ReactState { @@ -138,6 +169,9 @@ class ReactState {
138 169
139 if (matched) { 170 if (matched) {
140 for (DoAction item : actions) { 171 for (DoAction item : actions) {
  172 + if(ActionTypeEnum.MSG_NOTIFY.equals(item.getOutTarget())){
  173 + continue;
  174 + }
141 pushMsg(ctx, msg, item,detail.toString()); 175 pushMsg(ctx, msg, item,detail.toString());
142 } 176 }
143 } else { 177 } else {
@@ -162,6 +196,22 @@ class ReactState { @@ -162,6 +196,22 @@ class ReactState {
162 196
163 } 197 }
164 198
  199 + protected TriggerState getOrCreateClearState(String deviceId) {
  200 + if (triggerState.containsKey(deviceId)) {
  201 + return triggerState.get(deviceId);
  202 + }
  203 + if (alarmAction.getDeviceId().contains(deviceId)) {
  204 + ActionAlarmDTO alarm = JacksonUtil.convertValue(alarmAction.getDoContext(),ActionAlarmDTO.class);
  205 + if(alarm != null && alarm.getClearRule()!=null){
  206 + TriggerState state = createTriggerState(deviceId, alarm.getClearRule());
  207 + triggerState.put(deviceId, state);
  208 + return state;
  209 + }
  210 + }
  211 + return null;
  212 +
  213 + }
  214 +
165 protected TriggerState getOrCreateConditionState(String conditionId, String deviceId, AlarmRule condition) { 215 protected TriggerState getOrCreateConditionState(String conditionId, String deviceId, AlarmRule condition) {
166 String cacheKey = conditionId + deviceId; 216 String cacheKey = conditionId + deviceId;
167 if (conditionState.containsKey(cacheKey)) { 217 if (conditionState.containsKey(cacheKey)) {
@@ -197,9 +247,6 @@ class ReactState { @@ -197,9 +247,6 @@ class ReactState {
197 case SCENE_ACT: 247 case SCENE_ACT:
198 reactMsg(ctx, msg, action); 248 reactMsg(ctx, msg, action);
199 break; 249 break;
200 - case MSG_NOTIFY:  
201 - noticeMsg(ctx, msg, action,detail);  
202 - break;  
203 default: 250 default:
204 ctx.tellSuccess(msg); 251 ctx.tellSuccess(msg);
205 break; 252 break;
@@ -235,28 +282,59 @@ class ReactState { @@ -235,28 +282,59 @@ class ReactState {
235 * @param msg 282 * @param msg
236 * @param action 283 * @param action
237 */ 284 */
238 - private void noticeMsg(TbContext ctx, TbMsg msg, DoAction action,String detail) {  
239 - Alarm alarm = JacksonUtil.convertValue(msg.getData(), Alarm.class);  
240 - String tenantId = alarm.getTenantId().getId().toString();  
241 - String deviceId = alarm.getOriginator().getId().toString();  
242 - String severity = alarm.getSeverity().name(); 285 + private void noticeMsg(TbContext ctx, TbMsg msg, DoAction action,String deviceId,String detailStr,long startTs) {
  286 +
  287 + DeviceId entityId = new DeviceId(UUID.fromString(deviceId));
243 ActionAlarmDTO actionAlarm = JacksonUtil.convertValue(action.getDoContext(),ActionAlarmDTO.class); 288 ActionAlarmDTO actionAlarm = JacksonUtil.convertValue(action.getDoContext(),ActionAlarmDTO.class);
244 289
245 290
  291 + Alarm currentAlarm = new Alarm();
  292 + currentAlarm.setType(reactName);
  293 + currentAlarm.setStatus(AlarmStatus.ACTIVE_UNACK);
  294 + currentAlarm.setSeverity(actionAlarm.getAlarmLevel());
  295 + if (startTs == 0L) {
  296 + startTs = System.currentTimeMillis();
  297 + }
  298 + currentAlarm.setStartTs(startTs);
  299 + currentAlarm.setEndTs(currentAlarm.getStartTs());
  300 + ObjectNode detailData = JacksonUtil.newObjectNode();
  301 + detailData.put("msg",detailStr);
  302 + detailData.put("data",JacksonUtil.toJsonNode(msg.getData()));
  303 + currentAlarm.setDetails(detailData);
  304 + currentAlarm.setOriginator(entityId);
  305 + currentAlarm.setTenantId(ctx.getTenantId());
  306 + currentAlarm.setPropagate(false);
  307 +
  308 + currentAlarm = ctx.getAlarmService().createOrUpdateAlarm(currentAlarm);
  309 + ytDeviceService.freshAlarmStatus(entityId, 1);
  310 + currentAlarms.put(deviceId,currentAlarm);
  311 +
  312 +
  313 +
246 AlarmInfoDTO formData = new AlarmInfoDTO(); 314 AlarmInfoDTO formData = new AlarmInfoDTO();
247 formData.setDeviceName(msg.getMetaData().getData().get("deviceName")); 315 formData.setDeviceName(msg.getMetaData().getData().get("deviceName"));
248 - formData.setDetails(detail);  
249 - formData.setType(alarm.getType());  
250 - formData.setCreateTs(alarm.getCreatedTime());  
251 - formData.setStartTs(alarm.getStartTs());  
252 - formData.setEndTs(alarm.getEndTs());  
253 - formData.setStatus(alarm.getStatus().name()); 316 + formData.setDetails(JacksonUtil.toString(detailData));
  317 + formData.setType(currentAlarm.getType());
  318 + formData.setCreateTs(currentAlarm.getCreatedTime());
  319 + formData.setStartTs(currentAlarm.getStartTs());
  320 + formData.setEndTs(currentAlarm.getEndTs());
  321 + formData.setStatus(currentAlarm.getStatus().name());
254 formData.setDeviceId(deviceId); 322 formData.setDeviceId(deviceId);
255 - formData.setTenantId(tenantId); 323 + formData.setTenantId(currentAlarm.getTenantId().getId().toString());
256 formData.setSeverity(actionAlarm.getAlarmLevel().name()); 324 formData.setSeverity(actionAlarm.getAlarmLevel().name());
257 noticeService.alert(action.getAlarmProfileId(),formData); 325 noticeService.alert(action.getAlarmProfileId(),formData);
258 } 326 }
259 327
  328 + private void clearAlarm(TbContext ctx, TbMsg msg,String deviceId) throws ExecutionException, InterruptedException {
  329 + TriggerState clearStete = getOrCreateClearState(deviceId);
  330 + if(clearStete.process(ctx, msg)){
  331 + ctx.getAlarmService().clearAlarmForResult(ctx.getTenantId(), currentAlarms.get(deviceId).getId(), null, System.currentTimeMillis());
  332 + ytDeviceService.freshAlarmStatus(new DeviceId(UUID.fromString(deviceId)), 0);
  333 + currentAlarms.remove(deviceId);
  334 + }
  335 + }
  336 +
  337 +
260 private void reactMsg(TbContext ctx, TbMsg msg, DoAction action) { 338 private void reactMsg(TbContext ctx, TbMsg msg, DoAction action) {
261 //TODO: 场景联动关联消息通知 339 //TODO: 场景联动关联消息通知
262 String lastMsgQueueName = msg.getQueueName(); 340 String lastMsgQueueName = msg.getQueueName();
@@ -17,6 +17,8 @@ public class TbSceneReactNodeConfig implements NodeConfiguration<TbSceneReactNod @@ -17,6 +17,8 @@ public class TbSceneReactNodeConfig implements NodeConfiguration<TbSceneReactNod
17 17
18 /**【设备ID,场景】设备的哪些指标会触发场景联动*/ 18 /**【设备ID,场景】设备的哪些指标会触发场景联动*/
19 private Map<String, List<String>> scenes; 19 private Map<String, List<String>> scenes;
  20 + /**【场景ID,场景名称】场景联动信息*/
  21 + private Map<String, String> names;
20 22
21 23
22 24
@@ -27,6 +29,7 @@ public class TbSceneReactNodeConfig implements NodeConfiguration<TbSceneReactNod @@ -27,6 +29,7 @@ public class TbSceneReactNodeConfig implements NodeConfiguration<TbSceneReactNod
27 TbSceneReactNodeConfig config = new TbSceneReactNodeConfig(); 29 TbSceneReactNodeConfig config = new TbSceneReactNodeConfig();
28 Map<String, List<String>> sceneMap = new HashMap<>(); 30 Map<String, List<String>> sceneMap = new HashMap<>();
29 config.setScenes(sceneMap); 31 config.setScenes(sceneMap);
  32 + config.setNames(new HashMap<>());
30 return config; 33 return config;
31 } 34 }
32 } 35 }