core/homeassistant/components/harmony/subscriber.py

93 lines
3.0 KiB
Python

"""Mixin class for handling harmony callback subscriptions."""
import asyncio
import logging
from typing import Any, Callable, NamedTuple, Optional
from homeassistant.core import callback
_LOGGER = logging.getLogger(__name__)
NoParamCallback = Optional[Callable[[object], Any]]
ActivityCallback = Optional[Callable[[object, tuple], Any]]
class HarmonyCallback(NamedTuple):
"""Callback type for Harmony Hub notifications."""
connected: NoParamCallback
disconnected: NoParamCallback
config_updated: NoParamCallback
activity_starting: ActivityCallback
activity_started: ActivityCallback
class HarmonySubscriberMixin:
"""Base implementation for a subscriber."""
def __init__(self, hass):
"""Initialize an subscriber."""
super().__init__()
self._hass = hass
self._subscriptions = []
self._activity_lock = asyncio.Lock()
async def async_lock_start_activity(self):
"""Acquire the lock."""
await self._activity_lock.acquire()
@callback
def async_unlock_start_activity(self):
"""Release the lock."""
if self._activity_lock.locked():
self._activity_lock.release()
@callback
def async_subscribe(self, update_callbacks: HarmonyCallback) -> Callable:
"""Add a callback subscriber."""
self._subscriptions.append(update_callbacks)
def _unsubscribe():
self.async_unsubscribe(update_callbacks)
return _unsubscribe
@callback
def async_unsubscribe(self, update_callback: HarmonyCallback):
"""Remove a callback subscriber."""
self._subscriptions.remove(update_callback)
def _config_updated(self, _=None) -> None:
_LOGGER.debug("config_updated")
self._call_callbacks("config_updated")
def _connected(self, _=None) -> None:
_LOGGER.debug("connected")
self.async_unlock_start_activity()
self._available = True
self._call_callbacks("connected")
def _disconnected(self, _=None) -> None:
_LOGGER.debug("disconnected")
self.async_unlock_start_activity()
self._available = False
self._call_callbacks("disconnected")
def _activity_starting(self, activity_info: tuple) -> None:
_LOGGER.debug("activity %s starting", activity_info)
self._call_callbacks("activity_starting", activity_info)
def _activity_started(self, activity_info: tuple) -> None:
_LOGGER.debug("activity %s started", activity_info)
self.async_unlock_start_activity()
self._call_callbacks("activity_started", activity_info)
def _call_callbacks(self, callback_func_name: str, argument: tuple = None):
for subscription in self._subscriptions:
current_callback = getattr(subscription, callback_func_name)
if current_callback:
if argument:
self._hass.async_run_job(current_callback, argument)
else:
self._hass.async_run_job(current_callback)