Skip to content

Commit

Permalink
Use sets for central callbacks (SukramJ#970)
Browse files Browse the repository at this point in the history
  • Loading branch information
SukramJ authored Feb 22, 2023
1 parent 9d540e8 commit 5a60fc4
Showing 12 changed files with 139 additions and 64 deletions.
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Version 2023.2.10 (2023-02-23)

- Use sets for central callbacks

# Version 2023.2.9 (2023-02-18)

- Fix property types
6 changes: 3 additions & 3 deletions example.py
Original file line number Diff line number Diff line change
@@ -96,9 +96,9 @@ async def example_run(self):
# it while initializing.
config.CACHE_DIR = "cache"
# Add callbacks to handle the events and see what happens on the system.
self.central.callback_system_event = self._systemcallback
self.central.callback_entity_event = self._eventcallback
self.central.callback_ha_event = self._hacallback
self.central.register_system_event_callback(self._systemcallback)
self.central.register_entity_event_callback(self._eventcallback)
self.central.register_ha_event_callback(self._hacallback)

await self.central.start()
while not self.got_devices and self.SLEEPCOUNTER < 20:
6 changes: 3 additions & 3 deletions example_local.py
Original file line number Diff line number Diff line change
@@ -462,9 +462,9 @@ async def example_run(self):
# it while initializing.
config.CACHE_DIR = "cache"
# Add callbacks to handle the events and see what happens on the system.
self.central.callback_system_event = self._systemcallback
self.central.callback_entity_event = self._eventcallback
self.central.callback_ha_event = self._hacallback
self.central.register_system_event_callback(self._systemcallback)
self.central.register_entity_event_callback(self._eventcallback)
self.central.register_ha_event_callback(self._hacallback)

# Create clients
await self.central.start()
98 changes: 80 additions & 18 deletions hahomematic/central_unit.py
Original file line number Diff line number Diff line change
@@ -133,13 +133,13 @@ def __init__(self, central_config: CentralConfig) -> None:
# store last event received datetime by interface
self.last_events: Final[dict[str, datetime]] = {}
# Signature: (name, *args) #CC
self.callback_system_event: Callable | None = None
self._callback_system_event: Final[set[Callable]] = set()
# Signature: (interface_id, channel_address, value_key, value) #CC
self.callback_entity_event: Callable | None = None
self._callback_entity_event: Final[set[Callable]] = set()
# Signature: (interface_id, entity) #CC
self.callback_entity_data_event: Callable | None = None
self._callback_entity_data_event: Final[set[Callable]] = set()
# Signature: (event_type, event_data) #CC
self.callback_ha_event: Callable | None = None
self._callback_ha_event: Final[set[Callable]] = set()

self.json_rpc_client: Final[JsonRpcAioHttpClient] = central_config.create_json_rpc_client()

@@ -370,17 +370,12 @@ def fire_interface_event(
available: bool,
) -> None:
"""Fire an event about the interface status."""
event_data = {
event_data: dict[str, Any] = {
ATTR_INTERFACE_ID: interface_id,
ATTR_TYPE: interface_event_type,
ATTR_VALUE: available,
}
# pylint: disable=not-callable
if callable(self.callback_ha_event):
self.callback_ha_event(
HmEventType.INTERFACE,
event_data,
)
self.fire_ha_event_callback(event_type=HmEventType.INTERFACE, event_data=event_data)

async def _identify_callback_ip(self, port: int) -> str:
"""Identify local IP used for callbacks."""
@@ -610,13 +605,8 @@ async def _create_devices(self) -> None:
)
_LOGGER.debug("CREATE_DEVICES: Finished creating devices for %s", self._attr_name)

if (
len(new_devices) > 0
and self.callback_system_event is not None
and callable(self.callback_system_event)
):
# pylint: disable=not-callable
self.callback_system_event(name=HH_EVENT_DEVICES_CREATED, new_devices=new_devices)
if new_devices:
self.fire_system_event_callback(name=HH_EVENT_DEVICES_CREATED, new_devices=new_devices)

async def delete_device(self, interface_id: str, device_address: str) -> None:
"""Delete devices from central_unit. #CC."""
@@ -931,6 +921,78 @@ async def clear_all_caches(self) -> None:
await self.paramset_descriptions.clear()
self.clear_dynamic_caches()

def register_ha_event_callback(self, callback_handler: Callable) -> None:
"""Register ha_event callback in central."""
self._callback_ha_event.add(callback_handler)

def unregister_ha_event_callback(self, callback_handler: Callable) -> None:
"""RUn register ha_event callback in central."""
if callback_handler in self._callback_ha_event:
self._callback_ha_event.remove(callback_handler)

def fire_ha_event_callback(self, event_type: HmEventType, event_data: dict[str, str]) -> None:
"""Fire ha_event callback in central."""
for callback_handler in self._callback_ha_event:
try:
callback_handler(event_type, event_data)
except Exception as ex:
_LOGGER.error("FIRE_HA_EVENT_CALLBACK: Unable to call handler: %s", ex.args)

def register_entity_event_callback(self, callback_handler: Callable) -> None:
"""Register entity_event callback in central."""
self._callback_entity_event.add(callback_handler)

def unregister_entity_event_callback(self, callback_handler: Callable) -> None:
"""Un register entity_event callback in central."""
if callback_handler in self._callback_entity_event:
self._callback_entity_event.remove(callback_handler)

def fire_entity_event_callback(
self, interface_id: str, channel_address: str, value_key: str, value: Any
) -> None:
"""Fire entity callback in central."""
for callback_handler in self._callback_entity_event:
try:
callback_handler(interface_id, channel_address, value_key, value)
except Exception as ex:
_LOGGER.error("FIRE_ENTITY_EVENT_CALLBACK: Unable to call handler: %s", ex.args)

def register_entity_data_event_callback(self, callback_handler: Callable) -> None:
"""Register entity_event callback in central."""
self._callback_entity_data_event.add(callback_handler)

def unregister_entity_data_event_callback(self, callback_handler: Callable) -> None:
"""Un register entity_event callback in central."""
if callback_handler in self._callback_entity_data_event:
self._callback_entity_data_event.remove(callback_handler)

def fire_entity_data_event_callback(self, interface_id: str, entity: BaseEntity) -> None:
"""Fire entity_data callback in central."""
for callback_handler in self._callback_entity_data_event:
try:
callback_handler(interface_id, entity)
except Exception as ex:
_LOGGER.error(
"FIRE_ENTITY_DATA_EVENT_CALLBACK: Unable to call handler: %s", ex.args
)

def register_system_event_callback(self, callback_handler: Callable) -> None:
"""Register system_event callback in central."""
self._callback_system_event.add(callback_handler)

def unregister_system_event_callback(self, callback_handler: Callable) -> None:
"""Un register system_event callback in central."""
if callback_handler in self._callback_system_event:
self._callback_system_event.remove(callback_handler)

def fire_system_event_callback(self, name: str, **kwargs: Any) -> None:
"""Fire system_event callback in central."""
for callback_handler in self._callback_system_event:
try:
callback_handler(name, **kwargs)
except Exception as ex:
_LOGGER.error("FIRE_SYSTEM_EVENT_CALLBACK: Unable to call handler: %s", ex.args)


class ConnectionChecker(threading.Thread):
"""Periodically check Connection to CCU / Homegear."""
6 changes: 2 additions & 4 deletions hahomematic/decorators.py
Original file line number Diff line number Diff line change
@@ -73,8 +73,7 @@ def _exec_callback_system_event(name: str, *args: Any, **kwargs: Any) -> None:
raise HaHomematicException("args-exception callback_system_event") from err
if client:
client.last_updated = datetime.now()
if client.central.callback_system_event is not None:
client.central.callback_system_event(name, **kwargs)
client.central.fire_system_event_callback(name=name, **kwargs)


def callback_event(func: Callable[P, R]) -> Callable[P, R]:
@@ -100,8 +99,7 @@ def _exec_callback_entity_event(*args: Any, **kwargs: Any) -> None:
raise HaHomematicException("args-exception callback_event") from err
if client:
client.last_updated = datetime.now()
if client.central.callback_entity_event is not None:
client.central.callback_entity_event(*args, **kwargs)
client.central.fire_entity_event_callback(*args, **kwargs)

return wrapper_callback_event

15 changes: 7 additions & 8 deletions hahomematic/platforms/entity.py
Original file line number Diff line number Diff line change
@@ -119,22 +119,22 @@ def enabled_default(self) -> bool:
)

