diff --git a/aircon/__main__.py b/aircon/__main__.py index 51fe5a2..f0b4aad 100644 --- a/aircon/__main__.py +++ b/aircon/__main__.py @@ -209,6 +209,14 @@ async def run(parsed_args): 'name': device.name, 'sw_version': device.sw_version }, + 'availability': [ + { + 'topic': mqtt_topics['lwt'] + }, + { + 'topic': mqtt_topics['pub'].format(device.mac_address, 'available') + }, + ], 'current_temperature_topic': mqtt_topics['pub'].format(device.mac_address, 'f_temp_in'), 'fan_mode_command_topic': mqtt_topics['sub'].format(device.mac_address, 't_fan_speed'), 'fan_mode_state_topic': mqtt_topics['pub'].format(device.mac_address, 't_fan_speed'), diff --git a/aircon/aircon.py b/aircon/aircon.py index 96f7c51..91b09b8 100644 --- a/aircon/aircon.py +++ b/aircon/aircon.py @@ -33,6 +33,7 @@ def __init__(self, config: Dict[str, str], properties: Properties, notifier: Cal self._properties = properties self._properties_lock = threading.RLock() self._queue_listener = notifier + self._available = False self._next_command_id = 0 @@ -49,6 +50,15 @@ def __init__(self, config: Dict[str, str], properties: Properties, notifier: Cal def is_fahrenheit(self) -> bool: return self.temp_type == TemperatureUnit.FAHRENHEIT + @property + def available(self) -> bool: + return self._available + + @available.setter + def available(self, value: bool): + self._available = value + self._notify_listeners('available', 'online' if value else 'offline') + def add_property_change_listener(self, listener: Callable[[str, Any], None]): self._property_change_listeners.append(listener) @@ -183,15 +193,6 @@ class AcDevice(BaseDevice): def __init__(self, config: Dict[str, str], notifier: Callable[[None], None]): super().__init__(config, AcProperties(), notifier) - @property - def available(self) -> bool: - return self._available - - @available.setter - def available(self, value: bool): - self._available = value - self._notify_listeners("available", value) - # @override to add special support for t_power. def update_property(self, name: str, value) -> None: with self._properties_lock: diff --git a/aircon/notifier.py b/aircon/notifier.py index 2fdcce0..9ac8a84 100644 --- a/aircon/notifier.py +++ b/aircon/notifier.py @@ -23,7 +23,6 @@ class _NotifyConfiguration: device: BaseDevice headers: dict - alive: bool last_timestamp: int @@ -60,7 +59,7 @@ def register_device(self, device: BaseDevice): 'Host': device.ip_address, 'Accept-Encoding': 'gzip' } - self._configurations.append(_NotifyConfiguration(device, headers, False, 0)) + self._configurations.append(_NotifyConfiguration(device, headers, 0)) async def _notify(self): async with self._condition: @@ -75,17 +74,20 @@ async def start(self, session: aiohttp.ClientSession): async with self._condition: while self._running: queues_empty = True - for entry in self._configurations: + for config in self._configurations: try: now = time.time() - queue_size = entry.device.commands_queue.qsize() + queue_size = config.device.commands_queue.qsize() if queue_size > 1: queues_empty = False - if now - entry.last_timestamp >= self._KEEP_ALIVE_INTERVAL or queue_size > 0: - await self._perform_request(session, entry) - entry.last_timestamp = now + if now - config.last_timestamp >= self._KEEP_ALIVE_INTERVAL or queue_size > 0: + await self._perform_request(session, config) + config.last_timestamp = now except: logging.exception('[KeepAlive] Failed to send local_reg keep alive to the AC.') + config.device.available = False + else: + config.device.available = True if queues_empty: logging.debug('[KeepAlive] Waiting for notification or timeout') try: @@ -104,7 +106,7 @@ async def stop(self): wait=wait_incrementing(start=0.5, increment=1.5, max=10)) async def _perform_request(self, session: aiohttp.ClientSession, config: _NotifyConfiguration) -> None: - method = 'PUT' if config.alive else 'POST' + method = 'PUT' if config.device.available else 'POST' self._json['local_reg']['notify'] = int(config.device.commands_queue.qsize() > 0) url = 'http://{}/local_reg.json'.format(config.device.ip_address) try: @@ -116,6 +118,7 @@ async def _perform_request(self, session: aiohttp.ClientSession, resp.status, resp_data)) raise ConnectionError('Sending local_reg failed: {}, {}'.format(resp.status, resp_data)) except: - config.alive = False + config.device.available = False raise - config.alive = True + else: + config.device.available = True