Files
SecMPS/doc/设计文档/规则引擎实现方案_v1.0.md

11 KiB
Raw Blame History

规则引擎实现方案 v1.0

版本: 1.0 日期: 2025-05-24 基准: 现有 warehouse_rule / warehouse_rulecondition / warehouse_ruleaction 表 目标: 实现规则驱动的实时监测 → 条件比对 → 自动执行动作的完整闭环


1. 架构决策

1.1 部署位置:集成在 Vol.Pro 框架中 ✓

维度 Vol.Pro 集成 网关集成
规则存储 规则表在本库 需从 Vol.Pro 下发
规则管理 UI 已有完整 CRUD 无管理界面
定时调度 已集成 Quartz 无调度框架
前端推送 SignalR Hub 已就绪 无推送能力
适配器数据源 ⚠️ 需通过 B4 轮询 直接调用
状态维护 数据库持久化 网关无状态
实现复杂度

结论:规则引擎部署在 Vol.Pro 端,通过网关 B 组接口获取实时数据。与网关的 5~10 秒轮询延迟对于仓储环境规则(温湿度超标、人数越限)完全可接受。

1.2 核心设计思想

┌─────────────────────────────────────────────────────────────┐
│                      Vol.Pro 规则引擎                         │
│                                                              │
│  Quartz RuleEngineJob (每10秒)                                │
│       │                                                      │
│       ├─ 1. 加载启用的规则 (warehouse_rule WHERE Enable=1)    │
│       ├─ 2. 按 AdapterCode 分组去重设备列表                  │
│       ├─ 3. 调网关 B4 批量获取实时值                          │
│       ├─ 4. 逐规则评估条件 (AND/OR 组合)                     │
│       └─ 5. 条件匹配 → 执行动作链                             │
│              ├── 控制设备 → 网关 B5/B10                       │
│              ├── 生成告警 → iot_alarm 表                      │
│              └── 推送前端 → SignalR Hub                       │
└─────────────────────────────────────────────────────────────┘

2. 数据库改动

2.1 warehouse_rule 表新增字段

ALTER TABLE warehouse_rule ADD
  Enable         NVARCHAR(50)  DEFAULT '启用',   -- 启用/停用
  Priority       INT           DEFAULT 0,        -- 优先级(数字越大越优先)
  LastEvaluated  DATETIME      NULL,             -- 上次评估时间
  LastTriggered  DATETIME      NULL,             -- 上次触发时间
  CooldownSec    INT           DEFAULT 60;       -- 冷却时间(秒,防止重复触发)

2.2 warehouse_ruleaction 表确认字段

当前已含 Alert (生成告警/是/否) 和 AlertMessage (告警内容),需补充:

ALTER TABLE warehouse_ruleaction ADD
  ActionType     NVARCHAR(255) DEFAULT '控制',   -- 动作类型: 控制/告警/通知
  ExtraJson      NVARCHAR(MAX) NULL;            -- 扩展JSON(如控制指令参数)

2.3 新增规则执行日志表

CREATE TABLE warehouse_rulelog (
  LogID         INT IDENTITY PRIMARY KEY,
  RuleID        INT NOT NULL,                    -- 关联 warehouse_rule
  ConditionMet  NVARCHAR(50),                    -- 条件是否满足(满足/不满足)
  ActionResult  NVARCHAR(MAX),                   -- 动作执行结果JSON
  EvaluatedAt   DATETIME DEFAULT GETDATE(),      -- 评估时间
  Detail        NVARCHAR(MAX) NULL               -- 执行详情
);

3. 规则引擎核心设计

3.1 规则评估流程

/// <summary>
/// 规则引擎核心服务。由 Quartz RuleEngineJob 每 10s 调用一次。
/// 顺序:
///   1. 加载所有启用规则(含条件和动作)
///   2. 从 gateway 批量获取实时值
///   3. 逐规则评估条件 → 触发动作 → 写日志
/// </summary>
public class RuleEngineService
{
    // 注入
    private readonly IHttpClientFactory _httpClient;
    private readonly ISignalRHub _hub;       // 前端推送
    private readonly Iwarehouse_ruleRepository _ruleRepo;

