Commit a71d5b7ee4627e843ad0c8687c69b037468c8e93

Authored by xp.Huang
2 parents 0919bfe5 f1b33f6e

Merge branch '20220317' into 'master'

refactor: 动作之设备输出

See merge request huang/thingsboard3.3.2!66
Showing 17 changed files with 424 additions and 395 deletions
... ... @@ -28,17 +28,18 @@ import java.net.InetAddress;
28 28 @RequiredArgsConstructor
29 29 @Slf4j
30 30 @Api(tags = {"告警通知"})
  31 +@Deprecated
31 32 public class YtAlarmNoticeController {
32 33
33 34 private final YtNoticeService service;
34 35
35   - @PostMapping("/alert")
  36 + @PostMapping("/alert/{alarmProfileId}")
36 37 public void alertNotice(@RequestParam(value = "token", required = true) String token,
37   - @RequestBody AlarmInfoDTO alarmInfo) {
  38 + @PathVariable("alarmProfileId") String alarmProfileId, @RequestBody AlarmInfoDTO alarmInfo) {
38 39 Assert.notNull(token, "token cannot be null");
39 40 Assert.notNull(alarmInfo, "alarm info cannot be null");
40 41 if (parseTokenClaims(token, alarmInfo)) {
41   - service.alert(alarmInfo);
  42 + service.alert(alarmProfileId, alarmInfo);
42 43 }
43 44 }
44 45
... ...
... ... @@ -47,221 +47,220 @@ import static org.thingsboard.server.common.data.yunteng.constant.QueryConstant.
47 47 @RequestMapping("api/yt/convert")
48 48 @Api(tags = {"数据流转控制器"})
49 49 public class YtConvertDataToController extends BaseController {
50   - private final YtRuleChainService ytRuleChainService;
  50 + private final YtRuleChainService ytRuleChainService;
51 51
52   - @Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.enabled}")
53   - private boolean debugPerTenantEnabled;
  52 + @Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.enabled}")
  53 + private boolean debugPerTenantEnabled;
54 54
55   - @Autowired(required = false)
56   - private ActorSystemContext actorContext;
  55 + @Autowired(required = false)
  56 + private ActorSystemContext actorContext;
57 57
58   - private final ConvertConfigService convertConfigService;
59   - private final SceneLinkageService sceneLinkageService;
  58 + private final ConvertConfigService convertConfigService;
  59 + private final SceneLinkageService sceneLinkageService;
