Skip to content

Commit

Permalink
Send more ping pong events (#1295)
Browse files Browse the repository at this point in the history
* Send more ping pong events

* Update const.py

* Update test_central.py
  • Loading branch information
SukramJ authored Nov 19, 2023
1 parent 4a9e2ef commit be39ffd
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 52 deletions.
4 changes: 2 additions & 2 deletions hahomematic/caches/dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def check_pending_pongs(self) -> bool:
"""Check, if store contains too many pending pongs."""
with self._sema:
dt_now = datetime.now()
for ping_ts in self._pending_pongs:
for ping_ts in list(self._pending_pongs):
delta = dt_now - ping_ts
if delta.seconds > self._ttl:
self._pending_pongs.remove(ping_ts)
Expand All @@ -267,7 +267,7 @@ def check_unknown_pongs(self) -> bool:
"""Check, if store contains too many unknown pongs."""
with self._sema:
dt_now = datetime.now()
for pong_ts in self._unknown_pongs:
for pong_ts in list(self._unknown_pongs):
delta = dt_now - pong_ts
if delta.seconds > self._ttl:
self._unknown_pongs.remove(pong_ts)
Expand Down
68 changes: 35 additions & 33 deletions hahomematic/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ def __init__(self, client_config: _ClientConfig) -> None:
self._is_callback_alive: bool = True
self.last_updated: datetime = INIT_DATETIME
self._ping_pong_cache: Final = PingPongCache(interface_id=client_config.interface_id)
self._pending_pong_fired: bool = False
self._unknown_pong_fired: bool = False
self._pending_pong_logged: bool = False
self._unknown_pong_logged: bool = False

self._proxy: XmlRpcProxy
self._proxy_read: XmlRpcProxy
Expand Down Expand Up @@ -355,15 +355,14 @@ def get_event_data(pending_pong_count: int) -> dict[str, Any]:
},
}

if self._pending_pong_fired:
if self._ping_pong_cache.low_pending_pongs is True:
self.central.fire_ha_event_callback(
event_type=EventType.INTERFACE,
event_data=cast(
dict[str, Any],
hmcu.INTERFACE_EVENT_SCHEMA(get_event_data(pending_pong_count=0)),
),
)
if self._ping_pong_cache.low_pending_pongs is True:
self.central.fire_ha_event_callback(
event_type=EventType.INTERFACE,
event_data=cast(
dict[str, Any],
hmcu.INTERFACE_EVENT_SCHEMA(get_event_data(pending_pong_count=0)),
),
)
return

if self._ping_pong_cache.check_pending_pongs() is False:
Expand All @@ -379,13 +378,16 @@ def get_event_data(pending_pong_count: int) -> dict[str, Any]:
),
)

_LOGGER.warning(
"PING/PONG MISMATCH: There is a mismatch between send ping events and received pong events for HA instance %s. "
"Possible reason: Something is stuck on CCU, so try a restart.",
self.interface_id,
)
if self._pending_pong_logged is False:
_LOGGER.warning(
"Pending PONG Events: There is a mismatch between send ping events and received pong events for HA instance %s. "
"Possible reason 1: You are running multiple instances of HA with the same instance name configured for this integration. "
"Re-add one instance! Otherwise one HA instance will not receive update events from your CCU. "
"Possible reason 2: Something is stuck on CCU, so try a restart.",
self.interface_id,
)

self._pending_pong_fired = True
self._pending_pong_logged = True

def _check_and_fire_unknown_pong_event(self) -> None:
"""Fire an event about the unknown pong status."""
Expand All @@ -400,15 +402,14 @@ def get_event_data(unknown_pong_count: int) -> dict[str, Any]:
},
}

if self._unknown_pong_fired:
if self._ping_pong_cache.low_unknown_pongs is True:
self.central.fire_ha_event_callback(
event_type=EventType.INTERFACE,
event_data=cast(
dict[str, Any],
hmcu.INTERFACE_EVENT_SCHEMA(get_event_data(unknown_pong_count=0)),
),
)
if self._ping_pong_cache.low_unknown_pongs is True:
self.central.fire_ha_event_callback(
event_type=EventType.INTERFACE,
event_data=cast(
dict[str, Any],
hmcu.INTERFACE_EVENT_SCHEMA(get_event_data(unknown_pong_count=0)),
),
)
return