    public async Task EvaluateAllAsync()
    {
        var rules = await LoadEnabledRulesAsync();           // 1. 加载规则
        var adapters = rules.SelectMany(r => r.AdapterCodes).Distinct();
        var realtimeData = await BatchFetchRealtimeAsync(adapters); // 2. 批量取实时值

        foreach (var rule in rules)
        {
            if (await EvaluateRuleAsync(rule, realtimeData))  // 3. 评估条件
            {
                await ExecuteActionsAsync(rule);               // 4. 执行动作
            }
            await LogEvaluationAsync(rule);                    // 5. 写日志
        }
    }
}

3.2 条件评估模型

/// <summary>评估单条规则的所有条件</summary>
async Task<bool> EvaluateRuleAsync(Rule rule, Dictionary<string, List<PointValue>> realtimeData)
{
    // 从 realtimeData 中查找每个条件的实际值
    var results = new List<bool>();
    foreach (var cond in rule.Conditions)
    {
        var actualValue = FindValue(realtimeData, cond.DeviceId, cond.ValueId);
        bool met = Compare(actualValue, cond.CompareOperator, cond.TargetValue);
        results.Add(met);
    }

    // 按 JudgmentMode 组合条件结果
    return rule.JudgmentMode == "AND"
        ? results.All(r => r)
        : results.Any(r => r);
}

double? FindValue(Dictionary<...> data, int deviceId, int valueId)
{
    // 从批量取回的数据中定位对应设备+变量的实时值
    // 映射: valueId → 适配器点位索引
}

bool Compare(double? actual, string op, double target) => op switch
{
    "大于"   => (actual ?? double.MinValue) > target,
    "小于"   => (actual ?? double.MaxValue) < target,
    "等于"   => actual == target,
    "大于等于" => (actual ?? double.MinValue) >= target,
    "小于等于" => (actual ?? double.MaxValue) <= target,
    "不等于" => actual != target,
    _ => false
};

3.3 动作执行模型

/// <summary>按优先级执行规则的所有动作</summary>
async Task ExecuteActionsAsync(Rule rule)
{
    // 冷却检查:防止重复触发
    if (rule.LastTriggered.HasValue &&
        (DateTime.Now - rule.LastTriggered.Value).TotalSeconds < rule.CooldownSec)
        return;

    foreach (var action in rule.Actions.OrderByDescending(a => a.Priority))
    {
        switch (action.Type)
        {
            case "控制":
                // 调网关 B5 或 B10 向目标设备发控制指令
                // 例如: POST /api/gateway/realtime/MC4:31ku/control { deviceId, pointIndex, value }
                await ControlDeviceAsync(action);
                break;

            case "告警":
                if (action.Alert == "是")
                {
                    // 写入 iot_alarm 表
                    await CreateAlarmAsync(rule, action);
                }
                break;

            case "通知":
                // 通过 SignalR 推送前端弹窗
                await _hub.SendAsync("RuleTriggered", new { rule.Title, action.AlertMessage });
                break;
        }
    }
    rule.LastTriggered = DateTime.Now;
}

4. 定时调度

4.1 新增 RuleEngineJob

/// <summary>规则引擎定时任务。挂载到 Vol.Pro Quartz 调度。</summary>
public class RuleEngineJob : IJob
{
    public async Task Execute(IJobExecutionContext context)
    {
        var engine = ServiceProvider.GetService<RuleEngineService>();
        await engine.EvaluateAllAsync();
    }
}

4.2 Quartz 配置

在 Vol.Pro 管理端 → Quartz 管理 → 新建 Job

