review:【iot 物联网】场景联动的逻辑
This commit is contained in:
@@ -23,6 +23,7 @@ import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// TODO @puhui999:名字改成 IotSceneRuleDO
|
||||
/**
|
||||
* IoT 场景联动规则 DO
|
||||
*
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
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.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;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// TODO @puhui999:还是在 IotRuleSceneDO 里搞,这里主要可以看到变化字段哈。
|
||||
/**
|
||||
* IoT 场景联动 DO
|
||||
*
|
||||
* 基于 {@link Trigger} 触发 {@link Action}
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName(value = "iot_scene_rule", autoResultMap = true)
|
||||
@KeySequence("iot_scene_rule_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IotSceneRuleDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 场景联动编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 场景联动名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 场景联动描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 场景联动状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 场景定义配置
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<Trigger> triggers;
|
||||
|
||||
/**
|
||||
* 场景动作配置
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<Action> actions;
|
||||
|
||||
/**
|
||||
* 场景定义配置
|
||||
*/
|
||||
@Data
|
||||
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#getId()}
|
||||
*/
|
||||
private Long productId;
|
||||
/**
|
||||
* 设备编号
|
||||
*
|
||||
* 关联 {@link IotDeviceDO#getId()}
|
||||
* 特殊:如果为 {@link IotDeviceDO#DEVICE_ID_ALL} 时,则是全部设备
|
||||
*/
|
||||
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 value;
|
||||
|
||||
/**
|
||||
* CRON 表达式
|
||||
*/
|
||||
private String cronExpression;
|
||||
|
||||
// ========== 条件部分 ==========
|
||||
|
||||
/**
|
||||
* 触发条件分组(状态条件分组)的数组
|
||||
*
|
||||
* 第一层 List:分组与分组之间,是“或”的关系
|
||||
* 第二层 List:条件与条件之间,是“且”的关系
|
||||
*/
|
||||
private List<List<TriggerCondition>> conditionGroups;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发条件(状态条件)
|
||||
*/
|
||||
@Data
|
||||
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 IotProductDO#getId()}
|
||||
*/
|
||||
private Long productId;
|
||||
/**
|
||||
* 设备编号
|
||||
*
|
||||
* 关联 {@link IotDeviceDO#getId()}
|
||||
*/
|
||||
private Long deviceId;
|
||||
/**
|
||||
* 请求参数
|
||||
*
|
||||
* 一般来说,对应 {@link IotDeviceMessage#getParams()} 请求参数
|
||||
*/
|
||||
private Object params;
|
||||
|
||||
/**
|
||||
* 告警配置编号
|
||||
*
|
||||
* 关联 {@link IotAlertConfigDO#getId()}
|
||||
*/
|
||||
private Long alertConfigId;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -77,10 +77,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
||||
|
||||
@Override
|
||||
public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
IotRuleSceneDO ruleScene = BeanUtils.toBean(createReqVO, IotRuleSceneDO.class);
|
||||
ruleSceneMapper.insert(ruleScene);
|
||||
// 返回
|
||||
return ruleScene.getId();
|
||||
}
|
||||
|
||||
@@ -147,45 +145,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
||||
@Override
|
||||
@TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略
|
||||
public List<IotRuleSceneDO> getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
// TODO @puhui999:一些注释,看看要不要优化下;
|
||||
// 注意:旧的测试代码已删除,因为使用了废弃的数据结构
|
||||
// 如需测试,请使用上面的新结构测试代码示例
|
||||
List<IotRuleSceneDO> list = ruleSceneMapper.selectList();
|
||||
@@ -471,13 +431,13 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 构建 Spring 表达式的变量
|
||||
// 2.1 构建 Spring 表达式的变量
|
||||
Map<String, Object> springExpressionVariables = MapUtil.<String, Object>builder()
|
||||
.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue)
|
||||
.build();
|
||||
|
||||
// 3. 根据操作符类型处理参数值
|
||||
// 2.2 根据操作符类型处理参数值
|
||||
if (StrUtil.isNotBlank(paramValue)) {
|
||||
// TODO @puhui999:这里是不是在 IotRuleSceneConditionOperatorEnum 加个属性;
|
||||
if (operatorEnum == IotRuleSceneConditionOperatorEnum.IN
|
||||
|| operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_IN
|
||||
|| operatorEnum == IotRuleSceneConditionOperatorEnum.BETWEEN
|
||||
@@ -493,7 +453,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 计算 Spring 表达式
|
||||
// 3. 计算 Spring 表达式
|
||||
return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables);
|
||||
} catch (Exception e) {
|
||||
log.error("[evaluateCondition][条件评估异常] sourceValue: {}, operator: {}, paramValue: {}",
|
||||
|
||||
@@ -23,6 +23,7 @@ public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction {
|
||||
@Resource
|
||||
private IotDeviceMessageService deviceMessageService;
|
||||
|
||||
// TODO @puhui999:这里
|
||||
@Override
|
||||
public void execute(IotDeviceMessage message,
|
||||
IotRuleSceneDO rule, IotRuleSceneDO.Action actionConfig) {
|
||||
|
||||
Reference in New Issue
Block a user