Skip to content

Commit

Permalink
refactor: refactor background events
Browse files Browse the repository at this point in the history
BREAKING CHANGE: uses the client event loop for event updates
  • Loading branch information
muhlba91 committed Nov 17, 2023
1 parent 6cd58d4 commit d13df42
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 258 deletions.
10 changes: 5 additions & 5 deletions custom_components/hella_onyx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
CONF_ACCESS_TOKEN,
CONF_SCAN_INTERVAL,
CONF_FORCE_UPDATE,
EVENT_HOMEASSISTANT_STOP,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
Expand All @@ -21,10 +22,8 @@
DOMAIN,
ONYX_API,
ONYX_COORDINATOR,
ONYX_THREAD,
ONYX_TIMEZONE,
)
from .event_thread import EventThread

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -86,14 +85,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
request_refresh_debouncer=Debouncer(hass, _LOGGER, cooldown=0, immediate=True),
)

thread = EventThread(onyx_api, coordinator, force_update)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, onyx_api.stop)
onyx_api.set_event_callback(coordinator.async_set_updated_data)
onyx_api.start(force_update)

hass.data[DOMAIN][entry.entry_id] = {
ONYX_API: onyx_api,
ONYX_TIMEZONE: onyx_timezone,
ONYX_COORDINATOR: coordinator,
ONYX_THREAD: thread,
}
thread.start()

for platform in PLATFORMS:
hass.async_create_task(
Expand Down
57 changes: 29 additions & 28 deletions custom_components/hella_onyx/api_connector.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
"""API connector for the ONYX integration."""
import logging

from aiohttp import ClientSession, ClientTimeout
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from onyx_client.client import create
from onyx_client.data.device_command import DeviceCommand
from onyx_client.enum.action import Action

from custom_components.hella_onyx.const import MAX_BACKOFF_TIME

_LOGGER = logging.getLogger(__name__)


Expand All @@ -20,31 +21,30 @@ def __init__(self, hass, fingerprint, token):
self.token = token
self.devices = {}
self.groups = {}

def _client(self, session=None):
return create(
fingerprint=self.fingerprint,
access_token=self.token,
client_session=session
if session is not None
else async_get_clientsession(self.hass),
)
self.__client = None

def _client(self):
if self.__client is None:
self.__client = create(
fingerprint=self.fingerprint,
access_token=self.token,
client_session=async_get_clientsession(self.hass),
)
return self.__client

async def get_timezone(self):
"""Gets the ONYX.CENTER timezone."""
client = self._client()
date_information = await client.date_information()
date_information = await self._client().date_information()
if date_information is not None:
return date_information.timezone
else:
return "UTC"

async def update(self):
"""Update all entities."""
client = self._client()
devices = await client.devices(include_details=True)
devices = await self._client().devices(include_details=True)
self.devices = {device.identifier: device for device in devices}
groups = await client.groups()
groups = await self._client().groups()
self.groups = {group.identifier: group for group in groups}

def device(self, uuid: str):
Expand All @@ -55,8 +55,7 @@ def device(self, uuid: str):

async def update_device(self, uuid: str):
"""Update the given entity."""
client = self._client()
device = await client.device(uuid)
device = await self._client().device(uuid)
self.devices[device.identifier] = device
return device

Expand All @@ -74,17 +73,19 @@ async def send_device_command_properties(self, uuid: str, properties: dict):
if not success:
raise CommandException("ONYX_ACTION_ERROR", uuid)

async def listen_events(self, force_update: bool = False):
"""Listen for events."""
async with ClientSession(
timeout=ClientTimeout(
total=None, connect=None, sock_connect=None, sock_read=None
)
) as session:
client = self._client(session)
async for device in client.events(force_update):
_LOGGER.debug("received device data for %s", device.identifier)
yield device
def start(self, include_details):
"""Start the event loop."""
_LOGGER.info("Starting ONYX")
self._client().start(include_details, MAX_BACKOFF_TIME)

def set_event_callback(self, callback):
"""Set the event callback."""
self._client().set_event_callback(callback)

def stop(self):
"""Stop the event loop."""
_LOGGER.info("Shutting down ONYX")
self._client().stop()


class CommandException(Exception):
Expand Down
1 change: 0 additions & 1 deletion custom_components/hella_onyx/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
ONYX_API = "onyx_api"
ONYX_TIMEZONE = "onyx_timezone"
ONYX_COORDINATOR = "onyx_coordinator"
ONYX_THREAD = "onyx_thread"

CONF_FINGERPRINT = "fingerprint"

Expand Down
61 changes: 0 additions & 61 deletions custom_components/hella_onyx/event_thread.py

This file was deleted.

2 changes: 1 addition & 1 deletion custom_components/hella_onyx/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"documentation": "https://github.com/muhlba91/onyx-homeassistant-integration",
"issue_tracker": "https://github.com/muhlba91/onyx-homeassistant-integration/issues",
"requirements": [
"onyx-client==7.2.1"
"onyx-client==8.0.0"
],
"ssdp": [],
"zeroconf": [],
Expand Down
22 changes: 18 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ classifiers = [

[tool.poetry.dependencies]
python = "^3.11"
onyx-client = "^7.2.1"
onyx-client = "^8.0.0"

[tool.poetry.dev-dependencies]
pytest = "^7.3.1"
Expand Down
46 changes: 25 additions & 21 deletions tests/test_api_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
CommandException,
UnknownStateException,
)
from custom_components.hella_onyx.const import MAX_BACKOFF_TIME


class TestAPIConnector:
Expand Down Expand Up @@ -96,25 +97,29 @@ async def test_send_device_command_properties_failed(self, api, client):
assert client.is_called

@pytest.mark.asyncio
async def test_listen_events(self, api, client):
async def test__client(self, api):
api.hass = MagicMock()
client = api._client()
assert client is not None
assert isinstance(client, OnyxClient)

@pytest.mark.asyncio
async def test_start(self, api, client):
with patch.object(api, "_client", new=client.make):
async for device in api.listen_events():
assert device is not None
api.start(True)
assert client.is_called
assert not client.is_force_update

@pytest.mark.asyncio
async def test_listen_events_force_update(self, api, client):
async def test_stop(self, api, client):
with patch.object(api, "_client", new=client.make):
async for device in api.listen_events(True):
assert device is not None
api.stop()
assert client.is_called
assert client.is_force_update

def test__client(self, api):
client = api._client(session=MagicMock())
assert client is not None
assert isinstance(client, OnyxClient)
@pytest.mark.asyncio
async def test_set_event_callback(self, api, client):
with patch.object(api, "_client", new=client.make):
api.set_event_callback(None)
assert client.is_called


class MockClient:
Expand Down Expand Up @@ -170,16 +175,15 @@ async def send_command(self, uuid: str, command: DeviceCommand):
command.properties is not None and "fail" not in command.properties
)

async def events(self, force_update: bool):
def start(self, include_details, backoff_time):
self.called = True
assert backoff_time == MAX_BACKOFF_TIME

def stop(self):
self.called = True

def set_event_callback(self, callback):
self.called = True
self.force_update = force_update
yield Shutter(
"id",
"other",
DeviceType.RAFFSTORE_90,
DeviceMode(DeviceType.RAFFSTORE_90),
list(Action),
)

async def date_information(self):
self.called = True
Expand Down
Loading

0 comments on commit d13df42

Please sign in to comment.