Skip to content

Commit 5d13100

Browse files
committed
driver
1 parent 07ad7b3 commit 5d13100

4 files changed

Lines changed: 84 additions & 33 deletions

File tree

‎hass-addon-sunsynk-edge/CHANGELOG.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
All items below are changes since add-on **1.0.0** (stable release on GitHub `main`).
88

9+
- **Breaking:** leftover `DRIVER` is no longer ignored — startup fails until it is removed. `tcp://`
10+
plus a non-zero `DONGLE_SERIAL_NUMBER` still remaps to `solarman://`; a dongle serial with a
11+
serial device path fails instead of warning.
912
- **Breaking:** `power_flow_card` no longer includes per-MPPT live sensors (`pv1_power`, etc.). It
1013
still includes `pv_power` (dynamic total). Add `pv1`–`pv8` for the trackers you want.
1114
- Sensor groups `pv1`–`pv8` include that MPPT's `pvN_power`, `pvN_current` and `pvN_voltage`.

‎src/ha_addon_sunsynk_multi/options.py‎

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ class InverterOptions:
5656
dongle_serial_number: int = 0
5757

5858

59+
DRIVER_ERROR_MSG = (
60+
"DRIVER is obsolete; remove it and use PORT schemes "
61+
"(tcp://, serial-tcp://, udp://, /dev/..., or solarman://)."
62+
)
63+
64+
5965
@dataclass
6066
class Options(MQTTOptions):
6167
"""HASS Addon Options."""
@@ -90,28 +96,18 @@ async def init_addon(self) -> None:
9096
await super().init_addon()
9197
logging.addLevelName(LOG_TRACE, "TRACE")
9298

93-
global_solarman = self.driver == "solarman"
9499
if self.driver:
95-
_LOG.warning(
96-
"DRIVER is obsolete and ignored; use PORT schemes "
97-
"(tcp://, serial-tcp://, udp://, /dev/..., or solarman://). "
98-
"Got DRIVER=%r",
99-
self.driver,
100-
)
101-
self.driver = ""
100+
_LOG.error(DRIVER_ERROR_MSG)
101+
raise ValueError(DRIVER_ERROR_MSG)
102102

103103
for inv in self.inverters:
104104
inv.ha_prefix = slug(inv.ha_prefix.strip())
105+
if not inv.ha_prefix:
106+
raise ValueError(f"Inverter {inv.serial_nr}: HA_PREFIX is required")
105107

106-
inv_solarman = inv.driver == "solarman"
107108
if inv.driver:
108-
_LOG.warning(
109-
"%s: per-inverter DRIVER is obsolete and ignored "
110-
"(got %r); use PORT: solarman://... for Solarman",
111-
inv.ha_prefix or inv.serial_nr,
112-
inv.driver,
113-
)
114-
inv.driver = ""
109+
_LOG.error(DRIVER_ERROR_MSG)
110+
raise ValueError(DRIVER_ERROR_MSG)
115111

116112
if inv.port:
117113
normalized = _normalize_legacy_port(inv.port)
@@ -124,21 +120,17 @@ async def init_addon(self) -> None:
124120
)
125121
inv.port = normalized
126122

