Commit 91ee067d27dca1acdccefc1b075448946c61a915

Authored by puhui999
1 parent bb1210a1

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

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 24 private Integer status;
25 25  
26 26 @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED)
27   - private List<IotRuleSceneDO.TriggerConfig> triggers;
  27 + private List<IotRuleSceneDO.Trigger> triggers;
28 28  
29 29 @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
30   - private List<IotRuleSceneDO.ActionConfig> actions;
  30 + private List<IotRuleSceneDO.Action> actions;
31 31  
32 32 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
33 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 31  
32 32 @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED)
33 33 @NotEmpty(message = "触发器数组不能为空")
34   - private List<IotRuleSceneDO.TriggerConfig> triggers;
  34 + private List<IotRuleSceneDO.Trigger> triggers;
35 35  
36 36 @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
37 37 @NotEmpty(message = "执行器数组不能为空")
38   - private List<IotRuleSceneDO.ActionConfig> actions;
  38 + private List<IotRuleSceneDO.Action> actions;
39 39  
40 40 }
41 41 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java
1 1 package cn.iocoder.yudao.module.iot.dal.dataobject.rule;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 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 7 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
5 8 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
6 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 10 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
10 11 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum;
  12 +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum;
11 13 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
12 14 import com.baomidou.mybatisplus.annotation.KeySequence;
13 15 import com.baomidou.mybatisplus.annotation.TableField;
... ... @@ -20,9 +22,7 @@ import lombok.Data;
20 22 import lombok.NoArgsConstructor;
21 23  
22 24 import java.util.List;
23   -import java.util.Map;
24 25  
25   -// TODO @芋艿:优化注释;
26 26 /**
27 27 * IoT 场景联动规则 DO
28 28 *
... ... @@ -37,211 +37,200 @@ import java.util.Map;
37 37 public class IotRuleSceneDO extends TenantBaseDO {
38 38  
39 39 /**
40   - * 场景编号
  40 + * 场景联动编号
41 41 */
42 42 @TableId
43 43 private Long id;
44 44 /**
45   - * 场景名称
  45 + * 场景联动名称
46 46 */
47 47 private String name;
48 48 /**
49   - * 场景描述
  49 + * 场景联动描述
50 50 */
51 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 57 private Integer status;
58 58  
59 59 /**
60   - * 触发器数组
  60 + * 场景定义配置
61 61 */
62 62 @TableField(typeHandler = JacksonTypeHandler.class)
63   - private List<TriggerConfig> triggers;
  63 + private List<Trigger> triggers;
64 64  
65 65 /**
66   - * 执行器数组
  66 + * 场景动作配置
67 67 */
68 68 @TableField(typeHandler = JacksonTypeHandler.class)
69   - private List<ActionConfig> actions;
  69 + private List<Action> actions;
