!1396 perf:【IoT 物联网】场景联动代码优化
Merge pull request !1396 from puhui999/feature/iot
This commit is contained in:
@@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|||||||
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO;
|
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO;
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneRespVO;
|
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneRespVO;
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
|
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneUpdateStatusReqVO;
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
|
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
|
||||||
import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService;
|
import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -48,6 +49,14 @@ public class IotRuleSceneController {
|
|||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update-status")
|
||||||
|
@Operation(summary = "更新场景联动状态")
|
||||||
|
@PreAuthorize("@ss.hasPermission('iot:rule-scene:update')")
|
||||||
|
public CommonResult<Boolean> updateRuleSceneStatus(@Valid @RequestBody IotRuleSceneUpdateStatusReqVO updateReqVO) {
|
||||||
|
ruleSceneService.updateRuleSceneStatus(updateReqVO.getId(), updateReqVO.getStatus());
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping("/delete")
|
@DeleteMapping("/delete")
|
||||||
@Operation(summary = "删除场景联动")
|
@Operation(summary = "删除场景联动")
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ public class IotRuleSceneRespVO {
|
|||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
@Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private List<IotRuleSceneDO.TriggerConfig> triggers;
|
private List<IotRuleSceneDO.Trigger> triggers;
|
||||||
|
|
||||||
@Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private List<IotRuleSceneDO.ActionConfig> actions;
|
private List<IotRuleSceneDO.Action> actions;
|
||||||
|
|
||||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ public class IotRuleSceneSaveReqVO {
|
|||||||
|
|
||||||
@Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@NotEmpty(message = "触发器数组不能为空")
|
@NotEmpty(message = "触发器数组不能为空")
|
||||||
private List<IotRuleSceneDO.TriggerConfig> triggers;
|
private List<IotRuleSceneDO.Trigger> triggers;
|
||||||
|
|
||||||
@Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@NotEmpty(message = "执行器数组不能为空")
|
@NotEmpty(message = "执行器数组不能为空")
|
||||||
private List<IotRuleSceneDO.ActionConfig> actions;
|
private List<IotRuleSceneDO.Action> actions;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
|
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - IoT 场景联动更新状态 Request VO")
|
||||||
|
@Data
|
||||||
|
public class IotRuleSceneUpdateStatusReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "场景联动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
@NotNull(message = "场景联动编号不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||||
|
@NotNull(message = "状态不能为空")
|
||||||
|
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
package cn.iocoder.yudao.module.iot.dal.dataobject.rule;
|
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.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.device.IotDeviceDO;
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
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.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.IotRuleSceneActionTypeEnum;
|
||||||
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum;
|
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.enums.rule.IotRuleSceneTriggerTypeEnum;
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
@@ -20,9 +22,7 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
// TODO @芋艿:优化注释;
|
|
||||||
/**
|
/**
|
||||||
* IoT 场景联动规则 DO
|
* IoT 场景联动规则 DO
|
||||||
*
|
*
|
||||||
@@ -37,211 +37,200 @@ import java.util.Map;
|
|||||||
public class IotRuleSceneDO extends TenantBaseDO {
|
public class IotRuleSceneDO extends TenantBaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 场景编号
|
* 场景联动编号
|
||||||
*/
|
*/
|
||||||
@TableId
|
@TableId
|
||||||
private Long id;
|
private Long id;
|
||||||
/**
|
/**
|
||||||
* 场景名称
|
* 场景联动名称
|
||||||
*/
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
/**
|
/**
|
||||||
* 场景描述
|
* 场景联动描述
|
||||||
*/
|
*/
|
||||||
private String description;
|
private String description;
|
||||||
/**
|
/**
|
||||||
* 场景状态
|
* 场景联动状态
|
||||||
*
|
*
|
||||||
* 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
|
* 枚举 {@link CommonStatusEnum}
|
||||||
*/
|
*/
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 触发器数组
|
* 场景定义配置
|
||||||
*/
|
*/
|
||||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
private List<TriggerConfig> triggers;
|
private List<Trigger> triggers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行器数组
|
* 场景动作配置
|
||||||
*/
|
*/
|
||||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
private List<ActionConfig> actions;
|
private List<Action> actions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 触发器配置
|
* 场景定义配置
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public static class TriggerConfig {
|
public static class Trigger {
|
||||||
|
|
||||||
|
// ========== 事件部分 ==========
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 触发类型
|
* 场景事件类型
|
||||||
*
|
*
|
||||||
* 枚举 {@link IotRuleSceneTriggerTypeEnum}
|
* 枚举 {@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;
|
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<String> deviceNames;
|
private Long deviceId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 触发条件数组
|
* 物模型标识符
|
||||||
*
|
*
|
||||||
* 必填:当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#DEVICE} 时
|
* 对应:{@link IotThingModelDO#getIdentifier()}
|
||||||
* 条件与条件之间,是“或”的关系
|
|
||||||
*/
|
|
||||||
private List<TriggerCondition> conditions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CRON 表达式
|
|
||||||
*
|
|
||||||
* 必填:当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#TIMER} 时
|
|
||||||
*/
|
|
||||||
private String cronExpression;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 触发条件
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class TriggerCondition {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息类型
|
|
||||||
*
|
|
||||||
* 枚举 {@link IotDeviceMessageTypeEnum}
|
|
||||||
*/
|
|
||||||
private String type;
|
|
||||||
/**
|
|
||||||
* 消息标识符
|
|
||||||
*
|
|
||||||
* 枚举 {@link IotDeviceMessageIdentifierEnum}
|
|
||||||
*/
|
*/
|
||||||
private String identifier;
|
private String identifier;
|
||||||
|
|
||||||
/**
|
|
||||||
* 参数数组
|
|
||||||
*
|
|
||||||
* 参数与参数之间,是“或”的关系
|
|
||||||
*/
|
|
||||||
private List<TriggerConditionParameter> 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}
|
* 枚举 {@link IotRuleSceneConditionOperatorEnum}
|
||||||
*/
|
*/
|
||||||
private String operator;
|
private String operator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 比较值
|
* 参数(属性值、在线状态)
|
||||||
*
|
* <p>
|
||||||
* 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。
|
* 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。
|
||||||
* 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN}
|
* 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN}
|
||||||
*/
|
*/
|
||||||
private String value;
|
private String value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CRON 表达式
|
||||||
|
*/
|
||||||
|
private String cronExpression;
|
||||||
|
|
||||||
|
// ========== 条件部分 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发条件分组(状态条件分组)的数组
|
||||||
|
* <p>
|
||||||
|
* 第一层 List:分组与分组之间,是“或”的关系
|
||||||
|
* 第二层 List:条件与条件之间,是“且”的关系
|
||||||
|
*/
|
||||||
|
private List<List<TriggerCondition>> conditionGroups;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行器配置
|
* 触发条件(状态条件)
|
||||||
*/
|
*/
|
||||||
@Data
|
@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}
|
* 枚举 {@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;
|
private Integer type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备控制
|
* 产品编号
|
||||||
*
|
*
|
||||||
* 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DEVICE_PROPERTY_SET} 时
|
* 关联 {@link IotProductDO#getId()}
|
||||||
*/
|
*/
|
||||||
private ActionDeviceControl deviceControl;
|
private Long productId;
|
||||||
|
/**
|
||||||
}
|
* 设备编号
|
||||||
|
*
|
||||||
/**
|
* 关联 {@link IotDeviceDO#getId()}
|
||||||
* 执行设备控制
|
*/
|
||||||
*/
|
private Long deviceId;
|
||||||
@Data
|
/**
|
||||||
public static class ActionDeviceControl {
|
* 请求参数
|
||||||
|
*
|
||||||
|
* 一般来说,对应 {@link IotDeviceMessage#getParams()} 请求参数
|
||||||
|
*/
|
||||||
|
private Object params;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 产品标识
|
* 告警配置编号
|
||||||
*
|
*
|
||||||
* 关联 {@link IotProductDO#getProductKey()}
|
* 关联 {@link IotAlertConfigDO#getId()}
|
||||||
*/
|
*/
|
||||||
private String productKey;
|
private Long alertConfigId;
|
||||||
/**
|
|
||||||
* 设备名称数组
|
|
||||||
*
|
|
||||||
* 关联 {@link IotDeviceDO#getDeviceName()}
|
|
||||||
*/
|
|
||||||
private List<String> 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<String, Object> data;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,14 @@ public interface IotRuleSceneService {
|
|||||||
*/
|
*/
|
||||||
void updateRuleScene(@Valid IotRuleSceneSaveReqVO updateReqVO);
|
void updateRuleScene(@Valid IotRuleSceneSaveReqVO updateReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新场景联动状态
|
||||||
|
*
|
||||||
|
* @param id 场景联动编号
|
||||||
|
* @param status 状态
|
||||||
|
*/
|
||||||
|
void updateRuleSceneStatus(Long id, Integer status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除场景联动
|
* 删除场景联动
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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.IotRuleScenePageReqVO;
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
|
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.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.dataobject.rule.IotRuleSceneDO;
|
||||||
import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper;
|
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.IotRuleSceneActionTypeEnum;
|
||||||
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum;
|
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.enums.rule.IotRuleSceneTriggerTypeEnum;
|
||||||
import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager;
|
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.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 cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
@@ -39,10 +43,7 @@ import org.quartz.impl.StdSchedulerFactory;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
@@ -68,6 +69,12 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
|||||||
@Resource(name = "iotSchedulerManager")
|
@Resource(name = "iotSchedulerManager")
|
||||||
private IotSchedulerManager schedulerManager;
|
private IotSchedulerManager schedulerManager;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IotProductService productService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IotDeviceService deviceService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) {
|
public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) {
|
||||||
// 插入
|
// 插入
|
||||||
@@ -86,6 +93,15 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
|||||||
ruleSceneMapper.updateById(updateObj);
|
ruleSceneMapper.updateById(updateObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateRuleSceneStatus(Long id, Integer status) {
|
||||||
|
// 校验存在
|
||||||
|
validateRuleSceneExists(id);
|
||||||
|
// 更新状态
|
||||||
|
IotRuleSceneDO updateObj = new IotRuleSceneDO().setId(id).setStatus(status);
|
||||||
|
ruleSceneMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteRuleScene(Long id) {
|
public void deleteRuleScene(Long id) {
|
||||||
// 校验存在
|
// 校验存在
|
||||||
@@ -131,118 +147,61 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
|||||||
@Override
|
@Override
|
||||||
@TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略
|
@TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略
|
||||||
public List<IotRuleSceneDO> getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) {
|
public List<IotRuleSceneDO> getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) {
|
||||||
if (true) {
|
// TODO @芋艿:测试代码示例(使用新结构),可根据需要启用
|
||||||
IotRuleSceneDO ruleScene01 = new IotRuleSceneDO();
|
if (false) {
|
||||||
ruleScene01.setTriggers(CollUtil.newArrayList());
|
// 创建测试规则场景
|
||||||
IotRuleSceneDO.TriggerConfig trigger01 = new IotRuleSceneDO.TriggerConfig();
|
IotRuleSceneDO ruleScene = new IotRuleSceneDO();
|
||||||
trigger01.setType(IotRuleSceneTriggerTypeEnum.DEVICE.getType());
|
ruleScene.setId(1L);
|
||||||
trigger01.setConditions(CollUtil.newArrayList());
|
ruleScene.setName("测试场景");
|
||||||
// 属性
|
ruleScene.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
IotRuleSceneDO.TriggerCondition condition01 = new IotRuleSceneDO.TriggerCondition();
|
|
||||||
condition01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
|
// 创建触发器
|
||||||
condition01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier());
|
IotRuleSceneDO.Trigger trigger = new IotRuleSceneDO.Trigger();
|
||||||
condition01.setParameters(CollUtil.newArrayList());
|
trigger.setType(IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST.getType());
|
||||||
// IotRuleSceneDO.TriggerConditionParameter parameter010 = new IotRuleSceneDO.TriggerConditionParameter();
|
trigger.setProductId(1L); // 假设产品ID为1
|
||||||
// parameter010.setIdentifier("width");
|
trigger.setDeviceId(1L); // 假设设备ID为1
|
||||||
// parameter010.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator());
|
trigger.setIdentifier("temperature"); // 温度属性
|
||||||
// parameter010.setValue("abc");
|
trigger.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator());
|
||||||
// condition01.getParameters().add(parameter010);
|
trigger.setValue("25"); // 温度大于25度
|
||||||
IotRuleSceneDO.TriggerConditionParameter parameter011 = new IotRuleSceneDO.TriggerConditionParameter();
|
|
||||||
parameter011.setIdentifier("width");
|
// 创建条件分组
|
||||||
parameter011.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator());
|
IotRuleSceneDO.TriggerCondition condition = new IotRuleSceneDO.TriggerCondition();
|
||||||
parameter011.setValue("1");
|
condition.setType(IotRuleSceneConditionTypeEnum.DEVICE_PROPERTY.getType());
|
||||||
condition01.getParameters().add(parameter011);
|
condition.setIdentifier("temperature");
|
||||||
IotRuleSceneDO.TriggerConditionParameter parameter012 = new IotRuleSceneDO.TriggerConditionParameter();
|
condition.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator());
|
||||||
parameter012.setIdentifier("width");
|
condition.setParam("25");
|
||||||
parameter012.setOperator(IotRuleSceneConditionOperatorEnum.NOT_EQUALS.getOperator());
|
|
||||||
parameter012.setValue("2");
|
trigger.setConditionGroups(ListUtil.toList(Collections.singleton(ListUtil.toList(condition))));
|
||||||
condition01.getParameters().add(parameter012);
|
ruleScene.setTriggers(ListUtil.toList(trigger));
|
||||||
IotRuleSceneDO.TriggerConditionParameter parameter013 = new IotRuleSceneDO.TriggerConditionParameter();
|
|
||||||
parameter013.setIdentifier("width");
|
// 创建动作
|
||||||
parameter013.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator());
|
IotRuleSceneDO.Action action = new IotRuleSceneDO.Action();
|
||||||
parameter013.setValue("0");
|
action.setType(IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET.getType());
|
||||||
condition01.getParameters().add(parameter013);
|
action.setProductId(1L);
|
||||||
IotRuleSceneDO.TriggerConditionParameter parameter014 = new IotRuleSceneDO.TriggerConditionParameter();
|
action.setDeviceId(1L);
|
||||||
parameter014.setIdentifier("width");
|
action.setParams(MapUtil.of("fan", "on")); // 打开风扇
|
||||||
parameter014.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator());
|
|
||||||
parameter014.setValue("0");
|
ruleScene.setActions(ListUtil.toList(action));
|
||||||
condition01.getParameters().add(parameter014);
|
|
||||||
IotRuleSceneDO.TriggerConditionParameter parameter015 = new IotRuleSceneDO.TriggerConditionParameter();
|
return ListUtil.toList(ruleScene);
|
||||||
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.<String, Object>builder()
|
|
||||||
.put("power", 1)
|
|
||||||
.put("color", "red")
|
|
||||||
.build());
|
|
||||||
action01.setDeviceControl(actionDeviceControl01);
|
|
||||||
// ruleScene01.getActions().add(action01); // TODO 芋艿:先不测试了
|
|
||||||
return ListUtil.toList(ruleScene01);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 注意:旧的测试代码已删除,因为使用了废弃的数据结构
|
||||||
|
// 如需测试,请使用上面的新结构测试代码示例
|
||||||
List<IotRuleSceneDO> list = ruleSceneMapper.selectList();
|
List<IotRuleSceneDO> list = ruleSceneMapper.selectList();
|
||||||
// TODO @芋艿:需要考虑开启状态
|
// 只返回启用状态的规则场景
|
||||||
return filterList(list, ruleScene -> {
|
List<IotRuleSceneDO> enabledList = filterList(list,
|
||||||
for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) {
|
ruleScene -> CommonStatusEnum.ENABLE.getStatus().equals(ruleScene.getStatus()));
|
||||||
if (ObjUtil.notEqual(trigger.getProductKey(), productKey)) {
|
|
||||||
continue;
|
// 根据 productKey 和 deviceName 进行匹配
|
||||||
}
|
return filterList(enabledList, ruleScene -> {
|
||||||
if (CollUtil.isEmpty(trigger.getDeviceNames()) // 无设备名称限制
|
if (CollUtil.isEmpty(ruleScene.getTriggers())) {
|
||||||
|| trigger.getDeviceNames().contains(deviceName)) { // 包含设备名称
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) {
|
||||||
|
// 检查触发器是否匹配指定的产品和设备
|
||||||
|
if (isMatchProductAndDevice(trigger, productKey, deviceName)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,47 +209,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
|
@Override
|
||||||
public void executeRuleSceneByDevice(IotDeviceMessage message) {
|
public void executeRuleSceneByDevice(IotDeviceMessage message) {
|
||||||
// TODO @芋艿:这里的 tenantId,通过设备获取;
|
// TODO @芋艿:这里的 tenantId,通过设备获取;
|
||||||
// TenantUtils.execute(message.getTenantId(), () -> {
|
TenantUtils.execute(message.getTenantId(), () -> {
|
||||||
// // 1. 获得设备匹配的规则场景
|
// 1. 获得设备匹配的规则场景
|
||||||
// List<IotRuleSceneDO> ruleScenes = getMatchedRuleSceneListByMessage(message);
|
List<IotRuleSceneDO> ruleScenes = getMatchedRuleSceneListByMessage(message);
|
||||||
// if (CollUtil.isEmpty(ruleScenes)) {
|
if (CollUtil.isEmpty(ruleScenes)) {
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// // 2. 执行规则场景
|
// 2. 执行规则场景
|
||||||
// executeRuleSceneAction(message, ruleScenes);
|
executeRuleSceneAction(message, ruleScenes);
|
||||||
// });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeRuleSceneByTimer(Long id) {
|
public void executeRuleSceneByTimer(Long id) {
|
||||||
// 1.1 获得规则场景
|
// 1.1 获得规则场景
|
||||||
// IotRuleSceneDO scene = TenantUtils.executeIgnore(() -> ruleSceneMapper.selectById(id));
|
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.<String, Object>builder()
|
|
||||||
.put("power", 1)
|
|
||||||
.put("color", "red")
|
|
||||||
.build());
|
|
||||||
action01.setDeviceControl(iotRuleSceneActionDeviceControl01);
|
|
||||||
scene.setActions(ListUtil.toList(action01));
|
|
||||||
}
|
|
||||||
if (scene == null) {
|
if (scene == null) {
|
||||||
log.error("[executeRuleSceneByTimer][规则场景({}) 不存在]", id);
|
log.error("[executeRuleSceneByTimer][规则场景({}) 不存在]", id);
|
||||||
return;
|
return;
|
||||||
@@ -300,7 +282,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 1.2 判断是否有定时触发器,避免脏数据
|
// 1.2 判断是否有定时触发器,避免脏数据
|
||||||
IotRuleSceneDO.TriggerConfig config = CollUtil.findOne(scene.getTriggers(),
|
IotRuleSceneDO.Trigger config = CollUtil.findOne(scene.getTriggers(),
|
||||||
trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType()));
|
trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType()));
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene);
|
log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene);
|
||||||
@@ -321,72 +303,229 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
|||||||
private List<IotRuleSceneDO> getMatchedRuleSceneListByMessage(IotDeviceMessage message) {
|
private List<IotRuleSceneDO> getMatchedRuleSceneListByMessage(IotDeviceMessage message) {
|
||||||
// 1. 匹配设备
|
// 1. 匹配设备
|
||||||
// TODO @芋艿:可能需要 getSelf(); 缓存
|
// TODO @芋艿:可能需要 getSelf(); 缓存
|
||||||
List<IotRuleSceneDO> ruleScenes = null;
|
// 1.1 通过 deviceId 获取设备信息
|
||||||
// TODO @芋艿:这里需要适配
|
IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId());
|
||||||
// List<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache(
|
if (device == null) {
|
||||||
// message.getProductKey(), message.getDeviceName());
|
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<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache(
|
||||||
|
product.getProductKey(), device.getDeviceName());
|
||||||
if (CollUtil.isEmpty(ruleScenes)) {
|
if (CollUtil.isEmpty(ruleScenes)) {
|
||||||
return ruleScenes;
|
return ruleScenes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 匹配 trigger 触发器的条件
|
// 2. 匹配 trigger 触发器的条件
|
||||||
return filterList(ruleScenes, ruleScene -> {
|
return filterList(ruleScenes, ruleScene -> {
|
||||||
for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) {
|
for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) {
|
||||||
// 2.1 非设备触发,不匹配
|
// 2.1 检查触发器类型,根据新的枚举值进行匹配
|
||||||
if (ObjUtil.notEqual(trigger.getType(), IotRuleSceneTriggerTypeEnum.DEVICE.getType())) {
|
// TODO @芋艿:需要根据新的触发器类型枚举进行适配
|
||||||
|
// 原来使用 IotRuleSceneTriggerTypeEnum.DEVICE,新结构可能有不同的类型
|
||||||
|
|
||||||
|
// 2.2 条件分组为空,说明没有匹配的条件,因此不匹配
|
||||||
|
if (CollUtil.isEmpty(trigger.getConditionGroups())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// TODO 芋艿:产品、设备的匹配,要不要这里在做一次???貌似和 1. 部分重复了
|
|
||||||
// 2.2 条件为空,说明没有匹配的条件,因此不匹配
|
// 2.3 检查条件分组:分组与分组之间是"或"的关系,条件与条件之间是"且"的关系
|
||||||
if (CollUtil.isEmpty(trigger.getConditions())) {
|
boolean anyGroupMatched = false;
|
||||||
return false;
|
for (List<IotRuleSceneDO.TriggerCondition> 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 -> {
|
if (anyGroupMatched) {
|
||||||
// TODO @芋艿:这里的逻辑,需要适配
|
log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger);
|
||||||
// if (ObjUtil.notEqual(message.getType(), condition.getType())
|
return true;
|
||||||
// || 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;
|
|
||||||
}
|
}
|
||||||
log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
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<String, Object> springExpressionVariables = MapUtil.<String, Object>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<String> 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 @芋艿:【可优化】可以考虑增加下单测,边界太多了。
|
// TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断触发器的条件参数是否匹配
|
* 判断触发器的条件参数是否匹配
|
||||||
*
|
*
|
||||||
* @param message 设备消息
|
* @param message 设备消息
|
||||||
* @param parameter 触发器条件参数
|
* @param condition 触发条件
|
||||||
* @param ruleScene 规则场景(用于日志,无其它作用)
|
* @param ruleScene 规则场景(用于日志,无其它作用)
|
||||||
* @param trigger 触发器(用于日志,无其它作用)
|
* @param trigger 触发器(用于日志,无其它作用)
|
||||||
* @return 是否匹配
|
* @return 是否匹配
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unchecked", "DataFlowIssue"})
|
@SuppressWarnings({"unchecked", "DataFlowIssue"})
|
||||||
private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerConditionParameter parameter,
|
private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerCondition condition,
|
||||||
IotRuleSceneDO ruleScene, IotRuleSceneDO.TriggerConfig trigger) {
|
IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) {
|
||||||
// 1.1 校验操作符是否合法
|
// 1.1 校验操作符是否合法
|
||||||
IotRuleSceneConditionOperatorEnum operator =
|
IotRuleSceneConditionOperatorEnum operator =
|
||||||
IotRuleSceneConditionOperatorEnum.operatorOf(parameter.getOperator());
|
IotRuleSceneConditionOperatorEnum.operatorOf(condition.getOperator());
|
||||||
if (operator == null) {
|
if (operator == null) {
|
||||||
log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]",
|
log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]",
|
||||||
ruleScene.getId(), trigger, parameter.getOperator());
|
ruleScene.getId(), trigger, condition.getOperator());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 1.2 校验消息是否包含对应的值
|
// 1.2 校验消息是否包含对应的值
|
||||||
String messageValue = MapUtil.getStr((Map<String, Object>) message.getData(), parameter.getIdentifier());
|
String messageValue = MapUtil.getStr((Map<String, Object>) message.getData(), condition.getIdentifier());
|
||||||
if (messageValue == null) {
|
if (messageValue == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -395,8 +534,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
|||||||
Map<String, Object> springExpressionVariables = new HashMap<>();
|
Map<String, Object> springExpressionVariables = new HashMap<>();
|
||||||
try {
|
try {
|
||||||
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue);
|
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue);
|
||||||
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, parameter.getValue());
|
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, condition.getParam());
|
||||||
List<String> parameterValues = StrUtil.splitTrim(parameter.getValue(), CharPool.COMMA);
|
List<String> parameterValues = StrUtil.splitTrim(condition.getParam(), CharPool.COMMA);
|
||||||
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues);
|
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues);
|
||||||
// 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题!
|
// 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题!
|
||||||
if (ObjectUtils.equalsAny(operator, IotRuleSceneConditionOperatorEnum.BETWEEN,
|
if (ObjectUtils.equalsAny(operator, IotRuleSceneConditionOperatorEnum.BETWEEN,
|
||||||
@@ -410,7 +549,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
|||||||
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE,
|
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE,
|
||||||
NumberUtil.parseDouble(messageValue));
|
NumberUtil.parseDouble(messageValue));
|
||||||
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE,
|
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE,
|
||||||
NumberUtil.parseDouble(parameter.getValue()));
|
NumberUtil.parseDouble(condition.getParam()));
|
||||||
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST,
|
springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST,
|
||||||
convertList(parameterValues, NumberUtil::parseDouble));
|
convertList(parameterValues, NumberUtil::parseDouble));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class IotAlertRecoverSceneRuleAction implements IotSceneRuleAction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(IotDeviceMessage message,
|
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;
|
Long deviceId = message != null ? message.getDeviceId() : null;
|
||||||
List<IotAlertRecordDO> alertRecords = alertRecordService.getAlertRecordListBySceneRuleId(
|
List<IotAlertRecordDO> alertRecords = alertRecordService.getAlertRecordListBySceneRuleId(
|
||||||
rule.getId(), deviceId, false);
|
rule.getId(), deviceId, false);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(@Nullable IotDeviceMessage message,
|
public void execute(@Nullable IotDeviceMessage message,
|
||||||
IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception {
|
IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) throws Exception {
|
||||||
List<IotAlertConfigDO> alertConfigs = alertConfigService.getAlertConfigListBySceneRuleIdAndStatus(
|
List<IotAlertConfigDO> alertConfigs = alertConfigService.getAlertConfigListBySceneRuleIdAndStatus(
|
||||||
rule.getId(), CommonStatusEnum.ENABLE.getStatus());
|
rule.getId(), CommonStatusEnum.ENABLE.getStatus());
|
||||||
if (CollUtil.isEmpty(alertConfigs)) {
|
if (CollUtil.isEmpty(alertConfigs)) {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.iot.service.rule.scene.action;
|
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.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.dal.dataobject.rule.IotRuleSceneDO;
|
||||||
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
|
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
|
||||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||||
@@ -27,25 +25,25 @@ public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(IotDeviceMessage message,
|
public void execute(IotDeviceMessage message,
|
||||||
IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) {
|
IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) {
|
||||||
IotRuleSceneDO.ActionDeviceControl control = actionConfig.getDeviceControl();
|
//IotRuleSceneDO.ActionDeviceControl control = actionConfig.getDeviceControl();
|
||||||
Assert.notNull(control, "设备控制配置不能为空");
|
//Assert.notNull(control, "设备控制配置不能为空");
|
||||||
// 遍历每个设备,下发消息
|
//// 遍历每个设备,下发消息
|
||||||
control.getDeviceNames().forEach(deviceName -> {
|
//control.getDeviceNames().forEach(deviceName -> {
|
||||||
IotDeviceDO device = deviceService.getDeviceFromCache(control.getProductKey(), deviceName);
|
// IotDeviceDO device = deviceService.getDeviceFromCache(control.getProductKey(), deviceName);
|
||||||
if (device == null) {
|
// if (device == null) {
|
||||||
log.error("[execute][message({}) actionConfig({}) 对应的设备不存在]", message, actionConfig);
|
// log.error("[execute][message({}) actionConfig({}) 对应的设备不存在]", message, actionConfig);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
try {
|
// try {
|
||||||
// TODO @芋艿:@puhui999:这块可能要改,从 type => method
|
// // TODO @芋艿:@puhui999:这块可能要改,从 type => method
|
||||||
IotDeviceMessage downstreamMessage = deviceMessageService.sendDeviceMessage(IotDeviceMessage.requestOf(
|
// IotDeviceMessage downstreamMessage = deviceMessageService.sendDeviceMessage(IotDeviceMessage.requestOf(
|
||||||
control.getType() + control.getIdentifier(), control.getData()).setDeviceId(device.getId()));
|
// control.getType() + control.getIdentifier(), control.getData()).setDeviceId(device.getId()));
|
||||||
log.info("[execute][message({}) actionConfig({}) 下发消息({})成功]", message, actionConfig, downstreamMessage);
|
// log.info("[execute][message({}) actionConfig({}) 下发消息({})成功]", message, actionConfig, downstreamMessage);
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("[execute][message({}) actionConfig({}) 下发消息失败]", message, actionConfig, e);
|
// log.error("[execute][message({}) actionConfig({}) 下发消息失败]", message, actionConfig, e);
|
||||||
}
|
// }
|
||||||
});
|
//});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public interface IotSceneRuleAction {
|
|||||||
*/
|
*/
|
||||||
void execute(@Nullable IotDeviceMessage message,
|
void execute(@Nullable IotDeviceMessage message,
|
||||||
IotRuleSceneDO rule,
|
IotRuleSceneDO rule,
|
||||||
IotRuleSceneDO.ActionConfig actionConfig) throws Exception;
|
IotRuleSceneDO.Action actionConfig) throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得类型
|
* 获得类型
|
||||||
|
|||||||
Reference in New Issue
Block a user