329 lines
13 KiB
Markdown
329 lines
13 KiB
Markdown
|
|
# Modbus 新协议后端改造说明
|
|||
|
|
|
|||
|
|
## Summary
|
|||
|
|
|
|||
|
|
本次改造目标是让后端完全按 [显示界面modbus协议寄存器定义.md](file:///d:/Trae_space/EMCP/document/%E6%98%BE%E7%A4%BA%E7%95%8C%E9%9D%A2modbus%E5%8D%8F%E8%AE%AE%E5%AF%84%E5%AD%98%E5%99%A8%E5%AE%9A%E4%B9%89.md) 的新版协议工作,并取消 `backend/config` 作为配置真值来源的角色。
|
|||
|
|
|
|||
|
|
本次计划确认的边界如下:
|
|||
|
|
|
|||
|
|
- 只调整后端代码,不修改前端代码。
|
|||
|
|
- 配置页面首次加载时,后端需先从下位机通过 Modbus 读取参数并返回。
|
|||
|
|
- 界面保存配置时,后端只动态写入下位机,不再把配置写入 `backend/config` 下的 `device.json`、`channel.json`、`setting.json`。
|
|||
|
|
- 协议文档中没有定义寄存器的现有配置接口,本次先保留,并继续沿用原本地配置逻辑作为过渡。
|
|||
|
|
- 先生成本地说明文档,用户确认后再开始改代码。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Current State Analysis
|
|||
|
|
|
|||
|
|
### 1. 当前接口层现状
|
|||
|
|
|
|||
|
|
当前配置接口集中在 `backend/app/api/routes/config.py`:
|
|||
|
|
|
|||
|
|
- 保留协议可能覆盖的接口:
|
|||
|
|
- `GET/POST /api/config/channel`
|
|||
|
|
- `GET/POST /api/config/line_alarm_setting`
|
|||
|
|
- `GET/POST /api/config/ai_alarm_setting`
|
|||
|
|
- `GET/POST /api/config/system`
|
|||
|
|
- 当前存在但新版协议未覆盖的接口:
|
|||
|
|
- `GET/POST /api/config/device`
|
|||
|
|
- `POST /api/config/device/password`
|
|||
|
|
- `GET/POST /api/config/device/net`
|
|||
|
|
- `GET/POST /api/config/device/uart`
|
|||
|
|
|
|||
|
|
根据用户本轮决策,上述“协议未定义寄存器”的配置接口在本次后端改造先保留,并继续沿用原有本地配置文件逻辑。
|
|||
|
|
|
|||
|
|
### 2. 当前业务层现状
|
|||
|
|
|
|||
|
|
当前业务主要集中在 `backend/app/services/platform_service.py`,存在两个关键问题:
|
|||
|
|
|
|||
|
|
- 配置读取默认来自本地 JSON:
|
|||
|
|
- `get_device_config()`
|
|||
|
|
- `get_channel_config()`
|
|||
|
|
- `get_line_alarm_setting()`
|
|||
|
|
- `get_ai_alarm_setting()`
|
|||
|
|
- `get_system_config()`
|
|||
|
|
- 配置保存采用“先写本地 JSON,再下发设备”的双写模式:
|
|||
|
|
- `save_device_config()`
|
|||
|
|
- `save_channel_config()`
|
|||
|
|
- `save_line_alarm_setting()`
|
|||
|
|
- `save_ai_alarm_setting()`
|
|||
|
|
- `save_system_config()`
|
|||
|
|
|
|||
|
|
这与“首次从下位机读取显示、保存时只写下位机、不再落本地配置文件”的新需求直接冲突。
|
|||
|
|
|
|||
|
|
此外,实时数据一次值计算当前仍依赖 `setting.json -> line_alarm_setting[].transformer_change[]` 中的 PT/CT 变比;如果配置文件取消真值角色,则这部分变比来源也必须切到设备回读数据。
|
|||
|
|
|
|||
|
|
### 3. 当前设备适配层现状
|
|||
|
|
|
|||
|
|
真实 Modbus 设备适配集中在 `backend/app/adapters/device_client.py`,当前实现与新版协议的差异点如下:
|
|||
|
|
|
|||
|
|
- 已符合或基本可复用:
|
|||
|
|
- 四路实时数据输入寄存器读取
|
|||
|
|
- AI 输入 `0x00D0 ~ 0x00DE`
|
|||
|
|
- B 码对时 `0x00E0 ~ 0x00E2`
|
|||
|
|
- 开入读取 `0x00E3`
|
|||
|
|
- 开出线圈写 `0x0F`
|
|||
|
|
- 系统时间同步 `0x0000`
|
|||
|
|
- 明显不符合新版协议:
|
|||
|
|
- 当前事件总寄存器仍按旧逻辑读取 `0x00E4`,新版应为 `0x00E5`
|
|||
|
|
- 当前“读事件”按旧逻辑读保持寄存器 `0x0000 ~ 0x0003`,新版应改为读输入寄存器 `0x0100`,长度 `5 * n`
|
|||
|
|
- 当前 AI/AO/AI 报警写入地址仍是旧版:
|
|||
|
|
- AI 通道:`0x004C`,新版应为 `0x0054`
|
|||
|
|
- AO 通道:`0x006A`,新版应为 `0x0072`
|
|||
|
|
- AI 报警:`0x0088`,新版应为 `0x0090`
|
|||
|
|
- 当前线路定值写入长度按 14 寄存器/每路处理,未包含 2 个变比参数;新版总长度为 64,并明确包含变比参数
|
|||
|
|
- 当前没有“参数区回读”能力,只有写寄存器,没有从设备读取参数区并还原为 API 返回结构
|
|||
|
|
|
|||
|
|
### 4. 当前配置仓储现状
|
|||
|
|
|
|||
|
|
`backend/app/repositories/json_config_repo.py` 目前负责:
|
|||
|
|
|
|||
|
|
- 写 `device.json`
|
|||
|
|
- 写 `channel.json`
|
|||
|
|
- 写 `setting.json`
|
|||
|
|
- 读上述 JSON 作为配置真值
|
|||
|
|
|
|||
|
|
按照本次需求,`backend/config` 中的配置文件不再承担运行期配置真值角色;对应仓储将不再被配置接口和业务服务依赖,只能保留给极少数非配置场景,或在后续整理中弱化/下线。
|
|||
|
|
|
|||
|
|
### 5. 当前测试现状
|
|||
|
|
|
|||
|
|
- `backend/tests/test_api.py` 大量依赖本地 JSON 写入与读取断言
|
|||
|
|
- `backend/tests/test_modbus_client.py` 使用 FakeTransport 验证旧版寄存器地址、旧版事件读取方式和旧版参数写入地址
|
|||
|
|
|
|||
|
|
这些测试在本次改造后会大面积失效,必须同步调整。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Proposed Changes
|
|||
|
|
|
|||
|
|
### 1. 调整配置接口边界
|
|||
|
|
|
|||
|
|
#### 文件
|
|||
|
|
|
|||
|
|
- `backend/app/api/routes/config.py`
|
|||
|
|
|
|||
|
|
#### 改动内容
|
|||
|
|
|
|||
|
|
- 保留并继续支持的接口分为两类:
|
|||
|
|
- **按新版协议改造为纯 Modbus 真值**:
|
|||
|
|
- `GET/POST /api/config/channel`
|
|||
|
|
- `GET/POST /api/config/line_alarm_setting`
|
|||
|
|
- `GET/POST /api/config/ai_alarm_setting`
|
|||
|
|
- `GET/POST /api/config/system`
|
|||
|
|
- **协议未定义寄存器、先保留原本地逻辑**:
|
|||
|
|
- `GET/POST /api/config/device`
|
|||
|
|
- `POST /api/config/device/password`
|
|||
|
|
- `GET/POST /api/config/device/net`
|
|||
|
|
- `GET/POST /api/config/device/uart`
|
|||
|
|
|
|||
|
|
#### 原因
|
|||
|
|
|
|||
|
|
- 新协议文档已覆盖的配置项,需切换为“设备寄存器即真值”
|
|||
|
|
- 新协议文档未覆盖的配置项,用户明确要求先保留接口,避免立即影响现有前端调用
|
|||
|
|
- 这些未定义项本轮继续沿用本地配置文件逻辑,待后续协议补齐后再迁移
|
|||
|
|
|
|||
|
|
### 2. 配置读取改为“首次从下位机读”
|
|||
|
|
|
|||
|
|
#### 文件
|
|||
|
|
|
|||
|
|
- `backend/app/services/platform_service.py`
|
|||
|
|
- `backend/app/adapters/device_client.py`
|
|||
|
|
|
|||
|
|
#### 改动内容
|
|||
|
|
|
|||
|
|
- 移除 `get_channel_config()` 对 `channel.json` 的依赖,改为调用设备侧“参数区回读”能力
|
|||
|
|
- 移除 `get_line_alarm_setting()` 对 `setting.json` 的依赖,改为读取线路定值寄存器并按 `line_no` 解析
|
|||
|
|
- 移除 `get_ai_alarm_setting()` 对 `setting.json` 的依赖,改为读取 AI 报警寄存器并还原 API 结构
|
|||
|
|
- 移除 `get_system_config()` 对 `setting.json` 的依赖,改为从设备读取可回读的系统参数
|
|||
|
|
- PT/CT 变比不再从 `setting.json` 读取,而改为从线路定值寄存器回读结果中提取
|
|||
|
|
|
|||
|
|
#### 原因
|
|||
|
|
|
|||
|
|
- 配置页面首次加载必须从下位机读取显示
|
|||
|
|
- `backend/config` 不再保存配置真值
|
|||
|
|
|
|||
|
|
### 3. 配置保存改为“只写下位机,不写本地 JSON”
|
|||
|
|
|
|||
|
|
#### 文件
|
|||
|
|
|
|||
|
|
- `backend/app/services/platform_service.py`
|
|||
|
|
- `backend/app/repositories/json_config_repo.py`
|
|||
|
|
|
|||
|
|
#### 改动内容
|
|||
|
|
|
|||
|
|
- 删除以下方法中的本地 JSON 写入逻辑:
|
|||
|
|
- `save_channel_config()`
|
|||
|
|
- `save_line_alarm_setting()`
|
|||
|
|
- `save_ai_alarm_setting()`
|
|||
|
|
- `save_system_config()`
|
|||
|
|
- 返回值改为仅描述 Modbus 写入结果,不再返回本地 `save_path`
|
|||
|
|
- 业务层不再把配置结果回写 `channel.json` / `setting.json`
|
|||
|
|
- `JsonConfigRepository` 不再作为上述“协议已定义项”的运行期依赖
|
|||
|
|
- `device/device password/device net/device uart` 相关接口暂不纳入此调整,仍继续使用本地配置文件逻辑
|
|||
|
|
|
|||
|
|
#### 原因
|
|||
|
|
|
|||
|
|
- 用户已明确要求取消本地配置文件落盘
|
|||
|
|
- 配置应以设备当前寄存器值为唯一真值
|
|||
|
|
|
|||
|
|
### 4. 按新版协议更新寄存器地址和事件机制
|
|||
|
|
|
|||
|
|
#### 文件
|
|||
|
|
|
|||
|
|
- `backend/app/adapters/device_client.py`
|
|||
|
|
|
|||
|
|
#### 改动内容
|
|||
|
|
|
|||
|
|
- 更新常量地址:
|
|||
|
|
- 事件总寄存器:由旧值改为 `0x00E5`
|
|||
|
|
- 读事件起始地址:改为 `0x0100`
|
|||
|
|
- AI 通道写入起始地址:改为 `0x0054`
|
|||
|
|
- AO 通道写入起始地址:改为 `0x0072`
|
|||
|
|
- AI 报警写入起始地址:改为 `0x0090`
|
|||
|
|
- 新增/修改事件读取实现:
|
|||
|
|
- 先读 `0x00E5`
|
|||
|
|
- 若值为 `n > 0`,按 `0x04 + 0x0100 + 5*n` 读取输入寄存器
|
|||
|
|
- 解析事件结构:时间戳、毫秒、线路号、事件类型、事件代码、动作值
|
|||
|
|
- 读完后通过 `0x03 + 0x0100 + n` 发送“读事件成功回复”
|
|||
|
|
- 新增/修改事件映射逻辑:
|
|||
|
|
- 保护类
|
|||
|
|
- 动作类
|
|||
|
|
- 报警类
|
|||
|
|
- 操作类
|
|||
|
|
- AI 越限类
|
|||
|
|
|
|||
|
|
#### 原因
|
|||
|
|
|
|||
|
|
- 当前事件实现仍停留在旧协议,和最新文档不一致
|
|||
|
|
|
|||
|
|
### 5. 补齐参数区回读能力
|
|||
|
|
|
|||
|
|
#### 文件
|
|||
|
|
|
|||
|
|
- `backend/app/adapters/device_client.py`
|
|||
|
|
- `backend/app/services/platform_service.py`
|
|||
|
|
- `backend/app/schemas/platform.py`
|
|||
|
|
|
|||
|
|
#### 改动内容
|
|||
|
|
|
|||
|
|
- 在 `device_client.py` 中新增参数回读方法,例如:
|
|||
|
|
- 读取串口设置寄存器块
|
|||
|
|
- 读取线路定值设置寄存器块
|
|||
|
|
- 读取 AI 通道设置寄存器块
|
|||
|
|
- 读取 AO 通道设置寄存器块
|
|||
|
|
- 读取 AI 报警设置寄存器块
|
|||
|
|
- 读取系统设置寄存器块(仅限协议已定义项)
|
|||
|
|
- 将回读寄存器块解析成后端当前接口使用的结构:
|
|||
|
|
- `ChannelConfigIn`
|
|||
|
|
- `LineAlarmSettingIn`
|
|||
|
|
- `AiAlarmSettingIn`
|
|||
|
|
- `SystemConfigIn` 的可支持子集
|
|||
|
|
- 根据新版协议更新线路定值寄存器长度与解析方式:
|
|||
|
|
- 从原先 7 类规则扩展到包含 2 个变比参数
|
|||
|
|
- PT/CT 变比参与一次值换算
|
|||
|
|
|
|||
|
|
#### 原因
|
|||
|
|
|
|||
|
|
- 没有回读能力,就无法满足“参数页首次加载先从下位机读取显示”
|
|||
|
|
|
|||
|
|
### 6. 处理不再受协议支持的字段
|
|||
|
|
|
|||
|
|
#### 文件
|
|||
|
|
|
|||
|
|
- `backend/app/schemas/platform.py`
|
|||
|
|
- `backend/app/services/platform_service.py`
|
|||
|
|
- `backend/app/api/routes/config.py`
|
|||
|
|
|
|||
|
|
#### 改动内容
|
|||
|
|
|
|||
|
|
- 识别协议未覆盖字段并做“分层处理”
|
|||
|
|
- 对 `SystemConfigIn` 中协议未定义的字段(如 `brightness`、`screen_saver`)进行重新评估:
|
|||
|
|
- 若协议无寄存器,则从“纯 Modbus 真值范围”中剥离
|
|||
|
|
- `GET/POST /config/system` 需按协议实际可支持字段精简或拆分
|
|||
|
|
- 对历史仅本地保存的密码、网卡、版本号等结构:
|
|||
|
|
- 本轮不从后端 API 中移除
|
|||
|
|
- 继续保留 schema 与接口
|
|||
|
|
- 继续沿用本地配置文件逻辑作为兼容过渡
|
|||
|
|
- 在计划与代码实现中明确区分两类配置:
|
|||
|
|
- 协议已定义项:首次回读设备、保存只写设备、不落本地
|
|||
|
|
- 协议未定义项:接口先保留,继续本地逻辑
|
|||
|
|
|
|||
|
|
#### 原因
|
|||
|
|
|
|||
|
|
- 用户已确认:协议未定义寄存器的配置接口先保留,不直接移除,并继续沿用原本地配置逻辑
|
|||
|
|
|
|||
|
|
### 7. 重写测试,验证“纯设备真值”模式
|
|||
|
|
|
|||
|
|
#### 文件
|
|||
|
|
|
|||
|
|
- `backend/tests/test_modbus_client.py`
|
|||
|
|
- `backend/tests/test_api.py`
|
|||
|
|
|
|||
|
|
#### 改动内容
|
|||
|
|
|
|||
|
|
- 更新 `test_modbus_client.py`:
|
|||
|
|
- 使用新版地址与长度断言
|
|||
|
|
- 验证事件总寄存器 `0x00E5`
|
|||
|
|
- 验证“读事件内容 `0x0100` + 成功回复 `0x0100`”完整链路
|
|||
|
|
- 验证 AI/AO/AI报警新地址
|
|||
|
|
- 验证线路定值包含变比参数
|
|||
|
|
- 更新 `test_api.py`:
|
|||
|
|
- 删除“协议已定义项”对本地 JSON 写入/读取的依赖型断言
|
|||
|
|
- 改成 Mock/Stub 设备回读数据断言
|
|||
|
|
- 增加“首次 GET 来自设备回读、POST 只触发设备写入”的测试
|
|||
|
|
- 保留“协议未定义接口”的现有本地逻辑测试,或按兼容过渡方式调整断言
|
|||
|
|
|
|||
|
|
#### 原因
|
|||
|
|
|
|||
|
|
- 当前测试体系大量基于本地 JSON 真值,必须同步迁移
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Assumptions & Decisions
|
|||
|
|
|
|||
|
|
### 已确认决策
|
|||
|
|
|
|||
|
|
- 只修改后端,前端本次不动
|
|||
|
|
- 按新版协议文档改后端 Modbus 行为
|
|||
|
|
- `backend/config` 不再保存配置参数真值
|
|||
|
|
- 参数页面首次加载时,后端先从下位机读取显示
|
|||
|
|
- 配置保存时,后端只动态写入下位机
|
|||
|
|
- 协议未定义寄存器的现有配置接口,本次先保留
|
|||
|
|
- 协议未定义寄存器的现有配置接口,本次继续沿用原本地配置逻辑
|
|||
|
|
|
|||
|
|
### 当前计划中的实现假设
|
|||
|
|
|
|||
|
|
1. `line_alarm_setting` 中的 2 个变比参数可映射到现有 `transformer_change` 结构,或需在 schema 中进一步显式化为 PT/CT 变比字段。
|
|||
|
|
2. `system` 配置若协议只定义时间同步,则该接口最终可能会缩减为仅时间设置相关能力。
|
|||
|
|
3. 实时数据一次值计算仍由后端负责,但 PT/CT 变比来源将变更为设备回读参数,而非本地 JSON。
|
|||
|
|
4. `json_config_repo.py` 会退出“协议已定义项”的配置主链路,但仍保留给协议未定义接口使用。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Verification Steps
|
|||
|
|
|
|||
|
|
1. 代码层验证
|
|||
|
|
- 协议已定义项的配置 GET 接口都不再访问 `backend/config/*.json`
|
|||
|
|
- 协议已定义项的配置 POST 接口都不再写本地 JSON
|
|||
|
|
- `device_client.py` 的寄存器常量与新版文档一致
|
|||
|
|
|
|||
|
|
2. 自动化测试验证
|
|||
|
|
- `backend/tests/test_modbus_client.py` 通过
|
|||
|
|
- `backend/tests/test_api.py` 通过
|
|||
|
|
- 删除或更新“协议已定义项”依赖本地配置文件真值的旧断言
|
|||
|
|
- 保留或改造“协议未定义项”的本地逻辑断言
|
|||
|
|
|
|||
|
|
3. 联调验证
|
|||
|
|
- 手工调用协议已定义项的配置 GET 接口时,能从下位机回读数据
|
|||
|
|
- 手工调用协议已定义项的配置 POST 接口时,只触发 Modbus 写,不产生本地配置文件变更
|
|||
|
|
- 手工调用协议未定义项接口时,仍保持当前本地逻辑可用
|
|||
|
|
- 事件轮询流程符合:
|
|||
|
|
- 轮询 `0x00E5`
|
|||
|
|
- 读 `0x0100`
|
|||
|
|
- 成功回复 `0x0100`
|
|||
|
|
|
|||
|
|
4. 回归验证
|
|||
|
|
- 实时数据、设备状态、报警历史、开出控制功能不因本次改造而退化
|
|||
|
|
- WebSocket 轮询链路仍能持续推送数据
|