70 70  
71 71 /**
72   - * 触发器配置
  72 + * 场景定义配置
73 73 */
74 74 @Data
75   - public static class TriggerConfig {
  75 + public static class Trigger {
  76 +
  77 + // ========== 事件部分 ==========
76 78  
77 79 /**
78   - * 触发类型
  80 + * 场景事件类型
79 81 *
80 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 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 126 * CRON 表达式
107   - *
108   - * 必填:当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#TIMER} 时
109 127 */
110 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 145 @Data
118 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 173 * 关联 {@link IotThingModelDO#getIdentifier()}
161 174 */
162 175 private String identifier;
163   -
164 176 /**
165 177 * 操作符
166 178 *
167 179 * 枚举 {@link IotRuleSceneConditionOperatorEnum}
168 180 */
169 181 private String operator;
170   -
171 182 /**
172   - * 比较值
  183 + * 参数
173 184 *
174 185 * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。
175 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 195 @Data
185   - public static class ActionConfig {
  196 + public static class Action {
186 197  
187 198 /**
188 199 * 执行类型
189 200 *
190 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 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/IotRuleSceneServiceImpl.java
... ... @@ -18,15 +18,19 @@ import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
18 18 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO;
19 19 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
20 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 24 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
22 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 26 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
26 27 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum;
  28 +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum;
27 29 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
28 30 import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager;
29 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 34 import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction;
31 35 import jakarta.annotation.Resource;
32 36 import lombok.SneakyThrows;
... ... @@ -39,10 +43,7 @@ import org.quartz.impl.StdSchedulerFactory;
39 43 import org.springframework.stereotype.Service;
40 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 48 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
48 49 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
... ... @@ -68,6 +69,12 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
68 69 @Resource(name = "iotSchedulerManager")
69 70 private IotSchedulerManager schedulerManager;
70 71  
  72 + @Resource
  73 + private IotProductService productService;
  74 +
  75 + @Resource
  76 + private IotDeviceService deviceService;
  77 +
71 78 @Override
72 79 public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) {
73 80 // 插入
... ... @@ -131,118 +138,61 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
131 138 @Override
132 139 @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略
133 140 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);
  141 + // TODO @芋艿:测试代码示例(使用新结构),可根据需要启用
  142 + if (false) {
  143 + // 创建测试规则场景
  144 + IotRuleSceneDO ruleScene = new IotRuleSceneDO();
  145 + ruleScene.setId(1L);
  146 + ruleScene.setName("测试场景");
  147 + ruleScene.setStatus(CommonStatusEnum.ENABLE.getStatus());
  148 +
  149 + // 创建触发器
  150 + IotRuleSceneDO.Trigger trigger = new IotRuleSceneDO.Trigger();
  151 + trigger.setType(IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST.getType());
  152 + trigger.setProductId(1L); // 假设产品ID为1
  153 + trigger.setDeviceId(1L); // 假设设备ID为1
  154 + trigger.setIdentifier("temperature"); // 温度属性
  155 + trigger.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator());
  156 + trigger.setValue("25"); // 温度大于25度
  157 +
  158 + // 创建条件分组
  159 + IotRuleSceneDO.TriggerCondition condition = new IotRuleSceneDO.TriggerCondition();
  160 + condition.setType(IotRuleSceneConditionTypeEnum.DEVICE_PROPERTY.getType());
  161 + condition.setIdentifier("temperature");
  162 + condition.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator());
  163 + condition.setParam("25");
  164 +
  165 + trigger.setConditionGroups(ListUtil.toList(Collections.singleton(ListUtil.toList(condition))));
  166 + ruleScene.setTriggers(ListUtil.toList(trigger));
  167 +
  168 + // 创建动作
  169 + IotRuleSceneDO.Action action = new IotRuleSceneDO.Action();
  170 + action.setType(IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET.getType());
  171 + action.setProductId(1L);
  172 + action.setDeviceId(1L);
  173 + action.setParams(MapUtil.of("fan", "on")); // 打开风扇
  174 +
  175 + ruleScene.setActions(ListUtil.toList(action));
  176 +
  177 + return ListUtil.toList(ruleScene);
235 178 }
236 179  
  180 + // 注意:旧的测试代码已删除,因为使用了废弃的数据结构
  181 + // 如需测试,请使用上面的新结构测试代码示例
237 182 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)) { // 包含设备名称
  183 + // 只返回启用状态的规则场景
  184 + List<IotRuleSceneDO> enabledList = filterList(list,
  185 + ruleScene -> CommonStatusEnum.ENABLE.getStatus().equals(ruleScene.getStatus()));
  186 +
  187 + // 根据 productKey 和 deviceName 进行匹配
  188 + return filterList(enabledList, ruleScene -> {
  189 + if (CollUtil.isEmpty(ruleScene.getTriggers())) {
  190 + return false;
  191 + }
  192 +
  193 + for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) {
  194 + // 检查触发器是否匹配指定的产品和设备
  195 + if (isMatchProductAndDevice(trigger, productKey, deviceName)) {
246 196 return true;
247 197 }
248 198 }
... ... @@ -250,47 +200,70 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
250 200 });
251 201 }
252 202  
  203 + /**
  204 + * 检查触发器是否匹配指定的产品和设备
  205 + *
  206 + * @param trigger 触发器
  207 + * @param productKey 产品标识
  208 + * @param deviceName 设备名称
  209 + * @return 是否匹配
  210 + */
  211 + private boolean isMatchProductAndDevice(IotRuleSceneDO.Trigger trigger, String productKey, String deviceName) {
  212 + try {
  213 + // 1. 检查产品是否匹配
  214 + if (trigger.getProductId() != null) {
  215 + // 通过 productKey 获取产品信息
  216 + IotProductDO product = productService.getProductByProductKey(productKey);
  217 + if (product == null || !trigger.getProductId().equals(product.getId())) {
  218 + return false;
  219 + }
  220 + }
  221 +
  222 + // 2. 检查设备是否匹配
  223 + if (trigger.getDeviceId() != null) {
  224 + // 通过 productKey 和 deviceName 获取设备信息
  225 + IotDeviceDO device = deviceService.getDeviceFromCache(productKey, deviceName);
  226 + if (device == null) {
  227 + return false;
  228 + }
  229 +
  230 + // 检查是否是全部设备的特殊标识
  231 + if (IotDeviceDO.DEVICE_ID_ALL.equals(trigger.getDeviceId())) {
  232 + return true; // 匹配所有设备
  233 + }
  234 +
  235 + // 检查具体设备ID是否匹配
  236 + if (!trigger.getDeviceId().equals(device.getId())) {
  237 + return false;
  238 + }
  239 + }
  240 +
  241 + return true;
  242 + } catch (Exception e) {
  243 + log.warn("[isMatchProductAndDevice][产品({}) 设备({}) 匹配触发器异常]", productKey, deviceName, e);
  244 + return false;
  245 + }
  246 + }
  247 +
253 248 @Override
254 249 public void executeRuleSceneByDevice(IotDeviceMessage message) {
255 250 // 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   -// });
  251 + TenantUtils.execute(message.getTenantId(), () -> {
  252 + // 1. 获得设备匹配的规则场景
  253 + List<IotRuleSceneDO> ruleScenes = getMatchedRuleSceneListByMessage(message);
  254 + if (CollUtil.isEmpty(ruleScenes)) {
  255 + return;
  256 + }
  257 +
  258 + // 2. 执行规则场景
  259 + executeRuleSceneAction(message, ruleScenes);
  260 + });
266 261 }
267 262  
268 263 @Override
269 264 public void executeRuleSceneByTimer(Long id) {
270 265 // 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   - }
  266 + IotRuleSceneDO scene = TenantUtils.executeIgnore(() -> ruleSceneMapper.selectById(id));
294 267 if (scene == null) {
295 268 log.error("[executeRuleSceneByTimer][规则场景({}) 不存在]", id);
296 269 return;
... ... @@ -300,7 +273,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
300 273 return;
301 274 }
302 275 // 1.2 判断是否有定时触发器,避免脏数据
303   - IotRuleSceneDO.TriggerConfig config = CollUtil.findOne(scene.getTriggers(),
  276 + IotRuleSceneDO.Trigger config = CollUtil.findOne(scene.getTriggers(),
304 277 trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType()));
305 278 if (config == null) {
306 279 log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene);
... ... @@ -321,72 +294,229 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
321 294 private List<IotRuleSceneDO> getMatchedRuleSceneListByMessage(IotDeviceMessage message) {
322 295 // 1. 匹配设备
323 296 // TODO @芋艿:可能需要 getSelf(); 缓存
324   - List<IotRuleSceneDO> ruleScenes = null;
325   - // TODO @芋艿:这里需要适配
326   -// List<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache(
327   -// message.getProductKey(), message.getDeviceName());
  297 + // 1.1 通过 deviceId 获取设备信息
  298 + IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId());
  299 + if (device == null) {
  300 + log.warn("[getMatchedRuleSceneListByMessage][设备({}) 不存在]", message.getDeviceId());
  301 + return List.of();
  302 + }
  303 +
  304 + // 1.2 通过 productId 获取产品信息
  305 + IotProductDO product = productService.getProductFromCache(device.getProductId());
  306 + if (product == null) {
  307 + log.warn("[getMatchedRuleSceneListByMessage][产品({}) 不存在]", device.getProductId());
  308 + return List.of();
  309 + }
  310 +
  311 + // 1.3 获取匹配的规则场景
  312 + List<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache(
  313 + product.getProductKey(), device.getDeviceName());
328 314 if (CollUtil.isEmpty(ruleScenes)) {
329 315 return ruleScenes;
330 316 }
331 317  
332 318 // 2. 匹配 trigger 触发器的条件
333 319 return filterList(ruleScenes, ruleScene -> {
334   - for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) {
335   - // 2.1 非设备触发,不匹配
336   - if (ObjUtil.notEqual(trigger.getType(), IotRuleSceneTriggerTypeEnum.DEVICE.getType())) {
  320 + for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) {
  321 + // 2.1 检查触发器类型,根据新的枚举值进行匹配
  322 + // TODO @芋艿:需要根据新的触发器类型枚举进行适配
  323 + // 原来使用 IotRuleSceneTriggerTypeEnum.DEVICE,新结构可能有不同的类型
  324 +
  325 + // 2.2 条件分组为空,说明没有匹配的条件,因此不匹配
  326 + if (CollUtil.isEmpty(trigger.getConditionGroups())) {
337 327 return false;
338 328 }
339   - // TODO 芋艿:产品、设备的匹配,要不要这里在做一次???貌似和 1. 部分重复了
340   - // 2.2 条件为空,说明没有匹配的条件,因此不匹配
341   - if (CollUtil.isEmpty(trigger.getConditions())) {
342   - return false;
  329 +
  330 + // 2.3 检查条件分组:分组与分组之间是"或"的关系,条件与条件之间是"且"的关系
  331 + boolean anyGroupMatched = false;
  332 + for (List<IotRuleSceneDO.TriggerCondition> conditionGroup : trigger.getConditionGroups()) {
  333 + if (CollUtil.isEmpty(conditionGroup)) {
  334 + continue;
  335 + }
  336 +
  337 + // 检查当前分组中的所有条件是否都匹配(且关系)
  338 + boolean allConditionsMatched = true;
  339 + for (IotRuleSceneDO.TriggerCondition condition : conditionGroup) {
  340 + // TODO @芋艿:这里需要实现具体的条件匹配逻辑
  341 + // 根据新的 TriggerCondition 结构进行匹配
  342 + if (!isTriggerConditionMatched(message, condition, ruleScene, trigger)) {
  343 + allConditionsMatched = false;
  344 + break;
  345 + }
  346 + }
  347 +
  348 + if (allConditionsMatched) {
  349 + anyGroupMatched = true;
  350 + break; // 有一个分组匹配即可
  351 + }
343 352 }
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;
  353 +
  354 + if (anyGroupMatched) {
  355 + log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger);
  356 + return true;
358 357 }
359   - log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger);
360   - return true;
361 358 }
362 359 return false;
363 360 });
364 361 }
365 362  
  363 + /**
  364 + * 基于消息,判断触发器的条件是否匹配
  365 + *
  366 + * @param message 设备消息
  367 + * @param condition 触发条件
  368 + * @param ruleScene 规则场景(用于日志,无其它作用)
  369 + * @param trigger 触发器(用于日志,无其它作用)
  370 + * @return 是否匹配
  371 + */
  372 + private boolean isTriggerConditionMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition,
  373 + IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) {
  374 + try {
  375 + // 1. 根据条件类型进行匹配
  376 + if (IotRuleSceneConditionTypeEnum.DEVICE_STATE.getType().equals(condition.getType())) {
  377 + // 设备状态条件匹配
  378 + return matchDeviceStateCondition(message, condition);
  379 + } else if (IotRuleSceneConditionTypeEnum.DEVICE_PROPERTY.getType().equals(condition.getType())) {
  380 + // 设备属性条件匹配
  381 + return matchDevicePropertyCondition(message, condition);
  382 + } else if (IotRuleSceneConditionTypeEnum.CURRENT_TIME.getType().equals(condition.getType())) {
  383 + // 当前时间条件匹配
  384 + return matchCurrentTimeCondition(condition);
  385 + } else {
  386 + log.warn("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 存在未知的条件类型({})]",
  387 + ruleScene.getId(), trigger, condition.getType());
  388 + return false;
  389 + }
  390 + } catch (Exception e) {
  391 + log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]",
  392 + ruleScene.getId(), trigger, e);
  393 + return false;
  394 + }
  395 + }
  396 +
  397 + /**
  398 + * 匹配设备状态条件
  399 + *
  400 + * @param message 设备消息
  401 + * @param condition 触发条件
  402 + * @return 是否匹配
  403 + */
  404 + private boolean matchDeviceStateCondition(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition) {
  405 + // TODO @芋艿:需要根据设备状态进行匹配
  406 + // 这里需要检查消息中的设备状态是否符合条件中定义的状态
  407 + log.debug("[matchDeviceStateCondition][设备状态条件匹配逻辑待实现] condition: {}", condition);
  408 + return false;
  409 + }
  410 +
  411 + /**
  412 + * 匹配设备属性条件
  413 + *
  414 + * @param message 设备消息
  415 + * @param condition 触发条件
  416 + * @return 是否匹配
  417 + */
  418 + private boolean matchDevicePropertyCondition(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition) {
  419 + // 1. 检查标识符是否匹配
  420 + String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message);
  421 + if (StrUtil.isBlank(condition.getIdentifier()) || !condition.getIdentifier().equals(messageIdentifier)) {
  422 + return false;
  423 + }
  424 +
  425 + // 2. 获取消息中的属性值
  426 + Object messageValue = message.getData();
  427 + if (messageValue == null) {
  428 + return false;
  429 + }
  430 +
  431 + // 3. 根据操作符进行匹配
  432 + return evaluateCondition(messageValue, condition.getOperator(), condition.getParam());
  433 + }
  434 +
  435 + /**
  436 + * 匹配当前时间条件
  437 + *
  438 + * @param condition 触发条件
  439 + * @return 是否匹配
  440 + */
  441 + private boolean matchCurrentTimeCondition(IotRuleSceneDO.TriggerCondition condition) {
  442 + // TODO @芋艿:需要根据当前时间进行匹配
  443 + // 这里需要检查当前时间是否符合条件中定义的时间范围
  444 + log.debug("[matchCurrentTimeCondition][当前时间条件匹配逻辑待实现] condition: {}", condition);
  445 + return false;
  446 + }
  447 +
  448 + /**
  449 + * 评估条件是否匹配
  450 + *
  451 + * @param sourceValue 源值(来自消息)
  452 + * @param operator 操作符
  453 + * @param paramValue 参数值(来自条件配置)
  454 + * @return 是否匹配
  455 + */
  456 + private boolean evaluateCondition(Object sourceValue, String operator, String paramValue) {
  457 + try {
  458 + // 1. 校验操作符是否合法
  459 + IotRuleSceneConditionOperatorEnum operatorEnum = IotRuleSceneConditionOperatorEnum.operatorOf(operator);
  460 + if (operatorEnum == null) {
  461 + log.warn("[evaluateCondition][存在错误的操作符({})]", operator);
  462 + return false;
  463 + }
  464 +
  465 + // 2. 构建 Spring 表达式的变量
  466 + Map<String, Object> springExpressionVariables = MapUtil.<String, Object>builder()
  467 + .put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue)
  468 + .build();
  469 +
  470 + // 3. 根据操作符类型处理参数值
  471 + if (StrUtil.isNotBlank(paramValue)) {
  472 + if (operatorEnum == IotRuleSceneConditionOperatorEnum.IN
  473 + || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_IN
  474 + || operatorEnum == IotRuleSceneConditionOperatorEnum.BETWEEN
  475 + || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_BETWEEN) {
  476 + // 处理多值情况
  477 + List<String> paramValues = StrUtil.split(paramValue, CharPool.COMMA);
  478 + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST,
  479 + convertList(paramValues, NumberUtil::parseDouble));
  480 + } else {
  481 + // 处理单值情况
  482 + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE,
  483 + NumberUtil.parseDouble(paramValue));
  484 + }
  485 + }
  486 +
  487 + // 4. 计算 Spring 表达式
  488 + return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables);
  489 + } catch (Exception e) {
  490 + log.error("[evaluateCondition][条件评估异常] sourceValue: {}, operator: {}, paramValue: {}",
  491 + sourceValue, operator, paramValue, e);
  492 + return false;
  493 + }
  494 + }
  495 +
