feat(modbus): add DDSU666 profile and select read function code per profile
frontend / frontend (push) Successful in 2m21s
pytest / test (push) Successful in 9m50s
docker-image / build-and-push (push) Successful in 4m24s

- Add CHINT DDSU666 profile (ddsu666.yaml): FC03 holding registers, voltage/
  current/active power (kW)/reactive power (kvar)/PF/frequency, import+export
  active energy. Word/byte order left at big-endian as a documented best guess
  (manual has no float example) — to be confirmed on-device.
- Add DDSU666-Modbus-Protocol.md reference extracted from the official manual,
  plus the source PDF (parity with the SDM120 reference).
- Generalize driver.read_blocks to dispatch FC03 (holding) or FC04 (input)
  based on a function_code argument (default 4, SDM120 behaviour unchanged);
  the code is validated before any connection is attempted.
- Wire profile.function_code through the CLI read command, the background
  poller, and the device /test endpoint — previously the profile field was
  declared but never honoured (read path was hardcoded to FC04).
- Tests: default -> FC04, function_code=3 -> FC03 holding, invalid FC rejected
  before connecting.
This commit is contained in:
2026-06-30 17:16:25 +02:00
parent f2e8f6a8e7
commit 3e04b15656
8 changed files with 368 additions and 7 deletions
+2 -1
View File
@@ -131,6 +131,7 @@ def cmd_read(args: argparse.Namespace) -> None:
print(f"Profile : {profile.name}{profile.description}")
print(f"Gateway : {host}:{port} unit_id={unit_id}")
print(f"Function : FC{profile.function_code:02d}")
print(f"Blocks : {[(b.start, b.count) for b in profile.blocks]}")
print()
@@ -141,7 +142,7 @@ def cmd_read(args: argparse.Namespace) -> None:
from app.integrations.modbus.driver import read_blocks
try:
registers = read_blocks(host, port, unit_id, blocks)
registers = read_blocks(host, port, unit_id, blocks, function_code=profile.function_code)
except ModbusConnectionError as exc:
print(f"Connection error: {exc}", file=sys.stderr)
sys.exit(1)