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 | 77 | |
| 78 | 78 | @Override |
| 79 | 79 | public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) { |
| 80 | - // 插入 | |
| 81 | 80 | IotRuleSceneDO ruleScene = BeanUtils.toBean(createReqVO, IotRuleSceneDO.class); |
| 82 | 81 | ruleSceneMapper.insert(ruleScene); |
| 83 | - // 返回 | |
| 84 | 82 | return ruleScene.getId(); |
| 85 | 83 | } |
| 86 | 84 | |
| ... | ... | @@ -147,45 +145,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 147 | 145 | @Override |
| 148 | 146 | @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 |
| 149 | 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 | 151 | List<IotRuleSceneDO> list = ruleSceneMapper.selectList(); |
| ... | ... | @@ -471,13 +431,13 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 471 | 431 | return false; |
| 472 | 432 | } |
| 473 | 433 | |
| 474 | - // 2. 构建 Spring 表达式的变量 | |
| 434 | + // 2.1 构建 Spring 表达式的变量 | |
| 475 | 435 | Map<String, Object> springExpressionVariables = MapUtil.<String, Object>builder() |
| 476 | 436 | .put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue) |
| 477 | 437 | .build(); |
| 478 | - | |
| 479 | - // 3. 根据操作符类型处理参数值 | |
| 438 | + // 2.2 根据操作符类型处理参数值 | |
| 480 | 439 | if (StrUtil.isNotBlank(paramValue)) { |
| 440 | + // TODO @puhui999:这里是不是在 IotRuleSceneConditionOperatorEnum 加个属性; | |
| 481 | 441 | if (operatorEnum == IotRuleSceneConditionOperatorEnum.IN |
| 482 | 442 | || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_IN |
| 483 | 443 | || operatorEnum == IotRuleSceneConditionOperatorEnum.BETWEEN |
| ... | ... | @@ -493,7 +453,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 493 | 453 | } |
| 494 | 454 | } |
| 495 | 455 | |
| 496 | - // 4. 计算 Spring 表达式 | |
| 456 | + // 3. 计算 Spring 表达式 | |
| 497 | 457 | return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables); |
| 498 | 458 | } catch (Exception e) { |
| 499 | 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 | 23 | @Resource |
| 24 | 24 | private IotDeviceMessageService deviceMessageService; |
| 25 | 25 | |
| 26 | + // TODO @puhui999:这里 | |
| 26 | 27 | @Override |
| 27 | 28 | public void execute(IotDeviceMessage message, |
| 28 | 29 | IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) { | ... | ... |