def register_update_callback(self, update_callback: Callable) -> None:
"""register update callback."""
"""Register update callback."""
if callable(update_callback):
self._update_callbacks.append(update_callback)

def unregister_update_callback(self, update_callback: Callable) -> None:
"""remove update callback."""
"""Unregister update callback."""
if update_callback in self._update_callbacks:
self._update_callbacks.remove(update_callback)

def register_remove_callback(self, remove_callback: Callable) -> None:
"""register the remove callback."""
"""Register the remove callback."""
if callable(remove_callback) and remove_callback not in self._remove_callbacks:
self._remove_callbacks.append(remove_callback)

def unregister_remove_callback(self, remove_callback: Callable) -> None:
"""remove the remove callback."""
"""Unregister the remove callback."""
if remove_callback in self._remove_callbacks:
self._remove_callbacks.remove(remove_callback)

@@ -227,10 +227,9 @@ def set_usage(self, usage: HmEntityUsage) -> None:
def update_entity(self, *args: Any) -> None:
"""Do what is needed when the value of the entity has been updated."""
super().update_entity(*args)
if callable(self._central.callback_entity_data_event):
self._central.callback_entity_data_event(
interface_id=self.device.interface_id, entity=self
)
self._central.fire_entity_data_event_callback(
interface_id=self.device.interface_id, entity=self
)

