Commit e7a09de3daee0415eeb516759c0ac4a0e122b1bb

Authored by 芋道源码
Committed by Gitee
2 parents da6b970a 3a956adc

!1396 perf:【IoT 物联网】场景联动代码优化

Merge pull request !1396 from puhui999/feature/iot
Showing 11 changed files with 479 additions and 314 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java
@@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO; 7 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO;
8 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneRespVO; 8 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneRespVO;
9 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO; 9 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
  10 +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneUpdateStatusReqVO;
10 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; 11 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
11 import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; 12 import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService;
12 import io.swagger.v3.oas.annotations.Operation; 13 import io.swagger.v3.oas.annotations.Operation;
@@ -48,6 +49,14 @@ public class IotRuleSceneController { @@ -48,6 +49,14 @@ public class IotRuleSceneController {
48 return success(true); 49 return success(true);
49 } 50 }
50 51
  52 + @PutMapping("/update-status")
  53 + @Operation(summary = "更新场景联动状态")
  54 + @PreAuthorize("@ss.hasPermission('iot:rule-scene:update')")
  55 + public CommonResult<Boolean> updateRuleSceneStatus(@Valid @RequestBody IotRuleSceneUpdateStatusReqVO updateReqVO) {
  56 + ruleSceneService.updateRuleSceneStatus(updateReqVO.getId(), updateReqVO.getStatus());
  57 + return success(true);
  58 + }
  59 +