60 60
61   - @GetMapping(params = {PAGE_SIZE, PAGE})
62   - @ApiOperation("分页查询")
63   - public YtPageData<ConvertConfigDTO> pageMessageConfig(
64   - @RequestParam(PAGE_SIZE) int pageSize,
65   - @RequestParam(PAGE) int page,
66   - @ApiParam(value = "0:转换脚本 1:数据流转") @RequestParam(value = "nodeType") Integer nodeType,
67   - @RequestParam(value = "name", required = false) String name,
68   - @RequestParam(value = "status", required = false) Integer status,
69   - @RequestParam(value = ORDER_FILED, required = false) String orderBy,
70   - @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType)
71   - throws ThingsboardException {
  61 + @GetMapping(params = {PAGE_SIZE, PAGE})
  62 + @ApiOperation("分页查询")
  63 + public YtPageData<ConvertConfigDTO> pageMessageConfig(
  64 + @RequestParam(PAGE_SIZE) int pageSize,
  65 + @RequestParam(PAGE) int page,
  66 + @ApiParam(value = "0:转换脚本 1:数据流转") @RequestParam(value = "nodeType") Integer nodeType,
  67 + @RequestParam(value = "name", required = false) String name,
  68 + @RequestParam(value = "status", required = false) Integer status,
  69 + @RequestParam(value = ORDER_FILED, required = false) String orderBy,
  70 + @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType)
  71 + throws ThingsboardException {
72 72
73   - HashMap<String, Object> queryMap = new HashMap<>();
74   - queryMap.put(PAGE_SIZE, pageSize);
75   - queryMap.put(PAGE, page);
76   - queryMap.put(ORDER_FILED, orderBy);
77   - queryMap.put("nodeType", nodeType);
78   - queryMap.put("name", name);
79   - queryMap.put("status", status);
80   - if (orderType != null) {
81   - queryMap.put(ORDER_TYPE, orderType.name());
  73 + HashMap<String, Object> queryMap = new HashMap<>();
  74 + queryMap.put(PAGE_SIZE, pageSize);
  75 + queryMap.put(PAGE, page);
  76 + queryMap.put(ORDER_FILED, orderBy);
  77 + queryMap.put("nodeType", nodeType);
  78 + queryMap.put("name", name);
  79 + queryMap.put("status", status);
  80 + if (orderType != null) {
  81 + queryMap.put(ORDER_TYPE, orderType.name());
  82 + }
  83 + return convertConfigService.page(getCurrentUser().getCurrentTenantId(), queryMap);
82 84 }
83   - return convertConfigService.page(getCurrentUser().getCurrentTenantId(), queryMap);
84   - }
85   -
86   - @PostMapping("config")
87   - @ApiOperation("添加或修改转换配置")
88   - public ResponseEntity<ConvertConfigDTO> createOrUpdateConvertData(
89   - @Validated @RequestBody ConvertConfigDTO convertConfigDTO) throws ThingsboardException {
90   - convertConfigDTO.setTenantId(getCurrentUser().getCurrentTenantId());
91   - convertConfigDTO.setNodeType(FastIotConstants.CONVERT_DATA);
92   - return ResponseEntity.ok(convertConfigService.createOrUpdate(convertConfigDTO));
93   - }
94 85
95   - @PostMapping("js")
96   - @ApiOperation("添加或修改转换脚本")
97   - public ResponseEntity<ConvertConfigDTO> createOrUpdateConvertJS(
98   - @Validated @RequestBody ConvertConfigDTO convertConfigDTO) throws ThingsboardException {
99   - convertConfigDTO.setTenantId(getCurrentUser().getCurrentTenantId());
100   - convertConfigDTO.setNodeType(FastIotConstants.JAVA_SCRIPT);
101   - return ResponseEntity.ok(convertConfigService.createOrUpdate(convertConfigDTO));
102   - }
103   -
104   - @PostMapping("/check/config")
105   - @ApiOperation("检查配置名称是否存在")
106   - public ResponseEntity<Boolean> checkConvertConfig(@RequestBody Map<String, String> checkParam)
107   - throws ThingsboardException {
108   - String type = checkParam.get("type");
109   - String name = checkParam.get("name");
110   - if (StringUtils.isEmpty(type) || StringUtils.isEmpty(name)) {
111   - throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  86 + @PostMapping("config")
  87 + @ApiOperation("添加或修改转换配置")
  88 + public ResponseEntity<ConvertConfigDTO> createOrUpdateConvertData(
  89 + @Validated @RequestBody ConvertConfigDTO convertConfigDTO) throws ThingsboardException {
  90 + convertConfigDTO.setTenantId(getCurrentUser().getCurrentTenantId());
  91 + convertConfigDTO.setNodeType(FastIotConstants.CONVERT_DATA);
  92 + return ResponseEntity.ok(convertConfigService.createOrUpdate(convertConfigDTO));
112 93 }
113   - return ResponseEntity.ok(
114   - convertConfigService.checkConvertConfigNameExist(
115   - null, name, type, getCurrentUser().getCurrentTenantId()));
116   - }
117 94
118   - @DeleteMapping("config")
119   - @ApiOperation("删除转换配置")
120   - public ResponseEntity<Boolean> deleteConfig(
121   - @Validated(DeleteGroup.class) @RequestBody DeleteDTO deleteDTO) throws ThingsboardException {
122   - return delete(deleteDTO, FastIotConstants.CONVERT_DATA);
123   - }
  95 + @PostMapping("js")
  96 + @ApiOperation("添加或修改转换脚本")
  97 + public ResponseEntity<ConvertConfigDTO> createOrUpdateConvertJS(
  98 + @Validated @RequestBody ConvertConfigDTO convertConfigDTO) throws ThingsboardException {
  99 + convertConfigDTO.setTenantId(getCurrentUser().getCurrentTenantId());
  100 + convertConfigDTO.setNodeType(FastIotConstants.JAVA_SCRIPT);
  101 + return ResponseEntity.ok(convertConfigService.createOrUpdate(convertConfigDTO));
  102 + }
124 103
125   - @DeleteMapping("js")
126   - @ApiOperation("删除转换脚本")
127   - public ResponseEntity<Boolean> deleteJS(
128   - @Validated(DeleteGroup.class) @RequestBody DeleteDTO deleteDTO) throws ThingsboardException {
129   - return delete(deleteDTO, FastIotConstants.JAVA_SCRIPT);
130   - }
  104 + @PostMapping("/check/config")
  105 + @ApiOperation("检查配置名称是否存在")
  106 + public ResponseEntity<Boolean> checkConvertConfig(@RequestBody Map<String, String> checkParam)
  107 + throws ThingsboardException {
  108 + String type = checkParam.get("type");
  109 + String name = checkParam.get("name");
  110 + if (StringUtils.isEmpty(type) || StringUtils.isEmpty(name)) {
  111 + throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  112 + }
  113 + return ResponseEntity.ok(
  114 + convertConfigService.checkConvertConfigNameExist(
  115 + null, name, type, getCurrentUser().getCurrentTenantId()));
  116 + }
131 117
132   - @PostMapping("update/config")
133   - @ApiOperation("启用或禁用配置")
134   - public RuleChainMetaData updateConfig(
135   - @Validated(UpdateGroup.class) @RequestBody ConvertConfigReqDTO convertConfigReqDTO)
136   - throws ThingsboardException {
137   - if (convertConfigService.checkConvertConfigStatusExist(
138   - convertConfigReqDTO.getConvertIds(),
139   - convertConfigReqDTO.getStatus(),
140   - getCurrentUser().getCurrentTenantId())) {
141   - throw new YtDataValidationException(ErrorMessage.DATA_ALREADY_EXISTS.getMessage());
  118 + @DeleteMapping("config")
  119 + @ApiOperation("删除转换配置")
  120 + public ResponseEntity<Boolean> deleteConfig(
  121 + @Validated(DeleteGroup.class) @RequestBody DeleteDTO deleteDTO) throws ThingsboardException {
  122 + return delete(deleteDTO, FastIotConstants.CONVERT_DATA);
142 123 }
143   - List<String> ids = convertConfigReqDTO.getConvertIds();
144   - int status = convertConfigReqDTO.getStatus();
145   - List<RuleNode> nodes =
146   - convertConfigService.getRuleNodesByConvertConfigIds(
147   - ids, null, FastIotConstants.CONVERT_DATA);
148   - RuleChainMetaData ruleChainMetaData = new RuleChainMetaData();
149   - if (null != nodes && nodes.size() > 0) {
150   - ruleChainMetaData = saveRuleChain(nodes, status, FastIotConstants.CONVERT_DATA);
  124 +
  125 + @DeleteMapping("js")
  126 + @ApiOperation("删除转换脚本")
  127 + public ResponseEntity<Boolean> deleteJS(
  128 + @Validated(DeleteGroup.class) @RequestBody DeleteDTO deleteDTO) throws ThingsboardException {
  129 + return delete(deleteDTO, FastIotConstants.JAVA_SCRIPT);
151 130 }
152   - convertConfigService.updateConvertStatusByIds(
153   - ids, status, getCurrentUser().getCurrentTenantId());
154   - return ruleChainMetaData;
155   - }
156 131
157   - @PostMapping("update/js")
158   - @ApiOperation("启用或禁用转换脚本")
159   - public RuleChainMetaData updateJs(
160   - @Validated(UpdateGroup.class) @RequestBody ConvertReqDTO convertJSReqDTO)
161   - throws ThingsboardException {
162   - int status = convertJSReqDTO.getStatus();
163   - if (status == FastIotConstants.StateValue.ENABLE
164   - && convertConfigService.checkConvertJSStatusEnable(getCurrentUser().getCurrentTenantId())) {
165   - throw new YtDataValidationException(ErrorMessage.CONVERT_JS_IS_ALONE.getMessage());
  132 + @PostMapping("update/config")
  133 + @ApiOperation("启用或禁用配置")
  134 + public RuleChainMetaData updateConfig(
  135 + @Validated(UpdateGroup.class) @RequestBody ConvertConfigReqDTO convertConfigReqDTO)
  136 + throws ThingsboardException {
  137 + if (convertConfigService.checkConvertConfigStatusExist(
  138 + convertConfigReqDTO.getConvertIds(),
  139 + convertConfigReqDTO.getStatus(),
  140 + getCurrentUser().getCurrentTenantId())) {
  141 + throw new YtDataValidationException(ErrorMessage.DATA_ALREADY_EXISTS.getMessage());
  142 + }
  143 + List<String> ids = convertConfigReqDTO.getConvertIds();
  144 + int status = convertConfigReqDTO.getStatus();
  145 + List<RuleNode> nodes =
  146 + convertConfigService.getRuleNodesByConvertConfigIds(
  147 + ids, null, FastIotConstants.CONVERT_DATA);
  148 + RuleChainMetaData ruleChainMetaData = new RuleChainMetaData();
  149 + if (null != nodes && nodes.size() > 0) {
  150 + ruleChainMetaData = saveRuleChain(nodes, status, FastIotConstants.CONVERT_DATA);
  151 + }
  152 + convertConfigService.updateConvertStatusByIds(
  153 + ids, status, getCurrentUser().getCurrentTenantId());
  154 + return ruleChainMetaData;
166 155 }
167   - List<String> ids = new ArrayList<>();
168   - ids.add(convertJSReqDTO.getId());
169   - List<RuleNode> nodes =
170   - convertConfigService.getRuleNodesByConvertConfigIds(
171   - ids, null, FastIotConstants.JAVA_SCRIPT);
172 156
173   - RuleChainMetaData ruleChainMetaData =
174   - saveRuleChain(nodes, status, FastIotConstants.JAVA_SCRIPT);
175   - convertConfigService.updateConvertStatusByIds(
176   - ids, status, getCurrentUser().getCurrentTenantId());
177   - return ruleChainMetaData;
178   - }
  157 + @PostMapping("update/js")
  158 + @ApiOperation("启用或禁用转换脚本")
  159 + public RuleChainMetaData updateJs(
  160 + @Validated(UpdateGroup.class) @RequestBody ConvertReqDTO convertJSReqDTO)
  161 + throws ThingsboardException {
  162 + int status = convertJSReqDTO.getStatus();
  163 + if (status == FastIotConstants.StateValue.ENABLE
  164 + && convertConfigService.checkConvertJSStatusEnable(getCurrentUser().getCurrentTenantId())) {
  165 + throw new YtDataValidationException(ErrorMessage.CONVERT_JS_IS_ALONE.getMessage());
  166 + }
  167 + List<String> ids = new ArrayList<>();
  168 + ids.add(convertJSReqDTO.getId());
  169 + List<RuleNode> nodes =
  170 + convertConfigService.getRuleNodesByConvertConfigIds(
  171 + ids, null, FastIotConstants.JAVA_SCRIPT);
179 172
180   - @PostMapping("update/scene")
181   - @ApiOperation("启用或禁用场景联动")
182   - public RuleChainMetaData updateScene(
183   - @Validated(UpdateGroup.class) @RequestBody ConvertReqDTO convertReqDTO)
184   - throws ThingsboardException {
185   - //TODO 通过接口获取JsonNode
186   - int status = -1;
187   - String sceneId = convertReqDTO.getId();
188   - String currentTenant = getCurrentUser().getCurrentTenantId();
189   - Integer sceneStatus = convertReqDTO.getStatus();
190   - JsonNode configuration = sceneLinkageService.getRuleNodeConfig(sceneId,currentTenant,getCurrentUser().getCustomerId().getId().toString(),sceneStatus);
191   - boolean noValue = configuration == null;
192   - if (noValue && convertReqDTO.getStatus() == FastIotConstants.StateValue.DISABLE) {
193   - status = FastIotConstants.StateValue.DISABLE;
  173 + RuleChainMetaData ruleChainMetaData =
  174 + saveRuleChain(nodes, status, FastIotConstants.JAVA_SCRIPT);
  175 + convertConfigService.updateConvertStatusByIds(
  176 + ids, status, getCurrentUser().getCurrentTenantId());
  177 + return ruleChainMetaData;
194 178 }
195   - if (!noValue) {
196   - status = FastIotConstants.StateValue.ENABLE;
197   - }
198   - List<RuleNode> ruleNodes = new ArrayList<>();
199   - RuleNode scene = new RuleNode();
200   - scene.setName("Scene");
201   - scene.setType("org.thingsboard.rule.engine.yunteng.scene.TbSceneReactNode");
202   - scene.setConfiguration(configuration);
203   - ruleNodes.add(scene);
204   - RuleChainMetaData result = saveRuleChain(ruleNodes, status, FastIotConstants.SCENE_REACT);
205   - sceneLinkageService.updateSceneStatus(sceneId,sceneStatus,currentTenant);
206   - return result;
207   - }
208 179
209   - /**
210   - * 保存规则链
211   - *
212   - * @param nodes 规则节点
213   - * @param status 0禁用 1启用
214   - * @return 规则节点数据
215   - */
216   - private RuleChainMetaData saveRuleChain(List<RuleNode> nodes, Integer status, Integer nodeType)
217   - throws ThingsboardException {
218   - boolean needSaveRuleNode;
219   - TenantId tenantId = getTenantId();
220   - // 1. GET DEFAULT RULE CHAIN
221   - RuleChain ruleChain = ytRuleChainService.getRootTenantRuleChain(getTenantId());
222   - // 2. GET RULE CHAIN METADATA
223   - RuleChainMetaData ruleChainMetaData =
224   - ruleChainService.loadRuleChainMetaData(getTenantId(), ruleChain.getId());
225   - // 3. SETUP CONNECTION AND ADD OR DELETE RULE NODE
226   - if (status == FastIotConstants.MagicNumber.ZERO) {
227   - needSaveRuleNode = convertConfigService.deleteRuleNode(nodes, ruleChainMetaData, nodeType);
228   - } else {
229   - convertConfigService.addRuleNode(nodes, ruleChainMetaData, nodeType);
230   - needSaveRuleNode = true;
  180 + @PostMapping("update/scene")
  181 + @ApiOperation("启用或禁用场景联动")
  182 + public RuleChainMetaData updateScene(
  183 + @Validated(UpdateGroup.class) @RequestBody ConvertReqDTO convertReqDTO)
  184 + throws ThingsboardException {
  185 + int status = -1;
  186 + String sceneId = convertReqDTO.getId();
  187 + String currentTenant = getCurrentUser().getCurrentTenantId();
  188 + Integer sceneStatus = convertReqDTO.getStatus();
  189 + JsonNode configuration = sceneLinkageService.getRuleNodeConfig(sceneId, currentTenant, getCurrentUser().getCustomerId().getId().toString(), sceneStatus);
  190 + boolean noValue = configuration == null;
  191 + if (noValue && convertReqDTO.getStatus() == FastIotConstants.StateValue.DISABLE) {
  192 + status = FastIotConstants.StateValue.DISABLE;
  193 + }
  194 + if (!noValue) {
  195 + status = FastIotConstants.StateValue.ENABLE;
  196 + }
  197 + List<RuleNode> ruleNodes = new ArrayList<>();
  198 + RuleNode scene = new RuleNode();
  199 + scene.setName("Scene");
  200 + scene.setType("org.thingsboard.rule.engine.yunteng.scene.TbSceneReactNode");
  201 + scene.setConfiguration(configuration);
  202 + ruleNodes.add(scene);
  203 + RuleChainMetaData result = saveRuleChain(ruleNodes, status, FastIotConstants.SCENE_REACT);
  204 + sceneLinkageService.updateSceneStatus(sceneId, sceneStatus, currentTenant);
  205 + return result;
231 206 }
232   - // 4. SAVE METADATA
233   - RuleChainMetaData savedRuleChainMetaData = null;
234   - if (needSaveRuleNode) {
235   - if (debugPerTenantEnabled) {
236   - ConcurrentMap<TenantId, DebugTbRateLimits> debugPerTenantLimits =
237   - actorContext.getDebugPerTenantLimits();
238   - DebugTbRateLimits debugTbRateLimits = debugPerTenantLimits.getOrDefault(tenantId, null);
239   - if (debugTbRateLimits != null) {
240   - debugPerTenantLimits.remove(tenantId, debugTbRateLimits);
  207 +
  208 + /**
  209 + * 保存规则链
  210 + *
  211 + * @param nodes 规则节点
  212 + * @param status 0禁用 1启用
  213 + * @return 规则节点数据
  214 + */
  215 + private RuleChainMetaData saveRuleChain(List<RuleNode> nodes, Integer status, Integer nodeType)
  216 + throws ThingsboardException {
  217 + boolean needSaveRuleNode;
  218 + TenantId tenantId = getTenantId();
  219 + // 1. GET DEFAULT RULE CHAIN
  220 + RuleChain ruleChain = ytRuleChainService.getRootTenantRuleChain(getTenantId());
  221 + // 2. GET RULE CHAIN METADATA
  222 + RuleChainMetaData ruleChainMetaData =
  223 + ruleChainService.loadRuleChainMetaData(getTenantId(), ruleChain.getId());
  224 + // 3. SETUP CONNECTION AND ADD OR DELETE RULE NODE
  225 + if (status == FastIotConstants.MagicNumber.ZERO) {
  226 + needSaveRuleNode = convertConfigService.deleteRuleNode(nodes, ruleChainMetaData, nodeType);
  227 + } else {
  228 + convertConfigService.addRuleNode(nodes, ruleChainMetaData, nodeType);
  229 + needSaveRuleNode = true;
241 230 }
242   - }
243   - checkNotNull(
244   - ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData) ? true : null);
245   - savedRuleChainMetaData =
246   - checkNotNull(
247   - ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId()));
  231 + // 4. SAVE METADATA
  232 + RuleChainMetaData savedRuleChainMetaData = null;
  233 + if (needSaveRuleNode) {
  234 + if (debugPerTenantEnabled) {
  235 + ConcurrentMap<TenantId, DebugTbRateLimits> debugPerTenantLimits =
  236 + actorContext.getDebugPerTenantLimits();
  237 + DebugTbRateLimits debugTbRateLimits = debugPerTenantLimits.getOrDefault(tenantId, null);
  238 + if (debugTbRateLimits != null) {
  239 + debugPerTenantLimits.remove(tenantId, debugTbRateLimits);
  240 + }
  241 + }
  242 + checkNotNull(
  243 + ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData) ? true : null);
  244 + savedRuleChainMetaData =
  245 + checkNotNull(
  246 + ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId()));
248 247
249   - if (RuleChainType.CORE.equals(ruleChain.getType())) {
250   - tbClusterService.broadcastEntityStateChangeEvent(
251   - ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED);
252   - }
  248 + if (RuleChainType.CORE.equals(ruleChain.getType())) {
  249 + tbClusterService.broadcastEntityStateChangeEvent(
  250 + ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED);
  251 + }
  252 + }
  253 + return savedRuleChainMetaData;
253 254 }
254   - return savedRuleChainMetaData;
255   - }
256 255
257   - private ResponseEntity<Boolean> delete(DeleteDTO deleteDTO, Integer nodeType)
258   - throws ThingsboardException {
259   - List<RuleNode> nodes =
260   - convertConfigService.getRuleNodesByConvertConfigIds(
261   - new ArrayList<>(deleteDTO.getIds()), FastIotConstants.StateValue.ENABLE, nodeType);
262   - if (nodes != null && nodes.size() > FastIotConstants.MagicNumber.ZERO) {
263   - saveRuleChain(nodes, 0, nodeType);
  256 + private ResponseEntity<Boolean> delete(DeleteDTO deleteDTO, Integer nodeType)
  257 + throws ThingsboardException {
  258 + List<RuleNode> nodes =
  259 + convertConfigService.getRuleNodesByConvertConfigIds(
  260 + new ArrayList<>(deleteDTO.getIds()), FastIotConstants.StateValue.ENABLE, nodeType);
  261 + if (nodes != null && nodes.size() > FastIotConstants.MagicNumber.ZERO) {
  262 + saveRuleChain(nodes, 0, nodeType);
  263 + }
  264 + return ResponseEntity.ok(convertConfigService.deleteConvertConfig(deleteDTO, nodeType));
264 265 }
265   - return ResponseEntity.ok(convertConfigService.deleteConvertConfig(deleteDTO, nodeType));
266   - }
267 266 }
... ...
... ... @@ -72,14 +72,14 @@ public interface FastIotConstants {
72 72 }
73 73
74 74 interface ReceiverType {
75   - String PERSONAL = "3";
76   - String DEPARTMENT = "2";
77   - String ORGANIZATION = "1";
78   - String ALL = "0";
  75 + int PERSONAL = 3;
  76 + int DEPARTMENT = 2;
  77 + int ORGANIZATION = 1;
  78 + int ALL = 0;
79 79 }
80 80
81 81 interface DraftStatus {
82   - String PUBLISHED = "1";
83   - String DRAFT = "0";
  82 + int PUBLISHED = 1;
  83 + int DRAFT = 0;
84 84 }
85 85 }
... ...
... ... @@ -12,19 +12,14 @@ import org.thingsboard.server.common.data.yunteng.enums.ScopeEnum;
12 12 import java.util.List;
13 13
14 14 /**
15   - * @Description 场景联动动作告警通知
  15 + * @Description 场景联动动作告警通知
16 16 * @Author cxy
17 17 * @Date 2021/11/24 17:32
18 18 */
19 19 @Data
20   -public class ActionAlarmDTO extends TenantDTO{
  20 +public class ActionAlarmDTO extends TenantDTO {
21 21
22 22
23   - private List<ActionTypeEnum> noticeType;
24   -
25   - /**告警联系人*/
26   - private List<String> noticeUser;
27   -
28 23 private AlarmSeverity alarmLevel;
29 24
30 25
... ...
... ... @@ -6,37 +6,38 @@ import lombok.EqualsAndHashCode;
6 6
7 7 import javax.validation.constraints.NotEmpty;
8 8
9   -/** @Description @Author cxy @Date 2021/11/16 17:49 */
  9 +/**
  10 + * @Description @Author cxy @Date 2021/11/16 17:49
  11 + */
10 12 @Data
11 13 @EqualsAndHashCode(callSuper = true)
12 14 public class AlarmInfoDTO extends TenantDTO {
13   - @ApiModelProperty(value = "告警时间")
14   - private long createTs;
  15 + @ApiModelProperty(value = "告警时间")
  16 + private long createTs;
15 17
16   - @ApiModelProperty(value = "告警类型")
17   - private String type;
  18 + @ApiModelProperty(value = "告警名称")
  19 + private String type;
18 20
19   - @ApiModelProperty(value = "告警详情")
20   - private String details;
  21 + @ApiModelProperty(value = "告警详情")
  22 + private String details;
21 23
22 24
23   - @ApiModelProperty(value = "告警开始时间")
24   - private long startTs;
  25 + @ApiModelProperty(value = "告警开始时间")
  26 + private long startTs;
25 27
26   - @ApiModelProperty(value = "告警结束时间")
27   - private long endTs;
  28 + @ApiModelProperty(value = "告警结束时间")
  29 + private long endTs;
28 30
29   - @ApiModelProperty(value = "告警状态")
30   - private String status;
  31 + @ApiModelProperty(value = "告警状态")
  32 + private String status;
31 33
32   - @ApiModelProperty(value = "告警程度")
33   - private String severity;
  34 + @ApiModelProperty(value = "告警程度")
  35 + private String severity;
34 36
35 37
36   -
37   - @ApiModelProperty(value = "告警设备名称")
38   - private String deviceName;
39   - @ApiModelProperty(value = "告警设备ID")
40   - @NotEmpty(message = "设备ID不能为空")
41   - private String deviceId;
  38 + @ApiModelProperty(value = "告警设备名称")
  39 + private String deviceName;
  40 + @ApiModelProperty(value = "告警设备ID")
  41 + @NotEmpty(message = "设备ID不能为空")
  42 + private String deviceId;
42 43 }
... ...
... ... @@ -31,13 +31,13 @@ public class SysNoticeDTO extends TenantDTO {
31 31 private String content;
32 32
33 33 @ApiModelProperty(value = "接收者(字典值receiver_type) 0:全部 1:组织 2:部门 3:个人",required = true)
34   - private String receiverType;
  34 + private Integer receiverType;
35 35
36 36 @ApiModelProperty(value = "根据receiverType不同变化,0:传null,1:组织id,2:部门id,3:用户id",required = true)
37 37 private String pointId;
38 38
39 39 @ApiModelProperty(value = "发送状态(字典值draft_status) 0:草稿 1:已发布")
40   - private String status;
  40 + private Integer status;
41 41
42 42 @ApiModelProperty(value = "发送者")
43 43 private String senderName;
... ...
... ... @@ -27,9 +27,9 @@ public class SysNotice extends TenantBaseEntity {
27 27 /** 内容 */
28 28 private String content;
29 29 /** 接收者(字典值receiver_type) 0:全部 1:组织 2:部门 3:个人 */
30   - private String receiverType;
  30 + private int receiverType;
31 31 /** 发送状态(字典值draft_status) 0:草稿 1:已发布 */
32   - private String status;
  32 + private int status;
33 33 /** 发送者 */
34 34 private String senderName;
35 35 /** 发送时间 */
... ...
... ... @@ -30,5 +30,5 @@ public class SysNoticeUser extends TenantBaseEntity {
30 30 /** 阅读时间 */
31 31 private LocalDateTime readDate;
32 32 /** 通知用户状态: 0 草稿 1已发布 */
33   - private String status;
  33 + private Integer status;
34 34 }
... ...
... ... @@ -73,7 +73,7 @@ public class SysNoticeUserServiceImpl
73 73
74 74 @Override
75 75 public void saveSysNoticeUser(
76   - List<String> userIds, String tenantId, String noticeId, String status) {
  76 + List<String> userIds, String tenantId, String noticeId, Integer status) {
77 77 List<User> userList = userMapper
78 78 .selectList(
79 79 new LambdaQueryWrapper<User>().in(User::getId, userIds))
... ... @@ -108,8 +108,8 @@ public class SysNoticeUserServiceImpl
108 108 }
109 109
110 110 @Override
111   - public boolean updateSysNoticeUsersStatusByNoticeId(String id, String status) {
112   - if (StringUtils.isAllEmpty(id) || StringUtils.isAllEmpty(status)) {
  111 + public boolean updateSysNoticeUsersStatusByNoticeId(String id, Integer status) {
  112 + if (StringUtils.isAllEmpty(id) || status == null) {
113 113 throw new YtDataValidationException(ErrorMessage.INTERNAL_ERROR.name());
114 114 }
115 115 return baseMapper.updateSysNoticeUsersStatusByNoticeId(id, status);
... ...
... ... @@ -13,13 +13,10 @@ import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum;
13 13 import org.thingsboard.server.common.data.yunteng.utils.YtDateTimeUtils;
14 14 import org.thingsboard.server.dao.yunteng.entities.*;
15 15 import org.thingsboard.server.dao.yunteng.mapper.*;
16   -import org.thingsboard.server.dao.yunteng.service.YtNoticeService;
17 16 import org.thingsboard.server.dao.yunteng.service.YtMailService;
  17 +import org.thingsboard.server.dao.yunteng.service.YtNoticeService;
18 18 import org.thingsboard.server.dao.yunteng.service.YtSmsService;
19 19
20   -import java.time.LocalDateTime;
21   -import java.time.OffsetDateTime;
22   -import java.time.format.DateTimeFormatter;
23 20 import java.util.*;
24 21 import java.util.stream.Collectors;
25 22
... ... @@ -47,7 +44,7 @@ public class YtNoticeServiceImpl implements YtNoticeService {
47 44 private final YtMailService mailService;
48 45
49 46 @Override
50   - public void alert(AlarmInfoDTO alarmInfo) {
  47 + public void alert(String profileId, AlarmInfoDTO alarmInfo) {
51 48
52 49 /**
53 50 * 1、查找设备和设备所属组织
... ... @@ -68,11 +65,8 @@ public class YtNoticeServiceImpl implements YtNoticeService {
68 65 .eq(Organization::getId, device.getOrganizationId());
69 66 Organization organization = organizationMapper.selectOne(organizationQueryWrapper);
70 67
71   - QueryWrapper<AlarmProfile> alarmProfileQueryWrapper = new QueryWrapper<AlarmProfile>();
72   - //TODO junlianglee 修改通知
73   -// alarmProfileQueryWrapper.lambda()
74   -// .eq(AlarmProfile::getDeviceProfileId, device.getProfileId());
75   - AlarmProfile alarmProfile = alarmProfileMapper.selectOne(alarmProfileQueryWrapper);
  68 +
  69 + AlarmProfile alarmProfile = alarmProfileMapper.selectById(profileId);
76 70
77 71
78 72 if (alarmProfile == null || alarmProfile.getAlarmContactId().isEmpty() || alarmProfile.getMessageMode().isEmpty()) {
... ... @@ -80,7 +74,7 @@ public class YtNoticeServiceImpl implements YtNoticeService {
80 74 }
81 75 String messageCode = alarmProfile.getMessageMode();
82 76 List<AlarmContact> alarmContactList = alarmContactMapper.selectBatchIds(Arrays.stream(alarmProfile.getAlarmContactId().split(",")).distinct().collect(Collectors.toList()));
83   - noticeAll(messageCode, alarmContactList, alarmInfo, organization,alarmProfile.getTenantId());
  77 + noticeAll(messageCode, alarmContactList, alarmInfo, organization, alarmProfile.getTenantId());
84 78
85 79
86 80 }
... ... @@ -93,7 +87,7 @@ public class YtNoticeServiceImpl implements YtNoticeService {
93 87 * @param alarmInfo 通知内容
94 88 * @param organization 设备所属组织
95 89 */
96   - private void noticeAll(String messageCode, List<AlarmContact> alarmContactList, AlarmInfoDTO alarmInfo, Organization organization,String tenantId) {
  90 + private void noticeAll(String messageCode, List<AlarmContact> alarmContactList, AlarmInfoDTO alarmInfo, Organization organization, String tenantId) {
97 91 Optional.ofNullable(alarmContactList).ifPresent(contacts -> {
98 92
99 93 /**可用的告警通知模板*/
... ... @@ -113,35 +107,36 @@ public class YtNoticeServiceImpl implements YtNoticeService {
113 107
114 108 if (messageCode.contains(MessageTypeEnum.PHONE_MESSAGE.name())
115 109 && templatesMap.containsKey(MessageTypeEnum.PHONE_MESSAGE.name())) {
116   - sms4Alarm(alarmInfo,templatesMap.get(MessageTypeEnum.PHONE_MESSAGE.name()),organization,contacts);
  110 + sms4Alarm(alarmInfo, templatesMap.get(MessageTypeEnum.PHONE_MESSAGE.name()), organization, contacts);
117 111 }
118 112
119 113 if (messageCode.contains(MessageTypeEnum.EMAIL_MESSAGE.name())
120 114 && templatesMap.containsKey(MessageTypeEnum.EMAIL_MESSAGE.name())) {
121   - email4Alarm(alarmInfo,templatesMap.get(MessageTypeEnum.EMAIL_MESSAGE.name()),organization,contacts);
  115 + email4Alarm(alarmInfo, templatesMap.get(MessageTypeEnum.EMAIL_MESSAGE.name()), organization, contacts);
122 116 }
123 117
124 118
125 119 if (messageCode.contains(MessageTypeEnum.DING_TALK_MESSAGE.name())
126 120 && templatesMap.containsKey(MessageTypeEnum.DING_TALK_MESSAGE.name())) {
127   - dingTalk4Alarm(alarmInfo,templatesMap.get(MessageTypeEnum.DING_TALK_MESSAGE.name()),organization,contacts);
  121 + dingTalk4Alarm(alarmInfo, templatesMap.get(MessageTypeEnum.DING_TALK_MESSAGE.name()), organization, contacts);
128 122 }
129 123
130 124 if (messageCode.contains(MessageTypeEnum.WECHAT_MESSAGE.name())
131 125 && templatesMap.containsKey(MessageTypeEnum.WECHAT_MESSAGE.name())) {
132   - weChat4Alarm(alarmInfo,templatesMap.get(MessageTypeEnum.WECHAT_MESSAGE.name()),organization,contacts);
  126 + weChat4Alarm(alarmInfo, templatesMap.get(MessageTypeEnum.WECHAT_MESSAGE.name()), organization, contacts);
133 127 }
134 128 });
135 129 }
136 130
137 131 /**
138 132 * 短信通知设备告警信息
139   - * @param alarmInfo 告警信息
140   - * @param templateId 告警模板主键
141   - * @param organization 设备所属组织
142   - * @param contacts 设备告警联系人
  133 + *
  134 + * @param alarmInfo 告警信息
  135 + * @param templateId 告警模板主键
  136 + * @param organization 设备所属组织
  137 + * @param contacts 设备告警联系人
143 138 */
144   - private void sms4Alarm(AlarmInfoDTO alarmInfo,String templateId, Organization organization,List<AlarmContact> contacts){
  139 + private void sms4Alarm(AlarmInfoDTO alarmInfo, String templateId, Organization organization, List<AlarmContact> contacts) {
145 140 SmsReqDTO info = new SmsReqDTO();
146 141 info.setId(templateId);
147 142 info.setTemplatePurpose(MsgTemplatePurposeEnum.FOR_ALARM_NOTICE.name());
... ... @@ -163,12 +158,13 @@ public class YtNoticeServiceImpl implements YtNoticeService {
163 158
164 159 /**
165 160 * 邮件通知设备告警信息
166   - * @param alarmInfo 告警信息
167   - * @param templateId 告警模板主键
168   - * @param organization 设备所属组织
169   - * @param contacts 设备告警联系人
  161 + *
  162 + * @param alarmInfo 告警信息
  163 + * @param templateId 告警模板主键
  164 + * @param organization 设备所属组织
  165 + * @param contacts 设备告警联系人
170 166 */
171   - private void email4Alarm(AlarmInfoDTO alarmInfo,String templateId, Organization organization,List<AlarmContact> contacts){
  167 + private void email4Alarm(AlarmInfoDTO alarmInfo, String templateId, Organization organization, List<AlarmContact> contacts) {
172 168 List<String> emailReceivers = new ArrayList<>();
173 169 contacts.stream().parallel().forEach(item -> {
174 170 if (!item.getEmail().isEmpty()) {
... ... @@ -178,12 +174,12 @@ public class YtNoticeServiceImpl implements YtNoticeService {
178 174 if (!emailReceivers.isEmpty()) {
179 175 EmailReqDTO info = new EmailReqDTO();
180 176 info.setTo(emailReceivers.toArray(new String[emailReceivers.size()]));
181   - info.setSubject(String.format("【%s】告警通知",alarmInfo.getDeviceName()));
182   - String body =String.format("%s位于【%s】的设备【%s】触发【%s】级的【%s】,请尽快处理!"
183   - ,YtDateTimeUtils.formate(alarmInfo.getCreateTs())
  177 + info.setSubject(String.format("【%s】告警通知", alarmInfo.getDeviceName()));
  178 + String body = String.format("%s位于【%s】的设备【%s】触发【%s】级的【%s】,请尽快处理!"
  179 + , YtDateTimeUtils.formate(alarmInfo.getCreateTs())
184 180 , organization != null ? organization.getName() : ""
185   - ,alarmInfo.getDeviceName()
186   - ,alarmInfo.getSeverity()
  181 + , alarmInfo.getDeviceName()
  182 + , alarmInfo.getSeverity()
187 183 , alarmInfo.getType());
188 184 info.setBody(body);
189 185 info.setEmailFormatEnum(EmailFormatEnum.TEXT.name());
... ... @@ -196,12 +192,13 @@ public class YtNoticeServiceImpl implements YtNoticeService {
196 192
197 193 /**
198 194 * 钉钉通知设备告警信息
199   - * @param alarmInfo 告警信息
200   - * @param templateId 告警模板主键
201   - * @param organization 设备所属组织
202   - * @param contacts 设备告警联系人
  195 + *
  196 + * @param alarmInfo 告警信息
  197 + * @param templateId 告警模板主键
  198 + * @param organization 设备所属组织
  199 + * @param contacts 设备告警联系人
203 200 */
204   - private void dingTalk4Alarm(AlarmInfoDTO alarmInfo,String templateId, Organization organization,List<AlarmContact> contacts){
  201 + private void dingTalk4Alarm(AlarmInfoDTO alarmInfo, String templateId, Organization organization, List<AlarmContact> contacts) {
205 202 // TODO 推送钉钉消息
206 203 SmsReqDTO info = new SmsReqDTO();
207 204 info.setId(templateId);
... ... @@ -224,12 +221,13 @@ public class YtNoticeServiceImpl implements YtNoticeService {
224 221
225 222 /**
226 223 * 微信通知设备告警信息
227   - * @param alarmInfo 告警信息
228   - * @param templateId 告警模板主键
229   - * @param organization 设备所属组织
230   - * @param contacts 设备告警联系人
  224 + *
  225 + * @param alarmInfo 告警信息
  226 + * @param templateId 告警模板主键
  227 + * @param organization 设备所属组织
  228 + * @param contacts 设备告警联系人
231 229 */
232   - private void weChat4Alarm(AlarmInfoDTO alarmInfo,String templateId, Organization organization,List<AlarmContact> contacts){
  230 + private void weChat4Alarm(AlarmInfoDTO alarmInfo, String templateId, Organization organization, List<AlarmContact> contacts) {
233 231 // TODO 推送微信通知
234 232 SmsReqDTO info = new SmsReqDTO();
235 233 info.setId(templateId);
... ...
... ... @@ -30,7 +30,7 @@ public interface SysNoticeUserMapper extends BaseMapper<SysNoticeUser> {
30 30 */
31 31 SysNoticeUserDTO get(@Param("id") String id, @Param("tenantId") String tenantId);
32 32
33   - boolean updateSysNoticeUsersStatusByNoticeId(@Param("noticeId")String noticeId, @Param("status")String status);
  33 + boolean updateSysNoticeUsersStatusByNoticeId(@Param("noticeId")String noticeId, @Param("status")Integer status);
34 34
35 35
36 36 }
... ...
... ... @@ -21,11 +21,11 @@ public interface SysNoticeUserService extends BaseService<SysNoticeUser>{
21 21
22 22 SysNoticeUserDTO get(String id,String tenantId);
23 23
24   - void saveSysNoticeUser (List<String> userIds, String tenantId,String noticeId,String status);
  24 + void saveSysNoticeUser (List<String> userIds, String tenantId,String noticeId,Integer status);
25 25
26 26 List<String> getSysNoticeUserIdsByNoticeId(String noticeId);
27 27
28   - boolean updateSysNoticeUsersStatusByNoticeId(String noticeId, String status);
  28 + boolean updateSysNoticeUsersStatusByNoticeId(String noticeId, Integer status);
29 29
30 30 boolean deleteNoticUserByNoticeId(List<String> noticeId);
31 31 }
... ...
... ... @@ -18,8 +18,9 @@ public interface YtNoticeService {
18 18 * 设备告警通知负责人
19 19 * * @param alarmInfo
20 20 *
  21 + * @param profileId 告警配置主键
21 22 * @param alarmInfo 告警数据
22 23 */
23   - void alert(AlarmInfoDTO alarmInfo);
  24 + void alert(String profileId, AlarmInfoDTO alarmInfo);
24 25
25 26 }
... ...
... ... @@ -32,15 +32,15 @@
32 32 sn.id id,
33 33 sn.type AS type,
34 34 sn.title title,
35   - sn.content AS content,
36   - (
37   - <include refid="dict"/>
38   - AND sd.dict_code = 'receiver_type' AND sdi.item_value = sn.receiver_type
39   - ) receiver_type,
40   - (
41   - <include refid="dict"/>
42   - AND sd.dict_code = 'draft_status' AND sdi.item_value = sn.status
43   - ) status,
  35 + sn.content AS content,sn.receiver_type,sn.status,
  36 +<!-- (-->
  37 +<!-- <include refid="dict"/>-->
  38 +<!-- AND sd.dict_code = 'receiver_type' AND sdi.item_value = sn.receiver_type-->
  39 +<!-- ) receiver_type,-->
  40 +<!-- (-->
  41 +<!-- <include refid="dict"/>-->
  42 +<!-- AND sd.dict_code = 'draft_status' AND sdi.item_value = sn.status-->
  43 +<!-- ) status,-->
44 44 sn.sender_name sender_name,
45 45 sn.sender_date sender_date,
46 46 sn.creator creator,
... ...
... ... @@ -33,15 +33,9 @@ import java.net.InetAddress;
33 33 import static org.thingsboard.common.util.DonAsynchron.withCallback;
34 34
35 35 @Slf4j
36   -@RuleNode(
37   - type = ComponentType.EXTERNAL,
38   - name = "alarm notice",
39   - configClazz = AlarmNoticeNodeConfiguration.class,
40   - nodeDescription = "while device alarm, notice some people.",
41   - nodeDetails = "notice method include sms,email and so on.",
  36 +@RuleNode(type = ComponentType.EXTERNAL, name = "alarm notice", configClazz = AlarmNoticeNodeConfiguration.class, nodeDescription = "while device alarm, notice some people.", nodeDetails = "notice method include sms,email and so on.",
42 37 // configDirective = "tbActionNodeSendSmsConfig",
43   - icon = "sms"
44   -)
  38 + icon = "sms")
45 39 public class AlarmNoticeNode implements TbNode {
46 40
47 41 private AlarmNoticeNodeConfiguration config;
... ... @@ -64,11 +58,11 @@ public class AlarmNoticeNode implements TbNode {
64 58 public void onMsg(TbContext ctx, TbMsg msg) {
65 59 try {
66 60 withCallback(ctx.getSmsExecutor().executeAsync(() -> {
67   - posetApi(ctx, msg);
68   - return null;
69   - }),
70   - ok -> {ctx.tellSuccess(msg);},
71   - fail -> ctx.tellFailure(msg, fail));
  61 + posetApi(ctx, msg);
  62 + return null;
  63 + }), ok -> {
  64 + ctx.tellSuccess(msg);
  65 + }, fail -> ctx.tellFailure(msg, fail));
72 66 } catch (Exception ex) {
73 67 ctx.tellFailure(msg, ex);
74 68 }
... ... @@ -96,7 +90,7 @@ public class AlarmNoticeNode implements TbNode {
96 90 formData.setTenantId(tenantId);
97 91 formData.setSeverity(severity);
98 92
99   - service.alert(formData);
  93 + service.alert(null, formData);
100 94 }
101 95
102 96 @Override
... ...
... ... @@ -9,11 +9,14 @@ import org.apache.commons.lang3.StringUtils;
9 9 import org.jetbrains.annotations.NotNull;
10 10 import org.thingsboard.rule.engine.api.TbContext;
11 11 import org.thingsboard.server.common.data.DataConstants;
  12 +import org.thingsboard.server.common.data.alarm.Alarm;
12 13 import org.thingsboard.server.common.data.device.profile.AlarmCondition;
13 14 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter;
14 15 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey;
15 16 import org.thingsboard.server.common.data.device.profile.AlarmRule;
16 17 import org.thingsboard.server.common.data.rule.RuleNodeState;
  18 +import org.thingsboard.server.common.data.yunteng.dto.ActionAlarmDTO;
  19 +import org.thingsboard.server.common.data.yunteng.dto.AlarmInfoDTO;
17 20 import org.thingsboard.server.common.data.yunteng.dto.TriggerDTO;
18 21 import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil;
19 22 import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils;
... ... @@ -25,7 +28,9 @@ import org.thingsboard.server.dao.yunteng.entities.DoCondition;
25 28 import org.thingsboard.server.dao.yunteng.service.DoActionService;
26 29 import org.thingsboard.server.dao.yunteng.service.DoConditionService;
27 30 import org.thingsboard.server.dao.yunteng.service.TriggerService;
  31 +import org.thingsboard.server.dao.yunteng.service.YtNoticeService;
28 32
  33 +import java.net.InetAddress;
29 34 import java.util.*;
30 35 import java.util.concurrent.ConcurrentHashMap;
31 36 import java.util.concurrent.ExecutionException;
... ... @@ -33,121 +38,122 @@ import java.util.concurrent.ExecutionException;
33 38 @Slf4j
34 39 class ReactState {
35 40
36   - /**场景联动主键*/
  41 + /**
  42 + * 场景联动主键
  43 + */
37 44 String reactId;
38 45
39   - /**场景联动的触发器状态
  46 + /**
  47 + * 场景联动的触发器状态
40 48 * 键:设备主键
41 49 * 值:设备指标参与的触发器
42 50 */
43   - private ConcurrentHashMap<String, TriggerState > triggerState = new ConcurrentHashMap<>();
  51 + private ConcurrentHashMap<String, TriggerState> triggerState = new ConcurrentHashMap<>();
44 52
45 53 private ConcurrentHashMap<String, TriggerState> clearState = new ConcurrentHashMap<>();
46 54
47   - /**场景联动的执行条件状态
  55 + /**
  56 + * 场景联动的执行条件状态
48 57 * 键:设备主键
49 58 * 值:设备指标参与的触发器
50 59 */
51 60 private ConcurrentHashMap<String, TriggerState> conditionState = new ConcurrentHashMap<>();
52 61
53 62
54   -
55   -
56   -
57 63 private final List<TriggerDTO> triggers;
58   - /**【场景联动的执行条件】懒加载*/
  64 + /**
  65 + * 【场景联动的执行条件】懒加载
  66 + */
59 67 private final List<DoCondition> conditions;
60   - /**【场景联动的执行集合】懒加载*/
  68 + /**
  69 + * 【场景联动的执行集合】懒加载
  70 + */
61 71 private final List<DoAction> actions;
62   -
63   -
64   -
  72 + private final YtNoticeService noticeService;
65 73
66 74
67 75 private RuleNodeState state;
68 76
69 77
70   - ReactState(String reactId,TbContext ctx, TbSceneReactNodeConfig config) {
  78 + ReactState(String reactId, TbContext ctx, TbSceneReactNodeConfig config) {
71 79 this.reactId = reactId;
72 80 TriggerService triggerService = SpringBeanUtils.getBean(TriggerService.class);
73 81 this.triggers = triggerService.getTrigger(reactId);
74 82 DoConditionService conditionService = SpringBeanUtils.getBean(DoConditionService.class);
75 83 this.conditions = conditionService.getConditions(reactId);
76 84 DoActionService actionService = SpringBeanUtils.getBean(DoActionService.class);
77   - this.actions =actionService.getActions(reactId);
  85 + this.actions = actionService.getActions(reactId);
  86 + this.noticeService = SpringBeanUtils.getBean(YtNoticeService.class);
78 87
79 88 }
80 89
81 90
82   -
83   - public void process(TbContext ctx, TbMsg msg,String deviceId) throws ExecutionException, InterruptedException {
84   -
85   -
  91 + public void process(TbContext ctx, TbMsg msg, String deviceId) throws ExecutionException, InterruptedException {
86 92
87 93
88   - if( actions == null){
  94 + StringBuilder detail = new StringBuilder();
  95 + if (actions == null) {
89 96 ctx.tellSuccess(msg);
90 97 }
91 98
92 99 boolean matched;
93   - if(triggers == null || triggers.isEmpty()){
  100 + if (triggers == null || triggers.isEmpty()) {
94 101 matched = true;
95   - }else{
  102 + } else {
96 103 matched = false;
97   - for(TriggerDTO trigger: triggers){
98   - TriggerState triggerState = getOrCreateTriggerState(trigger,deviceId);
99   - matched = triggerState.process(ctx,msg);
100   - if(matched){
  104 + for (TriggerDTO trigger : triggers) {
  105 + TriggerState triggerState = getOrCreateTriggerState(trigger, deviceId);
  106 + matched = triggerState.process(ctx, msg);
  107 + if (matched) {
  108 + detail.append(triggerState.getAlarmDetails());
101 109 break;
102 110 }
103 111 }
104 112 }
105 113
106 114
107   - if(matched && conditions.size() >0 ){
  115 + if (matched && conditions.size() > 0) {
108 116 matched = false;
109   - for(DoCondition item:conditions){
  117 + for (DoCondition item : conditions) {
110 118 List<String> entityIds = item.getEntityId();
111   - if(entityIds == null || entityIds.isEmpty()){
  119 + if (entityIds == null || entityIds.isEmpty()) {
112 120 matched = true;
113 121 break;
114 122 }
115   - for(String id:entityIds){
116   - TriggerState conditionState = getOrCreateConditionState(item.getId(),id,item.getTriggerCondition());
117   - if( conditionState == null
118   - || conditionState.process(ctx,msg)){
  123 + for (String id : entityIds) {
  124 + TriggerState conditionState = getOrCreateConditionState(item.getId(), id, item.getTriggerCondition());
  125 + if (conditionState == null
  126 + || conditionState.process(ctx, msg)) {
  127 + detail.append(";");
  128 + detail.append(conditionState.getAlarmDetails());
119 129 matched = true;
120 130 break;
121 131 }
122 132 }
123   - if(matched){
  133 + if (matched) {
124 134 break;
125 135 }
126 136 }
127 137 }
128 138
129   - if(matched){
130   - for(DoAction item: actions){
131   - pushMsg(ctx, msg, item);
  139 + if (matched) {
  140 + for (DoAction item : actions) {
  141 + pushMsg(ctx, msg, item,detail.toString());
132 142 }
133   - }else{
  143 + } else {
134 144 ctx.tellSuccess(msg);
135 145 }
136 146
137 147 }
138 148
139 149
140   -
141   -
142   -
143   -
144   - protected TriggerState getOrCreateTriggerState(TriggerDTO trigger,String deviceId) {
  150 + protected TriggerState getOrCreateTriggerState(TriggerDTO trigger, String deviceId) {
145 151 String triggerId = trigger.getId();
146   - String cacheKey =triggerId+deviceId;
147   - if(triggerState.containsKey(cacheKey)){
  152 + String cacheKey = triggerId + deviceId;
  153 + if (triggerState.containsKey(cacheKey)) {
148 154 return triggerState.get(cacheKey);
149 155 }
150   - if(trigger.getEntityId().contains(deviceId)){
  156 + if (trigger.getEntityId().contains(deviceId)) {
151 157 TriggerState state = createTriggerState(deviceId, trigger.getTriggerCondition());
152 158 triggerState.put(cacheKey, state);
153 159 return state;
... ... @@ -157,13 +163,13 @@ class ReactState {
157 163 }
158 164
159 165 protected TriggerState getOrCreateConditionState(String conditionId, String deviceId, AlarmRule condition) {
160   - String cacheKey =conditionId+deviceId;
161   - if(conditionState.containsKey(cacheKey)){
  166 + String cacheKey = conditionId + deviceId;
  167 + if (conditionState.containsKey(cacheKey)) {
162 168 return conditionState.get(cacheKey);
163   - }else{
  169 + } else {
164 170 TriggerState state = createTriggerState(deviceId, condition);
165 171 conditionState.put(cacheKey, state);
166   - return state;
  172 + return state;
167 173 }
168 174
169 175 }
... ... @@ -171,51 +177,97 @@ class ReactState {
171 177 @NotNull
172 178 private TriggerState createTriggerState(String deviceId, AlarmRule rule) {
173 179 Set<AlarmConditionFilterKey> filterKeys = new HashSet<>();
174   - for(AlarmConditionFilter filter :rule.getCondition().getCondition()){
  180 + for (AlarmConditionFilter filter : rule.getCondition().getCondition()) {
175 181 filterKeys.add(filter.getKey());
176 182 }
177   - TriggerState state = new TriggerState(deviceId,rule, filterKeys,null);
  183 + TriggerState state = new TriggerState(deviceId, rule, filterKeys, rule.getAlarmDetails(),null);
178 184
179   - return state;
  185 + return state;
180 186 }
181 187
182   - private void pushMsg(TbContext ctx, TbMsg msg, DoAction action) {
  188 + private void pushMsg(TbContext ctx, TbMsg msg, DoAction action,String detail) {
183 189 TbMsgMetaData metaData = //lastMsgMetaData != null ? lastMsgMetaData.copy() :
184 190 new TbMsgMetaData();
185 191 String relationType = "";
186 192 TbMsg newMsg = null;
187   - switch(action.getOutTarget()){
  193 + switch (action.getOutTarget()) {
188 194 case DEVICE_OUT:
189   - relationType = "RPC Request";
190   - newMsg = rpcMsg(ctx,msg,action.getDoContext());
  195 + rpcMsg(ctx, msg, action.getDeviceId(), action.getDoContext());
191 196 break;
192 197 case SCENE_ACT:
193   - //TODO: 场景联动关联场景联动
194   - relationType = "Alarm Updated";
  198 + reactMsg(ctx, msg, action);
195 199 break;
196 200 case MSG_NOTIFY:
197   - relationType = "Message";
  201 + noticeMsg(ctx, msg, action,detail);
198 202 break;
199 203 default:
200 204 ctx.tellSuccess(msg);
201 205 break;
202 206 }
  207 + }
203 208
204   - if(newMsg != null){
205   - ctx.tellNext(newMsg, relationType);
  209 + /**
  210 + * 设备输出
  211 + *
  212 + * @param ctx
  213 + * @param msg
  214 + * @param devices
  215 + * @param context
  216 + */
  217 + private void rpcMsg(TbContext ctx, TbMsg msg, List<String> devices, JsonNode context) {
  218 + String lastMsgQueueName = msg.getQueueName();
  219 + TbMsgMetaData metaData = msg.getMetaData();
  220 + for (String id : devices) {
  221 + TbMsg newMsg = ctx.newMsg(lastMsgQueueName != null ? lastMsgQueueName : ServiceQueue.MAIN
  222 + , msg.getType()
  223 + , msg.getOriginator()
  224 + , msg != null ? msg.getCustomerId() : null
  225 + , metaData
  226 + , JacksonUtil.toString(context));
  227 + ctx.tellNext(newMsg, "RPC Request");
206 228 }
207 229 }
208 230
209   - private TbMsg rpcMsg(TbContext ctx, TbMsg msg, JsonNode context){
  231 + /**
  232 + * 告警通知
  233 + *
  234 + * @param ctx
  235 + * @param msg
  236 + * @param action
  237 + */
  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();
  243 + ActionAlarmDTO actionAlarm = JacksonUtil.convertValue(action.getDoContext(),ActionAlarmDTO.class);
  244 +
  245 +
  246 + AlarmInfoDTO formData = new AlarmInfoDTO();
  247 + 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());
  254 + formData.setDeviceId(deviceId);
  255 + formData.setTenantId(tenantId);
  256 + formData.setSeverity(actionAlarm.getAlarmLevel().name());
  257 + noticeService.alert(action.getAlarmProfileId(),formData);
  258 + }
  259 +
  260 + private void reactMsg(TbContext ctx, TbMsg msg, DoAction action) {
  261 + //TODO: 场景联动关联消息通知
210 262 String lastMsgQueueName = msg.getQueueName();
211 263 TbMsgMetaData metaData = msg.getMetaData();
212   - metaData.putValue(DataConstants.IS_CLEARED_ALARM, Boolean.TRUE.toString());
  264 + metaData.putValue(DataConstants.IS_CLEARED_ALARM, Boolean.TRUE.toString());
213 265 TbMsg newMsg = ctx.newMsg(lastMsgQueueName != null ? lastMsgQueueName : ServiceQueue.MAIN
214 266 , msg.getType()
215 267 , msg.getOriginator()
216 268 , msg != null ? msg.getCustomerId() : null
217 269 , metaData
218   - , JacksonUtil.toString(context));
219   - return newMsg;
  270 + , JacksonUtil.toString(action.getDoContext()));
  271 + ctx.tellNext(newMsg, "Message");
220 272 }
221 273 }
... ...
... ... @@ -72,13 +72,15 @@ class TriggerState {
72 72 private DataSnapshot latestValues;
73 73
74 74 private final Set<AlarmConditionFilterKey> entityKeys;
  75 + private final String alarmDetails;
75 76
76   - TriggerState( String originator, AlarmRule rule,Set<AlarmConditionFilterKey> filterKeys,DynamicPredicateValueCtx dynamicPredicateValueCtx) {
  77 + TriggerState(String originator, AlarmRule rule, Set<AlarmConditionFilterKey> filterKeys, String alarmDetails, DynamicPredicateValueCtx dynamicPredicateValueCtx) {
77 78
78 79 this.originator = originator;
79 80 this.dynamicPredicateValueCtx = dynamicPredicateValueCtx;
80   - ruleState = new TriggerRuleState(rule.getCondition(), filterKeys, new PersistedAlarmRuleState(),rule.getSchedule());
  81 + ruleState = new TriggerRuleState(rule.getCondition(), filterKeys, new PersistedAlarmRuleState(), rule.getSchedule());
81 82 this.entityKeys = filterKeys;
  83 + this.alarmDetails = alarmDetails;
82 84 }
83 85
84 86
... ... @@ -88,10 +90,10 @@ class TriggerState {
88 90 }
89 91 lastMsgMetaData = msg.getMetaData();
90 92 SnapshotUpdate update = null;
91   - if(msg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name())){
92   - update = processTelemetry(ctx,msg);
93   - }else{
94   - update = processAttributes(ctx,msg);
  93 + if (msg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name())) {
  94 + update = processTelemetry(ctx, msg);
  95 + } else {
  96 + update = processAttributes(ctx, msg);
95 97 }
96 98
97 99 if (update != null && update.hasUpdate()) {
... ... @@ -101,7 +103,6 @@ class TriggerState {
101 103 }
102 104
103 105
104   -
105 106 public boolean process(TbContext ctx, long ts) throws ExecutionException, InterruptedException {
106 107 return createOrClearAlarms(ctx, null, ts, null, (alarmState, tsParam) -> alarmState.eval(tsParam, latestValues));
107 108 }
... ... @@ -142,8 +143,6 @@ class TriggerState {
142 143 }
143 144
144 145
145   -
146   -
147 146 protected void setAlarmConditionMetadata(TriggerRuleState ruleState, TbMsgMetaData metaData) {
148 147 if (ruleState.getSpec().getType() == AlarmConditionSpecType.REPEATING) {
149 148 metaData.putValue(DataConstants.ALARM_CONDITION_REPEATS, String.valueOf(ruleState.getState().getEventCount()));
... ... @@ -154,9 +153,6 @@ class TriggerState {
154 153 }
155 154
156 155
157   -
158   -
159   -
160 156 public void processAckAlarm(Alarm alarm) {
161 157 if (currentAlarm != null && currentAlarm.getId().equals(alarm.getId())) {
162 158 currentAlarm.setStatus(alarm.getStatus());
... ... @@ -165,16 +161,6 @@ class TriggerState {
165 161 }
166 162
167 163
168   -
169   -
170   -
171   -
172   -
173   -
174   -
175   -
176   -
177   -
178 164 protected SnapshotUpdate processAttributes(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException {
179 165 Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData()));
180 166 if (!attributes.isEmpty()) {
... ... @@ -188,14 +174,13 @@ class TriggerState {
188 174 for (Map.Entry<Long, List<KvEntry>> entry : tsKvMap.entrySet()) {
189 175 Long ts = entry.getKey();
190 176 List<KvEntry> data = entry.getValue();
191   - return merge( ts, data);
  177 + return merge(ts, data);
192 178 }
193 179
194 180 return null;
195 181 }
196 182
197 183
198   -
199 184 private DataSnapshot fetchLatestValues(TbContext ctx, String originator) throws ExecutionException, InterruptedException {
200 185 DataSnapshot result = new DataSnapshot(entityKeys);
201 186 addEntityKeysToSnapshot(ctx, originator, result);
... ... @@ -254,6 +239,7 @@ class TriggerState {
254 239 addToSnapshot(result, ctx.getAttributesService().find(ctx.getTenantId(), new DeviceId(UUID.fromString(originator)), DataConstants.SERVER_SCOPE, attributeKeys).get());
255 240 }
256 241 }
  242 +
257 243 private void addToSnapshot(DataSnapshot snapshot, List<AttributeKvEntry> data) {
258 244 for (AttributeKvEntry entry : data) {
259 245 if (entry.getValue() != null) {
... ... @@ -262,6 +248,7 @@ class TriggerState {
262 248 }
263 249 }
264 250 }
  251 +
265 252 public static EntityKeyValue toEntityValue(KvEntry entry) {
266 253 switch (entry.getDataType()) {
267 254 case STRING:
... ... @@ -278,7 +265,8 @@ class TriggerState {
278 265 throw new RuntimeException("Can't parse entry: " + entry.getDataType());
279 266 }
280 267 }
281   - private SnapshotUpdate merge( Long newTs, List<KvEntry> data) {
  268 +
  269 + private SnapshotUpdate merge(Long newTs, List<KvEntry> data) {
282 270 Set<AlarmConditionFilterKey> keys = new HashSet<>();
283 271 for (KvEntry entry : data) {
284 272 AlarmConditionFilterKey entityKey = new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, entry.getKey());
... ...