@abstractmethod
async def load_entity_value(
8 changes: 3 additions & 5 deletions hahomematic/platforms/event.py
Original file line number Diff line number Diff line change
@@ -69,11 +69,9 @@ def event(self, value: Any) -> None:

def fire_event(self, value: Any) -> None:
"""Do what is needed to fire an event."""
if callable(self._central.callback_ha_event):
self._central.callback_ha_event(
self.event_type,
self.get_event_data(value=value),
)
self._central.fire_ha_event_callback(
event_type=self.event_type, event_data=self.get_event_data(value=value)
)

def _get_entity_name(self) -> EntityNameData:
"""Create the name for the entity."""
10 changes: 4 additions & 6 deletions hahomematic/platforms/generic/entity.py
Original file line number Diff line number Diff line change
@@ -79,12 +79,10 @@ def event(self, value: Any) -> None:
EVENT_STICKY_UN_REACH,
):
self.device.update_device(self._attr_unique_identifier)

if callable(self._central.callback_ha_event):
self._central.callback_ha_event(
HmEventType.DEVICE_AVAILABILITY,
self.get_event_data(new_value),
)
self._central.fire_ha_event_callback(
event_type=HmEventType.DEVICE_AVAILABILITY,
event_data=self.get_event_data(new_value),
)

async def send_value(
self,
16 changes: 4 additions & 12 deletions hahomematic/platforms/hub/__init__.py
Original file line number Diff line number Diff line change
@@ -84,12 +84,8 @@ async def _update_program_entities(self, include_internal: bool) -> None:
else:
new_programs.append(self._create_program(data=program_data))

if (
new_programs
and self._central.callback_system_event is not None
and callable(self._central.callback_system_event)
):
self._central.callback_system_event(
if new_programs:
self._central.fire_system_event_callback(
name=HH_EVENT_HUB_REFRESHED, new_hub_entities=new_programs
)

@@ -131,12 +127,8 @@ async def _update_sysvar_entities(self, include_internal: bool = True) -> None:
else:
new_sysvars.append(self._create_system_variable(data=sysvar))

if (
new_sysvars
and self._central.callback_system_event is not None
and callable(self._central.callback_system_event)
):
self._central.callback_system_event(
if new_sysvars:
self._central.fire_system_event_callback(
name=HH_EVENT_HUB_REFRESHED, new_hub_entities=new_sysvars
)

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "hahomematic"
version = "2023.2.9"
version = "2023.2.10"
license = {text = "MIT License"}
description = "Homematic interface for Home Assistant running on Python 3."
readme = "README.md"
26 changes: 25 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -62,8 +62,32 @@ async def central_unit_full(
pydev_ccu_full: pydevccu.Server, client_session: ClientSession
) -> CentralUnit:
"""Create and yield central."""

def entity_data_event_callback(*args, **kwargs):
"""Do dummy entity_data_event_callback."""

def entity_event_callback(*args, **kwargs):
"""Do dummy entity_event_callback."""

def ha_event_callback(*args, **kwargs):
"""Do dummy ha_event_callback."""

def system_event_callback(*args, **kwargs):
"""Do dummy system_event_callback."""

central_unit = await get_pydev_ccu_central_unit_full(client_session, use_caches=False)

central_unit.register_entity_data_event_callback(entity_data_event_callback)
central_unit.register_entity_event_callback(entity_event_callback)
central_unit.register_ha_event_callback(ha_event_callback)
central_unit.register_system_event_callback(system_event_callback)

yield central_unit

central_unit.unregister_entity_data_event_callback(entity_data_event_callback)
central_unit.unregister_entity_event_callback(entity_event_callback)
central_unit.unregister_ha_event_callback(ha_event_callback)
central_unit.unregister_system_event_callback(system_event_callback)
await central_unit.stop()


@@ -105,7 +129,7 @@ def systemcallback(name, *args, **kwargs):
client_session=client_session,
use_caches=use_caches,
).create_central()
central_unit.callback_system_event = systemcallback
central_unit.register_system_event_callback(systemcallback)
await central_unit.start()
while not GOT_DEVICES and sleep_counter < 300:
sleep_counter += 1
6 changes: 3 additions & 3 deletions tests/helper.py
Original file line number Diff line number Diff line change
@@ -57,9 +57,9 @@ async def get_raw_central(
un_ignore_list=un_ignore_list,
).create_central()

central.callback_system_event = self.system_event_mock
central.callback_entity_event = self.entity_event_mock
central.callback_ha_event = self.ha_event_mock
central.register_system_event_callback(self.system_event_mock)
central.register_entity_event_callback(self.entity_event_mock)
central.register_ha_event_callback(self.ha_event_mock)

return central

0 comments on commit 5a60fc4

Please sign in to comment.