diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlSceneRuleAction.java index b71a92091b..dd10ed8134 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlSceneRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlSceneRuleAction.java @@ -1,6 +1,10 @@ package cn.iocoder.yudao.module.iot.service.rule.scene.action; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleActionTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; @@ -9,8 +13,11 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.util.List; +import java.util.Map; + /** - * IoT 设备控制的 {@link IotSceneRuleAction} 实现类 + * IoT 设备属性设置的 {@link IotSceneRuleAction} 实现类 * * @author 芋道源码 */ @@ -23,28 +30,108 @@ public class IotDeviceControlSceneRuleAction implements IotSceneRuleAction { @Resource private IotDeviceMessageService deviceMessageService; - // TODO @puhui999:这里 @Override public void execute(IotDeviceMessage message, IotSceneRuleDO rule, IotSceneRuleDO.Action actionConfig) { - //IotSceneRuleDO.ActionDeviceControl control = actionConfig.getDeviceControl(); - //Assert.notNull(control, "设备控制配置不能为空"); - //// 遍历每个设备,下发消息 - //control.getDeviceNames().forEach(deviceName -> { - // IotDeviceDO device = deviceService.getDeviceFromCache(control.getProductKey(), deviceName); - // if (device == null) { - // log.error("[execute][message({}) actionConfig({}) 对应的设备不存在]", message, actionConfig); - // return; - // } - // try { - // // TODO @芋艿:@puhui999:这块可能要改,从 type => method - // IotDeviceMessage downstreamMessage = deviceMessageService.sendDeviceMessage(IotDeviceMessage.requestOf( - // control.getType() + control.getIdentifier(), control.getData()).setDeviceId(device.getId())); - // log.info("[execute][message({}) actionConfig({}) 下发消息({})成功]", message, actionConfig, downstreamMessage); - // } catch (Exception e) { - // log.error("[execute][message({}) actionConfig({}) 下发消息失败]", message, actionConfig, e); - // } - //}); + // 1. 参数校验 + if (actionConfig.getDeviceId() == null) { + log.error("[execute][规则场景({}) 动作配置({}) 设备编号不能为空]", rule.getId(), actionConfig); + return; + } + if (StrUtil.isEmpty(actionConfig.getIdentifier())) { + log.error("[execute][规则场景({}) 动作配置({}) 属性标识符不能为空]", rule.getId(), actionConfig); + return; + } + + // 2. 判断是否为全部设备 + if (IotDeviceDO.DEVICE_ID_ALL.equals(actionConfig.getDeviceId())) { + executeForAllDevices(message, rule, actionConfig); + } else { + executeForSingleDevice(message, rule, actionConfig); + } + } + + /** + * 为单个设备执行属性设置 + */ + private void executeForSingleDevice(IotDeviceMessage message, + IotSceneRuleDO rule, IotSceneRuleDO.Action actionConfig) { + // 1. 获取设备信息 + IotDeviceDO device = deviceService.getDeviceFromCache(actionConfig.getDeviceId()); + if (device == null) { + log.error("[executeForSingleDevice][规则场景({}) 动作配置({}) 对应的设备({}) 不存在]", + rule.getId(), actionConfig, actionConfig.getDeviceId()); + return; + } + + // 2. 执行属性设置 + executePropertySetForDevice(rule, actionConfig, device); + } + + /** + * 为产品下的所有设备执行属性设置 + */ + private void executeForAllDevices(IotDeviceMessage message, + IotSceneRuleDO rule, IotSceneRuleDO.Action actionConfig) { + // 1. 参数校验 + if (actionConfig.getProductId() == null) { + log.error("[executeForAllDevices][规则场景({}) 动作配置({}) 产品编号不能为空]", rule.getId(), actionConfig); + return; + } + + // 2. 获取产品下的所有设备 + List devices = deviceService.getDeviceListByProductId(actionConfig.getProductId()); + if (CollUtil.isEmpty(devices)) { + log.warn("[executeForAllDevices][规则场景({}) 动作配置({}) 产品({}) 下没有设备]", + rule.getId(), actionConfig, actionConfig.getProductId()); + return; + } + + // 3. 遍历所有设备执行属性设置 + for (IotDeviceDO device : devices) { + executePropertySetForDevice(rule, actionConfig, device); + } + } + + /** + * 为指定设备执行属性设置 + */ + private void executePropertySetForDevice(IotSceneRuleDO rule, IotSceneRuleDO.Action actionConfig, IotDeviceDO device) { + // 1. 构建属性设置消息 + IotDeviceMessage downstreamMessage = buildPropertySetMessage(actionConfig, device); + if (downstreamMessage == null) { + log.error("[executePropertySetForDevice][规则场景({}) 动作配置({}) 设备({}) 构建属性设置消息失败]", + rule.getId(), actionConfig, device.getId()); + return; + } + + // 2. 发送设备消息 + try { + IotDeviceMessage result = deviceMessageService.sendDeviceMessage(downstreamMessage, device); + log.info("[executePropertySetForDevice][规则场景({}) 动作配置({}) 设备({}) 属性设置消息({}) 发送成功]", + rule.getId(), actionConfig, device.getId(), result.getId()); + } catch (Exception e) { + log.error("[executePropertySetForDevice][规则场景({}) 动作配置({}) 设备({}) 属性设置消息发送失败]", + rule.getId(), actionConfig, device.getId(), e); + } + } + + /** + * 构建属性设置消息 + * + * @param actionConfig 动作配置 + * @param device 设备信息 + * @return 设备消息 + */ + private IotDeviceMessage buildPropertySetMessage(IotSceneRuleDO.Action actionConfig, IotDeviceDO device) { + try { + // 属性设置参数格式: {"properties": {"identifier": value}} + Object params = Map.of("properties", Map.of(actionConfig.getIdentifier(), actionConfig.getParams())); + return IotDeviceMessage.requestOf(IotDeviceMessageMethodEnum.PROPERTY_SET.getMethod(), params); + } catch (Exception e) { + log.error("[buildPropertySetMessage][构建属性设置消息异常]", e); + return null; + } } @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceServiceInvokeSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceServiceInvokeSceneRuleAction.java new file mode 100644 index 0000000000..eb7bedf2f0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceServiceInvokeSceneRuleAction.java @@ -0,0 +1,145 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene.action; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleActionTypeEnum; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +/** + * IoT 设备服务调用的 {@link IotSceneRuleAction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class IotDeviceServiceInvokeSceneRuleAction implements IotSceneRuleAction { + + @Resource + private IotDeviceService deviceService; + @Resource + private IotDeviceMessageService deviceMessageService; + + @Override + public void execute(IotDeviceMessage message, + IotSceneRuleDO rule, IotSceneRuleDO.Action actionConfig) { + // 1. 参数校验 + if (actionConfig.getDeviceId() == null) { + log.error("[execute][规则场景({}) 动作配置({}) 设备编号不能为空]", rule.getId(), actionConfig); + return; + } + if (StrUtil.isEmpty(actionConfig.getIdentifier())) { + log.error("[execute][规则场景({}) 动作配置({}) 服务标识符不能为空]", rule.getId(), actionConfig); + return; + } + + // 2. 判断是否为全部设备 + if (IotDeviceDO.DEVICE_ID_ALL.equals(actionConfig.getDeviceId())) { + executeForAllDevices(message, rule, actionConfig); + } else { + executeForSingleDevice(message, rule, actionConfig); + } + } + + /** + * 为单个设备执行服务调用 + */ + private void executeForSingleDevice(IotDeviceMessage message, + IotSceneRuleDO rule, IotSceneRuleDO.Action actionConfig) { + // 1. 获取设备信息 + IotDeviceDO device = deviceService.getDeviceFromCache(actionConfig.getDeviceId()); + if (device == null) { + log.error("[executeForSingleDevice][规则场景({}) 动作配置({}) 对应的设备({}) 不存在]", + rule.getId(), actionConfig, actionConfig.getDeviceId()); + return; + } + + // 2. 执行服务调用 + executeServiceInvokeForDevice(rule, actionConfig, device); + } + + /** + * 为产品下的所有设备执行服务调用 + */ + private void executeForAllDevices(IotDeviceMessage message, + IotSceneRuleDO rule, IotSceneRuleDO.Action actionConfig) { + // 1. 参数校验 + if (actionConfig.getProductId() == null) { + log.error("[executeForAllDevices][规则场景({}) 动作配置({}) 产品编号不能为空]", rule.getId(), actionConfig); + return; + } + + // 2. 获取产品下的所有设备 + List devices = deviceService.getDeviceListByProductId(actionConfig.getProductId()); + if (CollUtil.isEmpty(devices)) { + log.warn("[executeForAllDevices][规则场景({}) 动作配置({}) 产品({}) 下没有设备]", + rule.getId(), actionConfig, actionConfig.getProductId()); + return; + } + + // 3. 遍历所有设备执行服务调用 + for (IotDeviceDO device : devices) { + executeServiceInvokeForDevice(rule, actionConfig, device); + } + } + + /** + * 为指定设备执行服务调用 + */ + private void executeServiceInvokeForDevice(IotSceneRuleDO rule, IotSceneRuleDO.Action actionConfig, IotDeviceDO device) { + // 1. 构建服务调用消息 + IotDeviceMessage downstreamMessage = buildServiceInvokeMessage(actionConfig, device); + if (downstreamMessage == null) { + log.error("[executeServiceInvokeForDevice][规则场景({}) 动作配置({}) 设备({}) 构建服务调用消息失败]", + rule.getId(), actionConfig, device.getId()); + return; + } + + // 2. 发送设备消息 + try { + IotDeviceMessage result = deviceMessageService.sendDeviceMessage(downstreamMessage, device); + log.info("[executeServiceInvokeForDevice][规则场景({}) 动作配置({}) 设备({}) 服务调用消息({}) 发送成功]", + rule.getId(), actionConfig, device.getId(), result.getId()); + } catch (Exception e) { + log.error("[executeServiceInvokeForDevice][规则场景({}) 动作配置({}) 设备({}) 服务调用消息发送失败]", + rule.getId(), actionConfig, device.getId(), e); + } + } + + /** + * 构建服务调用消息 + * + * @param actionConfig 动作配置 + * @param device 设备信息 + * @return 设备消息 + */ + private IotDeviceMessage buildServiceInvokeMessage(IotSceneRuleDO.Action actionConfig, IotDeviceDO device) { + try { + // 服务调用参数格式: {"identifier": "serviceId", "params": {...}} + Object params = Map.of( + "identifier", actionConfig.getIdentifier(), + "params", actionConfig.getParams() != null ? actionConfig.getParams() : Map.of() + ); + return IotDeviceMessage.requestOf(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod(), params); + } catch (Exception e) { + log.error("[buildServiceInvokeMessage][构建服务调用消息异常]", e); + return null; + } + } + + @Override + public IotSceneRuleActionTypeEnum getType() { + return IotSceneRuleActionTypeEnum.DEVICE_SERVICE_INVOKE; + } + +}