if self._ping_pong_cache.check_unknown_pongs() is False:
Expand All @@ -423,14 +424,15 @@ def get_event_data(unknown_pong_count: int) -> dict[str, Any]:
),
),
)
_LOGGER.warning(
"PING/PONG MISMATCH: There is a mismatch between send ping events and received pong events for HA instance %s. "
"Possible reason: You are running multiple instances of HA with the same instance name configured for this integration. "
"Re-add one instance! Otherwise one HA instance will not receive update events from your CCU. ",
self.interface_id,
)
if self._unknown_pong_logged is False:
_LOGGER.warning(
"Unknown PONG Events received: There is a mismatch between send ping events and received pong events for interface %s. "
"Possible reason: You are running multiple instances of HA with the same instance name configured for this integration. "
"Re-add one instance! Otherwise one HA instance will not receive update events from your CCU. ",
self.interface_id,
)

self._unknown_pong_fired = True
self._unknown_pong_logged = True

async def set_install_mode(
self,
Expand Down
2 changes: 1 addition & 1 deletion hahomematic/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
DEFAULT_CONNECTION_CHECKER_INTERVAL: Final = 15 # check if connection is available via rpc ping
DEFAULT_ENCODING: Final = "UTF-8"
DEFAULT_JSON_SESSION_AGE: Final = 90
DEFAULT_PING_PONG_MISMATCH_COUNT: Final = 10
DEFAULT_PING_PONG_MISMATCH_COUNT: Final = 15
DEFAULT_RECONNECT_WAIT: Final = 120 # wait with reconnect after a first ping was successful
DEFAULT_TIMEOUT: Final = 60 # default timeout for a connection
DEFAULT_TLS: Final = False
Expand Down
21 changes: 5 additions & 16 deletions tests/test_central.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,10 +463,8 @@ async def test_ping_pong(factory: helper.Factory) -> None:
async def test_pending_pong_failure(factory: helper.Factory) -> None:
"""Test central other methods."""
central, client = await factory.get_default_central(TEST_DEVICES, do_mock_client=False)
interface_id = client.interface_id
count = 0
max_count = PING_PONG_MISMATCH_COUNT + 1
assert client._pending_pong_fired is False
while count < max_count:
await client.check_connection_availability()
count += 1
Expand All @@ -476,17 +474,13 @@ async def test_pending_pong_failure(factory: helper.Factory) -> None:
{
"data": {
"instance_name": "CentralTest",
"pending_pongs": 11,
"pending_pongs": 16,
},
"interface_id": "CentralTest-BidCos-RF",
"type": InterfaceEventType.PENDING_PONG,
},
)
assert client._pending_pong_fired is True
assert len(factory.ha_event_mock.mock_calls) == 2
# Check event fired only once
central.event(interface_id, "", Parameter.PONG, interface_id)
assert len(factory.ha_event_mock.mock_calls) == 2
assert len(factory.ha_event_mock.mock_calls) == 9


@pytest.mark.asyncio
Expand All @@ -496,7 +490,6 @@ async def test_unknown_pong_failure(factory: helper.Factory) -> None:
interface_id = client.interface_id
count = 0
max_count = PING_PONG_MISMATCH_COUNT + 1
assert client._unknown_pong_fired is False
while count < max_count:
central.event(
interface_id,
Expand All @@ -506,23 +499,19 @@ async def test_unknown_pong_failure(factory: helper.Factory) -> None:
)
count += 1

assert client._ping_pong_cache.unknown_pong_count == 11
assert client._ping_pong_cache.unknown_pong_count == 16
assert factory.ha_event_mock.mock_calls[-1] == call(
EventType.INTERFACE,
{
"data": {
"instance_name": "CentralTest",
"unknown_pongs": 11,
"unknown_pongs": 16,
},
"interface_id": "CentralTest-BidCos-RF",
"type": InterfaceEventType.UNKNOWN_PONG,
},
)
assert client._unknown_pong_fired is True
assert len(factory.ha_event_mock.mock_calls) == 2
# Check event fired only once
central.event(interface_id, "", Parameter.PONG, interface_id)
assert len(factory.ha_event_mock.mock_calls) == 2
assert len(factory.ha_event_mock.mock_calls) == 25


@pytest.mark.asyncio
Expand Down

0 comments on commit be39ffd

Please sign in to comment.