# PRD 需求文档 — 设备模拟模块

> **文档类型**: PRD 需求文档
> **创建日期**: 2026-07-29
> **作者**: czj
> **优先级**: P0
> **状态**: 待评审

---

## 一、需求背景

### 1.1 业务背景

当前平台已覆盖 UI 自动化测试、安全测试等模块，但随着物联网设备接入场景的增多，测试团队需要一套**设备模拟系统**来验证平台对各类设备的绑定、数据上报、状态监控等功能。

被测系统（统一管理平台，https://192.168.5.44）本身支持通过 MQTT 协议接入设备，但在实际测试中，物理设备资源有限、部署成本高，且无法灵活模拟异常场景。因此，需要在本测试平台中内置**设备模拟模块**，通过 MQTT 订阅/发布模拟设备行为，实现设备从注册到数据上报的全流程测试。

### 1.2 目标用户

| 用户角色 | 使用场景 | 核心需求 |
|---------|---------|---------|
| 测试工程师 | 模拟设备接入平台进行功能验证 | 快速创建模拟设备、配置 MQTT 连接、查看上报数据 |
| 开发工程师 | 调试平台设备接入逻辑 | 模拟异常设备、边界情况，验证平台处理逻辑 |
| 运维人员 | 验证平台设备管理功能 | 批量模拟设备上线/下线，验证平台稳定性 |

### 1.3 需求目标

1. **设备模拟管理**：新增"设备模拟"父级模块，包含 5 个子菜单页面，分别对应不同类型的模拟设备
2. **MQTT 通信**：通过 MQTT 协议订阅对应主题，模拟设备上报数据到配置的环境
3. **环境配置管理**：支持配置 MQTT Broker 连接参数（地址、端口、用户名、密码、主题前缀）
4. **设备类型模拟**：支持 5 种设备类型的模拟（门口屏、无纸化设备、中控设备、集控客户端）
5. **数据可视化**：实时展示设备模拟状态、上报数据记录、连接状态

---

## 二、功能需求

### 2.1 功能模块总览

```
设备模拟（父级模块，侧边栏独立菜单）
├── 环境配置          — MQTT Broker 连接配置管理
├── 门口屏模拟        — 门口屏设备模拟（门禁状态、呼叫、开锁等）
├── 无纸化模拟        — 无纸化会议设备模拟（签到、文件同步、投屏等）
├── 中控设备模拟      — 中控设备模拟（灯光、窗帘、投影控制等）
└── 集控客户端模拟    — 集控客户端模拟（设备注册、心跳、远程控制等）
```

### 2.2 环境配置

#### 功能描述

管理 MQTT Broker 连接参数，是设备模拟模块的基础配置。每个环境配置包含 Broker 地址、端口、认证信息、主题前缀等。

#### 功能清单

| 功能 | 说明 | 优先级 |
|------|------|--------|
| 新增环境配置 | 添加 MQTT Broker 连接参数（名称、地址、端口、用户名、密码、主题前缀） | P0 |
| 编辑环境配置 | 修改已有环境配置 | P0 |
| 删除环境配置 | 删除环境配置（有关联模拟设备时禁止删除） | P0 |
| 连接测试 | 测试 MQTT Broker 连接是否正常 | P0 |
| 环境列表 | 展示所有环境配置，支持状态标识（已连接/未连接/连接失败） | P0 |
| 连接状态监控 | 实时显示 MQTT 客户端连接状态 | P1 |

#### 环境配置字段

| 字段 | 类型 | 说明 |
|------|------|------|
| 配置名称 | string | 环境标识名称，如"测试环境""开发环境" |
| Broker 地址 | string | MQTT Broker IP 或域名 |
| 端口 | integer | 默认 1883（TCP）或 8883（TLS） |
| 用户名 | string | MQTT 认证用户名 |
| 密码 | string | MQTT 认证密码（加密存储） |
| 主题前缀 | string | 设备主题前缀，如 `device/platform/` |
| 使用 TLS | boolean | 是否启用 TLS 加密连接 |
| 客户端 ID 前缀 | string | MQTT 客户端 ID 前缀，用于区分不同环境 |
| 状态 | enum | 未连接 / 已连接 / 连接失败 |
| 最后连接时间 | datetime | 最近一次连接成功的时间 |

