Commit 48cfcdadc13a642f28859912c7e808f0f9d80302
1 parent
4f84182d
【代码优化】IoT:实现规则 IotRuleSceneDeviceControlAction 执行器
Showing
17 changed files
with
306 additions
and
115 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.enums.rule; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.core.ArrayValuable; | |
| 4 | +import lombok.Getter; | |
| 5 | +import lombok.RequiredArgsConstructor; | |
| 6 | + | |
| 7 | +import java.util.Arrays; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * Iot 规则场景的触发类型枚举 | |
| 11 | + * | |
| 12 | + * 设备触发,定时触发 | |
| 13 | + */ | |
| 14 | +@RequiredArgsConstructor | |
| 15 | +@Getter | |
| 16 | +public enum IotRuleSceneActionTypeEnum implements ArrayValuable<Integer> { | |
| 17 | + | |
| 18 | + DEVICE_CONTROL(1), // 设备执行 | |
| 19 | + ALERT(2), // 告警执行 | |
| 20 | + DATA_BRIDGE(3); // 桥接执行 | |
| 21 | + | |
| 22 | + private final Integer type; | |
| 23 | + | |
| 24 | + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneActionTypeEnum::getType).toArray(Integer[]::new); | |
| 25 | + | |
| 26 | + @Override | |
| 27 | + public Integer[] array() { | |
| 28 | + return ARRAYS; | |
| 29 | + } | |
| 30 | + | |
| 31 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | 4 | import cn.iocoder.yudao.framework.mybatis.core.type.LongSetTypeHandler; |
| 5 | +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; | |
| 5 | 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; |
| 6 | 7 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; |
| 7 | 8 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| ... | ... | @@ -27,7 +28,7 @@ import java.util.Set; |
| 27 | 28 | @Builder |
| 28 | 29 | @NoArgsConstructor |
| 29 | 30 | @AllArgsConstructor |
| 30 | -public class IotDeviceDO extends BaseDO { | |
| 31 | +public class IotDeviceDO extends TenantBaseDO { | |
| 31 | 32 | |
| 32 | 33 | /** |
| 33 | 34 | * 设备 ID,主键,自增 | ... | ... |
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.mybatis.core.dataobject.BaseDO; | |
| 3 | +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; | |
| 4 | 4 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; |
| 6 | 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; |
| 7 | 7 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; |
| 9 | +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; | |
| 9 | 10 | import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; |
| 11 | +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; | |
| 10 | 12 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 11 | 13 | import com.baomidou.mybatisplus.annotation.TableField; |
| 12 | 14 | import com.baomidou.mybatisplus.annotation.TableId; |
| ... | ... | @@ -30,7 +32,7 @@ import java.util.Map; |
| 30 | 32 | @Builder |
| 31 | 33 | @NoArgsConstructor |
| 32 | 34 | @AllArgsConstructor |
| 33 | -public class IotRuleSceneDO extends BaseDO { | |
| 35 | +public class IotRuleSceneDO extends TenantBaseDO { | |
| 34 | 36 | |
| 35 | 37 | /** |
| 36 | 38 | * 场景编号 |
| ... | ... | @@ -56,24 +58,26 @@ public class IotRuleSceneDO extends BaseDO { |
| 56 | 58 | * 触发器数组 |
| 57 | 59 | */ |
| 58 | 60 | @TableField(typeHandler = JacksonTypeHandler.class) |
| 59 | - private List<Trigger> triggers; | |
| 61 | + private List<TriggerConfig> triggers; | |
| 62 | + | |
| 63 | + // TODO @芋艿:需要调研下 https://help.aliyun.com/zh/iot/user-guide/scene-orchestration-1?spm=a2c4g.11186623.help-menu-30520.d_2_4_5_0.45413908fxCSVa | |
| 60 | 64 | |
| 61 | 65 | /** |
| 62 | 66 | * 执行器数组 |
| 63 | 67 | */ |
| 64 | 68 | @TableField(typeHandler = JacksonTypeHandler.class) |
| 65 | - private List<Actuator> actuators; | |
| 69 | + private List<ActionConfig> actions; | |
| 66 | 70 | |
| 67 | 71 | /** |
| 68 | - * 触发器 | |
| 72 | + * 触发器配置 | |
| 69 | 73 | */ |
| 70 | 74 | @Data |
| 71 | - public static class Trigger { | |
| 75 | + public static class TriggerConfig { | |
| 72 | 76 | |
| 73 | 77 | /** |
| 74 | 78 | * 触发类型 |
| 75 | 79 | * |
| 76 | - * 枚举 {@link cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum} | |
| 80 | + * 枚举 {@link IotRuleSceneTriggerTypeEnum} | |
| 77 | 81 | */ |
| 78 | 82 | private Integer type; |
| 79 | 83 | |
| ... | ... | @@ -93,14 +97,15 @@ public class IotRuleSceneDO extends BaseDO { |
| 93 | 97 | /** |
| 94 | 98 | * 触发条件数组 |
| 95 | 99 | * |
| 96 | - * TODO @芋艿:注释说明 | |
| 100 | + * 当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#DEVICE} 时,必填 | |
| 101 | + * 条件与条件之间,是“或”的关系 | |
| 97 | 102 | */ |
| 98 | 103 | private List<TriggerCondition> conditions; |
| 99 | 104 | |
| 100 | 105 | /** |
| 101 | 106 | * CRON 表达式 |
| 102 | 107 | * |
| 103 | - * TODO @芋艿:注释说明 | |
| 108 | + * 当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#TIMER} 时,必填 | |
| 104 | 109 | */ |
| 105 | 110 | private String cronExpression; |
| 106 | 111 | |
| ... | ... | @@ -127,6 +132,8 @@ public class IotRuleSceneDO extends BaseDO { |
| 127 | 132 | |
| 128 | 133 | /** |
| 129 | 134 | * 参数数组 |
| 135 | + * | |
| 136 | + * 参数与参数之间,是“或”的关系 | |
| 130 | 137 | */ |
| 131 | 138 | private List<TriggerConditionParameter> parameters; |
| 132 | 139 | |
| ... | ... | @@ -163,60 +170,60 @@ public class IotRuleSceneDO extends BaseDO { |
| 163 | 170 | } |
| 164 | 171 | |
| 165 | 172 | /** |
| 166 | - * 执行器 | |
| 173 | + * 执行器配置 | |
| 167 | 174 | */ |
| 168 | 175 | @Data |
| 169 | - public static class Actuator { | |
| 176 | + public static class ActionConfig { | |
| 170 | 177 | |
| 171 | 178 | /** |
| 172 | 179 | * 执行类型 |
| 173 | 180 | * |
| 174 | - * TODO @芋艿:control、alert、webhook(待定) | |
| 181 | + * 枚举 {@link IotRuleSceneActionTypeEnum} | |
| 175 | 182 | */ |
| 176 | 183 | private Integer type; |
| 177 | 184 | |
| 178 | 185 | /** |
| 179 | - * 产品标识 | |
| 180 | - * | |
| 181 | - * 关联 {@link IotProductDO#getProductKey()} | |
| 182 | - */ | |
| 183 | - private String productKey; | |
| 184 | - /** | |
| 185 | - * 设备名称数组 | |
| 186 | - * | |
| 187 | - * 关联 {@link IotDeviceDO#getDeviceName()} | |
| 188 | - */ | |
| 189 | - private List<String> deviceNames; | |
| 190 | - | |
| 191 | - /** | |
| 192 | - * 控制数组 | |
| 186 | + * 设备控制 | |
| 193 | 187 | * |
| 194 | - * TODO 芋艿:类型的情况下 | |
| 188 | + * 当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DEVICE_CONTROL} 时,必填 | |
| 195 | 189 | */ |
| 196 | - private List<ActuatorControl> controls; | |
| 190 | + private ActionDeviceControl deviceControl; | |
| 197 | 191 | |
| 198 | 192 | /** |
| 199 | 193 | * 数据桥接编号 |
| 200 | 194 | * |
| 201 | - * TODO 芋艿:暂定! | |
| 195 | + * 当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE} 时,必填 | |
| 202 | 196 | * TODO 芋艿:关联 |
| 203 | 197 | */ |
| 204 | - private Long bridgeId; | |
| 198 | + private Long dataBridgeId; | |
| 205 | 199 | |
| 206 | 200 | } |
| 207 | 201 | |
| 208 | 202 | /** |
| 209 | - * 执行器控制 | |
| 203 | + * 执行设备控制 | |
| 210 | 204 | */ |
| 211 | 205 | @Data |
| 212 | - public static class ActuatorControl { | |
| 206 | + public static class ActionDeviceControl { | |
| 207 | + | |
| 208 | + /** | |
| 209 | + * 产品标识 | |
| 210 | + * | |
| 211 | + * 关联 {@link IotProductDO#getProductKey()} | |
| 212 | + */ | |
| 213 | + private String productKey; | |
| 214 | + /** | |
| 215 | + * 设备名称数组 | |
| 216 | + * | |
| 217 | + * 关联 {@link IotDeviceDO#getDeviceName()} | |
| 218 | + */ | |
| 219 | + private List<String> deviceNames; | |
| 213 | 220 | |
| 214 | 221 | /** |
| 215 | 222 | * 消息类型 |
| 216 | 223 | * |
| 217 | 224 | * 枚举 {@link IotDeviceMessageTypeEnum#PROPERTY}、{@link IotDeviceMessageTypeEnum#SERVICE} |
| 218 | 225 | */ |
| 219 | - private Integer type; | |
| 226 | + private String type; | |
| 220 | 227 | /** |
| 221 | 228 | * 消息标识符 |
| 222 | 229 | * | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java
| ... | ... | @@ -17,7 +17,7 @@ public interface RedisKeyConstants { |
| 17 | 17 | * HASH KEY:identifier 属性标识 |
| 18 | 18 | * VALUE 数据类型:String(JSON) {@link IotDevicePropertyDO} |
| 19 | 19 | */ |
| 20 | - String DEVICE_PROPERTY = "device_property:%s"; | |
| 20 | + String DEVICE_PROPERTY = "iot:device_property:%s"; | |
| 21 | 21 | |
| 22 | 22 | /** |
| 23 | 23 | * 设备的最后上报时间,采用 ZSET 结构 |
| ... | ... | @@ -25,23 +25,23 @@ public interface RedisKeyConstants { |
| 25 | 25 | * KEY 格式:{deviceKey} |
| 26 | 26 | * SCORE:上报时间 |
| 27 | 27 | */ |
| 28 | - String DEVICE_REPORT_TIMES = "device_report_times"; | |
| 28 | + String DEVICE_REPORT_TIMES = "iot:device_report_times"; | |
| 29 | 29 | |
| 30 | 30 | /** |
| 31 | - * 设备信息的数据缓存,使用 Spring Cache 操作 | |
| 31 | + * 设备信息的数据缓存,使用 Spring Cache 操作(忽略租户) | |
| 32 | 32 | * |
| 33 | 33 | * KEY 格式:device_${productKey}_${deviceKey} |
| 34 | 34 | * VALUE 数据类型:String(JSON) |
| 35 | 35 | */ |
| 36 | - String DEVICE = "device"; | |
| 36 | + String DEVICE = "iot:device"; | |
| 37 | 37 | |
| 38 | 38 | /** |
| 39 | - * 物模型的数据缓存,使用 Spring Cache 操作 | |
| 39 | + * 物模型的数据缓存,使用 Spring Cache 操作(忽略租户) | |
| 40 | 40 | * |
| 41 | 41 | * KEY 格式:thing_model_${productKey} |
| 42 | 42 | * VALUE 数据类型:String 数组(JSON),即 {@link cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO} 列表 |
| 43 | 43 | */ |
| 44 | - String THING_MODEL_LIST = "thing_model_list"; | |
| 44 | + String THING_MODEL_LIST = "iot:thing_model_list"; | |
| 45 | 45 | |
| 46 | 46 | /** |
| 47 | 47 | * 设备插件的插件进程编号的映射,采用 HASH 结构 |
| ... | ... | @@ -50,6 +50,6 @@ public interface RedisKeyConstants { |
| 50 | 50 | * HASH KEY:${deviceKey} |
| 51 | 51 | * VALUE:插件进程编号,对应 {@link IotPluginInstanceDO#getProcessId()} 字段 |
| 52 | 52 | */ |
| 53 | - String DEVICE_PLUGIN_INSTANCE_PROCESS_IDS = "device_plugin_instance_process_ids"; | |
| 53 | + String DEVICE_PLUGIN_INSTANCE_PROCESS_IDS = "iot:device_plugin_instance_process_ids"; | |
| 54 | 54 | |
| 55 | 55 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java
| ... | ... | @@ -24,7 +24,7 @@ public class IotRuleSceneMessageHandler { |
| 24 | 24 | @Async |
| 25 | 25 | public void onMessage(IotDeviceMessage message) { |
| 26 | 26 | log.info("[onMessage][消息内容({})]", message); |
| 27 | - ruleSceneService.executeRuleScene(message); | |
| 27 | + ruleSceneService.executeRuleSceneByDevice(message); | |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java deleted
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
| ... | ... | @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 9 | 9 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 10 | 10 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 11 | 11 | import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; |
| 12 | +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | |
| 12 | 13 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |
| 13 | 14 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; |
| 14 | 15 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| ... | ... | @@ -261,13 +262,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { |
| 261 | 262 | } |
| 262 | 263 | |
| 263 | 264 | @Override |
| 264 | - public IotDeviceDO getDeviceByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { | |
| 265 | - // 保证在 @CacheEvict 之前,忽略租户 | |
| 266 | - return TenantUtils.executeIgnore(() -> getSelf().getDeviceByProductKeyAndDeviceNameFromCache0(productKey, deviceName)); | |
| 267 | - } | |
| 268 | - | |
| 269 | 265 | @Cacheable(value = RedisKeyConstants.DEVICE, key = "#productKey + '_' + #deviceName", unless = "#result == null") |
| 270 | - public IotDeviceDO getDeviceByProductKeyAndDeviceNameFromCache0(String productKey, String deviceName) { | |
| 266 | + @TenantIgnore // 忽略租户信息,跨租户 productKey + deviceName 是唯一的 | |
| 267 | + public IotDeviceDO getDeviceByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { | |
| 271 | 268 | return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); |
| 272 | 269 | } |
| 273 | 270 | |
| ... | ... | @@ -389,8 +386,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { |
| 389 | 386 | } |
| 390 | 387 | |
| 391 | 388 | private void deleteDeviceCache(IotDeviceDO device) { |
| 392 | - // 保证在 @CacheEvict 之前,忽略租户 | |
| 393 | - TenantUtils.executeIgnore(() -> getSelf().deleteDeviceCache0(device)); | |
| 389 | + // 保证 Spring AOP 触发 | |
| 390 | + getSelf().deleteDeviceCache0(device); | |
| 394 | 391 | } |
| 395 | 392 | |
| 396 | 393 | private void deleteDeviceCache(List<IotDeviceDO> devices) { | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.service.device.control; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; |
| 4 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | |
| 4 | 5 | import jakarta.validation.Valid; |
| 5 | 6 | |
| 6 | 7 | /** |
| ... | ... | @@ -16,7 +17,8 @@ public interface IotDeviceDownstreamService { |
| 16 | 17 | * 设备下行,可用于设备模拟 |
| 17 | 18 | * |
| 18 | 19 | * @param downstreamReqVO 设备下行请求 VO |
| 20 | + * @return 下发消息 | |
| 19 | 21 | */ |
| 20 | - void downstreamDevice(@Valid IotDeviceDownstreamReqVO downstreamReqVO); | |
| 22 | + IotDeviceMessage downstreamDevice(@Valid IotDeviceDownstreamReqVO downstreamReqVO); | |
| 21 | 23 | |
| 22 | 24 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java
| ... | ... | @@ -54,7 +54,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 54 | 54 | private IotDeviceProducer deviceProducer; |
| 55 | 55 | |
| 56 | 56 | @Override |
| 57 | - public void downstreamDevice(IotDeviceDownstreamReqVO downstreamReqVO) { | |
| 57 | + public IotDeviceMessage downstreamDevice(IotDeviceDownstreamReqVO downstreamReqVO) { | |
| 58 | 58 | // 校验设备是否存在 |
| 59 | 59 | IotDeviceDO device = deviceService.validateDeviceExists(downstreamReqVO.getId()); |
| 60 | 60 | // TODO 芋艿:父设备的处理 |
| ... | ... | @@ -62,31 +62,28 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 62 | 62 | |
| 63 | 63 | // 服务调用 |
| 64 | 64 | if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.SERVICE.getType())) { |
| 65 | - invokeDeviceService(downstreamReqVO, device, parentDevice); | |
| 66 | - return; | |
| 65 | + return invokeDeviceService(downstreamReqVO, device, parentDevice); | |
| 67 | 66 | } |
| 68 | 67 | // 属性相关 |
| 69 | 68 | if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) { |
| 70 | 69 | // 属性设置 |
| 71 | 70 | if (Objects.equals(downstreamReqVO.getIdentifier(), |
| 72 | 71 | IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())) { |
| 73 | - setDeviceProperty(downstreamReqVO, device, parentDevice); | |
| 74 | - return; | |
| 72 | + return setDeviceProperty(downstreamReqVO, device, parentDevice); | |
| 75 | 73 | } |
| 76 | 74 | // 属性设置 |
| 77 | 75 | if (Objects.equals(downstreamReqVO.getIdentifier(), |
| 78 | 76 | IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) { |
| 79 | - getDeviceProperty(downstreamReqVO, device, parentDevice); | |
| 80 | - return; | |
| 77 | + return getDeviceProperty(downstreamReqVO, device, parentDevice); | |
| 81 | 78 | } |
| 82 | 79 | } |
| 83 | 80 | // 配置下发 |
| 84 | 81 | if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.CONFIG.getType()) |
| 85 | 82 | && Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier())) { |
| 86 | - setDeviceConfig(downstreamReqVO, device, parentDevice); | |
| 87 | - return; | |
| 83 | + return setDeviceConfig(downstreamReqVO, device, parentDevice); | |
| 88 | 84 | } |
| 89 | 85 | // TODO 芋艿:ota 升级 |
| 86 | + return null; | |
| 90 | 87 | } |
| 91 | 88 | |
| 92 | 89 | /** |
| ... | ... | @@ -95,9 +92,10 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 95 | 92 | * @param downstreamReqVO 下行请求 |
| 96 | 93 | * @param device 设备 |
| 97 | 94 | * @param parentDevice 父设备 |
| 95 | + * @return 下发消息 | |
| 98 | 96 | */ |
| 99 | 97 | @SuppressWarnings("unchecked") |
| 100 | - private void invokeDeviceService(IotDeviceDownstreamReqVO downstreamReqVO, | |
| 98 | + private IotDeviceMessage invokeDeviceService(IotDeviceDownstreamReqVO downstreamReqVO, | |
| 101 | 99 | IotDeviceDO device, IotDeviceDO parentDevice) { |
| 102 | 100 | // 1. 参数校验 |
| 103 | 101 | if (!(downstreamReqVO.getData() instanceof Map<?, ?>)) { |
| ... | ... | @@ -124,6 +122,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 124 | 122 | device.getDeviceKey(), reqDTO, result); |
| 125 | 123 | throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); |
| 126 | 124 | } |
| 125 | + return message; | |
| 127 | 126 | } |
| 128 | 127 | |
| 129 | 128 | /** |
| ... | ... | @@ -132,10 +131,11 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 132 | 131 | * @param downstreamReqVO 下行请求 |
| 133 | 132 | * @param device 设备 |
| 134 | 133 | * @param parentDevice 父设备 |
| 134 | + * @return 下发消息 | |
| 135 | 135 | */ |
| 136 | 136 | @SuppressWarnings("unchecked") |
| 137 | - private void setDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, | |
| 138 | - IotDeviceDO device, IotDeviceDO parentDevice) { | |
| 137 | + private IotDeviceMessage setDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, | |
| 138 | + IotDeviceDO device, IotDeviceDO parentDevice) { | |
| 139 | 139 | // 1. 参数校验 |
| 140 | 140 | if (!(downstreamReqVO.getData() instanceof Map<?, ?>)) { |
| 141 | 141 | throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型"); |
| ... | ... | @@ -162,6 +162,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 162 | 162 | device.getDeviceKey(), reqDTO, result); |
| 163 | 163 | throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); |
| 164 | 164 | } |
| 165 | + return message; | |
| 165 | 166 | } |
| 166 | 167 | |
| 167 | 168 | /** |
| ... | ... | @@ -170,10 +171,11 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 170 | 171 | * @param downstreamReqVO 下行请求 |
| 171 | 172 | * @param device 设备 |
| 172 | 173 | * @param parentDevice 父设备 |
| 174 | + * @return 下发消息 | |
| 173 | 175 | */ |
| 174 | 176 | @SuppressWarnings("unchecked") |
| 175 | - private void getDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, | |
| 176 | - IotDeviceDO device, IotDeviceDO parentDevice) { | |
| 177 | + private IotDeviceMessage getDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, | |
| 178 | + IotDeviceDO device, IotDeviceDO parentDevice) { | |
| 177 | 179 | // 1. 参数校验 |
| 178 | 180 | if (!(downstreamReqVO.getData() instanceof List<?>)) { |
| 179 | 181 | throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 List 类型"); |
| ... | ... | @@ -200,6 +202,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 200 | 202 | device.getDeviceKey(), reqDTO, result); |
| 201 | 203 | throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); |
| 202 | 204 | } |
| 205 | + return message; | |
| 203 | 206 | } |
| 204 | 207 | |
| 205 | 208 | /** |
| ... | ... | @@ -208,10 +211,11 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 208 | 211 | * @param downstreamReqVO 下行请求 |
| 209 | 212 | * @param device 设备 |
| 210 | 213 | * @param parentDevice 父设备 |
| 214 | + * @return 下发消息 | |
| 211 | 215 | */ |
| 212 | 216 | @SuppressWarnings({"unchecked", "unused"}) |
| 213 | - private void setDeviceConfig(IotDeviceDownstreamReqVO downstreamReqVO, | |
| 214 | - IotDeviceDO device, IotDeviceDO parentDevice) { | |
| 217 | + private IotDeviceMessage setDeviceConfig(IotDeviceDownstreamReqVO downstreamReqVO, | |
| 218 | + IotDeviceDO device, IotDeviceDO parentDevice) { | |
| 215 | 219 | // 1. 参数转换,无需校验 |
| 216 | 220 | Map<String, Object> config = JsonUtils.parseObject(device.getConfig(), Map.class); |
| 217 | 221 | |
| ... | ... | @@ -235,6 +239,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 235 | 239 | device.getDeviceKey(), reqDTO, result); |
| 236 | 240 | throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); |
| 237 | 241 | } |
| 242 | + return message; | |
| 238 | 243 | } |
| 239 | 244 | |
| 240 | 245 | /** |
| ... | ... | @@ -275,7 +280,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 275 | 280 | private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device, Integer code) { |
| 276 | 281 | // 1. 完善消息 |
| 277 | 282 | message.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName()) |
| 278 | - .setDeviceKey(device.getDeviceKey()); | |
| 283 | + .setDeviceKey(device.getDeviceKey()) | |
| 284 | + .setTenantId(device.getTenantId()); | |
| 279 | 285 | Assert.notNull(message.getRequestId(), "requestId 不能为空"); |
| 280 | 286 | if (message.getReportTime() == null) { |
| 281 | 287 | message.setReportTime(LocalDateTime.now()); | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java
| ... | ... | @@ -98,26 +98,27 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { |
| 98 | 98 | updateReqDTO.getProductKey(), updateReqDTO.getDeviceName()); |
| 99 | 99 | return; |
| 100 | 100 | } |
| 101 | - // 1.2 记录设备的最后时间 | |
| 102 | - updateDeviceLastTime(device, updateReqDTO); | |
| 103 | - // 1.3 当前状态一致,不处理 | |
| 104 | - if (Objects.equals(device.getState(), updateReqDTO.getState())) { | |
| 105 | - return; | |
| 106 | - } | |
| 107 | - | |
| 108 | - // 2. 更新设备状态 | |
| 109 | - TenantUtils.executeIgnore(() -> | |
| 110 | - deviceService.updateDeviceState(device.getId(), updateReqDTO.getState())); | |
| 111 | - | |
| 112 | - // 3. TODO 芋艿:子设备的关联 | |
| 113 | - | |
| 114 | - // 4. 发送设备消息 | |
| 115 | - IotDeviceMessage message = BeanUtils.toBean(updateReqDTO, IotDeviceMessage.class) | |
| 116 | - .setType(IotDeviceMessageTypeEnum.STATE.getType()) | |
| 117 | - .setIdentifier(ObjUtil.equals(updateReqDTO.getState(), IotDeviceStateEnum.ONLINE.getState()) | |
| 118 | - ? IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier() | |
| 119 | - : IotDeviceMessageIdentifierEnum.STATE_OFFLINE.getIdentifier()); | |
| 120 | - sendDeviceMessage(message, device); | |
| 101 | + TenantUtils.execute(device.getTenantId(), () -> { | |
| 102 | + // 1.2 记录设备的最后时间 | |
| 103 | + updateDeviceLastTime(device, updateReqDTO); | |
| 104 | + // 1.3 当前状态一致,不处理 | |
| 105 | + if (Objects.equals(device.getState(), updateReqDTO.getState())) { | |
| 106 | + return; | |
| 107 | + } | |
| 108 | + | |
| 109 | + // 2. 更新设备状态 | |
| 110 | + deviceService.updateDeviceState(device.getId(), updateReqDTO.getState()); | |
| 111 | + | |
| 112 | + // 3. TODO 芋艿:子设备的关联 | |
| 113 | + | |
| 114 | + // 4. 发送设备消息 | |
| 115 | + IotDeviceMessage message = BeanUtils.toBean(updateReqDTO, IotDeviceMessage.class) | |
| 116 | + .setType(IotDeviceMessageTypeEnum.STATE.getType()) | |
| 117 | + .setIdentifier(ObjUtil.equals(updateReqDTO.getState(), IotDeviceStateEnum.ONLINE.getState()) | |
| 118 | + ? IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier() | |
| 119 | + : IotDeviceMessageIdentifierEnum.STATE_OFFLINE.getIdentifier()); | |
| 120 | + sendDeviceMessage(message, device); | |
| 121 | + }); | |
| 121 | 122 | } |
| 122 | 123 | |
| 123 | 124 | @Override |
| ... | ... | @@ -174,7 +175,8 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { |
| 174 | 175 | |
| 175 | 176 | private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { |
| 176 | 177 | // 1. 完善消息 |
| 177 | - message.setDeviceKey(device.getDeviceKey()); | |
| 178 | + message.setDeviceKey(device.getDeviceKey()) | |
| 179 | + .setTenantId(device.getTenantId()); | |
| 178 | 180 | if (StrUtil.isEmpty(message.getRequestId())) { |
| 179 | 181 | message.setRequestId(IdUtil.fastSimpleUUID()); |
| 180 | 182 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.service.rule; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; |
| 4 | +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; | |
| 4 | 5 | import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 5 | 6 | |
| 6 | 7 | import java.util.List; |
| ... | ... | @@ -22,10 +23,12 @@ public interface IotRuleSceneService { |
| 22 | 23 | List<IotRuleSceneDO> getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName); |
| 23 | 24 | |
| 24 | 25 | /** |
| 25 | - * 执行规则场景 | |
| 26 | + * 基于 {@link IotRuleSceneTriggerTypeEnum#DEVICE} 场景,执行规则场景 | |
| 26 | 27 | * |
| 27 | 28 | * @param message 消息 |
| 28 | 29 | */ |
| 29 | - void executeRuleScene(IotDeviceMessage message); | |
| 30 | + void executeRuleSceneByDevice(IotDeviceMessage message); | |
| 31 | + | |
| 32 | + // TODO @芋艿:基于 timer 场景,执行规则场景 | |
| 30 | 33 | |
| 31 | 34 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java
| ... | ... | @@ -11,13 +11,16 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 11 | 11 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| 12 | 12 | import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; |
| 13 | 13 | import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; |
| 14 | +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | |
| 14 | 15 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; |
| 15 | 16 | import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper; |
| 16 | 17 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; |
| 17 | 18 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; |
| 19 | +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; | |
| 18 | 20 | import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; |
| 19 | 21 | import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; |
| 20 | 22 | import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 23 | +import cn.iocoder.yudao.module.iot.service.rule.action.IotRuleSceneAction; | |
| 21 | 24 | import jakarta.annotation.Resource; |
| 22 | 25 | import lombok.extern.slf4j.Slf4j; |
| 23 | 26 | import org.springframework.stereotype.Service; |
| ... | ... | @@ -43,6 +46,9 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 43 | 46 | @Resource |
| 44 | 47 | private IotRuleSceneMapper ruleSceneMapper; |
| 45 | 48 | |
| 49 | + @Resource | |
| 50 | + private List<IotRuleSceneAction> ruleSceneActions; | |
| 51 | + | |
| 46 | 52 | // TODO 芋艿,缓存待实现 |
| 47 | 53 | @Override |
| 48 | 54 | @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 |
| ... | ... | @@ -50,7 +56,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 50 | 56 | if (true) { |
| 51 | 57 | IotRuleSceneDO ruleScene01 = new IotRuleSceneDO(); |
| 52 | 58 | ruleScene01.setTriggers(CollUtil.newArrayList()); |
| 53 | - IotRuleSceneDO.Trigger trigger01 = new IotRuleSceneDO.Trigger(); | |
| 59 | + IotRuleSceneDO.TriggerConfig trigger01 = new IotRuleSceneDO.TriggerConfig(); | |
| 54 | 60 | trigger01.setType(IotRuleSceneTriggerTypeEnum.DEVICE.getType()); |
| 55 | 61 | trigger01.setConditions(CollUtil.newArrayList()); |
| 56 | 62 | // 属性 |
| ... | ... | @@ -120,7 +126,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 120 | 126 | condition02.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier()); |
| 121 | 127 | condition02.setParameters(CollUtil.newArrayList()); |
| 122 | 128 | trigger01.getConditions().add(condition02); |
| 123 | - // TODO 芋艿:事件 | |
| 129 | + // 事件 | |
| 124 | 130 | IotRuleSceneDO.TriggerCondition condition03 = new IotRuleSceneDO.TriggerCondition(); |
| 125 | 131 | condition03.setType(IotDeviceMessageTypeEnum.EVENT.getType()); |
| 126 | 132 | condition03.setIdentifier("xxx"); |
| ... | ... | @@ -131,13 +137,28 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 131 | 137 | parameter030.setValue("1"); |
| 132 | 138 | trigger01.getConditions().add(condition03); |
| 133 | 139 | ruleScene01.getTriggers().add(trigger01); |
| 140 | + // 动作 | |
| 141 | + ruleScene01.setActions(CollUtil.newArrayList()); | |
| 142 | + IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig(); | |
| 143 | + action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType()); | |
| 144 | + IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl(); | |
| 145 | + actionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT"); | |
| 146 | + actionDeviceControl01.setDeviceNames(ListUtil.of("small")); | |
| 147 | + actionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); | |
| 148 | + actionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()); | |
| 149 | + actionDeviceControl01.setData(MapUtil.<String, Object>builder() | |
| 150 | + .put("power", 1) | |
| 151 | + .put("color", "red") | |
| 152 | + .build()); | |
| 153 | + action01.setDeviceControl(actionDeviceControl01); | |
| 154 | + ruleScene01.getActions().add(action01); | |
| 134 | 155 | return ListUtil.toList(ruleScene01); |
| 135 | 156 | } |
| 136 | 157 | |
| 137 | 158 | List<IotRuleSceneDO> list = ruleSceneMapper.selectList(); |
| 138 | 159 | // TODO @芋艿:需要考虑开启状态 |
| 139 | 160 | return filterList(list, ruleScene -> { |
| 140 | - for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { | |
| 161 | + for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) { | |
| 141 | 162 | if (ObjUtil.notEqual(trigger.getProductKey(), productKey)) { |
| 142 | 163 | continue; |
| 143 | 164 | } |
| ... | ... | @@ -151,12 +172,17 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 151 | 172 | } |
| 152 | 173 | |
| 153 | 174 | @Override |
| 154 | - public void executeRuleScene(IotDeviceMessage message) { | |
| 155 | - // 1. 获得设备匹配的规则场景 | |
| 156 | - List<IotRuleSceneDO> ruleScenes = getMatchedRuleSceneList(message); | |
| 157 | - if (CollUtil.isEmpty(ruleScenes)) { | |
| 158 | - return; | |
| 159 | - } | |
| 175 | + public void executeRuleSceneByDevice(IotDeviceMessage message) { | |
| 176 | + TenantUtils.execute(message.getTenantId(), () -> { | |
| 177 | + // 1. 获得设备匹配的规则场景 | |
| 178 | + List<IotRuleSceneDO> ruleScenes = getMatchedRuleSceneList(message); | |
| 179 | + if (CollUtil.isEmpty(ruleScenes)) { | |
| 180 | + return; | |
| 181 | + } | |
| 182 | + | |
| 183 | + // 2. 执行规则场景 | |
| 184 | + executeRuleSceneAction(message, ruleScenes); | |
| 185 | + }); | |
| 160 | 186 | } |
| 161 | 187 | |
| 162 | 188 | /** |
| ... | ... | @@ -176,7 +202,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 176 | 202 | |
| 177 | 203 | // 2. 匹配 trigger 触发器的条件 |
| 178 | 204 | return filterList(ruleScenes, ruleScene -> { |
| 179 | - for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { | |
| 205 | + for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) { | |
| 180 | 206 | // 2.1 非设备触发,不匹配 |
| 181 | 207 | if (ObjUtil.notEqual(trigger.getType(), IotRuleSceneTriggerTypeEnum.DEVICE.getType())) { |
| 182 | 208 | return false; |
| ... | ... | @@ -219,7 +245,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 219 | 245 | */ |
| 220 | 246 | @SuppressWarnings({"unchecked", "DataFlowIssue"}) |
| 221 | 247 | private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerConditionParameter parameter, |
| 222 | - IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) { | |
| 248 | + IotRuleSceneDO ruleScene, IotRuleSceneDO.TriggerConfig trigger) { | |
| 223 | 249 | // 1.1 校验操作符是否合法 |
| 224 | 250 | IotRuleSceneTriggerConditionParameterOperatorEnum operator = |
| 225 | 251 | IotRuleSceneTriggerConditionParameterOperatorEnum.operatorOf(parameter.getOperator()); |
| ... | ... | @@ -266,4 +292,36 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { |
| 266 | 292 | } |
| 267 | 293 | } |
| 268 | 294 | |
| 295 | + /** | |
| 296 | + * 执行规则场景的动作 | |
| 297 | + * | |
| 298 | + * @param message 设备消息 | |
| 299 | + * @param ruleScenes 规则场景列表 | |
| 300 | + */ | |
| 301 | + private void executeRuleSceneAction(IotDeviceMessage message, List<IotRuleSceneDO> ruleScenes) { | |
| 302 | + // 1. 遍历规则场景 | |
| 303 | + ruleScenes.forEach(ruleScene -> { | |
| 304 | + // 2. 遍历规则场景的动作 | |
| 305 | + ruleScene.getActions().forEach(actionConfig -> { | |
| 306 | + // 3.1 获取对应的动作 Action 数组 | |
| 307 | + List<IotRuleSceneAction> actions = filterList(ruleSceneActions, | |
| 308 | + action -> action.getType().getType().equals(actionConfig.getType())); | |
| 309 | + if (CollUtil.isEmpty(actions)) { | |
| 310 | + return; | |
| 311 | + } | |
| 312 | + // 3.2 执行动作 | |
| 313 | + actions.forEach(action -> { | |
| 314 | + try { | |
| 315 | + action.execute(message, actionConfig); | |
| 316 | + log.info("[executeRuleSceneAction][消息({}) 规则场景编号({}) 的执行动作({}) 成功]", | |
| 317 | + message, ruleScene.getId(), actionConfig); | |
| 318 | + } catch (Exception e) { | |
| 319 | + log.error("[executeRuleSceneAction][消息({}) 规则场景编号({}) 的执行动作({}) 执行异常]", | |
| 320 | + message, ruleScene.getId(), actionConfig, e); | |
| 321 | + } | |
| 322 | + }); | |
| 323 | + }); | |
| 324 | + }); | |
| 325 | + } | |
| 326 | + | |
| 269 | 327 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.rule.action; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; | |
| 4 | +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; | |
| 5 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * IOT 规则场景的场景执行器接口 | |
| 9 | + * | |
| 10 | + * @author 芋道源码 | |
| 11 | + */ | |
| 12 | +public interface IotRuleSceneAction { | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 执行场景 | |
| 16 | + * | |
| 17 | + * @param message 消息 | |
| 18 | + * @param config 配置 | |
| 19 | + */ | |
| 20 | + void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config); | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 获得类型 | |
| 24 | + * | |
| 25 | + * @return 类型 | |
| 26 | + */ | |
| 27 | + IotRuleSceneActionTypeEnum getType(); | |
| 28 | + | |
| 29 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.rule.action; | |
| 2 | + | |
| 3 | +import cn.hutool.core.lang.Assert; | |
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; | |
| 5 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | |
| 6 | +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; | |
| 7 | +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; | |
| 8 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | |
| 9 | +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | |
| 10 | +import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService; | |
| 11 | +import jakarta.annotation.Resource; | |
| 12 | +import lombok.extern.slf4j.Slf4j; | |
| 13 | +import org.springframework.stereotype.Component; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * IoT 设备控制的 {@link IotRuleSceneAction} 实现类 | |
| 17 | + * | |
| 18 | + * @author 芋道源码 | |
| 19 | + */ | |
| 20 | +@Component | |
| 21 | +@Slf4j | |
| 22 | +public class IotRuleSceneDeviceControlAction implements IotRuleSceneAction { | |
| 23 | + | |
| 24 | + @Resource | |
| 25 | + private IotDeviceDownstreamService deviceDownstreamService; | |
| 26 | + @Resource | |
| 27 | + private IotDeviceService deviceService; | |
| 28 | + | |
| 29 | + @Override | |
| 30 | + public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { | |
| 31 | + IotRuleSceneDO.ActionDeviceControl control = config.getDeviceControl(); | |
| 32 | + Assert.notNull(control, "设备控制配置不能为空"); | |
| 33 | + // 遍历每个设备,下发消息 | |
| 34 | + control.getDeviceNames().forEach(deviceName -> { | |
| 35 | + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(control.getProductKey(), deviceName); | |
| 36 | + if (device == null) { | |
| 37 | + log.error("[execute][message({}) config({}) 对应的设备不存在]", message, config); | |
| 38 | + return; | |
| 39 | + } | |
| 40 | + try { | |
| 41 | + IotDeviceMessage downstreamMessage = deviceDownstreamService.downstreamDevice(new IotDeviceDownstreamReqVO() | |
| 42 | + .setId(device.getId()).setType(control.getType()).setIdentifier(control.getIdentifier()) | |
| 43 | + .setData(control.getData())); | |
| 44 | + log.info("[execute][message({}) config({}) 下发消息({})成功]", message, config, downstreamMessage); | |
| 45 | + } catch (Exception e) { | |
| 46 | + log.error("[execute][message({}) config({}) 下发消息失败]", message, config, e); | |
| 47 | + } | |
| 48 | + }); | |
| 49 | + } | |
| 50 | + | |
| 51 | + @Override | |
| 52 | + public IotRuleSceneActionTypeEnum getType() { | |
| 53 | + return IotRuleSceneActionTypeEnum.DEVICE_CONTROL; | |
| 54 | + } | |
| 55 | + | |
| 56 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java
| ... | ... | @@ -6,7 +6,7 @@ import cn.hutool.core.util.StrUtil; |
| 6 | 6 | import cn.hutool.extra.spring.SpringUtil; |
| 7 | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | 8 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 9 | -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | |
| 9 | +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | |
| 10 | 10 | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; |
| 11 | 11 | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelParam; |
| 12 | 12 | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; |
| ... | ... | @@ -135,13 +135,9 @@ public class IotThingModelServiceImpl implements IotThingModelService { |
| 135 | 135 | } |
| 136 | 136 | |
| 137 | 137 | @Override |
| 138 | - public List<IotThingModelDO> getThingModelListByProductKeyFromCache(String productKey) { | |
| 139 | - // 保证在 @CacheEvict 之前,忽略租户 | |
| 140 | - return TenantUtils.executeIgnore(() -> getSelf().getThingModelListByProductKeyFromCache0(productKey)); | |
| 141 | - } | |
| 142 | - | |
| 143 | 138 | @Cacheable(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey") |
| 144 | - public List<IotThingModelDO> getThingModelListByProductKeyFromCache0(String productKey) { | |
| 139 | + @TenantIgnore // 忽略租户信息,跨租户 productKey 是唯一的 | |
| 140 | + public List<IotThingModelDO> getThingModelListByProductKeyFromCache(String productKey) { | |
| 145 | 141 | return thingModelMapper.selectListByProductKey(productKey); |
| 146 | 142 | } |
| 147 | 143 | |
| ... | ... | @@ -354,8 +350,8 @@ public class IotThingModelServiceImpl implements IotThingModelService { |
| 354 | 350 | } |
| 355 | 351 | |
| 356 | 352 | private void deleteThingModelListCache(String productKey) { |
| 357 | - // 保证在 @CacheEvict 之前,忽略租户 | |
| 358 | - TenantUtils.executeIgnore(() -> getSelf().deleteThingModelListCache0(productKey)); | |
| 353 | + // 保证 Spring AOP 触发 | |
| 354 | + getSelf().deleteThingModelListCache0(productKey); | |
| 359 | 355 | } |
| 360 | 356 | |
| 361 | 357 | @CacheEvict(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey") | ... | ... |
yudao-server/src/main/resources/application.yaml