From 99f9f8dec031d6e8d5f3f5443950d7980fceb739 Mon Sep 17 00:00:00 2001 From: Raj Laud <50647620+rajlaud@users.noreply.github.com> Date: Thu, 18 Mar 2021 07:07:35 -0500 Subject: [PATCH] Allow hdmi_cec to recover from lost connection to adapter without restart (#40714) * Only update CecDevice state when there is new data * Replace CecDevice with CecEntity * Support for losing and reconnecting to pycec TcpAdapter * Register listener in async_added_to_hass * Rename hdmi_cec watchdog * Only update CecDevice state when there is new data * Fix flake8 docstring error * Fix linter error * Bump pycec version to 0.5.0 * Bump pycec version to 0.5.1 * Fixe merge mistake Co-authored-by: Erik Montnemery --- homeassistant/components/hdmi_cec/__init__.py | 31 +++++++++++++++++-- .../components/hdmi_cec/manifest.json | 2 +- requirements_all.txt | 2 +- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/hdmi_cec/__init__.py b/homeassistant/components/hdmi_cec/__init__.py index 2f821c1d3a7..d92342c1fb0 100644 --- a/homeassistant/components/hdmi_cec/__init__.py +++ b/homeassistant/components/hdmi_cec/__init__.py @@ -1,6 +1,6 @@ """Support for HDMI CEC.""" from collections import defaultdict -from functools import reduce +from functools import partial, reduce import logging import multiprocessing @@ -38,9 +38,10 @@ from homeassistant.const import ( STATE_ON, STATE_PAUSED, STATE_PLAYING, + STATE_UNAVAILABLE, ) from homeassistant.core import HomeAssistant -from homeassistant.helpers import discovery +from homeassistant.helpers import discovery, event import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity @@ -162,6 +163,9 @@ CONFIG_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) +WATCHDOG_INTERVAL = 120 +EVENT_HDMI_CEC_UNAVAILABLE = "hdmi_cec_unavailable" + def pad_physical_address(addr): """Right-pad a physical address.""" @@ -210,6 +214,18 @@ def setup(hass: HomeAssistant, base_config): adapter = CecAdapter(name=display_name[:12], activate_source=False) hdmi_network = HDMINetwork(adapter, loop=loop) + def _adapter_watchdog(now=None): + _LOGGER.debug("Reached _adapter_watchdog") + event.async_call_later(hass, WATCHDOG_INTERVAL, _adapter_watchdog) + if not adapter.initialized: + _LOGGER.info("Adapter not initialized. Trying to restart.") + hass.bus.fire(EVENT_HDMI_CEC_UNAVAILABLE) + adapter.init() + + hdmi_network.set_initialized_callback( + partial(event.async_call_later, hass, WATCHDOG_INTERVAL, _adapter_watchdog) + ) + def _volume(call): """Increase/decrease volume and mute/unmute system.""" mute_key_mapping = { @@ -327,7 +343,7 @@ def setup(hass: HomeAssistant, base_config): def _shutdown(call): hdmi_network.stop() - def _start_cec(event): + def _start_cec(callback_event): """Register services and start HDMI network to watch for devices.""" hass.services.register( DOMAIN, SERVICE_SEND_COMMAND, _tx, SERVICE_SEND_COMMAND_SCHEMA @@ -364,6 +380,12 @@ class CecEntity(Entity): self._logical_address = logical self.entity_id = "%s.%d" % (DOMAIN, self._logical_address) + def _hdmi_cec_unavailable(self, callback_event): + # Change state to unavailable. Without this, entity would remain in + # its last state, since the state changes are pushed. + self._state = STATE_UNAVAILABLE + self.schedule_update_ha_state(False) + def update(self): """Update device status.""" device = self._device @@ -383,6 +405,9 @@ class CecEntity(Entity): async def async_added_to_hass(self): """Register HDMI callbacks after initialization.""" self._device.set_update_callback(self._update) + self.hass.bus.async_listen( + EVENT_HDMI_CEC_UNAVAILABLE, self._hdmi_cec_unavailable + ) def _update(self, device=None): """Device status changed, schedule an update.""" diff --git a/homeassistant/components/hdmi_cec/manifest.json b/homeassistant/components/hdmi_cec/manifest.json index 90ed7cc3359..4f6975f52df 100644 --- a/homeassistant/components/hdmi_cec/manifest.json +++ b/homeassistant/components/hdmi_cec/manifest.json @@ -2,6 +2,6 @@ "domain": "hdmi_cec", "name": "HDMI-CEC", "documentation": "https://www.home-assistant.io/integrations/hdmi_cec", - "requirements": ["pyCEC==0.4.14"], + "requirements": ["pyCEC==0.5.1"], "codeowners": [] } diff --git a/requirements_all.txt b/requirements_all.txt index 40a3e8545be..963b262ec60 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1216,7 +1216,7 @@ py-zabbix==1.1.7 py17track==2.2.2 # homeassistant.components.hdmi_cec -pyCEC==0.4.14 +pyCEC==0.5.1 # homeassistant.components.control4 pyControl4==0.0.6