### 2.3 门口屏模拟

#### 功能描述

模拟门口屏设备，通过 MQTT 上报门口机状态（在线/离线）、门禁事件（开门/关门/异常）、呼叫记录等，并接收平台下发的开锁指令。

#### 模拟功能

| 功能 | 说明 | 优先级 |
|------|------|--------|
| 设备注册 | 模拟门口屏向平台注册（设备 ID、名称、位置、型号） | P0 |
| 状态上报 | 上报在线状态（在线/离线/维护中） | P0 |
| 门禁事件上报 | 上报开门/关门/超时未关/非法闯入等事件 | P0 |
| 呼叫记录上报 | 模拟访客呼叫、业主应答、呼叫超时等场景 | P0 |
| 接收开锁指令 | 接收平台下发的开锁指令并返回执行结果 | P0 |
| 异常场景模拟 | 模拟设备离线、通信超时、认证失败等异常 | P1 |
| 批量模拟 | 同时模拟多台门口屏设备 | P1 |

#### MQTT 主题约定

| 主题方向 | 主题格式 | 说明 |
|---------|---------|------|
| 设备上报 | `{prefix}/door/{device_id}/status` | 设备状态上报 |
| 设备上报 | `{prefix}/door/{device_id}/event` | 门禁事件上报 |
| 设备上报 | `{prefix}/door/{device_id}/call` | 呼叫记录上报 |
| 平台下发 | `{prefix}/door/{device_id}/command` | 接收平台指令 |

### 2.4 无纸化模拟

#### 功能描述

模拟无纸化会议设备，上报会议签到状态、文件同步状态、投屏状态等，测试平台对无纸化会议系统的管理功能。

#### 模拟功能

| 功能 | 说明 | 优先级 |
|------|------|--------|
| 设备注册 | 模拟无纸化终端向平台注册 | P0 |
| 签到上报 | 模拟参会人员签到/签退 | P0 |
| 文件同步状态 | 上报会议文件同步进度 | P0 |
| 投屏状态 | 模拟投屏开始/结束/异常 | P0 |
| 会议状态 | 模拟会议开始/结束/延长 | P0 |
| 设备状态 | 上报终端在线/离线/故障 | P0 |
| 异常场景模拟 | 模拟文件同步失败、投屏断开等异常 | P1 |

#### MQTT 主题约定

| 主题方向 | 主题格式 | 说明 |
|---------|---------|------|
| 设备上报 | `{prefix}/paperless/{device_id}/status` | 设备状态上报 |
| 设备上报 | `{prefix}/paperless/{device_id}/signin` | 签到状态上报 |
| 设备上报 | `{prefix}/paperless/{device_id}/file_sync` | 文件同步状态 |
| 设备上报 | `{prefix}/paperless/{device_id}/screen` | 投屏状态 |
| 平台下发 | `{prefix}/paperless/{device_id}/command` | 接收平台指令 |

### 2.5 中控设备模拟

#### 功能描述

模拟中控设备（控制灯光、窗帘、投影、空调等），上报设备状态及控制结果，接收平台下发的控制指令。

#### 模拟功能

| 功能 | 说明 | 优先级 |
|------|------|--------|
| 设备注册 | 模拟中控设备向平台注册 | P0 |
| 子设备管理 | 模拟中控下挂的子设备（灯光、窗帘、投影等） | P0 |
| 状态上报 | 上报各子设备状态（开/关、亮度、温度等） | P0 |
| 控制指令响应 | 接收平台下发的控制指令并模拟执行结果 | P0 |
| 场景联动 | 模拟场景模式切换（会议模式、演讲模式、休息模式） | P1 |
| 异常场景模拟 | 模拟子设备通信异常、控制失败等 | P1 |

#### MQTT 主题约定

