Commit 059fe0b6e9005f6b9359752938d11462e94d3857

Authored by 云中非
1 parent df9ada88

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

... ... @@ -424,8 +424,10 @@ public class SceneLinkageServiceImpl extends AbstractBaseService<SceneLinkageMap
424 424 .eq(SceneLinkage::getStatus, FastIotConstants.StateValue.ENABLE)
425 425 );
426 426 Set<String> enableIds = new HashSet<>();
  427 + Map<String, String> sceneInform = new HashMap<>();
427 428 for (SceneLinkage item : runningScenes) {
428 429 enableIds.add(item.getId());
  430 + sceneInform.put(item.getId(),item.getName());
429 431 }
430 432 enableIds.add(currentSceneId);
431 433 if (state == FastIotConstants.StateValue.DISABLE) {
... ... @@ -488,6 +490,9 @@ public class SceneLinkageServiceImpl extends AbstractBaseService<SceneLinkageMap
488 490
489 491 Map<String, Map> engineConfig = new HashMap<>();
490 492 engineConfig.put("scenes", matchedDevices);
  493 + engineConfig.put("names", sceneInform);
  494 +
  495 +
491 496
492 497
493 498 return JacksonUtil.convertValue(engineConfig, JsonNode.class);
... ...
... ... @@ -4,31 +4,37 @@
4 4 package org.thingsboard.rule.engine.yunteng.scene;
5 5
6 6 import com.fasterxml.jackson.databind.JsonNode;
  7 +import com.fasterxml.jackson.databind.node.ObjectNode;
  8 +import com.google.common.util.concurrent.ListenableFuture;
7 9 import lombok.extern.slf4j.Slf4j;
8 10 import org.apache.commons.lang3.StringUtils;
9 11 import org.jetbrains.annotations.NotNull;
  12 +import org.thingsboard.common.util.DonAsynchron;
  13 +import org.thingsboard.rule.engine.action.TbAlarmResult;
10 14 import org.thingsboard.rule.engine.api.TbContext;
11 15 import org.thingsboard.server.common.data.DataConstants;
12 16 import org.thingsboard.server.common.data.alarm.Alarm;
  17 +import org.thingsboard.server.common.data.alarm.AlarmStatus;
13 18 import org.thingsboard.server.common.data.device.profile.AlarmCondition;
14 19 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter;
15 20 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey;
16 21 import org.thingsboard.server.common.data.device.profile.AlarmRule;
  22 +import org.thingsboard.server.common.data.id.DeviceId;
17 23 import org.thingsboard.server.common.data.rule.RuleNodeState;
18 24 import org.thingsboard.server.common.data.yunteng.dto.ActionAlarmDTO;
19 25 import org.thingsboard.server.common.data.yunteng.dto.AlarmInfoDTO;
  26 +import org.thingsboard.server.common.data.yunteng.dto.DoActionDTO;
20 27 import org.thingsboard.server.common.data.yunteng.dto.TriggerDTO;
  28 +import org.thingsboard.server.common.data.yunteng.enums.ActionTypeEnum;
21 29 import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil;
22 30 import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils;
23 31 import org.thingsboard.server.common.msg.TbMsg;
24 32 import org.thingsboard.server.common.msg.TbMsgMetaData;
25 33 import org.thingsboard.server.common.msg.queue.ServiceQueue;
  34 +import org.thingsboard.server.dao.alarm.AlarmOperationResult;
26 35 import org.thingsboard.server.dao.yunteng.entities.DoAction;
27 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 39 import java.net.InetAddress;
34 40 import java.util.*;
... ... @@ -42,25 +48,38 @@ class ReactState {
42 48 * 场景联动主键
43 49 */
44 50 String reactId;
  51 + String reactName;
45 52
46 53 /**
47 54 * 场景联动的触发器状态
48   - * 键:设备主
  55 + * 键:触发器ID和设备ID为
49 56 * 值:设备指标参与的触发器
50 57 */
51 58 private ConcurrentHashMap<String, TriggerState> triggerState = new ConcurrentHashMap<>();
52 59
  60 + /**
  61 + * 场景联动的告警清除触发器状态
  62 + * 键:设备ID为键
  63 + * 值:设备指标参与的触发器
  64 + */
53 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 78 private ConcurrentHashMap<String, TriggerState> conditionState = new ConcurrentHashMap<>();
61 79
62 80
63 81 private final List<TriggerDTO> triggers;
  82 + private DoAction alarmAction = null;
64 83 /**
65 84 * 【场景联动的执行条件】懒加载
66 85 */
... ... @@ -70,21 +89,28 @@ class ReactState {
70 89 */
71 90 private final List<DoAction> actions;
72 91 private final YtNoticeService noticeService;
  92 + private YtDeviceService ytDeviceService;
73 93
74 94
75   - private RuleNodeState state;
76   -
77 95
78 96 ReactState(String reactId, TbContext ctx, TbSceneReactNodeConfig config) {
79 97 this.reactId = reactId;
  98 + this.reactName = config.getNames().get(reactId);
80 99 TriggerService triggerService = SpringBeanUtils.getBean(TriggerService.class);
81 100 this.triggers = triggerService.getTrigger(reactId);
82 101 DoConditionService conditionService = SpringBeanUtils.getBean(DoConditionService.class);
83 102 this.conditions = conditionService.getConditions(reactId);
84 103 DoActionService actionService = SpringBeanUtils.getBean(DoActionService.class);
85 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 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 132 matched = triggerState.process(ctx, msg);
107 133 if (matched) {
108 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 169
139 170 if (matched) {
140 171 for (DoAction item : actions) {
  172 + if(ActionTypeEnum.MSG_NOTIFY.equals(item.getOutTarget())){
  173 + continue;
  174 + }
141 175 pushMsg(ctx, msg, item,detail.toString());
142 176 }
143 177 } else {
... ... @@ -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 215 protected TriggerState getOrCreateConditionState(String conditionId, String deviceId, AlarmRule condition) {
166 216 String cacheKey = conditionId + deviceId;
167 217 if (conditionState.containsKey(cacheKey)) {
... ... @@ -197,9 +247,6 @@ class ReactState {
197 247 case SCENE_ACT:
198 248 reactMsg(ctx, msg, action);
199 249 break;
200   - case MSG_NOTIFY:
201   - noticeMsg(ctx, msg, action,detail);
202   - break;
203 250 default:
204 251 ctx.tellSuccess(msg);
205 252 break;
... ... @@ -235,28 +282,59 @@ class ReactState {
235 282 * @param msg
236 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 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 314 AlarmInfoDTO formData = new AlarmInfoDTO();
247 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 322 formData.setDeviceId(deviceId);
255   - formData.setTenantId(tenantId);
  323 + formData.setTenantId(currentAlarm.getTenantId().getId().toString());
256 324 formData.setSeverity(actionAlarm.getAlarmLevel().name());
257 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 338 private void reactMsg(TbContext ctx, TbMsg msg, DoAction action) {
261 339 //TODO: 场景联动关联消息通知
262 340 String lastMsgQueueName = msg.getQueueName();
... ...
... ... @@ -17,6 +17,8 @@ public class TbSceneReactNodeConfig implements NodeConfiguration<TbSceneReactNod
17 17
18 18 /**【设备ID,场景】设备的哪些指标会触发场景联动*/
19 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 29 TbSceneReactNodeConfig config = new TbSceneReactNodeConfig();
28 30 Map<String, List<String>> sceneMap = new HashMap<>();
29 31 config.setScenes(sceneMap);
  32 + config.setNames(new HashMap<>());
30 33 return config;
31 34 }
32 35 }
... ...