Commit 00bd4293f02e1f6104a21bc336ad05657b27d833
1 parent
e7a09de3
review:【iot 物联网】场景联动的逻辑
Showing
4 changed files
with
7 additions
and
285 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.dal.dataobject.rule; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 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; | ||
| 7 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 8 | -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | ||
| 9 | -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | ||
| 10 | -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; | ||
| 11 | -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; | ||
| 12 | -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum; | ||
| 13 | -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; | ||
| 14 | -import com.baomidou.mybatisplus.annotation.KeySequence; | ||
| 15 | -import com.baomidou.mybatisplus.annotation.TableField; | ||
| 16 | -import com.baomidou.mybatisplus.annotation.TableId; | ||
| 17 | -import com.baomidou.mybatisplus.annotation.TableName; | ||
| 18 | -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; | ||
| 19 | -import lombok.AllArgsConstructor; | ||
| 20 | -import lombok.Builder; | ||
| 21 | -import lombok.Data; | ||
| 22 | -import lombok.NoArgsConstructor; | ||
| 23 | - | ||
| 24 | -import java.util.List; | ||
| 25 | - | ||
| 26 | -// TODO @puhui999:还是在 IotRuleSceneDO 里搞,这里主要可以看到变化字段哈。 | ||
| 27 | -/** | ||
| 28 | - * IoT 场景联动 DO | ||
| 29 | - * | ||
| 30 | - * 基于 {@link Trigger} 触发 {@link Action} | ||
| 31 | - * | ||
| 32 | - * @author 芋道源码 | ||
| 33 | - */ | ||
| 34 | -@TableName(value = "iot_scene_rule", autoResultMap = true) | ||
| 35 | -@KeySequence("iot_scene_rule_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | ||
| 36 | -@Data | ||
| 37 | -@Builder | ||
| 38 | -@NoArgsConstructor | ||
| 39 | -@AllArgsConstructor | ||
| 40 | -public class IotSceneRuleDO extends TenantBaseDO { | ||
| 41 | - | ||
| 42 | - /** | ||
| 43 | - * 场景联动编号 | ||
| 44 | - */ | ||
| 45 | - @TableId | ||
| 46 | - private Long id; | ||
| 47 | - /** | ||
| 48 | - * 场景联动名称 | ||
| 49 | - */ | ||
| 50 | - private String name; | ||
| 51 | - /** | ||
| 52 | - * 场景联动描述 | ||
| 53 | - */ | ||
| 54 | - private String description; | ||
| 55 | - /** | ||
| 56 | - * 场景联动状态 | ||
| 57 | - * | ||
| 58 | - * 枚举 {@link CommonStatusEnum} | ||
| 59 | - */ | ||
| 60 | - private Integer status; | ||
| 61 | - | ||
| 62 | - /** | ||
| 63 | - * 场景定义配置 | ||
| 64 | - */ | ||
| 65 | - @TableField(typeHandler = JacksonTypeHandler.class) | ||
| 66 | - private List<Trigger> triggers; | ||
| 67 | - | ||
| 68 | - /** | ||
| 69 | - * 场景动作配置 | ||
| 70 | - */ | ||
| 71 | - @TableField(typeHandler = JacksonTypeHandler.class) | ||
| 72 | - private List<Action> actions; | ||
| 73 | - | ||
| 74 | - /** | ||
| 75 | - * 场景定义配置 | ||
| 76 | - */ | ||
| 77 | - @Data | ||
| 78 | - public static class Trigger { | ||
| 79 | - | ||
| 80 | - // ========== 事件部分 ========== | ||
| 81 | - | ||
| 82 | - /** | ||
| 83 | - * 场景事件类型 | ||
| 84 | - * | ||
| 85 | - * 枚举 {@link IotRuleSceneTriggerTypeEnum} | ||
| 86 | - * 1. {@link IotRuleSceneTriggerTypeEnum#DEVICE_STATE_UPDATE} 时,operator 非空,并且 value 为在线状态 | ||
| 87 | - * 2. {@link IotRuleSceneTriggerTypeEnum#DEVICE_PROPERTY_POST} | ||
| 88 | - * {@link IotRuleSceneTriggerTypeEnum#DEVICE_EVENT_POST} 时,identifier、operator 非空,并且 value 为属性值 | ||
| 89 | - * 3. {@link IotRuleSceneTriggerTypeEnum#DEVICE_EVENT_POST} | ||
| 90 | - * {@link IotRuleSceneTriggerTypeEnum#DEVICE_SERVICE_INVOKE} 时,identifier 非空,但是 operator、value 为空 | ||
| 91 | - * 4. {@link IotRuleSceneTriggerTypeEnum#TIMER} 时,conditions 非空,并且设备无关(无需 productId、deviceId 字段) | ||
| 92 | - */ | ||
| 93 | - private Integer type; | ||
| 94 | - | ||
| 95 | - /** | ||
| 96 | - * 产品编号 | ||
| 97 | - * | ||
| 98 | - * 关联 {@link IotProductDO#getId()} | ||
| 99 | - */ | ||
| 100 | - private Long productId; | ||
| 101 | - /** | ||
| 102 | - * 设备编号 | ||
| 103 | - * | ||
| 104 | - * 关联 {@link IotDeviceDO#getId()} | ||
| 105 | - * 特殊:如果为 {@link IotDeviceDO#DEVICE_ID_ALL} 时,则是全部设备 | ||
| 106 | - */ | ||
| 107 | - private Long deviceId; | ||
| 108 | - /** | ||
| 109 | - * 物模型标识符 | ||
| 110 | - * | ||
| 111 | - * 对应:{@link IotThingModelDO#getIdentifier()} | ||
| 112 | - */ | ||
| 113 | - private String identifier; | ||
| 114 | - /** | ||
| 115 | - * 操作符 | ||
| 116 | - * | ||
| 117 | - * 枚举 {@link IotRuleSceneConditionOperatorEnum} | ||
| 118 | - */ | ||
| 119 | - private String operator; | ||
| 120 | - /** | ||
| 121 | - * 参数(属性值、在线状态) | ||
| 122 | - * | ||
| 123 | - * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 | ||
| 124 | - * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN} | ||
| 125 | - */ | ||
| 126 | - private String value; | ||
| 127 | - | ||
| 128 | - /** | ||
| 129 | - * CRON 表达式 | ||
| 130 | - */ | ||
| 131 | - private String cronExpression; | ||
| 132 | - | ||
| 133 | - // ========== 条件部分 ========== | ||
| 134 | - | ||
| 135 | - /** | ||
| 136 | - * 触发条件分组(状态条件分组)的数组 | ||
| 137 | - * | ||
| 138 | - * 第一层 List:分组与分组之间,是“或”的关系 | ||
| 139 | - * 第二层 List:条件与条件之间,是“且”的关系 | ||
| 140 | - */ | ||
| 141 | - private List<List<TriggerCondition>> conditionGroups; | ||
| 142 | - | ||
| 143 | - } | ||
| 144 | - | ||
| 145 | - /** | ||
| 146 | - * 触发条件(状态条件) | ||
| 147 | - */ | ||
| 148 | - @Data | ||
| 149 | - public static class TriggerCondition { | ||
| 150 | - | ||
| 151 | - /** | ||
| 152 | - * 触发条件类型 | ||
| 153 | - * | ||
| 154 | - * 枚举 {@link IotRuleSceneConditionTypeEnum} | ||
| 155 | - * 1. {@link IotRuleSceneConditionTypeEnum#DEVICE_STATE} 时,operator 非空,并且 value 为在线状态 | ||
| 156 | - * 2. {@link IotRuleSceneConditionTypeEnum#DEVICE_PROPERTY} 时,identifier、operator 非空,并且 value 为属性值 | ||
| 157 | - * 3. {@link IotRuleSceneConditionTypeEnum#CURRENT_TIME} 时,operator 非空(使用 DATE_TIME_ 和 TIME_ 部分),并且 value 非空 | ||
| 158 | - */ | ||
| 159 | - private Integer type; | ||
| 160 | - | ||
| 161 | - /** | ||
| 162 | - * 产品编号 | ||
| 163 | - * | ||
| 164 | - * 关联 {@link IotProductDO#getId()} | ||
| 165 | - */ | ||
| 166 | - private Long productId; | ||
| 167 | - /** | ||
| 168 | - * 设备编号 | ||
| 169 | - * | ||
| 170 | - * 关联 {@link IotDeviceDO#getId()} | ||
| 171 | - */ | ||
| 172 | - private Long deviceId; | ||
| 173 | - /** | ||
| 174 | - * 标识符(属性) | ||
| 175 | - * | ||
| 176 | - * 关联 {@link IotThingModelDO#getIdentifier()} | ||
| 177 | - */ | ||
| 178 | - private String identifier; | ||
| 179 | - /** | ||
| 180 | - * 操作符 | ||
| 181 | - * | ||
| 182 | - * 枚举 {@link IotRuleSceneConditionOperatorEnum} | ||
| 183 | - */ | ||
| 184 | - private String operator; | ||
| 185 | - /** | ||
| 186 | - * 参数 | ||
| 187 | - * | ||
| 188 | - * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 | ||
| 189 | - * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN} | ||
| 190 | - */ | ||
| 191 | - private String param; | ||
| 192 | - | ||
| 193 | - } | ||
| 194 | - | ||
| 195 | - /** | ||
| 196 | - * 场景动作配置 | ||
| 197 | - */ | ||
| 198 | - @Data | ||
| 199 | - public static class Action { | ||
| 200 | - | ||
| 201 | - /** | ||
| 202 | - * 执行类型 | ||
| 203 | - * | ||
| 204 | - * 枚举 {@link IotRuleSceneActionTypeEnum} | ||
| 205 | - * 1. {@link IotRuleSceneActionTypeEnum#DEVICE_PROPERTY_SET} 时,params 非空 | ||
| 206 | - * {@link IotRuleSceneActionTypeEnum#DEVICE_SERVICE_INVOKE} 时,params 非空 | ||
| 207 | - * 2. {@link IotRuleSceneActionTypeEnum#ALERT_TRIGGER} 时,alertConfigId 为空,因为是 {@link IotAlertConfigDO} 里面关联它 | ||
| 208 | - * 3. {@link IotRuleSceneActionTypeEnum#ALERT_RECOVER} 时,alertConfigId 非空 | ||
| 209 | - */ | ||
| 210 | - private Integer type; | ||
| 211 | - | ||
| 212 | - /** | ||
| 213 | - * 产品编号 | ||
| 214 | - * | ||
| 215 | - * 关联 {@link IotProductDO#getId()} | ||
| 216 | - */ | ||
| 217 | - private Long productId; | ||
| 218 | - /** | ||
| 219 | - * 设备编号 | ||
| 220 | - * | ||
| 221 | - * 关联 {@link IotDeviceDO#getId()} | ||
| 222 | - */ | ||
| 223 | - private Long deviceId; | ||
| 224 | - /** | ||
| 225 | - * 请求参数 | ||
| 226 | - * | ||
| 227 | - * 一般来说,对应 {@link IotDeviceMessage#getParams()} 请求参数 | ||
| 228 | - */ | ||
| 229 | - private Object params; | ||
| 230 | - | ||
| 231 | - /** | ||
| 232 | - * 告警配置编号 | ||
| 233 | - * | ||
| 234 | - * 关联 {@link IotAlertConfigDO#getId()} | ||
| 235 | - */ | ||
| 236 | - private Long alertConfigId; | ||
| 237 | - | ||
| 238 | - } | ||
| 239 | - | ||
| 240 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java
| @@ -77,10 +77,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | @@ -77,10 +77,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | ||
| 77 | 77 | ||
| 78 | @Override | 78 | @Override |
| 79 | public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) { | 79 | public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) { |
| 80 | - // 插入 | ||
| 81 | IotRuleSceneDO ruleScene = BeanUtils.toBean(createReqVO, IotRuleSceneDO.class); | 80 | IotRuleSceneDO ruleScene = BeanUtils.toBean(createReqVO, IotRuleSceneDO.class); |
| 82 | ruleSceneMapper.insert(ruleScene); | 81 | ruleSceneMapper.insert(ruleScene); |
| 83 | - // 返回 | ||
| 84 | return ruleScene.getId(); | 82 | return ruleScene.getId(); |
| 85 | } | 83 | } |
| 86 | 84 | ||
| @@ -147,45 +145,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | @@ -147,45 +145,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | ||
| 147 | @Override | 145 | @Override |
| 148 | @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 | 146 | @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 |
| 149 | public List<IotRuleSceneDO> getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { | 147 | public List<IotRuleSceneDO> getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { |
| 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); | ||
| 187 | - } | ||
| 188 | - | 148 | + // TODO @puhui999:一些注释,看看要不要优化下; |
| 189 | // 注意:旧的测试代码已删除,因为使用了废弃的数据结构 | 149 | // 注意:旧的测试代码已删除,因为使用了废弃的数据结构 |
| 190 | // 如需测试,请使用上面的新结构测试代码示例 | 150 | // 如需测试,请使用上面的新结构测试代码示例 |
| 191 | List<IotRuleSceneDO> list = ruleSceneMapper.selectList(); | 151 | List<IotRuleSceneDO> list = ruleSceneMapper.selectList(); |
| @@ -471,13 +431,13 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | @@ -471,13 +431,13 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | ||
| 471 | return false; | 431 | return false; |
| 472 | } | 432 | } |
| 473 | 433 | ||
| 474 | - // 2. 构建 Spring 表达式的变量 | 434 | + // 2.1 构建 Spring 表达式的变量 |
| 475 | Map<String, Object> springExpressionVariables = MapUtil.<String, Object>builder() | 435 | Map<String, Object> springExpressionVariables = MapUtil.<String, Object>builder() |
| 476 | .put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue) | 436 | .put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue) |
| 477 | .build(); | 437 | .build(); |
| 478 | - | ||
| 479 | - // 3. 根据操作符类型处理参数值 | 438 | + // 2.2 根据操作符类型处理参数值 |
| 480 | if (StrUtil.isNotBlank(paramValue)) { | 439 | if (StrUtil.isNotBlank(paramValue)) { |
| 440 | + // TODO @puhui999:这里是不是在 IotRuleSceneConditionOperatorEnum 加个属性; | ||
| 481 | if (operatorEnum == IotRuleSceneConditionOperatorEnum.IN | 441 | if (operatorEnum == IotRuleSceneConditionOperatorEnum.IN |
| 482 | || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_IN | 442 | || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_IN |
| 483 | || operatorEnum == IotRuleSceneConditionOperatorEnum.BETWEEN | 443 | || operatorEnum == IotRuleSceneConditionOperatorEnum.BETWEEN |
| @@ -493,7 +453,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | @@ -493,7 +453,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | ||
| 493 | } | 453 | } |
| 494 | } | 454 | } |
| 495 | 455 | ||
| 496 | - // 4. 计算 Spring 表达式 | 456 | + // 3. 计算 Spring 表达式 |
| 497 | return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables); | 457 | return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables); |
| 498 | } catch (Exception e) { | 458 | } catch (Exception e) { |
| 499 | log.error("[evaluateCondition][条件评估异常] sourceValue: {}, operator: {}, paramValue: {}", | 459 | log.error("[evaluateCondition][条件评估异常] sourceValue: {}, operator: {}, paramValue: {}", |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java
| @@ -23,6 +23,7 @@ public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction { | @@ -23,6 +23,7 @@ public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction { | ||
| 23 | @Resource | 23 | @Resource |
| 24 | private IotDeviceMessageService deviceMessageService; | 24 | private IotDeviceMessageService deviceMessageService; |
| 25 | 25 | ||
| 26 | + // TODO @puhui999:这里 | ||
| 26 | @Override | 27 | @Override |
| 27 | public void execute(IotDeviceMessage message, | 28 | public void execute(IotDeviceMessage message, |
| 28 | IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) { | 29 | IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) { |