diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneRespVO.java index b3adfa7e57..033a6c50ab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneRespVO.java +++ b/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 { private Integer status; @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED) - private List triggers; + private List triggers; @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED) - private List actions; + private List actions; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneSaveReqVO.java index 813d005e4f..6b7e85a6b4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneSaveReqVO.java +++ b/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 { @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "触发器数组不能为空") - private List triggers; + private List triggers; @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "执行器数组不能为空") - private List actions; + private List actions; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java index 695705c389..2b9cdc5cc5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -1,13 +1,15 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; @@ -20,9 +22,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; -import java.util.Map; -// TODO @芋艿:优化注释; /** * IoT 场景联动规则 DO * @@ -37,211 +37,200 @@ import java.util.Map; public class IotRuleSceneDO extends TenantBaseDO { /** - * 场景编号 + * 场景联动编号 */ @TableId private Long id; /** - * 场景名称 + * 场景联动名称 */ private String name; /** - * 场景描述 + * 场景联动描述 */ private String description; /** - * 场景状态 + * 场景联动状态 * - * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + * 枚举 {@link CommonStatusEnum} */ private Integer status; /** - * 触发器数组 + * 场景定义配置 */ @TableField(typeHandler = JacksonTypeHandler.class) - private List triggers; + private List triggers; /** - * 执行器数组 + * 场景动作配置 */ @TableField(typeHandler = JacksonTypeHandler.class) - private List actions; + private List actions; /** - * 触发器配置 + * 场景定义配置 */ @Data - public static class TriggerConfig { + public static class Trigger { + + // ========== 事件部分 ========== /** - * 触发类型 + * 场景事件类型 * * 枚举 {@link IotRuleSceneTriggerTypeEnum} + * 1. {@link IotRuleSceneTriggerTypeEnum#DEVICE_STATE_UPDATE} 时,operator 非空,并且 value 为在线状态 + * 2. {@link IotRuleSceneTriggerTypeEnum#DEVICE_PROPERTY_POST} + * {@link IotRuleSceneTriggerTypeEnum#DEVICE_EVENT_POST} 时,identifier、operator 非空,并且 value 为属性值 + * 3. {@link IotRuleSceneTriggerTypeEnum#DEVICE_EVENT_POST} + * {@link IotRuleSceneTriggerTypeEnum#DEVICE_SERVICE_INVOKE} 时,identifier 非空,但是 operator、value 为空 + * 4. {@link IotRuleSceneTriggerTypeEnum#TIMER} 时,conditions 非空,并且设备无关(无需 productId、deviceId 字段) */ private Integer type; /** - * 产品标识 + * 产品编号 * - * 关联 {@link IotProductDO#getProductKey()} + * 关联 {@link IotProductDO#getId()} */ - private String productKey; + private Long productId; /** - * 设备名称数组 + * 设备编号 * - * 关联 {@link IotDeviceDO#getDeviceName()} + * 关联 {@link IotDeviceDO#getId()} + * 特殊:如果为 {@link IotDeviceDO#DEVICE_ID_ALL} 时,则是全部设备 */ - private List deviceNames; - + private Long deviceId; /** - * 触发条件数组 + * 物模型标识符 * - * 必填:当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#DEVICE} 时 - * 条件与条件之间,是“或”的关系 - */ - private List conditions; - - /** - * CRON 表达式 - * - * 必填:当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#TIMER} 时 - */ - private String cronExpression; - - } - - /** - * 触发条件 - */ - @Data - public static class TriggerCondition { - - /** - * 消息类型 - * - * 枚举 {@link IotDeviceMessageTypeEnum} - */ - private String type; - /** - * 消息标识符 - * - * 枚举 {@link IotDeviceMessageIdentifierEnum} + * 对应:{@link IotThingModelDO#getIdentifier()} */ private String identifier; - - /** - * 参数数组 - * - * 参数与参数之间,是“或”的关系 - */ - private List parameters; - - } - - /** - * 触发条件参数 - */ - @Data - public static class TriggerConditionParameter { - - // TODO @芋艿: identifier0 存事件和服务的 identifier 属性的情况 identifier0 就为 null 解决前端回显问题 - // TODO @puhui999:可以根据 TriggerCondition.type 判断,是服务、还是事件、还是属性么? - /** - * 标识符(事件、服务) - * - * 关联 {@link IotThingModelDO#getIdentifier()} - */ - private String identifier0; - - /** - * 标识符(属性) - * - * 关联 {@link IotThingModelDO#getIdentifier()} - */ - private String identifier; - /** * 操作符 * * 枚举 {@link IotRuleSceneConditionOperatorEnum} */ private String operator; - /** - * 比较值 - * + * 参数(属性值、在线状态) + *