366 496 // TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。
367 497  
368 498 /**
369 499 * 判断触发器的条件参数是否匹配
370 500 *
371 501 * @param message 设备消息
372   - * @param parameter 触发器条件参数
  502 + * @param condition 触发条件
373 503 * @param ruleScene 规则场景(用于日志,无其它作用)
374 504 * @param trigger 触发器(用于日志,无其它作用)
375 505 * @return 是否匹配
376 506 */
377 507 @SuppressWarnings({"unchecked", "DataFlowIssue"})
378   - private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerConditionParameter parameter,
379   - IotRuleSceneDO ruleScene, IotRuleSceneDO.TriggerConfig trigger) {
  508 + private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition,
  509 + IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) {
380 510 // 1.1 校验操作符是否合法
381 511 IotRuleSceneConditionOperatorEnum operator =
382   - IotRuleSceneConditionOperatorEnum.operatorOf(parameter.getOperator());
  512 + IotRuleSceneConditionOperatorEnum.operatorOf(condition.getOperator());
383 513 if (operator == null) {
384 514 log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]",
385   - ruleScene.getId(), trigger, parameter.getOperator());
  515 + ruleScene.getId(), trigger, condition.getOperator());
386 516 return false;
387 517 }
388 518 // 1.2 校验消息是否包含对应的值
389   - String messageValue = MapUtil.getStr((Map<String, Object>) message.getData(), parameter.getIdentifier());
  519 + String messageValue = MapUtil.getStr((Map<String, Object>) message.getData(), condition.getIdentifier());
