Skip to content

Commit 2f470e5

Browse files
authored
Apply READ_ATTEMPTS to the identity read (#687)
1 parent e2466b6 commit 2f470e5

4 files changed

Lines changed: 39 additions & 3 deletions

File tree

‎src/ha_addon_sunsynk_multi/a_inverter.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,11 @@ async def lifecycle_attempt_recovery(self) -> None:
153153

154154
async def read_identity(self) -> Identity:
155155
"""Read device type, protocol, and serial via the Identity Component."""
156-
# HoldingUnit duck-types ModbusUnit for FC03; SolarmanUnit is the same shape.
157-
identity = Identity(self.inv.unit) # type: ignore[arg-type]
156+
# Read through Sunsynk, not self.inv.unit: same read_holding_registers
157+
# signature, but with READ_ATTEMPTS retries and the serial flush.
158+
# ponytail: only holds while Identity reads holding registers only. A field
159+
# in another space would need the unit's read_coils/read_input_registers.
160+
identity = Identity(self.inv) # type: ignore[arg-type]
158161
await identity.async_update()
159162
self.identity = identity
160163
return identity

‎src/sunsynk/sunsynk.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ async def read_holding_registers(self, start: int, length: int) -> Sequence[int]
183183
self.connection._params, ModbusSerialParams
184184
):
185185
await self._flush_modbus_connection(reason=type(err).__name__)
186-
except ModbusProtocolError:
186+
except ModbusProtocolError as err:
187+
errs.append(err)
187188
_LOG.error(
188189
"Read register %s x%s: protocol error [attempt %s/%s]",
189190
start,

‎src/tests/ha_addon_sunsynk_multi/test_a_inverter.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from unittest.mock import AsyncMock, MagicMock, patch
55

66
import pytest
7+
from modbus_connection import ModbusTimeoutError
78

89
from ha_addon_sunsynk_multi.a_inverter import AInverter
910
from ha_addon_sunsynk_multi.a_sensor import MQTT
@@ -289,3 +290,22 @@ async def test_connect_identity_failure_includes_cause() -> None:
289290
await ist.connect()
290291

291292
assert "solarman://192.168.5.30:50500" in str(raised.value)
293+
294+
295+
async def test_read_identity_retries_dropped_reply(state: InverterState) -> None:
296+
"""READ_ATTEMPTS must cover the identity read (regs 0-7), not only sensor reads."""
297+
unit = MagicMock()
298+
unit.read_holding_registers = AsyncMock(
299+
side_effect=[
300+
ModbusTimeoutError("no reply"),
301+
# device type 6, protocol 1.4, serial "2303218594"
302+
[6, 0, 0x0104, 0x3233, 0x3033, 0x3231, 0x3835, 0x3934],
303+
]
304+
)
305+
inv_opt = InverterOptions(modbus_id=1, ha_prefix="id", serial_nr="2303218594")
306+
ss = Sunsynk(unit=unit, port="/dev/ttyUSB0", state=state, read_attempts=3)
307+
308+
identity = await _ist(inv_opt, ss, state=state).read_identity()
309+
310+
assert unit.read_holding_registers.await_count == 2
311+
assert identity.serial == "2303218594"

‎src/tests/sunsynk/test_sunsynk.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from unittest.mock import MagicMock, call, patch
77

88
import pytest
9+
from modbus_connection import ModbusProtocolError
910

1011
from sunsynk import Sunsynk
1112
from sunsynk.rwsensors import NumberRWSensor
@@ -177,3 +178,14 @@ def rhr_side_effect(start: int, length: int) -> Sequence[int]:
177178
assert state[single] == 5
178179
assert state[pair] == 7 << 16
179180
assert state.registers == {1: 5, 10: 0, 11: 7}
181+
182+
183+
async def test_ss_protocol_error_raises_exception_group() -> None:
184+
"""Protocol errors must reach the ExceptionGroup, not leave it empty."""
185+
unit = MagicMock()
186+
unit.read_holding_registers.side_effect = ModbusProtocolError("desync")
187+
ss = Sunsynk(unit=unit, read_attempts=2) # type: ignore[arg-type]
188+
189+
with pytest.raises(ExceptionGroup) as excinfo:
190+
await ss.read_holding_registers(622, 4)
191+
assert len(excinfo.value.exceptions) == 2

0 commit comments

Comments
 (0)