51 @DeleteMapping("/delete") 60 @DeleteMapping("/delete")
52 @Operation(summary = "删除场景联动") 61 @Operation(summary = "删除场景联动")
53 @Parameter(name = "id", description = "编号", required = true) 62 @Parameter(name = "id", description = "编号", required = true)
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneRespVO.java
@@ -24,10 +24,10 @@ public class IotRuleSceneRespVO { @@ -24,10 +24,10 @@ public class IotRuleSceneRespVO {
24 private Integer status; 24 private Integer status;
25 25
26 @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED) 26 @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED)
27 - private List<IotRuleSceneDO.TriggerConfig> triggers; 27 + private List<IotRuleSceneDO.Trigger> triggers;
28 28
29 @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED) 29 @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
30 - private List<IotRuleSceneDO.ActionConfig> actions; 30 + private List<IotRuleSceneDO.Action> actions;
31 31
32 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 32 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
33 private LocalDateTime createTime; 33 private LocalDateTime createTime;
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneSaveReqVO.java
@@ -31,10 +31,10 @@ public class IotRuleSceneSaveReqVO { @@ -31,10 +31,10 @@ public class IotRuleSceneSaveReqVO {
31 31
32 @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED) 32 @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED)
33 @NotEmpty(message = "触发器数组不能为空") 33 @NotEmpty(message = "触发器数组不能为空")
34 - private List<IotRuleSceneDO.TriggerConfig> triggers; 34 + private List<IotRuleSceneDO.Trigger> triggers;
35 35
36 @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED) 36 @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
37 @NotEmpty(message = "执行器数组不能为空") 37 @NotEmpty(message = "执行器数组不能为空")
38 - private List<IotRuleSceneDO.ActionConfig> actions; 38 + private List<IotRuleSceneDO.Action> actions;
39 39
40 } 40 }
41 \ No newline at end of file 41 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneUpdateStatusReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import jakarta.validation.constraints.NotNull;
  7 +import lombok.Data;
  8 +
  9 +@Schema(description = "管理后台 - IoT 场景联动更新状态 Request VO")
  10 +@Data
  11 +public class IotRuleSceneUpdateStatusReqVO {
  12 +
  13 + @Schema(description = "场景联动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  14 + @NotNull(message = "场景联动编号不能为空")
  15 + private Long id;
  16 +
  17 + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  18 + @NotNull(message = "状态不能为空")
  19 + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
  20 + private Integer status;
  21 +
  22 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java
1 package cn.iocoder.yudao.module.iot.dal.dataobject.rule; 1 package cn.iocoder.yudao.module.iot.dal.dataobject.rule;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 4 import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
  5 +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  6 +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO;
4 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
5 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; 8 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
6 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; 9 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
7 -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;  
8 -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;  
9 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; 10 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
10 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; 11 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum;
  12 +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum;
11 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; 13 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
12 import com.baomidou.mybatisplus.annotation.KeySequence; 14 import com.baomidou.mybatisplus.annotation.KeySequence;
13 import com.baomidou.mybatisplus.annotation.TableField; 15 import com.baomidou.mybatisplus.annotation.TableField;
@@ -20,9 +22,7 @@ import lombok.Data; @@ -20,9 +22,7 @@ import lombok.Data;
20 import lombok.NoArgsConstructor; 22 import lombok.NoArgsConstructor;
21 23
22 import java.util.List; 24 import java.util.List;
23 -import java.util.Map;  
24 25
25 -// TODO @芋艿:优化注释;  
26 /** 26 /**
27 * IoT 场景联动规则 DO 27 * IoT 场景联动规则 DO
28 * 28 *
@@ -37,211 +37,200 @@ import java.util.Map; @@ -37,211 +37,200 @@ import java.util.Map;
37 public class IotRuleSceneDO extends TenantBaseDO { 37 public class IotRuleSceneDO extends TenantBaseDO {
38 38
39 /** 39 /**
40 - * 场景编号 40 + * 场景联动编号
41 */ 41 */
42 @TableId 42 @TableId
43 private Long id; 43 private Long id;
44 /** 44 /**
45 - * 场景名称 45 + * 场景联动名称
46 */ 46 */
47 private String name; 47 private String name;
48 /** 48 /**
49 - * 场景描述 49 + * 场景联动描述
50 */ 50 */
51 private String description; 51 private String description;
52 /** 52 /**
53 - * 场景状态 53 + * 场景联动状态
54 * 54 *
55 - * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} 55 + * 枚举 {@link CommonStatusEnum}
56 */ 56 */
57 private Integer status; 57 private Integer status;
58 58
59 /** 59 /**
60 - * 触发器数组 60 + * 场景定义配置
61 */ 61 */
62 @TableField(typeHandler = JacksonTypeHandler.class) 62 @TableField(typeHandler = JacksonTypeHandler.class)
63 - private List<TriggerConfig> triggers; 63 + private List<Trigger> triggers;
64 64
65 /** 65 /**
66 - * 执行器数组 66 + * 场景动作配置
67 */ 67 */
68 @TableField(typeHandler = JacksonTypeHandler.class) 68 @TableField(typeHandler = JacksonTypeHandler.class)
69 - private List<ActionConfig> actions; 69 + private List<Action> actions;
70 70
71 /** 71 /**
72 - * 触发器配置 72 + * 场景定义配置
73 */ 73 */
74 @Data 74 @Data
75 - public static class TriggerConfig { 75 + public static class Trigger {
  76 +
  77 + // ========== 事件部分 ==========
76 78
77 /** 79 /**
78 - * 触发类型 80 + * 场景事件类型
79 * 81 *
80 * 枚举 {@link IotRuleSceneTriggerTypeEnum} 82 * 枚举 {@link IotRuleSceneTriggerTypeEnum}
  83 + * 1. {@link IotRuleSceneTriggerTypeEnum#DEVICE_STATE_UPDATE} 时,operator 非空,并且 value 为在线状态
  84 + * 2. {@link IotRuleSceneTriggerTypeEnum#DEVICE_PROPERTY_POST}
  85 + * {@link IotRuleSceneTriggerTypeEnum#DEVICE_EVENT_POST} 时,identifier、operator 非空,并且 value 为属性值
  86 + * 3. {@link IotRuleSceneTriggerTypeEnum#DEVICE_EVENT_POST}
  87 + * {@link IotRuleSceneTriggerTypeEnum#DEVICE_SERVICE_INVOKE} 时,identifier 非空,但是 operator、value 为空
  88 + * 4. {@link IotRuleSceneTriggerTypeEnum#TIMER} 时,conditions 非空,并且设备无关(无需 productId、deviceId 字段)
81 */ 89 */
82 private Integer type; 90 private Integer type;
83 91
84 /** 92 /**
85 - * 产品标识 93 + * 产品编号
86 * 94 *
87 - * 关联 {@link IotProductDO#getProductKey()} 95 + * 关联 {@link IotProductDO#getId()}
88 */ 96 */
89 - private String productKey; 97 + private Long productId;
90 /** 98 /**
91 - * 设备名称数组 99 + * 设备编号
92 * 100 *
93 - * 关联 {@link IotDeviceDO#getDeviceName()} 101 + * 关联 {@link IotDeviceDO#getId()}
  102 + * 特殊:如果为 {@link IotDeviceDO#DEVICE_ID_ALL} 时,则是全部设备
94 */ 103 */
95 - private List<String> deviceNames;  
96 - 104 + private Long deviceId;
97 /** 105 /**
98 - * 触发条件数组 106 + * 物模型标识符
  107 + *
  108 + * 对应:{@link IotThingModelDO#getIdentifier()}
  109 + */
  110 + private String identifier;
  111 + /**
  112 + * 操作符
99 * 113 *
100 - * 必填:当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#DEVICE} 时  
101 - * 条件与条件之间,是“或”的关系 114 + * 枚举 {@link IotRuleSceneConditionOperatorEnum}
  115 + */
  116 + private String operator;
  117 + /**
  118 + * 参数(属性值、在线状态)
  119 + * <p>
  120 + * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。
  121 + * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN}
102 */ 122 */
103 - private List<TriggerCondition> conditions; 123 + private String value;
104 124
105 /** 125 /**
106 * CRON 表达式 126 * CRON 表达式
107 - *  
108 - * 必填:当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#TIMER} 时  
109 */ 127 */
110 private String cronExpression; 128 private String cronExpression;
111 129
  130 + // ========== 条件部分 ==========
  131 +
  132 + /**
  133 + * 触发条件分组(状态条件分组)的数组
  134 + * <p>
  135 + * 第一层 List:分组与分组之间,是“或”的关系
  136 + * 第二层 List:条件与条件之间,是“且”的关系
  137 + */
  138 + private List<List<TriggerCondition>> conditionGroups;
  139 +
112 } 140 }
113 141
114 /** 142 /**
115 - * 触发条件 143 + * 触发条件(状态条件)
116 */ 144 */
117 @Data 145 @Data
118 public static class TriggerCondition { 146 public static class TriggerCondition {
119 147
120 /** 148 /**
121 - * 消息类型 149 + * 触发条件类型
122 * 150 *
123 - * 枚举 {@link IotDeviceMessageTypeEnum} 151 + * 枚举 {@link IotRuleSceneConditionTypeEnum}
  152 + * 1. {@link IotRuleSceneConditionTypeEnum#DEVICE_STATE} 时,operator 非空,并且 value 为在线状态
  153 + * 2. {@link IotRuleSceneConditionTypeEnum#DEVICE_PROPERTY} 时,identifier、operator 非空,并且 value 为属性值
  154 + * 3. {@link IotRuleSceneConditionTypeEnum#CURRENT_TIME} 时,operator 非空(使用 DATE_TIME_ 和 TIME_ 部分),并且 value 非空
124 */ 155 */
125 - private String type;  
126 - /**  
127 - * 消息标识符  
128 - *  
129 - * 枚举 {@link IotDeviceMessageIdentifierEnum}  
130 - */  
131 - private String identifier; 156 + private Integer type;
132 157
133 /** 158 /**
134 - * 参数数组 159 + * 产品编号
135 * 160 *
136 - * 参数与参数之间,是“或”的关系 161 + * 关联 {@link IotProductDO#getId()}
137 */ 162 */
138 - private List<TriggerConditionParameter> parameters;  
139 -  
140 - }  
141 -  
142 - /**  
143 - * 触发条件参数  
144 - */  
145 - @Data  
146 - public static class TriggerConditionParameter {  
147 -  
148 - // TODO @芋艿: identifier0 存事件和服务的 identifier 属性的情况 identifier0 就为 null 解决前端回显问题  
149 - // TODO @puhui999:可以根据 TriggerCondition.type 判断,是服务、还是事件、还是属性么? 163 + private Long productId;
150 /** 164 /**
151 - * 标识符(事件、服务) 165 + * 设备编号
152 * 166 *
153 - * 关联 {@link IotThingModelDO#getIdentifier()} 167 + * 关联 {@link IotDeviceDO#getId()}
154 */ 168 */
155 - private String identifier0;  
156 - 169 + private Long deviceId;
157 /** 170 /**
158 * 标识符(属性) 171 * 标识符(属性)
159 * 172 *
160 * 关联 {@link IotThingModelDO#getIdentifier()} 173 * 关联 {@link IotThingModelDO#getIdentifier()}
161 */ 174 */
162 private String identifier; 175 private String identifier;
163 -  
164 /** 176 /**
165 * 操作符 177 * 操作符
166 * 178 *
167 * 枚举 {@link IotRuleSceneConditionOperatorEnum} 179 * 枚举 {@link IotRuleSceneConditionOperatorEnum}
168 */ 180 */
169 private String operator; 181 private String operator;
170 -  
171 /** 182 /**
172 - * 比较值 183 + * 参数
173 * 184 *
174 * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 185 * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。
175 * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN} 186 * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN}
176 */ 187 */
177 - private String value; 188 + private String param;
178 189
179 } 190 }
180 191
181 /** 192 /**
182 - * 执行器配置 193 + * 场景动作配置
183 */ 194 */
184 @Data 195 @Data
185 - public static class ActionConfig { 196 + public static class Action {
186 197
187 /** 198 /**
188 * 执行类型 199 * 执行类型
189 * 200 *
190 * 枚举 {@link IotRuleSceneActionTypeEnum} 201 * 枚举 {@link IotRuleSceneActionTypeEnum}
  202 + * 1. {@link IotRuleSceneActionTypeEnum#DEVICE_PROPERTY_SET} 时,params 非空
  203 + * {@link IotRuleSceneActionTypeEnum#DEVICE_SERVICE_INVOKE} 时,params 非空
  204 + * 2. {@link IotRuleSceneActionTypeEnum#ALERT_TRIGGER} 时,alertConfigId 为空,因为是 {@link IotAlertConfigDO} 里面关联它
  205 + * 3. {@link IotRuleSceneActionTypeEnum#ALERT_RECOVER} 时,alertConfigId 非空
191 */ 206 */
192 private Integer type; 207 private Integer type;
193 208
194 /** 209 /**
195 - * 设备控制  
196 - *  
197 - * 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DEVICE_PROPERTY_SET} 时  
198 - */  
199 - private ActionDeviceControl deviceControl;  
200 -  
201 - }  
202 -  
203 - /**  
204 - * 执行设备控制  
205 - */  
206 - @Data  
207 - public static class ActionDeviceControl {  
208 -  
209 - /**  
210 - * 产品标识 210 + * 产品编号
211 * 211 *
212 - * 关联 {@link IotProductDO#getProductKey()} 212 + * 关联 {@link IotProductDO#getId()}
213 */ 213 */
214 - private String productKey; 214 + private Long productId;
215 /** 215 /**
216 - * 设备名称数组 216 + * 设备编号
217 * 217 *
218 - * 关联 {@link IotDeviceDO#getDeviceName()} 218 + * 关联 {@link IotDeviceDO#getId()}
219 */ 219 */
220 - private List<String> deviceNames;  
221 -  
222 - /**  
223 - * 消息类型  
224 - *  
225 - * 枚举 {@link IotDeviceMessageTypeEnum#PROPERTY}、{@link IotDeviceMessageTypeEnum#SERVICE}  
226 - */  
227 - private String type; 220 + private Long deviceId;
228 /** 221 /**
229 - * 消息标识符  
230 - *  
231 - * 枚举 {@link IotDeviceMessageIdentifierEnum} 222 + * 请求参数
232 * 223 *
233 - * 1. 属性设置:对应 {@link IotDeviceMessageIdentifierEnum#PROPERTY_SET}  
234 - * 2. 服务调用:对应 {@link IotDeviceMessageIdentifierEnum#SERVICE_INVOKE} 224 + * 一般来说,对应 {@link IotDeviceMessage#getParams()} 请求参数
235 */ 225 */
236 - private String identifier; 226 + private Object params;
237 227
238 /** 228 /**
239 - * 具体数据 229 + * 告警配置编号
240 * 230 *
241 - * 1. 属性设置:在 {@link #type} 是 {@link IotDeviceMessageTypeEnum#PROPERTY} 时,对应 properties  
242 - * 2. 服务调用:在 {@link #type} 是 {@link IotDeviceMessageTypeEnum#SERVICE} 时,对应 params 231 + * 关联 {@link IotAlertConfigDO#getId()}
243 */ 232 */
244 - private Map<String, Object> data; 233 + private Long alertConfigId;
245 234
246 } 235 }
247 236
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java
@@ -34,6 +34,14 @@ public interface IotRuleSceneService { @@ -34,6 +34,14 @@ public interface IotRuleSceneService {
34 void updateRuleScene(@Valid IotRuleSceneSaveReqVO updateReqVO); 34 void updateRuleScene(@Valid IotRuleSceneSaveReqVO updateReqVO);
35 35
36 /** 36 /**
  37 + * 更新场景联动状态
  38 + *
  39 + * @param id 场景联动编号
  40 + * @param status 状态
  41 + */
  42 + void updateRuleSceneStatus(Long id, Integer status);
  43 +
  44 + /**
37 * 删除场景联动 45 * 删除场景联动
38 * 46 *
39 * @param id 编号 47 * @param id 编号
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java
@@ -18,15 +18,19 @@ import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; @@ -18,15 +18,19 @@ import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
18 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO; 18 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO;
19 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO; 19 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
20 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 20 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  21 +import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
  22 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  23 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
21 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; 24 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
22 import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper; 25 import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper;
23 -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;  
24 -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;  
25 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; 26 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
26 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; 27 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum;
  28 +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum;
27 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; 29 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
28 import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; 30 import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager;
29 import cn.iocoder.yudao.module.iot.job.rule.IotRuleSceneJob; 31 import cn.iocoder.yudao.module.iot.job.rule.IotRuleSceneJob;
  32 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  33 +import cn.iocoder.yudao.module.iot.service.product.IotProductService;
30 import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; 34 import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction;
31 import jakarta.annotation.Resource; 35 import jakarta.annotation.Resource;
32 import lombok.SneakyThrows; 36 import lombok.SneakyThrows;
@@ -39,10 +43,7 @@ import org.quartz.impl.StdSchedulerFactory; @@ -39,10 +43,7 @@ import org.quartz.impl.StdSchedulerFactory;
39 import org.springframework.stereotype.Service; 43 import org.springframework.stereotype.Service;
40 import org.springframework.validation.annotation.Validated; 44 import org.springframework.validation.annotation.Validated;
41 45
42 -import java.util.Collection;  
43 -import java.util.HashMap;  
44 -import java.util.List;  
45 -import java.util.Map; 46 +import java.util.*;
46 47
47 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 48 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
48 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; 49 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@@ -68,6 +69,12 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -68,6 +69,12 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
68 @Resource(name = "iotSchedulerManager") 69 @Resource(name = "iotSchedulerManager")
69 private IotSchedulerManager schedulerManager; 70 private IotSchedulerManager schedulerManager;
70 71
  72 + @Resource
  73 + private IotProductService productService;
  74 +
  75 + @Resource
  76 + private IotDeviceService deviceService;
  77 +
71 @Override 78 @Override
72 public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) { 79 public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) {
73 // 插入 80 // 插入
@@ -87,6 +94,15 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -87,6 +94,15 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
87 } 94 }
88 95
89 @Override 96 @Override
  97 + public void updateRuleSceneStatus(Long id, Integer status) {
  98 + // 校验存在
  99 + validateRuleSceneExists(id);
  100 + // 更新状态
  101 + IotRuleSceneDO updateObj = new IotRuleSceneDO().setId(id).setStatus(status);
  102 + ruleSceneMapper.updateById(updateObj);
  103 + }
  104 +
  105 + @Override
90 public void deleteRuleScene(Long id) { 106 public void deleteRuleScene(Long id) {
91 // 校验存在 107 // 校验存在
92 validateRuleSceneExists(id); 108 validateRuleSceneExists(id);
@@ -131,118 +147,61 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -131,118 +147,61 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
131 @Override 147 @Override
132 @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 148 @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略
133 public List<IotRuleSceneDO> getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { 149 public List<IotRuleSceneDO> getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) {
134 - if (true) {  
135 - IotRuleSceneDO ruleScene01 = new IotRuleSceneDO();  
136 - ruleScene01.setTriggers(CollUtil.newArrayList());  
137 - IotRuleSceneDO.TriggerConfig trigger01 = new IotRuleSceneDO.TriggerConfig();  
138 - trigger01.setType(IotRuleSceneTriggerTypeEnum.DEVICE.getType());  
139 - trigger01.setConditions(CollUtil.newArrayList());  
140 - // 属性  
141 - IotRuleSceneDO.TriggerCondition condition01 = new IotRuleSceneDO.TriggerCondition();  
142 - condition01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());  
143 - condition01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier());  
144 - condition01.setParameters(CollUtil.newArrayList());  
145 -// IotRuleSceneDO.TriggerConditionParameter parameter010 = new IotRuleSceneDO.TriggerConditionParameter();  
146 -// parameter010.setIdentifier("width");  
147 -// parameter010.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator());  
148 -// parameter010.setValue("abc");  
149 -// condition01.getParameters().add(parameter010);  
150 - IotRuleSceneDO.TriggerConditionParameter parameter011 = new IotRuleSceneDO.TriggerConditionParameter();  
151 - parameter011.setIdentifier("width");  
152 - parameter011.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator());  
153 - parameter011.setValue("1");  
154 - condition01.getParameters().add(parameter011);  
155 - IotRuleSceneDO.TriggerConditionParameter parameter012 = new IotRuleSceneDO.TriggerConditionParameter();  
156 - parameter012.setIdentifier("width");  
157 - parameter012.setOperator(IotRuleSceneConditionOperatorEnum.NOT_EQUALS.getOperator());  
158 - parameter012.setValue("2");  
159 - condition01.getParameters().add(parameter012);  
160 - IotRuleSceneDO.TriggerConditionParameter parameter013 = new IotRuleSceneDO.TriggerConditionParameter();  
161 - parameter013.setIdentifier("width");  
162 - parameter013.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator());  
163 - parameter013.setValue("0");  
164 - condition01.getParameters().add(parameter013);  
165 - IotRuleSceneDO.TriggerConditionParameter parameter014 = new IotRuleSceneDO.TriggerConditionParameter();  
166 - parameter014.setIdentifier("width");  
167 - parameter014.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator());  
168 - parameter014.setValue("0");  
169 - condition01.getParameters().add(parameter014);  
170 - IotRuleSceneDO.TriggerConditionParameter parameter015 = new IotRuleSceneDO.TriggerConditionParameter();  
171 - parameter015.setIdentifier("width");  
172 - parameter015.setOperator(IotRuleSceneConditionOperatorEnum.LESS_THAN.getOperator());  
173 - parameter015.setValue("2");  
174 - condition01.getParameters().add(parameter015);  
175 - IotRuleSceneDO.TriggerConditionParameter parameter016 = new IotRuleSceneDO.TriggerConditionParameter();  
176 - parameter016.setIdentifier("width");  
177 - parameter016.setOperator(IotRuleSceneConditionOperatorEnum.LESS_THAN_OR_EQUALS.getOperator());  
178 - parameter016.setValue("2");  
179 - condition01.getParameters().add(parameter016);  
180 - IotRuleSceneDO.TriggerConditionParameter parameter017 = new IotRuleSceneDO.TriggerConditionParameter();  
181 - parameter017.setIdentifier("width");  
182 - parameter017.setOperator(IotRuleSceneConditionOperatorEnum.IN.getOperator());  
183 - parameter017.setValue("1,2,3");  
184 - condition01.getParameters().add(parameter017);  
185 - IotRuleSceneDO.TriggerConditionParameter parameter018 = new IotRuleSceneDO.TriggerConditionParameter();  
186 - parameter018.setIdentifier("width");  
187 - parameter018.setOperator(IotRuleSceneConditionOperatorEnum.NOT_IN.getOperator());  
188 - parameter018.setValue("0,2,3");  
189 - condition01.getParameters().add(parameter018);  
190 - IotRuleSceneDO.TriggerConditionParameter parameter019 = new IotRuleSceneDO.TriggerConditionParameter();  
191 - parameter019.setIdentifier("width");  
192 - parameter019.setOperator(IotRuleSceneConditionOperatorEnum.BETWEEN.getOperator());  
193 - parameter019.setValue("1,3");  
194 - condition01.getParameters().add(parameter019);  
195 - IotRuleSceneDO.TriggerConditionParameter parameter020 = new IotRuleSceneDO.TriggerConditionParameter();  
196 - parameter020.setIdentifier("width");  
197 - parameter020.setOperator(IotRuleSceneConditionOperatorEnum.NOT_BETWEEN.getOperator());  
198 - parameter020.setValue("2,3");  
199 - condition01.getParameters().add(parameter020);  
200 - trigger01.getConditions().add(condition01);  
201 - // 状态  
202 - IotRuleSceneDO.TriggerCondition condition02 = new IotRuleSceneDO.TriggerCondition();  
203 - condition02.setType(IotDeviceMessageTypeEnum.STATE.getType());  
204 - condition02.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier());  
205 - condition02.setParameters(CollUtil.newArrayList());  
206 - trigger01.getConditions().add(condition02);  
207 - // 事件  
208 - IotRuleSceneDO.TriggerCondition condition03 = new IotRuleSceneDO.TriggerCondition();  
209 - condition03.setType(IotDeviceMessageTypeEnum.EVENT.getType());  
210 - condition03.setIdentifier("xxx");  
211 - condition03.setParameters(CollUtil.newArrayList());  
212 - IotRuleSceneDO.TriggerConditionParameter parameter030 = new IotRuleSceneDO.TriggerConditionParameter();  
213 - parameter030.setIdentifier("width");  
214 - parameter030.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator());  
215 - parameter030.setValue("1");  
216 - trigger01.getConditions().add(condition03);  
217 - ruleScene01.getTriggers().add(trigger01);  
218 - // 动作  
219 - ruleScene01.setActions(CollUtil.newArrayList());  
220 - // 设备控制  
221 - IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig();  
222 - action01.setType(IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET.getType());  
223 - IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl();  
224 - actionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT");  
225 - actionDeviceControl01.setDeviceNames(ListUtil.of("small"));  
226 - actionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());  
227 - actionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier());  
228 - actionDeviceControl01.setData(MapUtil.<String, Object>builder()  
229 - .put("power", 1)  
230 - .put("color", "red")  
231 - .build());  
232 - action01.setDeviceControl(actionDeviceControl01);  
233 -// ruleScene01.getActions().add(action01); // TODO 芋艿:先不测试了  
234 - return ListUtil.toList(ruleScene01); 150 + // TODO @芋艿:测试代码示例(使用新结构),可根据需要启用
  151 + if (false) {
  152 + // 创建测试规则场景
  153 + IotRuleSceneDO ruleScene = new IotRuleSceneDO();
  154 + ruleScene.setId(1L);
  155 + ruleScene.setName("测试场景");
  156 + ruleScene.setStatus(CommonStatusEnum.ENABLE.getStatus());
  157 +
  158 + // 创建触发器
  159 + IotRuleSceneDO.Trigger trigger = new IotRuleSceneDO.Trigger();
  160 + trigger.setType(IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST.getType());
  161 + trigger.setProductId(1L); // 假设产品ID为1
  162 + trigger.setDeviceId(1L); // 假设设备ID为1
  163 + trigger.setIdentifier("temperature"); // 温度属性
  164 + trigger.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator());
  165 + trigger.setValue("25"); // 温度大于25度
  166 +
  167 + // 创建条件分组
  168 + IotRuleSceneDO.TriggerCondition condition = new IotRuleSceneDO.TriggerCondition();
  169 + condition.setType(IotRuleSceneConditionTypeEnum.DEVICE_PROPERTY.getType());
  170 + condition.setIdentifier("temperature");
  171 + condition.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator());
  172 + condition.setParam("25");
  173 +
  174 + trigger.setConditionGroups(ListUtil.toList(Collections.singleton(ListUtil.toList(condition))));
  175 + ruleScene.setTriggers(ListUtil.toList(trigger));
  176 +
  177 + // 创建动作
  178 + IotRuleSceneDO.Action action = new IotRuleSceneDO.Action();
  179 + action.setType(IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET.getType());
  180 + action.setProductId(1L);
  181 + action.setDeviceId(1L);
  182 + action.setParams(MapUtil.of("fan", "on")); // 打开风扇
  183 +
  184 + ruleScene.setActions(ListUtil.toList(action));
  185 +
  186 + return ListUtil.toList(ruleScene);
235 } 187 }
236 188
  189 + // 注意:旧的测试代码已删除,因为使用了废弃的数据结构
  190 + // 如需测试,请使用上面的新结构测试代码示例
237 List<IotRuleSceneDO> list = ruleSceneMapper.selectList(); 191 List<IotRuleSceneDO> list = ruleSceneMapper.selectList();
238 - // TODO @芋艿:需要考虑开启状态  
239 - return filterList(list, ruleScene -> {  
240 - for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) {  
241 - if (ObjUtil.notEqual(trigger.getProductKey(), productKey)) {  
242 - continue;  
243 - }  
244 - if (CollUtil.isEmpty(trigger.getDeviceNames()) // 无设备名称限制  
245 - || trigger.getDeviceNames().contains(deviceName)) { // 包含设备名称 192 + // 只返回启用状态的规则场景
  193 + List<IotRuleSceneDO> enabledList = filterList(list,
  194 + ruleScene -> CommonStatusEnum.ENABLE.getStatus().equals(ruleScene.getStatus()));
  195 +
  196 + // 根据 productKey 和 deviceName 进行匹配
  197 + return filterList(enabledList, ruleScene -> {
  198 + if (CollUtil.isEmpty(ruleScene.getTriggers())) {
  199 + return false;
  200 + }
  201 +
  202 + for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) {
  203 + // 检查触发器是否匹配指定的产品和设备
  204 + if (isMatchProductAndDevice(trigger, productKey, deviceName)) {
246 return true; 205 return true;
247 } 206 }
248 } 207 }
@@ -250,47 +209,70 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -250,47 +209,70 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
250 }); 209 });
251 } 210 }
252 211
  212 + /**
  213 + * 检查触发器是否匹配指定的产品和设备
  214 + *
  215 + * @param trigger 触发器
  216 + * @param productKey 产品标识
  217 + * @param deviceName 设备名称
  218 + * @return 是否匹配
  219 + */
  220 + private boolean isMatchProductAndDevice(IotRuleSceneDO.Trigger trigger, String productKey, String deviceName) {
  221 + try {
  222 + // 1. 检查产品是否匹配
  223 + if (trigger.getProductId() != null) {
  224 + // 通过 productKey 获取产品信息
  225 + IotProductDO product = productService.getProductByProductKey(productKey);
  226 + if (product == null || !trigger.getProductId().equals(product.getId())) {
  227 + return false;
  228 + }
  229 + }
  230 +
  231 + // 2. 检查设备是否匹配
  232 + if (trigger.getDeviceId() != null) {
  233 + // 通过 productKey 和 deviceName 获取设备信息
  234 + IotDeviceDO device = deviceService.getDeviceFromCache(productKey, deviceName);
  235 + if (device == null) {
  236 + return false;
  237 + }
  238 +
  239 + // 检查是否是全部设备的特殊标识
  240 + if (IotDeviceDO.DEVICE_ID_ALL.equals(trigger.getDeviceId())) {
  241 + return true; // 匹配所有设备
  242 + }
  243 +
  244 + // 检查具体设备ID是否匹配
  245 + if (!trigger.getDeviceId().equals(device.getId())) {
  246 + return false;
  247 + }
  248 + }
  249 +
  250 + return true;
  251 + } catch (Exception e) {
  252 + log.warn("[isMatchProductAndDevice][产品({}) 设备({}) 匹配触发器异常]", productKey, deviceName, e);
  253 + return false;
  254 + }
  255 + }
  256 +
253 @Override 257 @Override
254 public void executeRuleSceneByDevice(IotDeviceMessage message) { 258 public void executeRuleSceneByDevice(IotDeviceMessage message) {
255 // TODO @芋艿:这里的 tenantId,通过设备获取; 259 // TODO @芋艿:这里的 tenantId,通过设备获取;
256 -// TenantUtils.execute(message.getTenantId(), () -> {  
257 -// // 1. 获得设备匹配的规则场景  
258 -// List<IotRuleSceneDO> ruleScenes = getMatchedRuleSceneListByMessage(message);  
259 -// if (CollUtil.isEmpty(ruleScenes)) {  
260 -// return;  
261 -// }  
262 -//  
263 -// // 2. 执行规则场景  
264 -// executeRuleSceneAction(message, ruleScenes);  
265 -// }); 260 + TenantUtils.execute(message.getTenantId(), () -> {
  261 + // 1. 获得设备匹配的规则场景
  262 + List<IotRuleSceneDO> ruleScenes = getMatchedRuleSceneListByMessage(message);
  263 + if (CollUtil.isEmpty(ruleScenes)) {
  264 + return;
  265 + }
  266 +
  267 + // 2. 执行规则场景
  268 + executeRuleSceneAction(message, ruleScenes);
  269 + });
266 } 270 }
267 271
268 @Override 272 @Override
269 public void executeRuleSceneByTimer(Long id) { 273 public void executeRuleSceneByTimer(Long id) {
270 // 1.1 获得规则场景 274 // 1.1 获得规则场景
271 -// IotRuleSceneDO scene = TenantUtils.executeIgnore(() -> ruleSceneMapper.selectById(id));  
272 - // TODO @芋艿:这里,临时测试,后续删除。  
273 - IotRuleSceneDO scene = new IotRuleSceneDO().setStatus(CommonStatusEnum.ENABLE.getStatus());  
274 - if (true) {  
275 - scene.setTenantId(1L);  
276 - IotRuleSceneDO.TriggerConfig triggerConfig = new IotRuleSceneDO.TriggerConfig();  
277 - triggerConfig.setType(IotRuleSceneTriggerTypeEnum.TIMER.getType());  
278 - scene.setTriggers(ListUtil.toList(triggerConfig));  
279 - // 动作  
280 - IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig();  
281 - action01.setType(IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET.getType());  
282 - IotRuleSceneDO.ActionDeviceControl iotRuleSceneActionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl();  
283 - iotRuleSceneActionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT");  
284 - iotRuleSceneActionDeviceControl01.setDeviceNames(ListUtil.of("small"));  
285 - iotRuleSceneActionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());  
286 - iotRuleSceneActionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier());  
287 - iotRuleSceneActionDeviceControl01.setData(MapUtil.<String, Object>builder()  
288 - .put("power", 1)  
289 - .put("color", "red")  
290 - .build());  
291 - action01.setDeviceControl(iotRuleSceneActionDeviceControl01);  
292 - scene.setActions(ListUtil.toList(action01));  
293 - } 275 + IotRuleSceneDO scene = TenantUtils.executeIgnore(() -> ruleSceneMapper.selectById(id));
294 if (scene == null) { 276 if (scene == null) {
295 log.error("[executeRuleSceneByTimer][规则场景({}) 不存在]", id); 277 log.error("[executeRuleSceneByTimer][规则场景({}) 不存在]", id);
296 return; 278 return;
@@ -300,7 +282,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -300,7 +282,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
300 return; 282 return;
301 } 283 }
302 // 1.2 判断是否有定时触发器,避免脏数据 284 // 1.2 判断是否有定时触发器,避免脏数据
303 - IotRuleSceneDO.TriggerConfig config = CollUtil.findOne(scene.getTriggers(), 285 + IotRuleSceneDO.Trigger config = CollUtil.findOne(scene.getTriggers(),
304 trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType())); 286 trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType()));
305 if (config == null) { 287 if (config == null) {
306 log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene); 288 log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene);
@@ -321,72 +303,229 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -321,72 +303,229 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
321 private List<IotRuleSceneDO> getMatchedRuleSceneListByMessage(IotDeviceMessage message) { 303 private List<IotRuleSceneDO> getMatchedRuleSceneListByMessage(IotDeviceMessage message) {
322 // 1. 匹配设备 304 // 1. 匹配设备
323 // TODO @芋艿:可能需要 getSelf(); 缓存 305 // TODO @芋艿:可能需要 getSelf(); 缓存
324 - List<IotRuleSceneDO> ruleScenes = null;  
325 - // TODO @芋艿:这里需要适配  
326 -// List<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache(  
327 -// message.getProductKey(), message.getDeviceName()); 306 + // 1.1 通过 deviceId 获取设备信息
  307 + IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId());
  308 + if (device == null) {
  309 + log.warn("[getMatchedRuleSceneListByMessage][设备({}) 不存在]", message.getDeviceId());
  310 + return List.of();
  311 + }
  312 +
  313 + // 1.2 通过 productId 获取产品信息
  314 + IotProductDO product = productService.getProductFromCache(device.getProductId());
  315 + if (product == null) {
  316 + log.warn("[getMatchedRuleSceneListByMessage][产品({}) 不存在]", device.getProductId());
  317 + return List.of();
  318 + }
  319 +
  320 + // 1.3 获取匹配的规则场景
  321 + List<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache(
  322 + product.getProductKey(), device.getDeviceName());
328 if (CollUtil.isEmpty(ruleScenes)) { 323 if (CollUtil.isEmpty(ruleScenes)) {
329 return ruleScenes; 324 return ruleScenes;
330 } 325 }
331 326
332 // 2. 匹配 trigger 触发器的条件 327 // 2. 匹配 trigger 触发器的条件
333 return filterList(ruleScenes, ruleScene -> { 328 return filterList(ruleScenes, ruleScene -> {
334 - for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) {  
335 - // 2.1 非设备触发,不匹配  
336 - if (ObjUtil.notEqual(trigger.getType(), IotRuleSceneTriggerTypeEnum.DEVICE.getType())) { 329 + for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) {
  330 + // 2.1 检查触发器类型,根据新的枚举值进行匹配
  331 + // TODO @芋艿:需要根据新的触发器类型枚举进行适配
  332 + // 原来使用 IotRuleSceneTriggerTypeEnum.DEVICE,新结构可能有不同的类型
  333 +
  334 + // 2.2 条件分组为空,说明没有匹配的条件,因此不匹配
  335 + if (CollUtil.isEmpty(trigger.getConditionGroups())) {
337 return false; 336 return false;
338 } 337 }
339 - // TODO 芋艿:产品、设备的匹配,要不要这里在做一次???貌似和 1. 部分重复了  
340 - // 2.2 条件为空,说明没有匹配的条件,因此不匹配  
341 - if (CollUtil.isEmpty(trigger.getConditions())) {  
342 - return false; 338 +
  339 + // 2.3 检查条件分组:分组与分组之间是"或"的关系,条件与条件之间是"且"的关系
  340 + boolean anyGroupMatched = false;
  341 + for (List<IotRuleSceneDO.TriggerCondition> conditionGroup : trigger.getConditionGroups()) {
  342 + if (CollUtil.isEmpty(conditionGroup)) {
  343 + continue;
  344 + }
  345 +
  346 + // 检查当前分组中的所有条件是否都匹配(且关系)
  347 + boolean allConditionsMatched = true;
  348 + for (IotRuleSceneDO.TriggerCondition condition : conditionGroup) {
  349 + // TODO @芋艿:这里需要实现具体的条件匹配逻辑
  350 + // 根据新的 TriggerCondition 结构进行匹配
  351 + if (!isTriggerConditionMatched(message, condition, ruleScene, trigger)) {
  352 + allConditionsMatched = false;
  353 + break;
  354 + }
  355 + }
  356 +
  357 + if (allConditionsMatched) {
  358 + anyGroupMatched = true;
  359 + break; // 有一个分组匹配即可
  360 + }
343 } 361 }
344 - // 2.3 多个条件,只需要满足一个即可  
345 - IotRuleSceneDO.TriggerCondition matchedCondition = CollUtil.findOne(trigger.getConditions(), condition -> {  
346 - // TODO @芋艿:这里的逻辑,需要适配  
347 -// if (ObjUtil.notEqual(message.getType(), condition.getType())  
348 -// || ObjUtil.notEqual(message.getIdentifier(), condition.getIdentifier())) {  
349 -// return false;  
350 -// }  
351 - // 多个条件参数,必须全部满足。所以,下面的逻辑就是找到一个不满足的条件参数  
352 - IotRuleSceneDO.TriggerConditionParameter notMatchedParameter = CollUtil.findOne(condition.getParameters(),  
353 - parameter -> !isTriggerConditionParameterMatched(message, parameter, ruleScene, trigger));  
354 - return notMatchedParameter == null;  
355 - });  
356 - if (matchedCondition == null) {  
357 - return false; 362 +
  363 + if (anyGroupMatched) {
  364 + log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger);
  365 + return true;
358 } 366 }
359 - log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger);  
360 - return true;  
361 } 367 }
362 return false; 368 return false;
363 }); 369 });
364 } 370 }
365 371
  372 + /**
  373 + * 基于消息,判断触发器的条件是否匹配
  374 + *
  375 + * @param message 设备消息
  376 + * @param condition 触发条件
  377 + * @param ruleScene 规则场景(用于日志,无其它作用)
  378 + * @param trigger 触发器(用于日志,无其它作用)
  379 + * @return 是否匹配
  380 + */
  381 + private boolean isTriggerConditionMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition,
  382 + IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) {
  383 + try {
  384 + // 1. 根据条件类型进行匹配
  385 + if (IotRuleSceneConditionTypeEnum.DEVICE_STATE.getType().equals(condition.getType())) {
  386 + // 设备状态条件匹配
  387 + return matchDeviceStateCondition(message, condition);
  388 + } else if (IotRuleSceneConditionTypeEnum.DEVICE_PROPERTY.getType().equals(condition.getType())) {
  389 + // 设备属性条件匹配
  390 + return matchDevicePropertyCondition(message, condition);
  391 + } else if (IotRuleSceneConditionTypeEnum.CURRENT_TIME.getType().equals(condition.getType())) {
  392 + // 当前时间条件匹配
  393 + return matchCurrentTimeCondition(condition);
  394 + } else {
  395 + log.warn("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 存在未知的条件类型({})]",
  396 + ruleScene.getId(), trigger, condition.getType());
  397 + return false;
  398 + }
  399 + } catch (Exception e) {
  400 + log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]",
  401 + ruleScene.getId(), trigger, e);
  402 + return false;
  403 + }
  404 + }
  405 +
  406 + /**
  407 + * 匹配设备状态条件
  408 + *
  409 + * @param message 设备消息
  410 + * @param condition 触发条件
  411 + * @return 是否匹配
  412 + */
  413 + private boolean matchDeviceStateCondition(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition) {
  414 + // TODO @芋艿:需要根据设备状态进行匹配
  415 + // 这里需要检查消息中的设备状态是否符合条件中定义的状态
  416 + log.debug("[matchDeviceStateCondition][设备状态条件匹配逻辑待实现] condition: {}", condition);
  417 + return false;
  418 + }
  419 +
  420 + /**
  421 + * 匹配设备属性条件
  422 + *
  423 + * @param message 设备消息
  424 + * @param condition 触发条件
  425 + * @return 是否匹配
  426 + */
  427 + private boolean matchDevicePropertyCondition(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition) {
  428 + // 1. 检查标识符是否匹配
  429 + String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message);
  430 + if (StrUtil.isBlank(condition.getIdentifier()) || !condition.getIdentifier().equals(messageIdentifier)) {
  431 + return false;
  432 + }
  433 +
  434 + // 2. 获取消息中的属性值
  435 + Object messageValue = message.getData();
  436 + if (messageValue == null) {
  437 + return false;
  438 + }
  439 +
  440 + // 3. 根据操作符进行匹配
  441 + return evaluateCondition(messageValue, condition.getOperator(), condition.getParam());
  442 + }
  443 +
  444 + /**
  445 + * 匹配当前时间条件
  446 + *
  447 + * @param condition 触发条件
  448 + * @return 是否匹配
  449 + */
  450 + private boolean matchCurrentTimeCondition(IotRuleSceneDO.TriggerCondition condition) {
  451 + // TODO @芋艿:需要根据当前时间进行匹配
  452 + // 这里需要检查当前时间是否符合条件中定义的时间范围
  453 + log.debug("[matchCurrentTimeCondition][当前时间条件匹配逻辑待实现] condition: {}", condition);
  454 + return false;
  455 + }
  456 +
  457 + /**
  458 + * 评估条件是否匹配
  459 + *
  460 + * @param sourceValue 源值(来自消息)
  461 + * @param operator 操作符
  462 + * @param paramValue 参数值(来自条件配置)
  463 + * @return 是否匹配
  464 + */
  465 + private boolean evaluateCondition(Object sourceValue, String operator, String paramValue) {
  466 + try {
  467 + // 1. 校验操作符是否合法
  468 + IotRuleSceneConditionOperatorEnum operatorEnum = IotRuleSceneConditionOperatorEnum.operatorOf(operator);
  469 + if (operatorEnum == null) {
  470 + log.warn("[evaluateCondition][存在错误的操作符({})]", operator);
  471 + return false;
  472 + }
  473 +
  474 + // 2. 构建 Spring 表达式的变量
  475 + Map<String, Object> springExpressionVariables = MapUtil.<String, Object>builder()
  476 + .put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue)
  477 + .build();
  478 +
  479 + // 3. 根据操作符类型处理参数值
  480 + if (StrUtil.isNotBlank(paramValue)) {
  481 + if (operatorEnum == IotRuleSceneConditionOperatorEnum.IN
  482 + || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_IN
  483 + || operatorEnum == IotRuleSceneConditionOperatorEnum.BETWEEN
  484 + || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_BETWEEN) {
  485 + // 处理多值情况
  486 + List<String> paramValues = StrUtil.split(paramValue, CharPool.COMMA);
  487 + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST,
  488 + convertList(paramValues, NumberUtil::parseDouble));
  489 + } else {
  490 + // 处理单值情况
  491 + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE,
  492 + NumberUtil.parseDouble(paramValue));
  493 + }
  494 + }
  495 +
  496 + // 4. 计算 Spring 表达式
  497 + return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables);
  498 + } catch (Exception e) {
  499 + log.error("[evaluateCondition][条件评估异常] sourceValue: {}, operator: {}, paramValue: {}",
  500 + sourceValue, operator, paramValue, e);
  501 + return false;
  502 + }
  503 + }
  504 +
