diff --git a/src/homematicip/events/event_manager.py b/src/homematicip/events/event_manager.py index 0c4f3432..22a29dfa 100644 --- a/src/homematicip/events/event_manager.py +++ b/src/homematicip/events/event_manager.py @@ -15,7 +15,7 @@ def unsubscribe(self, event_type, callback): if callback in self._subscriptions[event_type]: self._subscriptions[event_type].remove(callback) - async def publish(self, event_type: ModelUpdateEvent, event_args): + async def async_publish(self, event_type: ModelUpdateEvent, event_args): if event_type in self._subscriptions: for callback in self._subscriptions[event_type]: await callback(event_type, event_args) diff --git a/src/homematicip/events/hmip_event_handler.py b/src/homematicip/events/hmip_event_handler.py index ed18d091..6b0e7646 100644 --- a/src/homematicip/events/hmip_event_handler.py +++ b/src/homematicip/events/hmip_event_handler.py @@ -32,14 +32,14 @@ async def process_event_async(self, event_json): data = event['client'] client: Client = Client(**data) self._model.clients[data['id']] = client - await self._event_manager.publish(ModelUpdateEvent.ITEM_CREATED, client) + await self._event_manager.async_publish(ModelUpdateEvent.ITEM_CREATED, client) elif event_type == EventType.CLIENT_CHANGED: data = event['client'] if data['id'] in self._model.clients: client: HmipBaseModel = self._model.clients[data['id']] client.update_from_dict(data) - await self._event_manager.publish(ModelUpdateEvent.ITEM_UPDATED, client) + await self._event_manager.async_publish(ModelUpdateEvent.ITEM_UPDATED, client) elif event_type == EventType.CLIENT_REMOVED: data = event['client'] @@ -47,21 +47,21 @@ async def process_event_async(self, event_json): client = self._model.clients.pop(data['id'], None) if client is not None: client.remove_object() - await self._event_manager.publish(ModelUpdateEvent.ITEM_REMOVED, client) + await self._event_manager.async_publish(ModelUpdateEvent.ITEM_REMOVED, client) elif event_type == EventType.DEVICE_ADDED: data = event['device'] if data['id'] not in self._model.devices: device: Device = Device(**data) self._model.devices[data['id']] = device - await self._event_manager.publish(ModelUpdateEvent.ITEM_CREATED, device) + await self._event_manager.async_publish(ModelUpdateEvent.ITEM_CREATED, device) elif event_type == EventType.DEVICE_CHANGED: data = event['device'] if data['id'] in self._model.devices: device: HmipBaseModel = self._model.devices[data['id']] device.update_from_dict(data) - await self._event_manager.publish(ModelUpdateEvent.ITEM_UPDATED, device) + await self._event_manager.async_publish(ModelUpdateEvent.ITEM_UPDATED, device) elif event_type == EventType.DEVICE_REMOVED: data = event['device'] @@ -69,34 +69,34 @@ async def process_event_async(self, event_json): device = self._model.devices.pop(data['id'], None) if device is not None: device.remove_object() - await self._event_manager.publish(ModelUpdateEvent.ITEM_REMOVED, device) + await self._event_manager.async_publish(ModelUpdateEvent.ITEM_REMOVED, device) elif event_type == EventType.GROUP_ADDED: data = event['group'] if data['id'] not in self._model.groups: group: Group = Group(**data) self._model.groups[data['id']] = group - await self._event_manager.publish(ModelUpdateEvent.ITEM_CREATED, group) + await self._event_manager.async_publish(ModelUpdateEvent.ITEM_CREATED, group) elif event_type == EventType.GROUP_CHANGED: data = event['group'] if data['id'] in self._model.groups: group: HmipBaseModel = self._model.groups[data['id']] group.update_from_dict(data) - await self._event_manager.publish(ModelUpdateEvent.ITEM_UPDATED, group) + await self._event_manager.async_publish(ModelUpdateEvent.ITEM_UPDATED, group) elif event_type == EventType.GROUP_REMOVED: data = event['group'] group = self._model.groups.pop(data['id'], None) if group is not None: group.remove_object() - await self._event_manager.publish(ModelUpdateEvent.ITEM_REMOVED, group) + await self._event_manager.async_publish(ModelUpdateEvent.ITEM_REMOVED, group) elif event_type == EventType.HOME_CHANGED: data = event['home'] self._model.home.update_from_dict(data) - await self._event_manager.publish(ModelUpdateEvent.ITEM_UPDATED, self._model.home) + await self._event_manager.async_publish(ModelUpdateEvent.ITEM_UPDATED, self._model.home) elif event_type == EventType.SECURITY_JOURNAL_CHANGED: pass diff --git a/src/homematicip/model/hmip_base.py b/src/homematicip/model/hmip_base.py index 1df6a2e9..ec564327 100644 --- a/src/homematicip/model/hmip_base.py +++ b/src/homematicip/model/hmip_base.py @@ -1,3 +1,5 @@ +import logging + try: from pydantic.v1 import BaseModel, PrivateAttr # type: ignore # noqa F401 # pragma: no cover except ImportError: diff --git a/src/homematicip/model/model.py b/src/homematicip/model/model.py index 5294abed..595e97cb 100644 --- a/src/homematicip/model/model.py +++ b/src/homematicip/model/model.py @@ -35,7 +35,7 @@ def build_model_from_json(data) -> Model: LOGGER.fatal("Error while building model from json.", exc_info=e) -def update_model_from_json(model: Model, event_manager: EventManager, data): +async def async_update_model_from_json(model: Model, event_manager: EventManager, data): """Update a model from json data. :param model: The model to update. @@ -48,37 +48,37 @@ def update_model_from_json(model: Model, event_manager: EventManager, data): for key in data: if key == "home": if model.home.update_from_dict(data[key]): - event_manager.publish(ModelUpdateEvent.ITEM_UPDATED, model.home) + await event_manager.async_publish(ModelUpdateEvent.ITEM_UPDATED, model.home) elif key == "clients": for client_json in data[key].items(): client_id = client_json[0] client_data = client_json[1] if client_id in model.clients: if model.clients[client_id].update_from_dict(client_data): - event_manager.publish(ModelUpdateEvent.ITEM_UPDATED, model.clients[client_id]) + await event_manager.async_publish(ModelUpdateEvent.ITEM_UPDATED, model.clients[client_id]) else: model.clients[client_id] = Client(**client_data) - event_manager.publish(ModelUpdateEvent.ITEM_CREATED, model.clients[client_id]) + await event_manager.async_publish(ModelUpdateEvent.ITEM_CREATED, model.clients[client_id]) elif key == "devices": for device_json in data[key].items(): device_id = device_json[0] device_data = device_json[1] if device_id in model.devices: if model.devices[device_id].update_from_dict(device_data): - event_manager.publish(ModelUpdateEvent.ITEM_UPDATED, model.devices[device_id]) + await event_manager.async_publish(ModelUpdateEvent.ITEM_UPDATED, model.devices[device_id]) else: model.devices[device_id] = Device(**device_data) - event_manager.publish(ModelUpdateEvent.ITEM_CREATED, model.devices[device_id]) + await event_manager.async_publish(ModelUpdateEvent.ITEM_CREATED, model.devices[device_id]) elif key == "groups": for group_json in data[key].items(): group_id = group_json[0] group_data = group_json[1] if group_id in model.groups: if model.groups[group_id].update_from_dict(group_data): - event_manager.publish(ModelUpdateEvent.ITEM_UPDATED, model.groups[group_id]) + await event_manager.async_publish(ModelUpdateEvent.ITEM_UPDATED, model.groups[group_id]) else: model.groups[group_id] = Group(**group_data) - event_manager.publish(ModelUpdateEvent.ITEM_CREATED, model.groups[group_id]) + await event_manager.async_publish(ModelUpdateEvent.ITEM_CREATED, model.groups[group_id]) except ValidationError as e: LOGGER.fatal("Error while updating model from json.", exc_info=e) diff --git a/src/homematicip/runner.py b/src/homematicip/runner.py index 4994ccda..33a3b6ab 100644 --- a/src/homematicip/runner.py +++ b/src/homematicip/runner.py @@ -16,7 +16,7 @@ from homematicip.events.event_manager import EventManager from homematicip.events.event_types import ModelUpdateEvent from homematicip.events.hmip_event_handler import HmipEventHandler -from homematicip.model.model import Model, build_model_from_json, update_model_from_json +from homematicip.model.model import Model, build_model_from_json, async_update_model_from_json LOGGER = logging.getLogger(__name__) @@ -135,7 +135,7 @@ async def async_get_current_state(self): async def async_refresh_model(self): """Refresh the model with the current state from the access point.""" current_configuration = await self.async_get_current_state() - update_model_from_json(self.model, self.event_manager, current_configuration) + await async_update_model_from_json(self.model, self.event_manager, current_configuration) async def _async_start_listening_for_updates(self, context: ConnectionContext): self.websocket_handler = WebSocketHandler() @@ -172,9 +172,9 @@ def _publish_websocket_connected(self, connected_value: bool): :param connected_value: The new state of the websocket connection.""" if connected_value: - self.event_manager.publish(ModelUpdateEvent.HOME_CONNECTED, connected_value) + self.event_manager.async_publish(ModelUpdateEvent.HOME_CONNECTED, connected_value) else: - self.event_manager.publish(ModelUpdateEvent.HOME_DISCONNECTED, connected_value) + self.event_manager.async_publish(ModelUpdateEvent.HOME_DISCONNECTED, connected_value) @property def rest_connection(self): diff --git a/tests/model/test_model.py b/tests/model/test_model.py index 0dc54154..efbcd6d7 100644 --- a/tests/model/test_model.py +++ b/tests/model/test_model.py @@ -1,8 +1,8 @@ import copy import json -from unittest.mock import Mock +from unittest.mock import Mock, AsyncMock -from homematicip.model.model import build_model_from_json, update_model_from_json +from homematicip.model.model import build_model_from_json, async_update_model_from_json from homematicip.model.model_components import GroupChannelReference, Group, Device from homematicip.model.hmip_base import HmipBaseModel from homematicip.model.home import Home, FunctionalHome @@ -130,7 +130,7 @@ def test_hmip_base_model_subscribers_after_update(sample_data_complete): assert base.devices[device_id].lastStatusUpdate == device.lastStatusUpdate -def test_update_home_from_json(sample_data_complete): +async def test_update_home_from_json(sample_data_complete): """Test, if the home is updated correctly.""" # arrange manipulated = copy.deepcopy(sample_data_complete) @@ -139,7 +139,7 @@ def test_update_home_from_json(sample_data_complete): model_current = build_model_from_json(sample_data_complete) model_expected = build_model_from_json(manipulated) - event_manager = Mock() + event_manager = AsyncMock() old_state_climate = model_current.home.functionalHomes['INDOOR_CLIMATE'].active new_state_climate = model_expected.home.functionalHomes['INDOOR_CLIMATE'].active @@ -147,7 +147,7 @@ def test_update_home_from_json(sample_data_complete): new_state_connected = model_expected.home.connected # act - update_model_from_json(model_current, event_manager, manipulated) + await async_update_model_from_json(model_current, event_manager, manipulated) # assert assert len(event_manager.mock_calls) == 1 @@ -155,7 +155,7 @@ def test_update_home_from_json(sample_data_complete): assert old_state_connected != new_state_connected -def test_update_model_from_json_changed_devices(sample_data_complete): +async def test_update_model_from_json_changed_devices(sample_data_complete): """Test, if the home is updated correctly.""" # arrange manipulated = copy.deepcopy(sample_data_complete) @@ -164,7 +164,7 @@ def test_update_model_from_json_changed_devices(sample_data_complete): model_current = build_model_from_json(sample_data_complete) model_expected = build_model_from_json(manipulated) - event_manager = Mock() + event_manager = AsyncMock() old_state_duty = model_current.devices['3014F7110000RAIN_SENSOR'].functionalChannels["0"].dutyCycle new_state_duty = model_expected.devices['3014F7110000RAIN_SENSOR'].functionalChannels["0"].dutyCycle @@ -172,7 +172,7 @@ def test_update_model_from_json_changed_devices(sample_data_complete): new_state_on = model_expected.devices['3014F7110DIN_RAIL_SWITCH'].functionalChannels["1"].on # act - update_model_from_json(model_current, event_manager, manipulated) + await async_update_model_from_json(model_current, event_manager, manipulated) # assert assert len(event_manager.mock_calls) == 2 @@ -180,7 +180,7 @@ def test_update_model_from_json_changed_devices(sample_data_complete): assert old_state_on != new_state_on -def test_update_model_from_json_with_new_device(sample_data_complete): +async def test_update_model_from_json_with_new_device(sample_data_complete): """Test, if the home is updated correctly.""" # arrange manipulated = copy.deepcopy(sample_data_complete) @@ -188,11 +188,11 @@ def test_update_model_from_json_with_new_device(sample_data_complete): sample_data_complete["devices"]["3014F7110000RAIN_SENSOR"]) model_current = build_model_from_json(sample_data_complete) - event_manager = Mock() + event_manager = AsyncMock() contains_device_before = "3014F7110000RAIN_SENSO2" in model_current.devices # act - update_model_from_json(model_current, event_manager, manipulated) + await async_update_model_from_json(model_current, event_manager, manipulated) # assert assert contains_device_before is False @@ -200,7 +200,7 @@ def test_update_model_from_json_with_new_device(sample_data_complete): assert len(event_manager.mock_calls) == 1 -def test_update_model_from_json_updated_group(sample_data_complete): +async def test_update_model_from_json_updated_group(sample_data_complete): """Test, if the home is updated correctly.""" # arrange manipulated = copy.deepcopy(sample_data_complete) @@ -208,13 +208,13 @@ def test_update_model_from_json_updated_group(sample_data_complete): model_current = build_model_from_json(sample_data_complete) model_expected = build_model_from_json(manipulated) - event_manager = Mock() + event_manager = AsyncMock() old_label = model_current.groups['00000000-0000-0000-0000-0000000000EN'].label new_label = model_expected.groups['00000000-0000-0000-0000-0000000000EN'].label # act - update_model_from_json(model_current, event_manager, manipulated) + await async_update_model_from_json(model_current, event_manager, manipulated) # assert assert len(event_manager.mock_calls) == 1 @@ -222,7 +222,7 @@ def test_update_model_from_json_updated_group(sample_data_complete): assert model_current.groups['00000000-0000-0000-0000-0000000000EN'].label == new_label -def test_update_model_from_json_with_new_group(sample_data_complete): +async def test_update_model_from_json_with_new_group(sample_data_complete): """Test, if the home is updated correctly.""" # arrange manipulated = copy.deepcopy(sample_data_complete) @@ -230,11 +230,11 @@ def test_update_model_from_json_with_new_group(sample_data_complete): sample_data_complete["groups"]["00000000-0000-0000-0000-0000000000EN"]) model_current = build_model_from_json(sample_data_complete) - event_manager = Mock() + event_manager = AsyncMock() contains_group_before = "00000000-0000-0000-0000-0000000000EN2" in model_current.groups # act - update_model_from_json(model_current, event_manager, manipulated) + await async_update_model_from_json(model_current, event_manager, manipulated) # assert assert contains_group_before is False @@ -242,7 +242,7 @@ def test_update_model_from_json_with_new_group(sample_data_complete): assert len(event_manager.mock_calls) == 1 -def test_update_model_from_json_with_new_client(sample_data_complete): +async def test_update_model_from_json_with_new_client(sample_data_complete): """Test, if the home is updated correctly.""" # arrange manipulated = copy.deepcopy(sample_data_complete) @@ -250,11 +250,11 @@ def test_update_model_from_json_with_new_client(sample_data_complete): sample_data_complete["clients"]["00000000-0000-0000-0000-000000000000"]) model_current = build_model_from_json(sample_data_complete) - event_manager = Mock() + event_manager = AsyncMock() contains_client_before = "00000000-0000-0000-0000-000000000NEW" in model_current.clients # act - update_model_from_json(model_current, event_manager, manipulated) + await async_update_model_from_json(model_current, event_manager, manipulated) # assert assert contains_client_before is False @@ -262,7 +262,7 @@ def test_update_model_from_json_with_new_client(sample_data_complete): assert len(event_manager.mock_calls) == 1 -def test_update_model_from_json_updated_client(sample_data_complete): +async def test_update_model_from_json_updated_client(sample_data_complete): """Test, if the home is updated correctly.""" # arrange manipulated = copy.deepcopy(sample_data_complete) @@ -270,13 +270,13 @@ def test_update_model_from_json_updated_client(sample_data_complete): model_current = build_model_from_json(sample_data_complete) model_expected = build_model_from_json(manipulated) - event_manager = Mock() + event_manager = AsyncMock() old_label = model_current.clients['00000000-0000-0000-0000-000000000000'].label new_label = model_expected.clients['00000000-0000-0000-0000-000000000000'].label # act - update_model_from_json(model_current, event_manager, manipulated) + await async_update_model_from_json(model_current, event_manager, manipulated) # assert assert len(event_manager.mock_calls) == 1 diff --git a/tests/test_runner.py b/tests/test_runner.py index 848e8340..43eac725 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -65,7 +65,7 @@ def test_runner_websocket_connected_event_is_raised(mocker): """Test that the HOME_CONNECTED event is raised when the websocket connection is established.""" mock_publish = mocker.Mock() runner = Runner() - runner.event_manager.publish = mock_publish + runner.event_manager.async_publish = mock_publish runner._websocket_connected = False runner._set_websocket_connected_state(True) @@ -76,7 +76,7 @@ def test_runner_websocket_disconnected_event_is_raised(mocker): """Test that the HOME_DISCONNECTED event is raised when the websocket connection is lost.""" mock_publish = mocker.Mock() runner = Runner() - runner.event_manager.publish = mock_publish + runner.event_manager.async_publish = mock_publish runner._websocket_connected = True runner._set_websocket_connected_state(False) @@ -102,7 +102,7 @@ async def test_runner_refresh_model(mocker, filled_model, sample_data_complete): mocked_get_current_state = mocker.patch("homematicip.runner.Runner.async_get_current_state", new_callable=AsyncMock) mocked_get_current_state.return_value = sample_data_complete - mocked_update_function = mocker.patch("homematicip.runner.update_model_from_json") + mocked_update_function = mocker.patch("homematicip.runner.async_update_model_from_json") # act await runner.async_refresh_model()