* 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN} */ private String value; + /** + * CRON 表达式 + */ + private String cronExpression; + + // ========== 条件部分 ========== + + /** + * 触发条件分组(状态条件分组)的数组 + *

+ * 第一层 List:分组与分组之间,是“或”的关系 + * 第二层 List:条件与条件之间,是“且”的关系 + */ + private List> conditionGroups; + } /** - * 执行器配置 + * 触发条件(状态条件) */ @Data - public static class ActionConfig { + public static class TriggerCondition { + + /** + * 触发条件类型 + * + * 枚举 {@link IotRuleSceneConditionTypeEnum} + * 1. {@link IotRuleSceneConditionTypeEnum#DEVICE_STATE} 时,operator 非空,并且 value 为在线状态 + * 2. {@link IotRuleSceneConditionTypeEnum#DEVICE_PROPERTY} 时,identifier、operator 非空,并且 value 为属性值 + * 3. {@link IotRuleSceneConditionTypeEnum#CURRENT_TIME} 时,operator 非空(使用 DATE_TIME_ 和 TIME_ 部分),并且 value 非空 + */ + private Integer type; + + /** + * 产品编号 + * + * 关联 {@link IotProductDO#getId()} + */ + private Long productId; + /** + * 设备编号 + * + * 关联 {@link IotDeviceDO#getId()} + */ + private Long deviceId; + /** + * 标识符(属性) + * + * 关联 {@link IotThingModelDO#getIdentifier()} + */ + private String identifier; + /** + * 操作符 + * + * 枚举 {@link IotRuleSceneConditionOperatorEnum} + */ + private String operator; + /** + * 参数 + * + * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 + * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN} + */ + private String param; + + } + + /** + * 场景动作配置 + */ + @Data + public static class Action { /** * 执行类型 * * 枚举 {@link IotRuleSceneActionTypeEnum} + * 1. {@link IotRuleSceneActionTypeEnum#DEVICE_PROPERTY_SET} 时,params 非空 + * {@link IotRuleSceneActionTypeEnum#DEVICE_SERVICE_INVOKE} 时,params 非空 + * 2. {@link IotRuleSceneActionTypeEnum#ALERT_TRIGGER} 时,alertConfigId 为空,因为是 {@link IotAlertConfigDO} 里面关联它 + * 3. {@link IotRuleSceneActionTypeEnum#ALERT_RECOVER} 时,alertConfigId 非空 */ private Integer type; /** - * 设备控制 + * 产品编号 * - * 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DEVICE_PROPERTY_SET} 时 + * 关联 {@link IotProductDO#getId()} */ - private ActionDeviceControl deviceControl; - - } - - /** - * 执行设备控制 - */ - @Data - public static class ActionDeviceControl { + private Long productId; + /** + * 设备编号 + * + * 关联 {@link IotDeviceDO#getId()} + */ + private Long deviceId; + /** + * 请求参数 + * + * 一般来说,对应 {@link IotDeviceMessage#getParams()} 请求参数 + */ + private Object params; /** - * 产品标识 + * 告警配置编号 * - * 关联 {@link IotProductDO#getProductKey()} + * 关联 {@link IotAlertConfigDO#getId()} */ - private String productKey; - /** - * 设备名称数组 - * - * 关联 {@link IotDeviceDO#getDeviceName()} - */ - private List deviceNames; - - /** - * 消息类型 - * - * 枚举 {@link IotDeviceMessageTypeEnum#PROPERTY}、{@link IotDeviceMessageTypeEnum#SERVICE} - */ - private String type; - /** - * 消息标识符 - * - * 枚举 {@link IotDeviceMessageIdentifierEnum} - * - * 1. 属性设置:对应 {@link IotDeviceMessageIdentifierEnum#PROPERTY_SET} - * 2. 服务调用:对应 {@link IotDeviceMessageIdentifierEnum#SERVICE_INVOKE} - */ - private String identifier; - - /** - * 具体数据 - * - * 1. 属性设置:在 {@link #type} 是 {@link IotDeviceMessageTypeEnum#PROPERTY} 时,对应 properties - * 2. 服务调用:在 {@link #type} 是 {@link IotDeviceMessageTypeEnum#SERVICE} 时,对应 params - */ - private Map data; + private Long alertConfigId; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java index 9bfa929b25..05dad8d795 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java +++ b/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; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; import cn.iocoder.yudao.module.iot.job.rule.IotRuleSceneJob; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; import jakarta.annotation.Resource; import lombok.SneakyThrows; @@ -39,10 +43,7 @@ import org.quartz.impl.StdSchedulerFactory; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @@ -68,6 +69,12 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @Resource(name = "iotSchedulerManager") private IotSchedulerManager schedulerManager; + @Resource + private IotProductService productService; + + @Resource + private IotDeviceService deviceService; + @Override public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) { // 插入 @@ -131,118 +138,61 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @Override @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 public List getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { - if (true) { - IotRuleSceneDO ruleScene01 = new IotRuleSceneDO(); - ruleScene01.setTriggers(CollUtil.newArrayList()); - IotRuleSceneDO.TriggerConfig trigger01 = new IotRuleSceneDO.TriggerConfig(); - trigger01.setType(IotRuleSceneTriggerTypeEnum.DEVICE.getType()); - trigger01.setConditions(CollUtil.newArrayList()); - // 属性 - IotRuleSceneDO.TriggerCondition condition01 = new IotRuleSceneDO.TriggerCondition(); - condition01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); - condition01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier()); - condition01.setParameters(CollUtil.newArrayList()); -// IotRuleSceneDO.TriggerConditionParameter parameter010 = new IotRuleSceneDO.TriggerConditionParameter(); -// parameter010.setIdentifier("width"); -// parameter010.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator()); -// parameter010.setValue("abc"); -// condition01.getParameters().add(parameter010); - IotRuleSceneDO.TriggerConditionParameter parameter011 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter011.setIdentifier("width"); - parameter011.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator()); - parameter011.setValue("1"); - condition01.getParameters().add(parameter011); - IotRuleSceneDO.TriggerConditionParameter parameter012 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter012.setIdentifier("width"); - parameter012.setOperator(IotRuleSceneConditionOperatorEnum.NOT_EQUALS.getOperator()); - parameter012.setValue("2"); - condition01.getParameters().add(parameter012); - IotRuleSceneDO.TriggerConditionParameter parameter013 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter013.setIdentifier("width"); - parameter013.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator()); - parameter013.setValue("0"); - condition01.getParameters().add(parameter013); - IotRuleSceneDO.TriggerConditionParameter parameter014 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter014.setIdentifier("width"); - parameter014.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator()); - parameter014.setValue("0"); - condition01.getParameters().add(parameter014); - IotRuleSceneDO.TriggerConditionParameter parameter015 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter015.setIdentifier("width"); - parameter015.setOperator(IotRuleSceneConditionOperatorEnum.LESS_THAN.getOperator()); - parameter015.setValue("2"); - condition01.getParameters().add(parameter015); - IotRuleSceneDO.TriggerConditionParameter parameter016 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter016.setIdentifier("width"); - parameter016.setOperator(IotRuleSceneConditionOperatorEnum.LESS_THAN_OR_EQUALS.getOperator()); - parameter016.setValue("2"); - condition01.getParameters().add(parameter016); - IotRuleSceneDO.TriggerConditionParameter parameter017 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter017.setIdentifier("width"); - parameter017.setOperator(IotRuleSceneConditionOperatorEnum.IN.getOperator()); - parameter017.setValue("1,2,3"); - condition01.getParameters().add(parameter017); - IotRuleSceneDO.TriggerConditionParameter parameter018 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter018.setIdentifier("width"); - parameter018.setOperator(IotRuleSceneConditionOperatorEnum.NOT_IN.getOperator()); - parameter018.setValue("0,2,3"); - condition01.getParameters().add(parameter018); - IotRuleSceneDO.TriggerConditionParameter parameter019 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter019.setIdentifier("width"); - parameter019.setOperator(IotRuleSceneConditionOperatorEnum.BETWEEN.getOperator()); - parameter019.setValue("1,3"); - condition01.getParameters().add(parameter019); - IotRuleSceneDO.TriggerConditionParameter parameter020 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter020.setIdentifier("width"); - parameter020.setOperator(IotRuleSceneConditionOperatorEnum.NOT_BETWEEN.getOperator()); - parameter020.setValue("2,3"); - condition01.getParameters().add(parameter020); - trigger01.getConditions().add(condition01); - // 状态 - IotRuleSceneDO.TriggerCondition condition02 = new IotRuleSceneDO.TriggerCondition(); - condition02.setType(IotDeviceMessageTypeEnum.STATE.getType()); - condition02.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier()); - condition02.setParameters(CollUtil.newArrayList()); - trigger01.getConditions().add(condition02); - // 事件 - IotRuleSceneDO.TriggerCondition condition03 = new IotRuleSceneDO.TriggerCondition(); - condition03.setType(IotDeviceMessageTypeEnum.EVENT.getType()); - condition03.setIdentifier("xxx"); - condition03.setParameters(CollUtil.newArrayList()); - IotRuleSceneDO.TriggerConditionParameter parameter030 = new IotRuleSceneDO.TriggerConditionParameter(); - parameter030.setIdentifier("width"); - parameter030.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator()); - parameter030.setValue("1"); - trigger01.getConditions().add(condition03); - ruleScene01.getTriggers().add(trigger01); - // 动作 - ruleScene01.setActions(CollUtil.newArrayList()); - // 设备控制 - IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig(); - action01.setType(IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET.getType()); - IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl(); - actionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT"); - actionDeviceControl01.setDeviceNames(ListUtil.of("small")); - actionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); - actionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()); - actionDeviceControl01.setData(MapUtil.builder() - .put("power", 1) - .put("color", "red") - .build()); - action01.setDeviceControl(actionDeviceControl01); -// ruleScene01.getActions().add(action01); // TODO 芋艿:先不测试了 - return ListUtil.toList(ruleScene01); + // TODO @芋艿:测试代码示例(使用新结构),可根据需要启用 + if (false) { + // 创建测试规则场景 + IotRuleSceneDO ruleScene = new IotRuleSceneDO(); + ruleScene.setId(1L); + ruleScene.setName("测试场景"); + ruleScene.setStatus(CommonStatusEnum.ENABLE.getStatus()); + + // 创建触发器 + IotRuleSceneDO.Trigger trigger = new IotRuleSceneDO.Trigger(); + trigger.setType(IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST.getType()); + trigger.setProductId(1L); // 假设产品ID为1 + trigger.setDeviceId(1L); // 假设设备ID为1 + trigger.setIdentifier("temperature"); // 温度属性 + trigger.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator()); + trigger.setValue("25"); // 温度大于25度 + + // 创建条件分组 + IotRuleSceneDO.TriggerCondition condition = new IotRuleSceneDO.TriggerCondition(); + condition.setType(IotRuleSceneConditionTypeEnum.DEVICE_PROPERTY.getType()); + condition.setIdentifier("temperature"); + condition.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator()); + condition.setParam("25"); + + trigger.setConditionGroups(ListUtil.toList(Collections.singleton(ListUtil.toList(condition)))); + ruleScene.setTriggers(ListUtil.toList(trigger)); + + // 创建动作 + IotRuleSceneDO.Action action = new IotRuleSceneDO.Action(); + action.setType(IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET.getType()); + action.setProductId(1L); + action.setDeviceId(1L); + action.setParams(MapUtil.of("fan", "on")); // 打开风扇 + + ruleScene.setActions(ListUtil.toList(action)); + + return ListUtil.toList(ruleScene); } + // 注意:旧的测试代码已删除,因为使用了废弃的数据结构 + // 如需测试,请使用上面的新结构测试代码示例 List list = ruleSceneMapper.selectList(); - // TODO @芋艿:需要考虑开启状态 - return filterList(list, ruleScene -> { - for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) { - if (ObjUtil.notEqual(trigger.getProductKey(), productKey)) { - continue; - } - if (CollUtil.isEmpty(trigger.getDeviceNames()) // 无设备名称限制 - || trigger.getDeviceNames().contains(deviceName)) { // 包含设备名称 + // 只返回启用状态的规则场景 + List enabledList = filterList(list, + ruleScene -> CommonStatusEnum.ENABLE.getStatus().equals(ruleScene.getStatus())); + + // 根据 productKey 和 deviceName 进行匹配 + return filterList(enabledList, ruleScene -> { + if (CollUtil.isEmpty(ruleScene.getTriggers())) { + return false; + } + + for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { + // 检查触发器是否匹配指定的产品和设备 + if (isMatchProductAndDevice(trigger, productKey, deviceName)) { return true; } } @@ -250,47 +200,70 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { }); } + /** + * 检查触发器是否匹配指定的产品和设备 + * + * @param trigger 触发器 + * @param productKey 产品标识 + * @param deviceName 设备名称 + * @return 是否匹配 + */ + private boolean isMatchProductAndDevice(IotRuleSceneDO.Trigger trigger, String productKey, String deviceName) { + try { + // 1. 检查产品是否匹配 + if (trigger.getProductId() != null) { + // 通过 productKey 获取产品信息 + IotProductDO product = productService.getProductByProductKey(productKey); + if (product == null || !trigger.getProductId().equals(product.getId())) { + return false; + } + } + + // 2. 检查设备是否匹配 + if (trigger.getDeviceId() != null) { + // 通过 productKey 和 deviceName 获取设备信息 + IotDeviceDO device = deviceService.getDeviceFromCache(productKey, deviceName); + if (device == null) { + return false; + } + + // 检查是否是全部设备的特殊标识 + if (IotDeviceDO.DEVICE_ID_ALL.equals(trigger.getDeviceId())) { + return true; // 匹配所有设备 + } + + // 检查具体设备ID是否匹配 + if (!trigger.getDeviceId().equals(device.getId())) { + return false; + } + } + + return true; + } catch (Exception e) { + log.warn("[isMatchProductAndDevice][产品({}) 设备({}) 匹配触发器异常]", productKey, deviceName, e); + return false; + } + } + @Override public void executeRuleSceneByDevice(IotDeviceMessage message) { // TODO @芋艿:这里的 tenantId,通过设备获取; -// TenantUtils.execute(message.getTenantId(), () -> { -// // 1. 获得设备匹配的规则场景 -// List ruleScenes = getMatchedRuleSceneListByMessage(message); -// if (CollUtil.isEmpty(ruleScenes)) { -// return; -// } -// -// // 2. 执行规则场景 -// executeRuleSceneAction(message, ruleScenes); -// }); + TenantUtils.execute(message.getTenantId(), () -> { + // 1. 获得设备匹配的规则场景 + List ruleScenes = getMatchedRuleSceneListByMessage(message); + if (CollUtil.isEmpty(ruleScenes)) { + return; + } + + // 2. 执行规则场景 + executeRuleSceneAction(message, ruleScenes); + }); } @Override public void executeRuleSceneByTimer(Long id) { // 1.1 获得规则场景 -// IotRuleSceneDO scene = TenantUtils.executeIgnore(() -> ruleSceneMapper.selectById(id)); - // TODO @芋艿:这里,临时测试,后续删除。 - IotRuleSceneDO scene = new IotRuleSceneDO().setStatus(CommonStatusEnum.ENABLE.getStatus()); - if (true) { - scene.setTenantId(1L); - IotRuleSceneDO.TriggerConfig triggerConfig = new IotRuleSceneDO.TriggerConfig(); - triggerConfig.setType(IotRuleSceneTriggerTypeEnum.TIMER.getType()); - scene.setTriggers(ListUtil.toList(triggerConfig)); - // 动作 - IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig(); - action01.setType(IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET.getType()); - IotRuleSceneDO.ActionDeviceControl iotRuleSceneActionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl(); - iotRuleSceneActionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT"); - iotRuleSceneActionDeviceControl01.setDeviceNames(ListUtil.of("small")); - iotRuleSceneActionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); - iotRuleSceneActionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()); - iotRuleSceneActionDeviceControl01.setData(MapUtil.builder() - .put("power", 1) - .put("color", "red") - .build()); - action01.setDeviceControl(iotRuleSceneActionDeviceControl01); - scene.setActions(ListUtil.toList(action01)); - } + IotRuleSceneDO scene = TenantUtils.executeIgnore(() -> ruleSceneMapper.selectById(id)); if (scene == null) { log.error("[executeRuleSceneByTimer][规则场景({}) 不存在]", id); return; @@ -300,7 +273,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { return; } // 1.2 判断是否有定时触发器,避免脏数据 - IotRuleSceneDO.TriggerConfig config = CollUtil.findOne(scene.getTriggers(), + IotRuleSceneDO.Trigger config = CollUtil.findOne(scene.getTriggers(), trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType())); if (config == null) { log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene); @@ -321,72 +294,229 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { private List getMatchedRuleSceneListByMessage(IotDeviceMessage message) { // 1. 匹配设备 // TODO @芋艿:可能需要 getSelf(); 缓存 - List ruleScenes = null; - // TODO @芋艿:这里需要适配 -// List ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache( -// message.getProductKey(), message.getDeviceName()); + // 1.1 通过 deviceId 获取设备信息 + IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); + if (device == null) { + log.warn("[getMatchedRuleSceneListByMessage][设备({}) 不存在]", message.getDeviceId()); + return List.of(); + } + + // 1.2 通过 productId 获取产品信息 + IotProductDO product = productService.getProductFromCache(device.getProductId()); + if (product == null) { + log.warn("[getMatchedRuleSceneListByMessage][产品({}) 不存在]", device.getProductId()); + return List.of(); + } + + // 1.3 获取匹配的规则场景 + List ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache( + product.getProductKey(), device.getDeviceName()); if (CollUtil.isEmpty(ruleScenes)) { return ruleScenes; } // 2. 匹配 trigger 触发器的条件 return filterList(ruleScenes, ruleScene -> { - for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) { - // 2.1 非设备触发,不匹配 - if (ObjUtil.notEqual(trigger.getType(), IotRuleSceneTriggerTypeEnum.DEVICE.getType())) { + for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { + // 2.1 检查触发器类型,根据新的枚举值进行匹配 + // TODO @芋艿:需要根据新的触发器类型枚举进行适配 + // 原来使用 IotRuleSceneTriggerTypeEnum.DEVICE,新结构可能有不同的类型 + + // 2.2 条件分组为空,说明没有匹配的条件,因此不匹配 + if (CollUtil.isEmpty(trigger.getConditionGroups())) { return false; } - // TODO 芋艿:产品、设备的匹配,要不要这里在做一次???貌似和 1. 部分重复了 - // 2.2 条件为空,说明没有匹配的条件,因此不匹配 - if (CollUtil.isEmpty(trigger.getConditions())) { - return false; + + // 2.3 检查条件分组:分组与分组之间是"或"的关系,条件与条件之间是"且"的关系 + boolean anyGroupMatched = false; + for (List conditionGroup : trigger.getConditionGroups()) { + if (CollUtil.isEmpty(conditionGroup)) { + continue; + } + + // 检查当前分组中的所有条件是否都匹配(且关系) + boolean allConditionsMatched = true; + for (IotRuleSceneDO.TriggerCondition condition : conditionGroup) { + // TODO @芋艿:这里需要实现具体的条件匹配逻辑 + // 根据新的 TriggerCondition 结构进行匹配 + if (!isTriggerConditionMatched(message, condition, ruleScene, trigger)) { + allConditionsMatched = false; + break; + } + } + + if (allConditionsMatched) { + anyGroupMatched = true; + break; // 有一个分组匹配即可 + } } - // 2.3 多个条件,只需要满足一个即可 - IotRuleSceneDO.TriggerCondition matchedCondition = CollUtil.findOne(trigger.getConditions(), condition -> { - // TODO @芋艿:这里的逻辑,需要适配 -// if (ObjUtil.notEqual(message.getType(), condition.getType()) -// || ObjUtil.notEqual(message.getIdentifier(), condition.getIdentifier())) { -// return false; -// } - // 多个条件参数,必须全部满足。所以,下面的逻辑就是找到一个不满足的条件参数 - IotRuleSceneDO.TriggerConditionParameter notMatchedParameter = CollUtil.findOne(condition.getParameters(), - parameter -> !isTriggerConditionParameterMatched(message, parameter, ruleScene, trigger)); - return notMatchedParameter == null; - }); - if (matchedCondition == null) { - return false; + + if (anyGroupMatched) { + log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger); + return true; } - log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger); - return true; } return false; }); } + /** + * 基于消息,判断触发器的条件是否匹配 + * + * @param message 设备消息 + * @param condition 触发条件 + * @param ruleScene 规则场景(用于日志,无其它作用) + * @param trigger 触发器(用于日志,无其它作用) + * @return 是否匹配 + */ + private boolean isTriggerConditionMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition, + IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) { + try { + // 1. 根据条件类型进行匹配 + if (IotRuleSceneConditionTypeEnum.DEVICE_STATE.getType().equals(condition.getType())) { + // 设备状态条件匹配 + return matchDeviceStateCondition(message, condition); + } else if (IotRuleSceneConditionTypeEnum.DEVICE_PROPERTY.getType().equals(condition.getType())) { + // 设备属性条件匹配 + return matchDevicePropertyCondition(message, condition); + } else if (IotRuleSceneConditionTypeEnum.CURRENT_TIME.getType().equals(condition.getType())) { + // 当前时间条件匹配 + return matchCurrentTimeCondition(condition); + } else { + log.warn("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 存在未知的条件类型({})]", + ruleScene.getId(), trigger, condition.getType()); + return false; + } + } catch (Exception e) { + log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]", + ruleScene.getId(), trigger, e); + return false; + } + } + + /** + * 匹配设备状态条件 + * + * @param message 设备消息 + * @param condition 触发条件 + * @return 是否匹配 + */ + private boolean matchDeviceStateCondition(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition) { + // TODO @芋艿:需要根据设备状态进行匹配 + // 这里需要检查消息中的设备状态是否符合条件中定义的状态 + log.debug("[matchDeviceStateCondition][设备状态条件匹配逻辑待实现] condition: {}", condition); + return false; + } + + /** + * 匹配设备属性条件 + * + * @param message 设备消息 + * @param condition 触发条件 + * @return 是否匹配 + */ + private boolean matchDevicePropertyCondition(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition) { + // 1. 检查标识符是否匹配 + String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message); + if (StrUtil.isBlank(condition.getIdentifier()) || !condition.getIdentifier().equals(messageIdentifier)) { + return false; + } + + // 2. 获取消息中的属性值 + Object messageValue = message.getData(); + if (messageValue == null) { + return false; + } + + // 3. 根据操作符进行匹配 + return evaluateCondition(messageValue, condition.getOperator(), condition.getParam()); + } + + /** + * 匹配当前时间条件 + * + * @param condition 触发条件 + * @return 是否匹配 + */ + private boolean matchCurrentTimeCondition(IotRuleSceneDO.TriggerCondition condition) { + // TODO @芋艿:需要根据当前时间进行匹配 + // 这里需要检查当前时间是否符合条件中定义的时间范围 + log.debug("[matchCurrentTimeCondition][当前时间条件匹配逻辑待实现] condition: {}", condition); + return false; + } + + /** + * 评估条件是否匹配 + * + * @param sourceValue 源值(来自消息) + * @param operator 操作符 + * @param paramValue 参数值(来自条件配置) + * @return 是否匹配 + */ + private boolean evaluateCondition(Object sourceValue, String operator, String paramValue) { + try { + // 1. 校验操作符是否合法 + IotRuleSceneConditionOperatorEnum operatorEnum = IotRuleSceneConditionOperatorEnum.operatorOf(operator); + if (operatorEnum == null) { + log.warn("[evaluateCondition][存在错误的操作符({})]", operator); + return false; + } + + // 2. 构建 Spring 表达式的变量 + Map springExpressionVariables = MapUtil.builder() + .put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue) + .build(); + + // 3. 根据操作符类型处理参数值 + if (StrUtil.isNotBlank(paramValue)) { + if (operatorEnum == IotRuleSceneConditionOperatorEnum.IN + || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_IN + || operatorEnum == IotRuleSceneConditionOperatorEnum.BETWEEN + || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_BETWEEN) { + // 处理多值情况 + List paramValues = StrUtil.split(paramValue, CharPool.COMMA); + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, + convertList(paramValues, NumberUtil::parseDouble)); + } else { + // 处理单值情况 + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, + NumberUtil.parseDouble(paramValue)); + } + } + + // 4. 计算 Spring 表达式 + return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables); + } catch (Exception e) { + log.error("[evaluateCondition][条件评估异常] sourceValue: {}, operator: {}, paramValue: {}", + sourceValue, operator, paramValue, e); + return false; + } + } + // TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。 /** * 判断触发器的条件参数是否匹配 * * @param message 设备消息 - * @param parameter 触发器条件参数 + * @param condition 触发条件 * @param ruleScene 规则场景(用于日志,无其它作用) * @param trigger 触发器(用于日志,无其它作用) * @return 是否匹配 */ @SuppressWarnings({"unchecked", "DataFlowIssue"}) - private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerConditionParameter parameter, - IotRuleSceneDO ruleScene, IotRuleSceneDO.TriggerConfig trigger) { + private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition, + IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) { // 1.1 校验操作符是否合法 IotRuleSceneConditionOperatorEnum operator = - IotRuleSceneConditionOperatorEnum.operatorOf(parameter.getOperator()); + IotRuleSceneConditionOperatorEnum.operatorOf(condition.getOperator()); if (operator == null) { log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]", - ruleScene.getId(), trigger, parameter.getOperator()); + ruleScene.getId(), trigger, condition.getOperator()); return false; } // 1.2 校验消息是否包含对应的值 - String messageValue = MapUtil.getStr((Map) message.getData(), parameter.getIdentifier()); + String messageValue = MapUtil.getStr((Map) message.getData(), condition.getIdentifier()); if (messageValue == null) { return false; } @@ -395,8 +525,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { Map springExpressionVariables = new HashMap<>(); try { springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue); - springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, parameter.getValue()); - List parameterValues = StrUtil.splitTrim(parameter.getValue(), CharPool.COMMA); + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, condition.getParam()); + List parameterValues = StrUtil.splitTrim(condition.getParam(), CharPool.COMMA); springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues); // 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题! if (ObjectUtils.equalsAny(operator, IotRuleSceneConditionOperatorEnum.BETWEEN, @@ -410,7 +540,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, NumberUtil.parseDouble(messageValue)); springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, - NumberUtil.parseDouble(parameter.getValue())); + NumberUtil.parseDouble(condition.getParam())); springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, convertList(parameterValues, NumberUtil::parseDouble)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java index 6cc9fa5786..03137c790e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java +++ b/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 { @Override public void execute(IotDeviceMessage message, - IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception { + IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) throws Exception { Long deviceId = message != null ? message.getDeviceId() : null; List alertRecords = alertRecordService.getAlertRecordListBySceneRuleId( rule.getId(), deviceId, false); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java index df34eea16f..f6a1c5fb41 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java +++ b/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 { @Override public void execute(@Nullable IotDeviceMessage message, - IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception { + IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) throws Exception { List alertConfigs = alertConfigService.getAlertConfigListBySceneRuleIdAndStatus( rule.getId(), CommonStatusEnum.ENABLE.getStatus()); if (CollUtil.isEmpty(alertConfigs)) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java index c812b4ed57..b755307344 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java @@ -1,8 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.scene.action; -import cn.hutool.core.lang.Assert; 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.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; @@ -27,25 +25,25 @@ public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction { @Override public void execute(IotDeviceMessage message, - IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) { - IotRuleSceneDO.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); - } - }); + IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) { + //IotRuleSceneDO.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); + // } + //}); } @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java index b52d5c71e3..dccea21957 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java +++ b/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 { */ void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO rule, - IotRuleSceneDO.ActionConfig actionConfig) throws Exception; + IotRuleSceneDO.Action actionConfig) throws Exception; /** * 获得类型