modify: IN2 DI 输入监听

This commit is contained in:
2026-09-13 20:34:10 +08:00
parent d7636c4c3b
commit 293254c61a
9 changed files with 272 additions and 704 deletions
+37 -8
View File
@@ -12,7 +12,7 @@
| # | 功能 | 说明 |
| --- | -------------------- | ------------------------------------------------------------------------------------------ |
| 1 | **MQTT 心跳上报** | 通过网关 MQTT Bridge 订阅 `box/aibox_sophon/board_ping`,解析设备系统参数并持久化到 SQLite |
| 1 | **MQTT 心跳上报** | 通过网关 MQTT Bridge 订阅 `box/aibox_sophon/board_ping`,解析设备系统参数并持久化到数据库 |
| 2 | **设备状态查询** | 提供 HTTP API 查询设备在线状态、详情、离线设备列表 |
| 3 | **离线检测告警** | 后台任务周期扫描,超过 `heartbeat.timeout` 未上报心跳的设备标记为离线并输出告警日志 |
| 4 | **视频流管理** | 心跳中状态为「正常」的通道自动通过 MediaMTX 拉取 RTSP 视频流(`StreamManager`) |
@@ -20,9 +20,11 @@
| 6 | **告警上报接口** | 盒子违规事件 JSON 报文字动解析入库(`alarm_record` 表) |
| 7 | **告警查询接口** | 告警列表(分页/筛选)与单条告警详情查询 |
| 8 | **豆包 AI 分析** | 告警图片可交由 `doubao` 插件判定是否为误报(可配置开关) |
| 9 | **外部 MQTT 转发** | 心跳数据转发到外部 MQTT Broker(`mqtt_forward`) |
| 10 | **外部 MQTT 订阅** | 直接订阅外部 Broker,实现 `edge_app_controller` 请求-响应协议(`mqtt_subscribe`) |
| 11 | **告警转发外部平台** | 先上传视频再上报告警到外部开放平台(`alarm_forward`) |
| 9 | **IP 音柱 TTS 播报** | 告警时按违规类型调用 `ip_sound_column` 插件播放 TTS 语音(可配置开关/音量/文案) |
| 10 | **外部 MQTT 转发** | 心跳数据转发到外部 MQTT Broker(`mqtt_forward`) |
| 11 | **外部 MQTT 订阅** | 直接订阅外部 Broker,实现 `edge_app_controller` 请求-响应协议(`mqtt_subscribe`) |
| 12 | **告警转发外部平台** | 先上传视频再上报告警到外部开放平台(`alarm_forward`) |
| 13 | **IN2 任务启停开关** | 监听盒子 IN2 数字输入:有电启动全部算法任务,断电停止全部任务(`task_switch`) |
---
@@ -96,7 +98,10 @@ src/plugins/aibox_sophon_adapter/
├── global_var.py # 模块级全局变量(db / stream_manager / mqtt_* / 各配置)
├── routes.py # 自定义 FastAPI 路由(video_upload / video / alarm_report)
├── edge_app_controller.py # 外部 MQTT 请求-响应处理器(command 注册表分发)
├── task_switch.py # IN2 数字输入控制任务启停(复用 diwatch 的 IN2 通道)
├── alarm_trim.py # 告警记录清理(超限裁剪 + 删除关联视频)
├── diwatch/ # DI 数字输入监听库(SE5/SE9 的 IN1/IN2,独立 CLI:python3 -m diwatch;task_switch 复用其 IN2 通道)
├── in1.py / in11.py # diwatch 前身:IN1 事件脚本 / IN2 轮询脚本(保留备用)
├── router/ # Zenoh RPC 端点(@rpc_method)
│ ├── __init__.py # 导出全部端点模块
│ ├── board_ping.py # MQTT 心跳上报
@@ -188,8 +193,9 @@ curl "http://127.0.0.1:8000/api/v1/aibox_sophon_adapter/list_devices"
1. 手动 Pydantic 验证基础字段(`alarm_models.AlarmReportRequest`,失败记录完整请求体并返回 422)
2. **豆包 AI 分析**:判定为 `False` 时忽略告警(返回 Code 0 + "忽略告警")
3. **写库**:按 `AlarmId/UniqueId` 去重写入 `alarm_record`,超限自动裁剪(`alarm_trim`)
4. **外部转发**:先上传视频替换 `VideoFile` 为外部 `VideoId`,再上报告警
3. **IP 音柱 TTS 播报**:按 `Summary` 匹配文案调用 `ip_sound_column.tts` 播放语音(失败仅记录日志,不阻断)
4. **写库**:按 `AlarmId/UniqueId` 去重写入 `alarm_record`,超限自动裁剪(`alarm_trim`)
5. **外部转发**:先上传视频替换 `VideoFile` 为外部 `VideoId`,再上报告警
> 盒子仅当 **HTTP 200 且 `Result.Code` 非 0** 时才认为上报失败。
@@ -257,9 +263,11 @@ curl "http://127.0.0.1:8000/api/v1/aibox_sophon_adapter/list_devices"
---
## 数据库表(SQLite)
## 数据库表
数据库文件:`{data_dir}/aibox_sophon_adapter.db`(默认 `./data/aibox_sophon_adapter.db`)。
数据库默认为 SQLite 文件 `{data_dir}/aibox_sophon_adapter.db`(默认 `./data/`);
配置了 `[workers.config.database].url` 时优先走 PostgreSQL(当前 config.toml 即此模式),
由 `chongming_worker.Plugin` 基类统一初始化。
### `board_heartbeat` — 设备心跳记录
@@ -323,6 +331,8 @@ tags = ["aibox_sophon_adapter", "sophon", "adapter"]
| `internal_mqtt` | `enabled` / `uri` / `request_topic` / `response_topic` | false / `mqtt://127.0.0.1:1883` / … | 内部请求-响应客户端 |
| `alarm_retention` | `max_records` | `0` | 最多保留告警记录数(0 不限制) |
| `doubao_analysis` | `enabled` | `true` | 是否启用豆包 AI 分析告警图片 |
| `ip_sound_column` | `enabled` / `volume` / `tts` | `true` / `50` / `{}` | 告警时 IP 音柱 TTS 播报(`tts` 为 Summary → 播报文案映射,未命中用默认文案) |
| `task_switch` | `enabled` / `api_base` / `start_command` / `stop_command` / `poll_interval` / `debounce` / `active_low` | true / `http://127.0.0.1` / 1 / 0 / 0.05 / 3 / false | IN2 数字输入控制任务启停(见下节) |
| `alarm_forward` | `enabled` / `url` / `video_upload_url` / `timeout` | false / … / … / 10.0 | 告警转发外部开放平台 |
> 示例:`mqtt_forward.uri = "mqtt://admin:Mixc%402021@192.168.1.6:1883"` —— 密码中特殊字符
@@ -340,6 +350,25 @@ tags = ["aibox_sophon_adapter", "sophon", "adapter"]
---
## IN2 任务启停开关(task_switch)
监听盒子 IN2 数字输入(diwatch `SysfsBackend` 轮询 `gpio_status`,含抗抖),
电平变化时通过盒子本地 HTTP 接口控制**全部**算法任务:
- IN2 **有电**(电平 1)→ 启动全部任务(`ControlCommand = start_command`,默认 1)
- IN2 **断电**(电平 0)→ 停止全部任务(`ControlCommand = stop_command`,默认 0)
控制流程:`POST {api_base}/api/alg_task_fetch`(查全部任务的 `AlgTaskSession`)→
逐个 `POST {api_base}/api/alg_task_control`(启停控制,按返回 `Result.Code` 判定成败并记日志)。
行为约定:
1. **只响应电平跳变**,不按插件启动时的初始电平动作(避免插件重启时误触发全量启停)。
2. DI 轮询跑在独立线程,HTTP 控制调度回事件循环并加锁串行,快速抖动不会并发穿插。
3. 找不到 IN2 状态文件(非盒子环境)时降级为不启动,仅输出警告,不影响插件其他功能。
---
## 开发指南
### 新增 RPC 端点