- Decode SlaveError (reg 0x0BC5) with full table (codes 0-10) into new
slaveErrorMessage state; code 04 (WiFi reconnect) also surfaces in
statusMessage for immediate SAV visibility.
- Add L1/L2/L3 phase powers (regs 0x0BD9-0x0BDB, confirmed hw) as
diagnostic states polled every 30 s.
- Add RegChargeTime (0x0BC6) to enum for completeness (not yet exposed).
- Collapse debian/changelog to single 1.15.0+etm1 entry (new plugin).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Architecture choice: separate the register map / business logic from the
physical transport. TrydanModbusMaster (abstract QObject) holds:
- the complete ReadRegister / WriteRegister enums with addresses
- float32 Big/Big decode helpers (memcpy pattern, matches pymodbus
BinaryPayloadDecoder byteorder=Endian.Big wordorder=Endian.Big)
- all last-polled cached values accessible via simple getters
TrydanModbusTcpMaster (concrete, Étape 1) wraps libnymea-modbus
ModbusTcpMaster. Each register read is a distinct FC3(addr, 2)
transaction via a recursive runReadSequence/doNextRead pattern —
never a block read, because the V2C firmware's register windows
overlap (0x0BC2 and 0x0BC3 each span 2 registers, so a range read
starting at 0x0BC2 for ≥3 registers returns garbage for the second
value). Writes use FC6 (single uint16, not float).
writeCompleted(quint16 address, bool success) carries the originating
register address so that concurrent background writes (e.g. PauseDynamic
from the conflict manager firing during an action) do not interfere with
action handlers waiting on a specific register's acknowledgement.
0x177E (Dynamic) is intentionally absent from WriteRegister: writing it
to 0 silences ChargePower telemetry even though the charger keeps running.
cf. evcc charger/trydan.go and github.com/evcc-io/evcc/issues/28047.
Étape 2 (RTU) will add TrydanModbusRtuMaster on the same interface;
no changes to plugin or register logic will be required.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>