366 // TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。 505 // TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。
367 506
368 /** 507 /**
369 * 判断触发器的条件参数是否匹配 508 * 判断触发器的条件参数是否匹配
370 * 509 *
371 * @param message 设备消息 510 * @param message 设备消息
372 - * @param parameter 触发器条件参数 511 + * @param condition 触发条件
373 * @param ruleScene 规则场景(用于日志,无其它作用) 512 * @param ruleScene 规则场景(用于日志,无其它作用)
374 * @param trigger 触发器(用于日志,无其它作用) 513 * @param trigger 触发器(用于日志,无其它作用)
375 * @return 是否匹配 514 * @return 是否匹配
376 */ 515 */
377 @SuppressWarnings({"unchecked", "DataFlowIssue"}) 516 @SuppressWarnings({"unchecked", "DataFlowIssue"})
378 - private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerConditionParameter parameter,  
379 - IotRuleSceneDO ruleScene, IotRuleSceneDO.TriggerConfig trigger) { 517 + private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition,
  518 + IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) {
380 // 1.1 校验操作符是否合法 519 // 1.1 校验操作符是否合法
381 IotRuleSceneConditionOperatorEnum operator = 520 IotRuleSceneConditionOperatorEnum operator =
382 - IotRuleSceneConditionOperatorEnum.operatorOf(parameter.getOperator()); 521 + IotRuleSceneConditionOperatorEnum.operatorOf(condition.getOperator());
383 if (operator == null) { 522 if (operator == null) {
384 log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]", 523 log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]",
385 - ruleScene.getId(), trigger, parameter.getOperator()); 524 + ruleScene.getId(), trigger, condition.getOperator());
386 return false; 525 return false;
387 } 526 }
388 // 1.2 校验消息是否包含对应的值 527 // 1.2 校验消息是否包含对应的值
389 - String messageValue = MapUtil.getStr((Map<String, Object>) message.getData(), parameter.getIdentifier()); 528 + String messageValue = MapUtil.getStr((Map<String, Object>) message.getData(), condition.getIdentifier());
390 if (messageValue == null) { 529 if (messageValue == null) {
391 return false; 530 return false;
392 } 531 }
@@ -395,8 +534,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -395,8 +534,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
395 Map<String, Object> springExpressionVariables = new HashMap<>(); 534 Map<String, Object> springExpressionVariables = new HashMap<>();
396 try { 535 try {
397 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue); 536 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue);
398 - springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, parameter.getValue());  
399 - List<String> parameterValues = StrUtil.splitTrim(parameter.getValue(), CharPool.COMMA); 537 + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, condition.getParam());
  538 + List<String> parameterValues = StrUtil.splitTrim(condition.getParam(), CharPool.COMMA);