390 520 if (messageValue == null) {
391 521 return false;
392 522 }
... ... @@ -395,8 +525,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
395 525 Map<String, Object> springExpressionVariables = new HashMap<>();
396 526 try {
397 527 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);
  528 + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, condition.getParam());
  529 + List<String> parameterValues = StrUtil.splitTrim(condition.getParam(), CharPool.COMMA);
400 530 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues);
401 531 // 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题!
402 532 if (ObjectUtils.equalsAny(operator, IotRuleSceneConditionOperatorEnum.BETWEEN,
... ... @@ -410,7 +540,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
410 540 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE,
411 541 NumberUtil.parseDouble(messageValue));
412 542 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE,
413   - NumberUtil.parseDouble(parameter.getValue()));
  543 + NumberUtil.parseDouble(condition.getParam()));
414 544 springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST,
415 545 convertList(parameterValues, NumberUtil::parseDouble));
416 546 }
... ...
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 30  
31 31 @Override
32 32 public void execute(IotDeviceMessage message,
33   - IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception {
  33 + IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) throws Exception {
34 34 Long deviceId = message != null ? message.getDeviceId() : null;
35 35 List<IotAlertRecordDO> alertRecords = alertRecordService.getAlertRecordListBySceneRuleId(
36 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 40  
41 41 @Override
42 42 public void execute(@Nullable IotDeviceMessage message,
43   - IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception {
  43 + IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) throws Exception {
44 44 List<IotAlertConfigDO> alertConfigs = alertConfigService.getAlertConfigListBySceneRuleIdAndStatus(
45 45 rule.getId(), CommonStatusEnum.ENABLE.getStatus());
46 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 1 package cn.iocoder.yudao.module.iot.service.rule.scene.action;
2 2  
3   -import cn.hutool.core.lang.Assert;
4 3 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
5   -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
6 4 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
7 5 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
8 6 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
... ... @@ -27,25 +25,25 @@ public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction {
27 25  
28 26 @Override
29 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 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 24 */
25 25 void execute(@Nullable IotDeviceMessage message,
26 26 IotRuleSceneDO rule,
27   - IotRuleSceneDO.ActionConfig actionConfig) throws Exception;
  27 + IotRuleSceneDO.Action actionConfig) throws Exception;
28 28  
29 29 /**
30 30 * 获得类型
... ...