| 主题方向 | 主题格式 | 说明 |
|---------|---------|------|
| 设备上报 | `{prefix}/central/{device_id}/status` | 设备状态上报 |
| 设备上报 | `{prefix}/central/{device_id}/sub_status` | 子设备状态上报 |
| 设备上报 | `{prefix}/central/{device_id}/scene` | 场景状态上报 |
| 平台下发 | `{prefix}/central/{device_id}/command` | 接收平台指令 |

### 2.6 集控客户端模拟

#### 功能描述

模拟集控客户端设备，实现设备注册、心跳保活、远程控制指令响应等，测试平台对集控客户端的管理能力。

#### 模拟功能

| 功能 | 说明 | 优先级 |
|------|------|--------|
| 设备注册 | 模拟集控客户端向平台注册 | P0 |
| 心跳上报 | 定时发送心跳包维持在线状态 | P0 |
| 远程控制响应 | 接收并响应平台下发的远程控制指令 | P0 |
| 日志上报 | 模拟客户端运行日志上报 | P0 |
| 版本上报 | 上报客户端版本信息 | P0 |
| 固件升级响应 | 模拟固件升级流程（下载、安装、重启） | P1 |
| 异常场景模拟 | 模拟心跳超时、指令执行失败等 | P1 |

#### MQTT 主题约定

| 主题方向 | 主题格式 | 说明 |
|---------|---------|------|
| 设备上报 | `{prefix}/client/{device_id}/status` | 设备状态上报 |
| 设备上报 | `{prefix}/client/{device_id}/heartbeat` | 心跳上报 |
| 设备上报 | `{prefix}/client/{device_id}/log` | 日志上报 |
| 设备上报 | `{prefix}/client/{device_id}/version` | 版本信息上报 |
| 平台下发 | `{prefix}/client/{device_id}/command` | 接收平台指令 |

### 2.7 模拟设备通用功能

所有模拟设备类型共享以下功能：

| 功能 | 说明 | 优先级 |
|------|------|--------|
| 设备创建 | 在模拟设备列表中添加新设备（设置设备 ID、名称、关联环境） | P0 |
| 设备启停 | 启动/停止模拟设备（控制 MQTT 连接和模拟任务） | P0 |
| 设备列表 | 展示所有模拟设备，支持按类型/环境筛选 | P0 |
| 设备状态 | 实时显示设备连接状态、最后上报时间、上报次数 | P0 |
| 上报记录 | 查看设备上报的历史记录（主题、内容、时间、状态） | P0 |
| 手动上报 | 手动触发指定数据上报，用于调试 | P0 |
| 自动上报策略 | 配置自动上报间隔和上报内容模板 | P1 |
| 设备删除 | 删除模拟设备及关联数据 | P0 |

### 2.8 侧边栏导航更新

在左侧导航菜单中新增"设备模拟"父级菜单，包含 5 个子菜单项：

```
设备模拟（新图标: Connection / Monitor）
├── 环境配置          → /device-sim/settings
├── 门口屏模拟        → /device-sim/door
├── 无纸化模拟        → /device-sim/paperless
├── 中控设备模拟      → /device-sim/central
└── 集控客户端模拟    → /device-sim/client
```

---

## 三、非功能需求

### 3.1 性能要求

| 指标 | 要求 |
|------|------|
| 单设备模拟启动时间 | ≤ 2 秒 |
| 并发模拟设备数 | 单环境支持 ≥ 20 台设备同时模拟 |
| 消息上报延迟 | 定时上报延迟 ≤ 500ms |
| 页面加载时间 | 列表页 ≤ 2 秒，详情页 ≤ 3 秒 |

### 3.2 可靠性要求

- MQTT 连接断开后自动重连（指数退避，最大间隔 60 秒）
- 模拟设备状态持久化，页面刷新后恢复
- 上报记录保留最近 7 天数据，自动清理过期数据

### 3.3 安全要求

- MQTT 密码加密存储（AES-256）
- 敏感配置（Broker 密码）在 API 响应中脱敏
- 模拟设备不能影响实际生产环境设备

---

## 四、数据结构