JobName:      RuleEngineJob
Cron:         0/10 * * * * ?            (每 10 秒)
ClassName:    Warehouse.Services.RuleEngineJob

5. 数据字典补充

字典键 字典值 用途
条件判断方式 AND / OR warehouse_rule.JudgmentMode
比较运算 大于 / 小于 / 等于 / 大于等于 / 小于等于 / 不等于 warehouse_rulecondition.CompareOperator
比对类型 数值 / 开关状态 / 字符串 warehouse_rulecondition.Type
开关状态 开 / 关 TargetValue_Switch
动作类型 控制 / 告警 / 通知 warehouse_ruleaction.ActionType

6. 前端改动

6.1 规则管理页增强

基于现有 warehouse_rule.vue(已在管理端运行),无需重建页面。仅优化表单绑定:

  • 条件表格中"设备"列绑定到 allDevices 动态字典
  • "变量"列绑定到对应变量的动态字典
  • 动作表格中"生成告警"列改为 select(是/否)
  • 新增 ExtraJson 字段(高级模式)提供 JSON 编辑器

6.2 前端告警接收

// warehouse 大屏端 - SignalR 订阅规则推送
connection.on("RuleTriggered", (data) => {
    showMessage({
        title: data.title,
        type: "alarm",
        content: data.alertMessage
    });
});

7. Gateway 端配套

7.1 现有接口即用

规则需求 网关接口 状态
获取 MC4 IoT 实时值 GET /api/gateway/realtime/{adapter}/{deviceId} (B4) 已实现
向 MC4 设备发控制指令 POST /api/gateway/realtime/{adapter}/control (B5) 已实现
获取 Owl 人数统计 GET /api/gateway/devices?adapter=Owl:main (B2) 已实现
远程开门/道闸 POST /api/gateway/control/{adapter} (B10) 已实现

7.2 新增:批量实时值查询(可选优化)

当前 B4 需要逐设备调M 条规则 × N 个条件会导致过多 HTTP 调用。建议新增批量接口:

POST /api/gateway/realtime/{adapter}/batch
Body: { "deviceIds": ["sid1", "sid2", ...] }
Return: { "sid1": [{pointIndex, value}], "sid2": [{...}] }

此接口为可选优化。初期可直接逐设备调 B4每设备 ~100ms10 设备 = 1s可接受


8. 实施计划

阶段 内容 涉及文件 预计
R1 补充数据库表字段 + 新增 warehouse_rulelog 表 + 建字典 SQL + 管理端 1h
R2 实现 RuleEngineService (规则评估 + 动作执行) 1 个新文件 3h
R3 实现 RuleEngineJob + Quartz 注册 1 文件 + 管理端配置 30min
R4 网关批量实时值接口 (B4-batch) Program.cs 30min
R5 规则管理页 UI 增强(动态字典绑定) warehouse_rule.vue 1h
R6 warehouse 大屏端 SignalR 规则推送接收 warehouse DataView.vue 30min
R7 联调验证 2h
合计 8 文件 ~8.5h

9. 规则示例

示例 1温湿度超标自动开空调

规则标题: 库房31温度过高自动开空调
判断方式: AND
条件:
  - 设备: MC4:31ku/温湿度变送器1 | 变量: 温度 | 比较: 大于 | 目标值: 28
动作:
  - 设备: MC4:31ku/空调控制器1 | 动作类型: 控制 | 目标值开关: 开

示例 2摄像机人数越限告警

规则标题: 仓库A区人数超限告警
判断方式: AND
条件:
  - 设备: Owl:main/摄像头1 | 变量: 人数统计 | 比较: 大于等于 | 目标值: 50
动作:
  - 动作类型: 告警 | 生成告警: 是 | 告警内容: "仓库A区人数已达{value}人,请立即检查"

结论: 规则引擎作为 Vol.Pro 内部 Quartz Job 运行,每 10s 拉网关数据评估零网关状态改造。8 个文件 ~8.5h 可完成闭环。