400 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues); 539 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues);
401 // 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题! 540 // 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题!
402 if (ObjectUtils.equalsAny(operator, IotRuleSceneConditionOperatorEnum.BETWEEN, 541 if (ObjectUtils.equalsAny(operator, IotRuleSceneConditionOperatorEnum.BETWEEN,
@@ -410,7 +549,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -410,7 +549,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
410 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, 549 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE,
411 NumberUtil.parseDouble(messageValue)); 550 NumberUtil.parseDouble(messageValue));
412 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, 551 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE,
413 - NumberUtil.parseDouble(parameter.getValue())); 552 + NumberUtil.parseDouble(condition.getParam()));
414 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, 553 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST,
415 convertList(parameterValues, NumberUtil::parseDouble)); 554 convertList(parameterValues, NumberUtil::parseDouble));
416 } 555 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java
@@ -30,7 +30,7 @@ public class IotAlertRecoverSceneRuleAction implements IotSceneRuleAction { @@ -30,7 +30,7 @@ public class IotAlertRecoverSceneRuleAction implements IotSceneRuleAction {
30 30
31 @Override 31 @Override
32 public void execute(IotDeviceMessage message, 32 public void execute(IotDeviceMessage message,
33 - IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception { 33 + IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) throws Exception {
34 Long deviceId = message != null ? message.getDeviceId() : null; 34 Long deviceId = message != null ? message.getDeviceId() : null;
35 List<IotAlertRecordDO> alertRecords = alertRecordService.getAlertRecordListBySceneRuleId( 35 List<IotAlertRecordDO> alertRecords = alertRecordService.getAlertRecordListBySceneRuleId(
36 rule.getId(), deviceId, false); 36 rule.getId(), deviceId, false);
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java
@@ -40,7 +40,7 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { @@ -40,7 +40,7 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction {
40 40
41 @Override 41 @Override
42 public void execute(@Nullable IotDeviceMessage message, 42 public void execute(@Nullable IotDeviceMessage message,
43 - IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception { 43 + IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) throws Exception {
44 List<IotAlertConfigDO> alertConfigs = alertConfigService.getAlertConfigListBySceneRuleIdAndStatus( 44 List<IotAlertConfigDO> alertConfigs = alertConfigService.getAlertConfigListBySceneRuleIdAndStatus(
45 rule.getId(), CommonStatusEnum.ENABLE.getStatus()); 45 rule.getId(), CommonStatusEnum.ENABLE.getStatus());
46 if (CollUtil.isEmpty(alertConfigs)) { 46 if (CollUtil.isEmpty(alertConfigs)) {
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java
1 package cn.iocoder.yudao.module.iot.service.rule.scene.action; 1 package cn.iocoder.yudao.module.iot.service.rule.scene.action;
2 2
3 -import cn.hutool.core.lang.Assert;  
4 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 3 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
5 -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;  
6 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; 4 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
7 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; 5 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
8 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; 6 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
@@ -27,25 +25,25 @@ public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction { @@ -27,25 +25,25 @@ public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction {
27 25
28 @Override 26 @Override
29 public void execute(IotDeviceMessage message, 27 public void execute(IotDeviceMessage message,
30 - IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) {  
31 - IotRuleSceneDO.ActionDeviceControl control = actionConfig.getDeviceControl();  
32 - Assert.notNull(control, "设备控制配置不能为空");  
33 - // 遍历每个设备,下发消息  
34 - control.getDeviceNames().forEach(deviceName -> {  
35 - IotDeviceDO device = deviceService.getDeviceFromCache(control.getProductKey(), deviceName);  
36 - if (device == null) {  
37 - log.error("[execute][message({}) actionConfig({}) 对应的设备不存在]", message, actionConfig);  
38 - return;  
39 - }  
40 - try {  
41 - // TODO @芋艿:@puhui999:这块可能要改,从 type => method  
42 - IotDeviceMessage downstreamMessage = deviceMessageService.sendDeviceMessage(IotDeviceMessage.requestOf(  
43 - control.getType() + control.getIdentifier(), control.getData()).setDeviceId(device.getId()));  
44 - log.info("[execute][message({}) actionConfig({}) 下发消息({})成功]", message, actionConfig, downstreamMessage);  
45 - } catch (Exception e) {  
46 - log.error("[execute][message({}) actionConfig({}) 下发消息失败]", message, actionConfig, e);  
47 - }  
48 - }); 28 + IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) {
  29 + //IotRuleSceneDO.ActionDeviceControl control = actionConfig.getDeviceControl();
  30 + //Assert.notNull(control, "设备控制配置不能为空");
  31 + //// 遍历每个设备,下发消息
  32 + //control.getDeviceNames().forEach(deviceName -> {
  33 + // IotDeviceDO device = deviceService.getDeviceFromCache(control.getProductKey(), deviceName);
  34 + // if (device == null) {
  35 + // log.error("[execute][message({}) actionConfig({}) 对应的设备不存在]", message, actionConfig);
  36 + // return;
  37 + // }
  38 + // try {
  39 + // // TODO @芋艿:@puhui999:这块可能要改,从 type => method
  40 + // IotDeviceMessage downstreamMessage = deviceMessageService.sendDeviceMessage(IotDeviceMessage.requestOf(
  41 + // control.getType() + control.getIdentifier(), control.getData()).setDeviceId(device.getId()));
  42 + // log.info("[execute][message({}) actionConfig({}) 下发消息({})成功]", message, actionConfig, downstreamMessage);
  43 + // } catch (Exception e) {
  44 + // log.error("[execute][message({}) actionConfig({}) 下发消息失败]", message, actionConfig, e);
  45 + // }
  46 + //});
49 } 47 }
50 48
51 @Override 49 @Override
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java
@@ -24,7 +24,7 @@ public interface IotSceneRuleAction { @@ -24,7 +24,7 @@ public interface IotSceneRuleAction {
24 */ 24 */
25 void execute(@Nullable IotDeviceMessage message, 25 void execute(@Nullable IotDeviceMessage message,
26 IotRuleSceneDO rule, 26 IotRuleSceneDO rule,
27 - IotRuleSceneDO.ActionConfig actionConfig) throws Exception; 27 + IotRuleSceneDO.Action actionConfig) throws Exception;
28 28
29 /** 29 /**
30 * 获得类型 30 * 获得类型