Skip to content

Commit db3d965

Browse files
CIclaude
andcommitted
fix(gateway): re-send rate caps when the hub's online message arrives
_check_rate_caps() only noticed the hub was offline if a run() cycle landed while it was. A reboot after a firmware update is quicker than the gap between cycles, so the offline state was never seen and unchanged caps were not sent again - leaving a hub that had just gained the command, or lost its stored caps, without them. The online-message handler now clears what was sent on any online/offline transition. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 8a30e5b commit db3d965

2 files changed

Lines changed: 34 additions & 0 deletions

File tree

‎apps/predbat/gateway.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,10 @@ async def _handle_message(self, message):
773773
self._gateway_online = payload == "1"
774774
if self._gateway_online != was_online:
775775
self.log(f"Info: GatewayMQTT: Gateway is {'online' if self._gateway_online else 'offline'}")
776+
# A hub that has been away may be on new firmware or have lost its stored
777+
# rate caps, so send them again. Done here, not only in _check_rate_caps():
778+
# a reboot is quicker than the gap between two run() cycles.
779+
self._rate_caps_sent.clear()
776780
self.dashboard_item(
777781
f"binary_sensor.{self.prefix}_gateway_online",
778782
self._gateway_online,

‎apps/predbat/tests/test_gateway.py‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3876,6 +3876,36 @@ def test_held_while_hub_offline_and_sent_again_when_it_returns(self):
38763876
self._run(gw._check_rate_caps())
38773877
assert len(gw._published) == 2
38783878

3879+
def test_hub_restart_between_cycles_is_told_again(self):
3880+
"""A hub that goes offline and returns between two run() cycles is still re-sent its caps.
3881+
3882+
A reboot after a firmware update takes well under the 60 seconds between cycles, so
3883+
_check_rate_caps() never sees the hub offline. The online message itself must clear
3884+
what was sent.
3885+
"""
3886+
from unittest.mock import MagicMock
3887+
3888+
gw = self._make_gateway()
3889+
gw._inverter_slot_serials = ["CH2330G098"]
3890+
gw.base.inverters = [self._inverter(0, 3000, 3600)]
3891+
gw.prefix = "predbat"
3892+
gw.topic_status = "predbat/devices/pbgw_test/status"
3893+
gw.topic_online = "predbat/devices/pbgw_test/online"
3894+
gw.dashboard_item = MagicMock()
3895+
gw._error_count = 0
3896+
self._run(gw._check_rate_caps())
3897+
assert len(gw._published) == 1
3898+
3899+
for payload in (b"0", b"1"):
3900+
message = MagicMock()
3901+
message.topic = gw.topic_online
3902+
message.payload = payload
3903+
self._run(gw._handle_message(message))
3904+
3905+
self._run(gw._check_rate_caps())
3906+
assert len(gw._published) == 2
3907+
assert gw._error_count == 0
3908+
38793909
def test_nothing_sent_before_auto_config(self):
38803910
"""Until auto-config has bound slots to serials there is nothing to key a cap on."""
38813911
gw = self._make_gateway(auto_configured=False)

0 commit comments

Comments
 (0)