MiBeeNvr v0.3.0: 小米摄像头内置支持与架构演进之路

v0.2.0 发布之后又折腾了不少,这次 v0.3.0 带来了几个重量级更新:小米摄像头内置支持、归档录像功能,以及一大波安全加固。说实话,从外部依赖到内置实现的架构演进过程,比我想象的要曲折得多。

上一篇介绍了 v0.2.0 的 15 个新功能(v0.2.0 更新),没看过第一篇的可以先看 MiBeeNvr 介绍。这次 v0.3.0 主要聚焦在小米摄像头的深度集成上,完整更新列表见 GitHub Release Notes

架构演变:从外部依赖到内置实现的曲折之路

小米摄像头支持的开发过程,是我做过最有趣的架构实验之一。整个过程经历了三个截然不同的阶段,每个阶段都有其独特的教训。

第一阶段:go2rtc 外部依赖 (v0.1.0 时代)

早期的 MiBeeNvr 完全依赖 go2rtc 来处理小米摄像头的协议转换:

mermaid
graph TB
    subgraph "小米摄像头"
        A[Camera]
    end
    
    subgraph "外部容器"
        B[go2rtc]
    end
    
    subgraph "MiBeeNvr"
        C[RTSP 客户端]
        D[HLS 编码]
        E[存储管理]
    end
    
    A -->|"miss 协议"| B
    B -->|"RTSP"| C
    C -->|HLS| D
    D -->|存储| E
    
    classDef hardware fill:#e3f2fd,stroke:#1976d2
    classDef process fill:#e8f5e9,stroke:#4caf50
    classDef storage fill:#fff3e0,stroke:#ff9800
    classDef network fill:#f3e5f5,stroke:#9c27b0
    
    class A hardware
    class B process
    class C,D,E storage

说实话,这个方案一开始看起来很优雅:用一个现成的 Docker 容器解决协议转换问题,主程序专心做 NVR 功能。但很快问题就来了:

  1. CS2 P2P 连接不稳定:小米摄像头的 P2P 连接大约 20 分钟就会超时卡死
  2. 调试困难:go2rtc 是独立项目,出了问题很难定位
  3. 运维复杂:需要管理两个 Docker 容器,端口冲突、资源争抢问题不断

归根结底,把核心功能依赖到外部容器上,本身就是个设计上的失误。

第二阶段:插件架构实验 (v0.2.0 到 v0.3.0 之间)

吸取教训之后,我决定把 go2rtc 的 Xiaomi 代码移植到 MiBeeNvr 里,做成插件系统。当时的想法很好:

  • 通过 Go 接口注册实现协议解耦
  • 使用 init() 基础的插件机制
  • 甚至实验了 gRPC 进程隔离

听起来很美好对吧?让架构变得可扩展,牺牲一点性能换来开发便利性。结果现实给了我一记响亮的耳光:

mermaid
flowchart LR
    subgraph "小米摄像头"
        A[Camera]
    end
    
    subgraph "插件进程"
        B[Plugin Process]
        C[gRPC 通信]
    end
    
    subgraph "MiBeeNvr 主程序"
        D[主 NVR 引擎]
        E[HLS 编码]
        F[存储管理]
    end
    
    A -->|"miss 协议"| B
    B -->|gRPC| C
    C -->|处理| D
    D -->|HLS| E
    E -->|存储| F
    
    classDef hardware fill:#e3f2fd,stroke:#1976d2
    classDef process fill:#e8f5e9,stroke:#4caf50
    classDef storage fill:#fff3e0,stroke:#ff9800
    classDef network fill:#f3e5f5,stroke:#9c27b0
    
    class A hardware
    class B,C process
    class D,E,F storage

实际使用中发现的问题:

  1. 架构过度复杂:实时预览多了好几层中间环节,性能下降明显
  2. 资源消耗增加:额外的进程和通信开销
  3. 新人门槛高:代码库变得难以理解,一个简单的功能需要跨进程通信

折腾了一圈才发现,有时候最简单的方案反而是最好的。

第三阶段:回归简洁 (v0.3.0)

最终在 v0.3.0 中,我彻底移除了插件系统,将 Xiaomi 代码迁移到内置的 internal/xiaomi/ 包中:

mermaid
graph TB
    subgraph "小米摄像头"
        A[Camera]
    end
    
    subgraph "MiBeeNvr 核心"
        B[internal/xiaomi/ 包]
        C[核心 NVR 引擎]
        D[HLS 编码]
        E[存储管理]
    end
    
    A -->|"miss 协议"| B
    B -->|直接处理| C
    C -->|HLS| D
    D -->|存储| E
    
    classDef hardware fill:#e3f2fd,stroke:#1976d2
    classDef process fill:#e8f5e9,stroke:#4caf50
    classDef storage fill:#fff3e0,stroke:#ff9800
    
    class A hardware
    class B,C,D,E process

正如 Release Notes 中所说:

“Plugin System Removed — Xiaomi migrated from gRPC plugin to built-in internal/xiaomi/ package”

“Full Xiaomi IP camera integration — no plugins, no external dependencies”

现在的架构就是一个单二进制文件,无需外部进程,无需 Docker 依赖。有时候,对于这个阶段的项目,简洁性比扩展性更重要。

小米摄像头功能详解

内置 CS2 P2P 协议

现在 MiBeeNvr 直接支持小米摄像头的 CS2 P2P 协议,不再需要 go2rtc 这个中间人。

云端认证流程

完整的认证流程包括:

  1. 使用小米账号登录
  2. 获取 passToken
  3. 自动发现设备列表
  4. 建立直连

支持的设备类型包括:

  • .camera. - 普通摄像头
  • .cateye. - 猫眼摄像头
  • .feeder. - 喂养器(HLC8 型号)

配置示例

mibeenvr.yaml 中添加小米摄像头配置:

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
xiaomi:
  user_id: "123456789"
  token: "your_passToken"
  region: "cn"

cameras:
  - id: "xiaomi-living"
    name: "客厅小米"
    protocol: "xiaomi"
    encoding: "h264"
    did: "device_id_here"
    vendor: "cs2"
    enabled: true

Web 界面

Web 界面提供了完整的账号管理功能:

  • 小米账号登录页面
  • 自动发现摄像头
  • 一键添加功能

说实话,这个认证流程比我想象的要复杂,但最终实现出来的用户体验还算不错。

实际界面是这样的:

小米设备自动发现界面

归档录像:独特的摄像机管理方式

归档录像功能是这次 v0.3.0 的一大亮点。这个需求的场景很简单:当你需要移除一个摄像头(坏了、搬家、升级)但又想保留历史录像时,传统 NVR 系统通常的做法是直接删除所有相关数据。

MiBeeNvr 提供了更人性化的解决方案:

mermaid
flowchart LR
    A[活跃摄像头] --> B[停止录制]
    B --> C[合并片段]
    C --> D[标记归档]
    D --> E[从配置移除]
    E --> F[录像保留]
    
    classDef process fill:#e8f5e9,stroke:#4caf50
    classDef storage fill:#fff3e0,stroke:#ff9800
    classDef network fill:#f3e5f5,stroke:#9c27b0
    
    class A,B,C,E process
    class D,F storage

三态摄像头管理

摄像头现在有三种状态:

  • Active - 正在录制
  • Disabled - 已暂停
  • Archived - 只读(历史记录)

归档流程

归档操作很直观:

  1. 在摄像头列表中点击"归档"
  2. 弹出确认对话框
  3. 输入 “DELETE” 确认
  4. 系统自动合并片段并标记归档
  5. 摄像头从实时列表移除,但录像完整保留

归档后管理

归档后的录像支持:

  • 播放历史录像
  • 下载单个录像文件
  • 删除指定录像
  • 设置归档组保留期限

实际效果如下:

归档摄像头管理界面
说实话,这个功能是我在使用其他 NVR 系统时最想要的。大多数系统在移除摄像头时直接一刀切删除,完全没有保留历史数据的意识。

其他 v0.3.0 亮点

安全加固

这次 v0.3.0 包含了 15+ 个安全修复:

  • 路径验证加强
  • 认证机制硬化
  • 速率限制优化
  • 安全头设置
  • SQL 注入防护

前端全面升级

前端完成了 Svelte 5 的完整迁移:

  • 运行模式 (runes) 语法
  • 移除所有遗留语法
  • 国际化 500+ 个键值

HLS 改进

HLS 播放器优化:

  • 指数退避自动重试
  • 僵尸播放器检测
  • 子流降级支持

总结 + 开源链接

v0.3.0 从 v0.2.0 到现在,总共 141 个提交,45 个新功能,48 个修复。从外部依赖到插件实验,再到内置简洁实现的架构演进,让我深刻体会到:

有时候,最"正确"的架构并不是最灵活的那个。对于一个当前阶段的项目,简洁性往往比扩展性更重要。

开源地址:

折腾了这么久,小米摄像头的支持终于稳定了。如果你也在折腾智能家居,不妨试试看。