### 4.1 环境配置表（device_env_configs）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | VARCHAR(64) | 主键，UUID |
| name | VARCHAR(100) | 配置名称 |
| broker_host | VARCHAR(255) | Broker 地址 |
| broker_port | INTEGER | 端口号 |
| username | VARCHAR(100) | MQTT 用户名 |
| password_encrypted | VARCHAR(500) | 密码（加密存储） |
| topic_prefix | VARCHAR(200) | 主题前缀 |
| use_tls | BOOLEAN | 是否启用 TLS |
| client_id_prefix | VARCHAR(100) | 客户端 ID 前缀 |
| status | VARCHAR(20) | 连接状态 |
| last_connected_at | DATETIME | 最后连接时间 |
| created_at | DATETIME | 创建时间 |
| updated_at | DATETIME | 更新时间 |

### 4.2 模拟设备表（device_simulators）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | VARCHAR(64) | 主键，UUID |
| env_config_id | VARCHAR(64) | 关联环境配置 ID |
| device_type | VARCHAR(50) | 设备类型（door/paperless/central/client） |
| device_name | VARCHAR(200) | 模拟设备名称 |
| device_id | VARCHAR(200) | 模拟设备 ID（MQTT 主题中使用） |
| status | VARCHAR(20) | 运行状态（running/stopped/error） |
| auto_reconnect | BOOLEAN | 是否自动重连 |
| metadata | JSON | 设备自定义属性（型号、位置等） |
| last_reported_at | DATETIME | 最后上报时间 |
| total_reports | INTEGER | 累计上报次数 |
| created_at | DATETIME | 创建时间 |
| updated_at | DATETIME | 更新时间 |

### 4.3 上报记录表（device_report_logs）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | VARCHAR(64) | 主键，UUID |
| device_id | VARCHAR(64) | 关联模拟设备 ID |
| topic | VARCHAR(500) | MQTT 主题 |
| payload | JSON | 上报数据内容 |
| direction | VARCHAR(10) | 方向（publish/subscribe） |
| status | VARCHAR(20) | 发送状态（success/failed） |
| error_message | TEXT | 错误信息 |
| created_at | DATETIME | 创建时间 |

---

## 五、技术方案

### 5.1 技术选型

| 组件 | 技术方案 | 说明 |
|------|---------|------|
| MQTT 客户端 | `paho-mqtt` | Python 同步 MQTT 客户端库，与 Playwright 同步 API 风格一致 |
| 后台任务 | FastAPI `BackgroundTasks` + 独立线程 | 每个模拟设备使用独立线程运行 MQTT 循环 |
| 实时状态 | WebSocket + 轮询 | 设备状态变化通过 WebSocket 推送，列表页轮询 |
| 数据存储 | MySQL（生产）/ SQLite（本地） | 复用现有数据库配置 |
| 加密存储 | `cryptography` | AES-256 加密 Broker 密码 |

### 5.2 架构设计

```
┌─────────────────────────────────────────────────────────────┐
│                    设备模拟模块架构                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐   │
│  │ 前端页面      │    │ MQTT 管理器  │    │ 模拟引擎     │   │
│  │ (5个子页面)   │◄──►│ (连接池管理)  │◄──►│ (设备模拟逻辑)│   │
│  └──────────────┘    └──────────────┘    └──────┬───────┘   │
│         │                                        │          │
│         ▼                                        ▼          │
│  ┌──────────────┐                        ┌──────────────┐   │
│  │ 后端 API      │                        │  MQTT Broker  │   │
│  │ (CRUD + 控制) │                        │ (外部/内置)   │   │
│  └──────┬───────┘                        └──────────────┘   │
│         │                                        │          │
│         ▼                                        ▼          │
│  ┌──────────────┐                        ┌──────────────┐   │
│  │ 数据库        │                        │ 被测平台     │   │
│  │ (MySQL/SQLite)│                        │ (192.168.5.44)│   │
│  └──────────────┘                        └──────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

### 5.3 MQTT 管理器设计

```python
class MqttManager:
    """MQTT 连接管理器，管理到 Broker 的连接池"""

    _connections: dict[str, MqttClient]  # env_config_id -> MqttClient
    _simulators: dict[str, Simulator]    # device_id -> Simulator

    def connect(env_config_id: str, config: EnvConfig) -> bool
    def disconnect(env_config_id: str) -> None
    def subscribe(env_config_id: str, topic: str, callback) -> bool
    def publish(env_config_id: str, topic: str, payload: dict) -> bool
    def start_simulator(device_id: str, config: SimConfig) -> None
    def stop_simulator(device_id: str) -> None
