emcp/.trae/documents/2026-05-25-modbus-backend-refactor-plan.md

13 KiB
Raw Blame History

Modbus 新协议后端改造说明

Summary

本次改造目标是让后端完全按 显示界面modbus协议寄存器定义.md 的新版协议工作,并取消 backend/config 作为配置真值来源的角色。

本次计划确认的边界如下:

  • 只调整后端代码,不修改前端代码。
  • 配置页面首次加载时,后端需先从下位机通过 Modbus 读取参数并返回。
  • 界面保存配置时,后端只动态写入下位机,不再把配置写入 backend/config 下的 device.jsonchannel.jsonsetting.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 中协议未定义的字段(如 brightnessscreen_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 轮询链路仍能持续推送数据