127-
want_solarman = (
128-
is_solarman_port(inv.port)
129-
or inv_solarman
130-
or global_solarman
131-
or bool(inv.dongle_serial_number)
132-
)
133-
if want_solarman and inv.port and not is_solarman_port(inv.port):
123+
if is_solarman_port(inv.port) or bool(inv.dongle_serial_number):
134124
try:
135125
rewritten = as_solarman_port(inv.port)
136126
except ValueError as err:
137-
_LOG.warning("%s: %s", inv.ha_prefix or inv.serial_nr, err)
138-
else:
127+
raise ValueError(
128+
f"{inv.ha_prefix or inv.serial_nr}: {err}"
129+
) from err
130+
if rewritten != inv.port:
139131
_LOG.warning(
140132
"%s: Remapped PORT %r to %r "
141-
"(use solarman:// and DONGLE_SERIAL_NUMBER; DRIVER is obsolete)",
133+
"(use solarman:// and DONGLE_SERIAL_NUMBER)",
142134
inv.ha_prefix or inv.serial_nr,
143135
inv.port,
144136
rewritten,

‎src/tests/ha_addon_sunsynk_multi/test_options.py‎

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ def test_load_env_bad() -> None:
5353

5454
@patch("ha_addon_sunsynk_multi.options.MQTTOptions.init_addon")
5555
async def test_legacy_port_migration(mock_init: MagicMock) -> None:
56-
"""Legacy DRIVER / serial:// / tcp+dongle migrate via PORT schemes."""
56+
"""Legacy serial:// and tcp+dongle migrate via PORT schemes."""
57+
OPT.driver = ""
5758
OPT.load_dict(
5859
{
59-
"driver": "pymodbus",
6060
"inverters": [
6161
{
6262
"ha_prefix": "inv1",
@@ -71,7 +71,6 @@ async def test_legacy_port_migration(mock_init: MagicMock) -> None:
7171

7272
OPT.load_dict(
7373
{
74-
"driver": "solarman",
7574
"inverters": [
7675
{
7776
"ha_prefix": "inv1",
@@ -90,9 +89,9 @@ async def test_legacy_port_migration(mock_init: MagicMock) -> None:
9089
"inverters": [
9190
{
9291
"ha_prefix": "inv1",
93-
"port": "tcp://192.168.1.182:8899",
92+
"port": "solarman://192.168.1.182:8899",
9493
"serial_nr": "1",
95-
"dongle_serial_number": 99,
94+
"dongle_serial_number": 1,
9695
}
9796
],
9897
}
@@ -101,9 +100,66 @@ async def test_legacy_port_migration(mock_init: MagicMock) -> None:
101100
assert OPT.inverters[0].port == "solarman://192.168.1.182:8899"
102101

103102

103+
@patch("ha_addon_sunsynk_multi.options.MQTTOptions.init_addon")
104+
async def test_init_addon_rejects_incorrect_config(mock_init: MagicMock) -> None:
105+
"""DRIVER, empty HA_PREFIX, and unusable Solarman PORT fail startup."""
106+
OPT.load_dict(
107+
{
108+
"driver": "pymodbus",
109+
"inverters": [
110+
{"ha_prefix": "inv1", "port": "/dev/ttyUSB0", "serial_nr": "1"}
111+
],
112+
}
113+
)
114+
with pytest.raises(ValueError, match="DRIVER is obsolete"):
115+
await OPT.init_addon()
116+
117+
OPT.driver = ""
118+
OPT.load_dict(
119+
{
120+
"inverters": [
121+
{
122+
"ha_prefix": "inv1",
123+
"port": "/dev/ttyUSB0",
124+
"serial_nr": "1",
125+
"driver": "solarman",
126+
}
127+
],
128+
}
129+
)
130+
with pytest.raises(ValueError, match="DRIVER is obsolete"):
131+
await OPT.init_addon()
132+
133+
OPT.load_dict(
134+
{
135+
"inverters": [
136+
{"ha_prefix": "", "port": "tcp://192.168.1.1:502", "serial_nr": "1"}
137+
],
138+
}
139+
)
140+
with pytest.raises(ValueError, match="HA_PREFIX is required"):
141+
await OPT.init_addon()
142+
143+
OPT.load_dict(
144+
{
145+
"inverters": [
146+
{
147+
"ha_prefix": "inv1",
148+
"port": "/dev/ttyUSB0",
149+
"serial_nr": "1",
150+
"dongle_serial_number": 99,
151+
}
152+
],
153+
}
154+
)
155+
with pytest.raises(ValueError, match="Cannot use Solarman"):
156+
await OPT.init_addon()
157+
158+
104159
@patch("ha_addon_sunsynk_multi.options.MQTTOptions.init_addon")
105160
async def test_unique(mock_init: MagicMock) -> None:
106161
"""Tests."""
162+
OPT.driver = ""
107163
invs = [
108164
{"ha_prefix": "inv1", "port": "a"},
109165
{"ha_prefix": "inv2", "port": "b"},

‎www/docs/reference/multi-options.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ The transport is selected by the `PORT` URL scheme:
6262

6363
Reduce read frequency for Solarman — see [Schedules](./schedules).
6464

65-
Legacy configs with `DRIVER: solarman` and `PORT: tcp://...` (or a non-zero
66-
`DONGLE_SERIAL_NUMBER`) are remapped to `solarman://` at startup.
65+
A non-zero `DONGLE_SERIAL_NUMBER` with `tcp://host` is remapped to `solarman://`. `DRIVER` is
66+
obsolete; the add-on will not start if it is still set.
6767
:::
6868
::: tip Shared RS485 bus (one connector, many inverters)
6969
You can repeat the **same** `PORT` value for **multiple** `INVERTERS` entries. Each inverter still

0 commit comments

Comments
 (0)