|
|
@@ -0,0 +1,59 @@
|
|
|
+# 舱室故障隔离与双端故障提示 · 设计
|
|
|
+
|
|
|
+> 新增加固专项(2026-06-23 由真机调试中发现 + 用户明确要求)。独立于 D2-02,改 control 启动核心,需单独 TDD + 真机谨慎验证。
|
|
|
+> 设计依据:本次真机排障对 `StartMain`/`SerialBin`/`HouseBin`/`ComBin` 源码逐行核实(见下 §2 file:line 证据)。
|
|
|
+
|
|
|
+## 一、背景与问题
|
|
|
+
|
|
|
+培养箱是多舱室设备,**别的舱里有胚胎在养**。两个现实场景必须扛住:
|
|
|
+1. **开机时就有部分舱坏**(相机坏/串口坏/编号冲突),好的舱**仍要正常启动、继续培养**。
|
|
|
+2. **运行中某舱突然坏**,**不能影响其他舱**。
|
|
|
+
|
|
|
+且用户提出**硬约束**:**舱室的任何异常,operate 和 front 两个客户端都必须给用户明确提示(哪个舱、什么故障、何时),不能"坏了却不知道哪坏"。**
|
|
|
+
|
|
|
+## 二、现状分析(源码逐行核实,2026-06-23)
|
|
|
+
|
|
|
+| 场景 | 现状 | 证据 |
|
|
|
+|---|---|---|
|
|
|
+| **运行期单舱突然坏** | ✅ **已隔离** | 每舱独立 `HouseBin`→`ComBin`→`Channel`→独立 COM 口→独立线程;`HouseBin/BufferBottleBin.MainThread` 是 `Task.Factory.StartNew(LongRunning)` 的 `while(true){ try{采集/换气/气压} catch{记日志} }`,单舱异常被捕获记录、循环继续、别舱线程无感;`ComBin.StartSendCommandThread` 同构 `while(true){try/catch}`。`StartMain.cs:228-250`、`BufferBottleBin.cs:136-192`、`ComBin.cs:114-181` |
|
|
|
+| **舱完全坏死/没接** | ✅ **跳过,好舱继续** | 相机枚举 `GetCameraSn` 失败→SN 记 null 不报错(`SerialBin.cs:108-114`);扫口 `GetHouseInfo` 口打不开/握手失败→`goto CC` 跳过不报错(`SerialBin.cs:204/206`);模块数≠11 已改可继续(`ContinueOnModuleCountMismatch` 默认 true,`StartMain.cs:103-117`) |
|
|
|
+| **舱半坏(串口活、相机坏/编号冲突)** | ❌ **拖垮整机启动** | `GetHouseInfo` 对"相机列表无此舱 CCDSN"(`SerialBin.cs:252`)、舱号重复(`:212`)、CCDSN 重复(`:260`)、相机重复 SN(`:121`)→ `errorlist.Add`;而 `InitTL` 只要 `errorList.Any()` 就整体 `return 空`(`StartMain.cs:78-83`/`89-94`)→ `StartRun` 拿到 errorInfo 直接返回、`StartAsync()` 不执行 → **一个舱都起不来** |
|
|
|
+| **故障可见性** | ◑ **部分** | 已有 `alarm_data` 入库 + MQTT 上报管道(D1-07 实测舱11低压告警入库);但"舱启动被排除""舱串口/相机突然坏"这类**结构性故障**是否作为告警上报双端、front/operate 是否明确展示"哪个舱什么故障",未成体系 |
|
|
|
+
|
|
|
+**结论**:运行期隔离做到了;**启动期有"半坏拖垮全体"的真实缺口**;故障提示需成体系打通双端。
|
|
|
+
|
|
|
+## 三、目标
|
|
|
+
|
|
|
+1. **启动期按舱容错**:任何舱在任何阶段(相机枚举/扫口握手/EEPROM 读/舱初始化)坏 → **只把该舱登记为故障并排除**,其余好舱继续 `StartAsync` 正常培养。整机启动**绝不因单舱失败而中止**。
|
|
|
+2. **双端故障明确提示(硬约束)**:舱室任何异常(① 启动被排除 ② 运行期突发故障)→ 经统一故障通道上报 → **operate 监控页 + front 都明确显示:哪个舱 / 什么故障 / 发生时间 / 当前是否已被隔离**。
|
|
|
+
|
|
|
+## 四、设计要点
|
|
|
+
|
|
|
+### 4.1 启动期按舱容错(control)
|
|
|
+- `SerialBin.Start/UpdataCamera` 的 `errorlist`:**区分"致命"与"单舱故障"**。单舱故障(相机坏/CCDSN 不匹配/该舱编号冲突)→ 记入**坏舱清单**(houseSn + 原因 + 阶段),**不**作为整体中止信号。
|
|
|
+- `StartMain.InitTL`:不再"errorList 非空即整体 return";改为**剔除坏舱**后用好舱继续(`runHouses` 排除坏舱)。仅在**全部舱都失败/总控11失败**等真致命情形才中止。
|
|
|
+- `InitHouse`:大 try-catch 内**逐舱构造/StartTask 各自 try-catch**,单舱构造抛异常只跳过该舱。
|
|
|
+- 坏舱清单贯穿到状态快照(`MonitorSnapshot`)与告警上报。
|
|
|
+
|
|
|
+### 4.2 统一故障上报(复用现有管道)
|
|
|
+- 接**现有 `alarm_data` + MQTT 上报**机制(D1-07 已验通)。新增舱级故障告警类型:`HOUSE_INIT_EXCLUDED`(启动排除)、`HOUSE_RUNTIME_FAULT`(运行期串口/相机失联)、`HOUSE_CAMERA_FAULT`、`HOUSE_SERIAL_FAULT` 等。
|
|
|
+- control 的 `/status` 快照增"舱故障列表"字段(houseSn/类型/原因/时间/是否已隔离),供 operate 监控页轮询展示。
|
|
|
+- 运行期 `MainThread`/`ComBin` 的 catch 里:连续失败达阈值 → 升级为舱级故障告警(避免每圈刷屏,做去抖/阈值)。
|
|
|
+
|
|
|
+### 4.3 双端展示(硬约束落地)
|
|
|
+- **operate**:监控页新增"舱故障"区,红色高亮列出每个故障舱(舱号/故障类型/时间/已隔离),与现有监控三块并列。
|
|
|
+- **front**:接告警流,故障舱在舱位图/告警列表明确标红 + 文案("X 号舱相机故障,已隔离,其余舱正常")。
|
|
|
+- 两端文案统一、可定位(舱号 + 故障类型 + 时间),满足"一眼知道哪坏了"。
|
|
|
+
|
|
|
+## 五、验收(真机)
|
|
|
+1. **启动期**:制造一个舱"半坏"(如拔该舱相机 / 让 CCDSN 不匹配)→ control 启动:该舱被排除、**其余舱全部正常 StartAsync 培养**;control 不中止。
|
|
|
+2. **运行期**:运行中拔某舱串口/相机 → 该舱告警上报、被隔离,**其余舱采集不中断**。
|
|
|
+3. **双端提示**:上述两种情况,**operate 监控页 + front 都明确显示故障舱(舱号/类型/时间)**。
|
|
|
+
|
|
|
+## 六、与其他任务关系
|
|
|
+- **独立于 D2-02**(调试命令代理):本专项是 control 启动/运行健壮性 + 双端可观测性。
|
|
|
+- 改 **control 启动核心**(InitTL/InitHouse/SerialBin),风险较高 → 单独 feature 分支,bite-sized TDD(纯逻辑可单测:坏舱剔除、坏舱清单、阈值去抖)+ 真机拔插验证。
|
|
|
+- 故障上报可与 D1-10 oplog 审计、阶段2 监控页复用同一展示面。
|
|
|
+
|
|
|
+## 七、待拆
|
|
|
+- 实现计划(开发计划/*.md):①control 坏舱剔除(InitTL/SerialBin 重构,TDD)②故障上报/快照字段 ③operate 监控页展示 ④front 告警展示 ⑤真机拔插验收。第一阶段(①②control 侧)纯单测+真机可由 Claude 自主;③④双端 UI 真机门控。
|