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 <erik@montnemery.com>
pull/48088/head
Raj Laud 2021-03-18 07:07:35 -05:00 committed by GitHub
parent 25a13d1554
commit 99f9f8dec0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 5 deletions

View File

@ -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."""

View File

@ -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": []
}

View File

@ -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