...
|
...
|
@@ -127,53 +127,51 @@ class ReactState { |
127
|
127
|
calculateTrigger(ctx,msg,detail,triggerMatched,prefixId,deviceId);
|
128
|
128
|
|
129
|
129
|
/** 1、单个执行条件内全部设备满足条件才为true 2、多个执行条件全部执行条件满足条件才为true */
|
130
|
|
- AtomicBoolean conditionMatched = new AtomicBoolean(false);
|
131
|
|
- boolean allowExecuteCondition = triggerMatched.get() || triggerDevices.size() > FastIotConstants.MagicNumber.ZERO;
|
|
130
|
+ AtomicBoolean conditionMatched = new AtomicBoolean(true);
|
|
131
|
+ boolean allowExecuteCondition = triggerMatched.get() && triggerDevices.size() > FastIotConstants.MagicNumber.ZERO;
|
132
|
132
|
/** 执行条件执行 **/
|
133
|
|
- if(null!=conditions && !conditions.isEmpty()){
|
134
|
|
- calculateCondition(ctx,msg,conditionMatched,prefixId);
|
135
|
|
- }else{
|
136
|
|
- conditionMatched.set(true);
|
137
|
|
- }
|
|
133
|
+ calculateCondition(ctx,msg,conditionMatched,prefixId);
|
138
|
134
|
|
139
|
135
|
String msgData = msg.getData();
|
140
|
136
|
if (allowExecuteCondition && conditionMatched.get()) {
|
141
|
137
|
log.debug(String.format("设备【%s】的消息内容【%s】触发动作", deviceId, msgData));
|
|
138
|
+ ConcurrentHashMap<String, TriggerData> clonedMap =
|
|
139
|
+ actions.isEmpty()?null:SerializationUtils.clone(triggerDevices);
|
142
|
140
|
actions.forEach(
|
143
|
141
|
act -> {
|
144
|
142
|
if (ActionTypeEnum.MSG_NOTIFY.equals(act.getOutTarget())) {
|
145
|
143
|
/** 创建告警,只会以触发器的设备进行告警通知* */
|
146
|
|
- ConcurrentHashMap<String, TriggerData> clonedMap =
|
147
|
|
- SerializationUtils.clone(triggerDevices);
|
148
|
144
|
clonedMap.entrySet().stream()
|
149
|
145
|
.forEach(
|
150
|
146
|
triggerDataEntry -> {
|
151
|
147
|
String key = triggerDataEntry.getKey();
|
152
|
148
|
TriggerData triggerData = triggerDataEntry.getValue();
|
153
|
|
- noticeMsg(
|
154
|
|
- ctx,
|
155
|
|
- triggerData.getMsg(),
|
156
|
|
- act,
|
157
|
|
- key.split("_")[0],
|
158
|
|
- triggerData.getTriggerDetail(),
|
159
|
|
- triggerData.getMsg().getTs());
|
|
149
|
+ noticeMsg(ctx,triggerData.getMsg(),act,key.split("_")[0],triggerData.getTriggerDetail(),
|
|
150
|
+ triggerData.getMsg().getTs());
|
160
|
151
|
/** 通知完一个移除一个 */
|
161
|
|
- triggerDevices.remove(key);
|
162
|
|
- if(triggerDevices.isEmpty()){
|
163
|
|
- cache.evict(triggerDevicesKey);
|
164
|
|
- }else{
|
165
|
|
- cache.put(triggerDevicesKey,triggerDevices);
|
166
|
|
- }
|
|
152
|
+ updateDeviceTriggerCache(key,true);
|
167
|
153
|
});
|
168
|
154
|
} else {
|
169
|
155
|
pushMsg(ctx, msg, act);
|
170
|
156
|
}
|
171
|
157
|
});
|
|
158
|
+ clonedMap.entrySet().stream().forEach(triggerDataEntry-> updateDeviceTriggerCache(triggerDataEntry.getKey(),true));
|
172
|
159
|
} else {
|
173
|
160
|
ctx.tellSuccess(msg);
|
174
|
161
|
}
|
175
|
162
|
}
|
176
|
163
|
|
|
164
|
+ private void updateDeviceTriggerCache(String key, boolean needRemove)
|
|
165
|
+ {
|
|
166
|
+ if(needRemove){
|
|
167
|
+ triggerDevices.remove(key);
|
|
168
|
+ }
|
|
169
|
+ if(triggerDevices.isEmpty()){
|
|
170
|
+ cache.evict(triggerDevicesKey);
|
|
171
|
+ }else{
|
|
172
|
+ cache.put(triggerDevicesKey,triggerDevices);
|
|
173
|
+ }
|
|
174
|
+ }
|
177
|
175
|
private AtomicBoolean calculateTrigger(TbContext ctx, TbMsg msg,ObjectNode detail,AtomicBoolean triggerMatched,
|
178
|
176
|
String prefixId, String deviceId)
|
179
|
177
|
{
|
...
|
...
|
@@ -192,40 +190,20 @@ class ReactState { |
192
|
190
|
tkProjectId, trigger.getTenantId());
|
193
|
191
|
}
|
194
|
192
|
AtomicReference<String> matchKey = new AtomicReference<>("");
|
195
|
|
- boolean matched =
|
196
|
|
- trifggerDevices.stream()
|
197
|
|
- .anyMatch(
|
|
193
|
+ AtomicBoolean matched = new AtomicBoolean(false);
|
|
194
|
+ trifggerDevices.stream()
|
|
195
|
+ .forEach(
|
198
|
196
|
devId -> {
|
199
|
197
|
TriggerState triggerState =
|
200
|
198
|
getOrCreateTriggerState(trigger, tkProjectId, devId);
|
201
|
199
|
if (triggerState == null) {
|
202
|
|
- return false;
|
|
200
|
+ return;
|
203
|
201
|
}
|
204
|
202
|
boolean triggerResult;
|
205
|
203
|
try {
|
206
|
|
- boolean fresh = false;
|
207
|
|
- String originatorId;
|
208
|
|
- if(msg.getType().equals(SessionMsgType.POST_EVENT_REQUEST.name())){
|
209
|
|
- originatorId = msg.getMetaData().getValue("deviceId");
|
210
|
|
- }else{
|
211
|
|
- originatorId = msg.getOriginator().getId().toString();
|
212
|
|
- }
|
213
|
|
- if (trigger.getId().equals(prefixId)
|
214
|
|
- && originatorId.equals(devId)) {
|
215
|
|
- fresh = true;
|
216
|
|
- }
|
217
|
|
- triggerResult = triggerState.process(ctx, msg,fresh);
|
218
|
|
- if(fresh){
|
219
|
|
- String triggerKey = deviceId + "_" + matchKey.get();
|
220
|
|
- if(triggerResult){
|
221
|
|
- //放入满足的触发器信息,设备ID+触发关键字
|
222
|
|
- triggerDevices.put(triggerKey,
|
223
|
|
- new TriggerData(msg,detail));
|
224
|
|
- cache.put(triggerDevicesKey,triggerDevices);
|
225
|
|
- }else{
|
226
|
|
- triggerDevices.remove(triggerKey);
|
227
|
|
- }
|
228
|
|
- }
|
|
204
|
+ boolean isCurrentDeviceTrigger = isCurrentDeviceTrigger(msg,
|
|
205
|
+ trigger.getId(),prefixId,devId);
|
|
206
|
+ triggerResult = triggerState.process(ctx, msg,isCurrentDeviceTrigger);
|
229
|
207
|
ObjectNode result = triggerState.getRuleState().getDetailInform();
|
230
|
208
|
log.debug(
|
231
|
209
|
String.format(
|
...
|
...
|
@@ -235,7 +213,7 @@ class ReactState { |
235
|
213
|
devId,
|
236
|
214
|
msg.getOriginator(),
|
237
|
215
|
msg.getData()));
|
238
|
|
- if (!result.isEmpty() && triggerResult && fresh) {
|
|
216
|
+ if (!result.isEmpty() && triggerResult && isCurrentDeviceTrigger) {
|
239
|
217
|
ObjectNode triggerData = JacksonUtil.newObjectNode();
|
240
|
218
|
triggerData.put(FastIotConstants.Scene.TRIGGER_DATA,result);
|
241
|
219
|
detail.set(devId,triggerData);
|
...
|
...
|
@@ -247,78 +225,117 @@ class ReactState { |
247
|
225
|
clearAlarm(ctx, msg, deviceId, entityKey.getKey());
|
248
|
226
|
}
|
249
|
227
|
}
|
|
228
|
+ if(isCurrentDeviceTrigger){
|
|
229
|
+ String triggerKey = deviceId + "_" + matchKey.get();
|
|
230
|
+ if(triggerResult){
|
|
231
|
+ //放入满足的触发器信息,设备ID+触发关键字
|
|
232
|
+ triggerDevices.put(triggerKey,
|
|
233
|
+ new TriggerData(msg,detail));
|
|
234
|
+ }else{
|
|
235
|
+ triggerDevices.remove(triggerKey);
|
|
236
|
+ }
|
|
237
|
+ updateDeviceTriggerCache(triggerKey,false);
|
|
238
|
+ }
|
250
|
239
|
} catch (ExecutionException e) {
|
251
|
240
|
throw new RuntimeException(e);
|
252
|
241
|
} catch (InterruptedException e) {
|
253
|
242
|
throw new RuntimeException(e);
|
254
|
243
|
}
|
255
|
|
- return triggerResult;
|
|
244
|
+ if(triggerResult){
|
|
245
|
+ matched.set(true);
|
|
246
|
+ }
|
256
|
247
|
});
|
257
|
|
- if(matched){
|
258
|
|
- triggerMatched.set(matched);
|
|
248
|
+ if(matched.get()){
|
|
249
|
+ triggerMatched.set(matched.get());
|
259
|
250
|
}
|
260
|
251
|
});
|
261
|
252
|
});
|
262
|
253
|
return triggerMatched;
|
263
|
254
|
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+ /**
|
|
258
|
+ * 根据当前设备的ID和触发器ID与场景联动里面的触发器ID进行比较,判断当前设备是否与触发条件里面设备匹配
|
|
259
|
+ * @param msg 设备消息
|
|
260
|
+ * @param triggerId 场景联动里面的触发器ID
|
|
261
|
+ * @param currentTriggerId 当前触发器ID
|
|
262
|
+ * @param currentDeviceId 当前设备ID
|
|
263
|
+ * @return true匹配 false不匹配
|
|
264
|
+ */
|
|
265
|
+ private boolean isCurrentDeviceTrigger(TbMsg msg,String triggerId,String currentTriggerId,String currentDeviceId){
|
|
266
|
+ boolean isCurrentDeviceTrigger = false;
|
|
267
|
+ String originatorId;
|
|
268
|
+ if(msg.getType().equals(SessionMsgType.POST_EVENT_REQUEST.name())){
|
|
269
|
+ originatorId = msg.getMetaData().getValue("deviceId");
|
|
270
|
+ }else{
|
|
271
|
+ originatorId = msg.getOriginator().getId().toString();
|
|
272
|
+ }
|
|
273
|
+ if (triggerId.equals(currentTriggerId)
|
|
274
|
+ && originatorId.equals(currentDeviceId)) {
|
|
275
|
+ isCurrentDeviceTrigger = true;
|
|
276
|
+ }
|
|
277
|
+ return isCurrentDeviceTrigger;
|
|
278
|
+ }
|
264
|
279
|
private AtomicBoolean calculateCondition(TbContext ctx, TbMsg msg,AtomicBoolean conditionMatched,String prefixId){
|
265
|
280
|
Optional.ofNullable(conditions)
|
266
|
281
|
.ifPresent(
|
267
|
|
- all -> {
|
268
|
|
- conditionMatched.set(
|
269
|
|
- all.stream()
|
270
|
|
- .allMatch(
|
271
|
|
- condition -> {
|
272
|
|
- ScopeEnum entityType = condition.getEntityType();
|
273
|
|
- List<String> conditionDevices = condition.getEntityId();
|
274
|
|
- String tkProjectId = condition.getDeviceProfileId();
|
275
|
|
- if (ScopeEnum.ALL.equals(entityType)) {
|
276
|
|
- conditionDevices =
|
277
|
|
- ytDeviceService.findTbDeviceIdsByDeviceProfileId(
|
278
|
|
- tkProjectId, condition.getTenantId());
|
279
|
|
- }
|
280
|
|
-
|
281
|
|
- return conditionDevices.stream()
|
282
|
|
- .allMatch(
|
283
|
|
- devId -> {
|
284
|
|
- TriggerState conditionState =
|
285
|
|
- getOrCreateConditionState(condition, tkProjectId, devId);
|
286
|
|
- boolean conditionResult;
|
287
|
|
- try {
|
288
|
|
- String originatorId;
|
289
|
|
- boolean fresh = false;
|
290
|
|
- if(msg.getType().equals(SessionMsgType.POST_EVENT_REQUEST.name())){
|
291
|
|
- originatorId = msg.getMetaData().getValue("deviceId");
|
292
|
|
- }else{
|
293
|
|
- originatorId = msg.getOriginator().getId().toString();
|
294
|
|
- }
|
295
|
|
- if (condition.getId().equals(prefixId)
|
296
|
|
- && originatorId.equals(devId)) {
|
297
|
|
- fresh = true;
|
298
|
|
- }
|
299
|
|
- conditionResult = conditionState.process(ctx, msg,fresh);
|
300
|
|
- ObjectNode result = conditionState.getRuleState().getDetailInform();
|
301
|
|
- log.debug(
|
302
|
|
- String.format(
|
303
|
|
- "执行器【%s】结果【%s】执行器设备【%s】数据设备【%s】数据内容【%s】",
|
304
|
|
- condition.getId(),
|
305
|
|
- result,
|
306
|
|
- devId,
|
307
|
|
- msg.getOriginator(),
|
308
|
|
- msg.getData()));
|
309
|
|
- if (!result.isEmpty() && conditionResult) {
|
310
|
|
- //更新触发器的详情
|
311
|
|
- updateTriggerDetail(devId,result);
|
312
|
|
- }
|
313
|
|
- } catch (ExecutionException e) {
|
314
|
|
- throw new RuntimeException(e);
|
315
|
|
- } catch (InterruptedException e) {
|
316
|
|
- throw new RuntimeException(e);
|
317
|
|
- }
|
318
|
|
- return conditionResult;
|
319
|
|
- });
|
320
|
|
- }));
|
321
|
|
- });
|
|
282
|
+ all -> all.stream()
|
|
283
|
+ .forEach(
|
|
284
|
+ condition -> {
|
|
285
|
+ ScopeEnum entityType = condition.getEntityType();
|
|
286
|
+ List<String> conditionDevices = condition.getEntityId();
|
|
287
|
+ String tkProjectId = condition.getDeviceProfileId();
|
|
288
|
+ if (ScopeEnum.ALL.equals(entityType)) {
|
|
289
|
+ conditionDevices =
|
|
290
|
+ ytDeviceService.findTbDeviceIdsByDeviceProfileId(
|
|
291
|
+ tkProjectId, condition.getTenantId());
|
|
292
|
+ }
|
|
293
|
+ AtomicBoolean oneConditionResult = new AtomicBoolean(true);
|
|
294
|
+ conditionDevices.stream()
|
|
295
|
+ .forEach(
|
|
296
|
+ devId -> {
|
|
297
|
+ TriggerState conditionState =
|
|
298
|
+ getOrCreateConditionState(condition, tkProjectId, devId);
|
|
299
|
+ boolean conditionResult;
|
|
300
|
+ try {
|
|
301
|
+ String originatorId;
|
|
302
|
+ boolean fresh = false;
|
|
303
|
+ if(msg.getType().equals(SessionMsgType.POST_EVENT_REQUEST.name())){
|
|
304
|
+ originatorId = msg.getMetaData().getValue("deviceId");
|
|
305
|
+ }else{
|
|
306
|
+ originatorId = msg.getOriginator().getId().toString();
|
|
307
|
+ }
|
|
308
|
+ if (condition.getId().equals(prefixId)
|
|
309
|
+ && originatorId.equals(devId)) {
|
|
310
|
+ fresh = true;
|
|
311
|
+ }
|
|
312
|
+ conditionResult = conditionState.process(ctx, msg,fresh);
|
|
313
|
+ ObjectNode result = conditionState.getRuleState().getDetailInform();
|
|
314
|
+ log.debug(
|
|
315
|
+ String.format(
|
|
316
|
+ "执行器【%s】结果【%s】执行器设备【%s】数据设备【%s】数据内容【%s】",
|
|
317
|
+ condition.getId(),
|
|
318
|
+ result,
|
|
319
|
+ devId,
|
|
320
|
+ msg.getOriginator(),
|
|
321
|
+ msg.getData()));
|
|
322
|
+ if (!result.isEmpty() && conditionResult) {
|
|
323
|
+ //更新触发器的详情
|
|
324
|
+ updateTriggerDetail(devId,result);
|
|
325
|
+ }
|
|
326
|
+ } catch (ExecutionException e) {
|
|
327
|
+ throw new RuntimeException(e);
|
|
328
|
+ } catch (InterruptedException e) {
|
|
329
|
+ throw new RuntimeException(e);
|
|
330
|
+ }
|
|
331
|
+ if(!conditionResult){
|
|
332
|
+ oneConditionResult.set(false);
|
|
333
|
+ }
|
|
334
|
+ });
|
|
335
|
+ if(!oneConditionResult.get()){
|
|
336
|
+ conditionMatched.set(false);
|
|
337
|
+ }
|
|
338
|
+ }));
|
322
|
339
|
return conditionMatched;
|
323
|
340
|
}
|
324
|
341
|
/**
|
...
|
...
|
@@ -416,7 +433,8 @@ class ReactState { |
416
|
433
|
List<String> rpcDevices = action.getDeviceId();
|
417
|
434
|
if (ScopeEnum.ALL.equals(action.getEntityType())) {
|
418
|
435
|
rpcDevices =
|
419
|
|
- ytDeviceService.rpcDevices(action.getTenantId(), orgId, action.getDeviceProfileId());
|
|
436
|
+ ytDeviceService.getDevicesByOrganizationIdAndProjectId(action.getTenantId(), orgId,
|
|
437
|
+ msg.getMetaData().getValue("deviceProfileId"));
|
420
|
438
|
}
|
421
|
439
|
rpcMsg(ctx, msg, rpcDevices, action.getDoContext(), action.getCallType());
|
422
|
440
|
break;
|
...
|
...
|
|