Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions apps/predbat/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,9 @@ def automatic_config(self):
discharge_enable_entities = []
export_limit_entities = []
inverter_limit_entities = []
battery_scaling_entities = []
battery_rate_max_entities = []
inverter_time_entities = []

for inv in inverters:
suffix = inv.serial[-6:].lower()
Expand Down Expand Up @@ -1323,6 +1326,10 @@ def automatic_config(self):
self.log(f"Warn: GatewayMQTT: inverter {inv.serial} has no battery capacity, setting to None for automatic discovery")

inverter_limit_entities.append(f"sensor.{base}_inverter_rate_max")
battery_scaling_entities.append(f"sensor.{base}_battery_dod")
battery_rate_max_entities.append(f"sensor.{base}_battery_rate_max")
# Clock drift detection — uses GatewayStatus.timestamp
inverter_time_entities.append(f"sensor.{base}_inverter_time")

# Map entity lists to PredBat args
self.set_arg("soc_percent", soc_entities)
Expand Down Expand Up @@ -1355,13 +1362,11 @@ def automatic_config(self):

# Battery health (first inverter)
self.set_arg("battery_temperature_history", f"sensor.{base0}_battery_temperature")
self.set_arg("battery_scaling", [f"sensor.{base0}_battery_dod"])

# Battery rate max
self.set_arg("battery_rate_max", [f"sensor.{base0}_battery_rate_max"])

# Inverter time (clock drift detection — uses GatewayStatus.timestamp)
self.set_arg("inverter_time", [f"sensor.{base0}_inverter_time"])
# Per-inverter: inverter.py reads these at index=self.id, so each needs one entry per inverter
self.set_arg("battery_scaling", battery_scaling_entities)
self.set_arg("battery_rate_max", battery_rate_max_entities)
self.set_arg("inverter_time", inverter_time_entities)

# EMS aggregate entities (GivEnergy EMS only)
inv0 = inverters[0]
Expand Down
22 changes: 22 additions & 0 deletions apps/predbat/tests/test_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,28 @@ def test_multi_inverter_produces_multiple_entity_lists(self):
assert "000aa1" in gw._args["soc_percent"][0]
assert "000bb2" in gw._args["soc_percent"][1]

def test_multi_inverter_battery_args_have_one_entry_per_inverter(self):
"""battery_scaling, battery_rate_max and inverter_time are per-inverter args, so each gets one entry per primary inverter.

A single entry leaves inverter 1 reading index 1 out of range: PredBat falls back to a 2600 W battery_rate_max
and 1.0 battery_scaling, and never checks that inverter's clock.
"""
gw = self._make_gateway()
status = pb.GatewayStatus()
status.device_id = "pbgw_multi"
status.firmware = "1.0.0"
status.schema_version = 1
self._make_inverter(status, serial="CE2223G800", primary=True)
self._make_inverter(status, serial="CE2225G400", primary=True)
gw._last_status = status
gw.automatic_config()

base0 = f"{gw.prefix}_gateway_23g800"
base1 = f"{gw.prefix}_gateway_25g400"
assert gw._args["battery_scaling"] == [f"sensor.{base0}_battery_dod", f"sensor.{base1}_battery_dod"]
assert gw._args["battery_rate_max"] == [f"sensor.{base0}_battery_rate_max", f"sensor.{base1}_battery_rate_max"]
assert gw._args["inverter_time"] == [f"sensor.{base0}_inverter_time", f"sensor.{base1}_inverter_time"]

# ------------------------------------------------------------------
# Secondary (cloud) and unsupported feature args
# ------------------------------------------------------------------
Expand Down
Loading