规则引擎实现方案v1.0: VolPro集成Quartz驱动 实时监测→条件匹配→执行动作闭环
This commit is contained in:
333
doc/设计文档/规则引擎实现方案_v1.0.md
Normal file
333
doc/设计文档/规则引擎实现方案_v1.0.md
Normal file
@@ -0,0 +1,333 @@
|
||||
# 规则引擎实现方案 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(每设备 ~100ms,10 设备 = 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 可完成闭环。
|
||||
Reference in New Issue
Block a user