Commit e7a09de3daee0415eeb516759c0ac4a0e122b1bb
Committed by
Gitee
!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 | 7 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneRespVO; |
| 9 | 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 | 11 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; |
| 11 | 12 | import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; |
| 12 | 13 | import io.swagger.v3.oas.annotations.Operation; |
| ... | ... | @@ -48,6 +49,14 @@ public class IotRuleSceneController { |
| 48 | 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 | 60 | @DeleteMapping("/delete") |
| 52 | 61 | @Operation(summary = "删除场景联动") |
| 53 | 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 | 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/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 | 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/IotRuleSceneService.java
| ... | ... | @@ -34,6 +34,14 @@ public interface IotRuleSceneService { |
| 34 | 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 | 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 | 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 | // 插入 |
| ... | ... | @@ -87,6 +94,15 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 87 | 94 | } |
| 88 | 95 | |
| 89 | 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 | 106 | public void deleteRuleScene(Long id) { |
| 91 | 107 | // 校验存在 |
| 92 | 108 | validateRuleSceneExists(id); |
| ... | ... | @@ -131,118 +147,61 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 131 | 147 | @Override |
| 132 | 148 | @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 |
| 133 | 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 | 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 | 205 | return true; |
| 247 | 206 | } |
| 248 | 207 | } |
| ... | ... | @@ -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 | 257 | @Override |
| 254 | 258 | public void executeRuleSceneByDevice(IotDeviceMessage message) { |
| 255 | 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 | 272 | @Override |
| 269 | 273 | public void executeRuleSceneByTimer(Long id) { |
| 270 | 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 | 276 | if (scene == null) { |
| 295 | 277 | log.error("[executeRuleSceneByTimer][规则场景({}) 不存在]", id); |
| 296 | 278 | return; |
| ... | ... | @@ -300,7 +282,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 300 | 282 | return; |
| 301 | 283 | } |
| 302 | 284 | // 1.2 判断是否有定时触发器,避免脏数据 |
| 303 | - IotRuleSceneDO.TriggerConfig config = CollUtil.findOne(scene.getTriggers(), | |
| 285 | + IotRuleSceneDO.Trigger config = CollUtil.findOne(scene.getTriggers(), | |
| 304 | 286 | trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType())); |
| 305 | 287 | if (config == null) { |
| 306 | 288 | log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene); |
| ... | ... | @@ -321,72 +303,229 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 321 | 303 | private List<IotRuleSceneDO> getMatchedRuleSceneListByMessage(IotDeviceMessage message) { |
| 322 | 304 | // 1. 匹配设备 |
| 323 | 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 | 323 | if (CollUtil.isEmpty(ruleScenes)) { |
| 329 | 324 | return ruleScenes; |
| 330 | 325 | } |
| 331 | 326 | |
| 332 | 327 | // 2. 匹配 trigger 触发器的条件 |
| 333 | 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 | 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 | 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 | 505 | // TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。 |
| 367 | 506 | |
| 368 | 507 | /** |
| 369 | 508 | * 判断触发器的条件参数是否匹配 |
| 370 | 509 | * |
| 371 | 510 | * @param message 设备消息 |
| 372 | - * @param parameter 触发器条件参数 | |
| 511 | + * @param condition 触发条件 | |
| 373 | 512 | * @param ruleScene 规则场景(用于日志,无其它作用) |
| 374 | 513 | * @param trigger 触发器(用于日志,无其它作用) |
| 375 | 514 | * @return 是否匹配 |
| 376 | 515 | */ |
| 377 | 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 | 519 | // 1.1 校验操作符是否合法 |
| 381 | 520 | IotRuleSceneConditionOperatorEnum operator = |
| 382 | - IotRuleSceneConditionOperatorEnum.operatorOf(parameter.getOperator()); | |
| 521 | + IotRuleSceneConditionOperatorEnum.operatorOf(condition.getOperator()); | |
| 383 | 522 | if (operator == null) { |
| 384 | 523 | log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]", |
| 385 | - ruleScene.getId(), trigger, parameter.getOperator()); | |
| 524 | + ruleScene.getId(), trigger, condition.getOperator()); | |
| 386 | 525 | return false; |
| 387 | 526 | } |
| 388 | 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 | 529 | if (messageValue == null) { |
| 391 | 530 | return false; |
| 392 | 531 | } |
| ... | ... | @@ -395,8 +534,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 395 | 534 | Map<String, Object> springExpressionVariables = new HashMap<>(); |
| 396 | 535 | try { |
| 397 | 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 | 539 | springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues); |
| 401 | 540 | // 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题! |
| 402 | 541 | if (ObjectUtils.equalsAny(operator, IotRuleSceneConditionOperatorEnum.BETWEEN, |
| ... | ... | @@ -410,7 +549,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 410 | 549 | springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, |
| 411 | 550 | NumberUtil.parseDouble(messageValue)); |
| 412 | 551 | springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, |
| 413 | - NumberUtil.parseDouble(parameter.getValue())); | |
| 552 | + NumberUtil.parseDouble(condition.getParam())); | |
| 414 | 553 | springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, |
| 415 | 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 | 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 | * 获得类型 | ... | ... |