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

334 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 规则引擎实现方案 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 表新增字段
```sql
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` (告警内容),需补充:
```sql
ALTER TABLE warehouse_ruleaction ADD
ActionType NVARCHAR(255) DEFAULT '控制', -- 动作类型: 控制/告警/通知
ExtraJson NVARCHAR(MAX) NULL; -- 扩展JSON(如控制指令参数)
```
### 2.3 新增规则执行日志表
```sql
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 规则评估流程
```csharp
/// <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 条件评估模型
```csharp
/// <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 动作执行模型
```csharp
/// <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
```csharp
/// <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 前端告警接收
```javascript
// 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 可完成闭环。