```

### 5.4 模拟设备基类设计

```python
class BaseSimulator(ABC):
    """模拟设备基类，各设备类型继承此类"""

    device_id: str
    device_type: str
    mqtt_manager: MqttManager
    config: SimConfig
    _running: bool
    _thread: threading.Thread

    @abstractmethod
    def build_register_payload(self) -> dict
    @abstractmethod
    def build_status_payload(self) -> dict
    def start(self) -> None          # 启动模拟（注册 + 开始定时上报）
    def stop(self) -> None           # 停止模拟（发送离线 + 断开连接）
    def report(self, topic: str, payload: dict) -> bool  # 手动上报
    def _auto_report_loop(self)      # 定时上报循环
    def _on_command(self, topic: str, payload: dict)     # 处理平台指令
```

---

## 六、约束与限制

### 6.1 技术约束

1. **MQTT 客户端使用同步 API**：遵循项目现有规范，不使用异步 MQTT 库（与 Playwright 同步 API 风格一致）
2. **模拟设备运行在独立线程**：每个模拟设备使用独立线程运行 MQTT 循环，避免阻塞主线程
3. **复用现有数据库配置**：支持 MySQL（生产）/ SQLite（本地）自动切换
4. **前端 Element Plus 组件**：使用现有 UI 组件库，保持风格一致

### 6.2 业务约束

1. **设备 ID 唯一性**：同一环境下的模拟设备 ID 必须唯一
2. **主题前缀隔离**：不同环境使用不同的主题前缀，避免数据串扰
3. **模拟设备不影响生产**：模拟设备应使用专用测试环境，不得连接生产 MQTT Broker

---

## 七、依赖与前提

| 依赖项 | 说明 | 状态 |
|--------|------|------|
| `paho-mqtt` Python 库 | MQTT 客户端库 | 需新增依赖 |
| 被测平台 MQTT 接口文档 | 设备主题格式、数据协议 | 需确认 |
| MQTT Broker 测试环境 | 用于模拟设备连接的 Broker | 需确认/搭建 |
| `cryptography` Python 库 | 密码加密存储 | 可能已存在 |

---

## 八、验收标准

| 验收项 | 预期结果 |
|--------|---------|
| 环境配置 CRUD | 可新增/编辑/删除环境配置，支持连接测试 |
| 5 种模拟设备类型 | 每种类型可创建模拟设备并启动 |
| MQTT 连接与上报 | 模拟设备可成功连接 MQTT Broker 并上报数据 |
| 平台接收数据 | 被测平台（192.168.5.44）可接收到模拟设备上报的数据 |
| 设备状态管理 | 可启动/停止模拟设备，状态实时更新 |
| 上报记录查看 | 可查看设备上报的历史记录 |
| 页面导航 | 侧边栏新增"设备模拟"菜单，5 个子页面可正常切换 |
| 数据持久化 | 页面刷新后模拟设备列表和状态正确恢复 |
| 异常场景模拟 | 可模拟设备离线、上报失败等异常场景 |
| 批量模拟 | 单环境支持 ≥ 20 台模拟设备同时运行 |

---

## 九、工作量估算

| 阶段 | 内容 | 预计工时 |
|------|------|---------|
| 阶段一 | 数据库模型 + 后端基础 API（环境配置 CRUD） | 2 天 |
| 阶段二 | MQTT 管理器 + 模拟设备基类 | 2 天 |
| 阶段三 | 5 种设备类型模拟逻辑实现 | 3 天 |
| 阶段四 | 前端页面（5 个子页面 + 侧边栏） | 3 天 |
| 阶段五 | 上报记录 + 实时状态 + 异常场景 | 1.5 天 |
| 阶段六 | 集成测试 + 部署 | 1 天 |
| **总计** | | **12.5 天** |

---

*本文档由 Claude Code 生成，用于指导设备模拟模块的开发。*