Fix hdmi_cec entity race (#18753)

* Update shouldn't be called before adding the entity.
* Transitional states from
  8adc786bac/include/cectypes.h (L458-L459)

Addressing https://github.com/home-assistant/home-assistant/issues/12846
This commit is contained in:
Vladimir Eremin 2018-12-02 14:51:04 +00:00 committed by Paulus Schoutsen
parent eec4564c71
commit debae6ad2e
3 changed files with 57 additions and 53 deletions

View file

@ -320,26 +320,20 @@ def setup(hass: HomeAssistant, base_config):
class CecDevice(Entity):
"""Representation of a HDMI CEC device entity."""
def __init__(self, hass: HomeAssistant, device, logical) -> None:
def __init__(self, device, logical) -> None:
"""Initialize the device."""
self._device = device
self.hass = hass
self._icon = None
self._state = STATE_UNKNOWN
self._logical_address = logical
self.entity_id = "%s.%d" % (DOMAIN, self._logical_address)
device.set_update_callback(self._update)
def update(self):
"""Update device status."""
self._update()
def _update(self, device=None):
"""Update device status."""
if device:
device = self._device
from pycec.const import STATUS_PLAY, STATUS_STOP, STATUS_STILL, \
POWER_OFF, POWER_ON
if device.power_status == POWER_OFF:
if device.power_status in [POWER_OFF, 3]:
self._state = STATE_OFF
elif device.status == STATUS_PLAY:
self._state = STATE_PLAYING
@ -347,11 +341,18 @@ class CecDevice(Entity):
self._state = STATE_IDLE
elif device.status == STATUS_STILL:
self._state = STATE_PAUSED
elif device.power_status == POWER_ON:
elif device.power_status in [POWER_ON, 4]:
self._state = STATE_ON
else:
_LOGGER.warning("Unknown state: %d", device.power_status)
self.schedule_update_ha_state()
async def async_added_to_hass(self):
"""Register HDMI callbacks after initialization."""
self._device.set_update_callback(self._update)
def _update(self, device=None):
"""Device status changed, schedule an update."""
self.schedule_update_ha_state(True)
@property
def name(self):

View file

@ -13,7 +13,6 @@ from homeassistant.components.media_player import (
SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_STEP, MediaPlayerDevice)
from homeassistant.const import (
STATE_IDLE, STATE_OFF, STATE_ON, STATE_PAUSED, STATE_PLAYING)
from homeassistant.core import HomeAssistant
DEPENDENCIES = ['hdmi_cec']
@ -26,20 +25,23 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
"""Find and return HDMI devices as +switches."""
if ATTR_NEW in discovery_info:
_LOGGER.info("Setting up HDMI devices %s", discovery_info[ATTR_NEW])
add_entities(CecPlayerDevice(hass, hass.data.get(device),
hass.data.get(device).logical_address) for
device in discovery_info[ATTR_NEW])
entities = []
for device in discovery_info[ATTR_NEW]:
hdmi_device = hass.data.get(device)
entities.append(CecPlayerDevice(
hdmi_device, hdmi_device.logical_address,
))
add_entities(entities, True)
class CecPlayerDevice(CecDevice, MediaPlayerDevice):
"""Representation of a HDMI device as a Media player."""
def __init__(self, hass: HomeAssistant, device, logical) -> None:
def __init__(self, device, logical) -> None:
"""Initialize the HDMI device."""
CecDevice.__init__(self, hass, device, logical)
CecDevice.__init__(self, device, logical)
self.entity_id = "%s.%s_%s" % (
DOMAIN, 'hdmi', hex(self._logical_address)[2:])
self.update()
def send_keypress(self, key):
"""Send keypress to CEC adapter."""
@ -137,15 +139,15 @@ class CecPlayerDevice(CecDevice, MediaPlayerDevice):
"""Cache state of device."""
return self._state
def _update(self, device=None):
def update(self):
"""Update device status."""
if device:
device = self._device
from pycec.const import STATUS_PLAY, STATUS_STOP, STATUS_STILL, \
POWER_OFF, POWER_ON
if device.power_status == POWER_OFF:
if device.power_status in [POWER_OFF, 3]:
self._state = STATE_OFF
elif not self.support_pause:
if device.power_status == POWER_ON:
if device.power_status in [POWER_ON, 4]:
self._state = STATE_ON
elif device.status == STATUS_PLAY:
self._state = STATE_PLAYING
@ -155,7 +157,6 @@ class CecPlayerDevice(CecDevice, MediaPlayerDevice):
self._state = STATE_PAUSED
else:
_LOGGER.warning("Unknown state: %s", device.status)
self.schedule_update_ha_state()
@property
def supported_features(self):

View file

@ -9,7 +9,6 @@ import logging
from homeassistant.components.hdmi_cec import CecDevice, ATTR_NEW
from homeassistant.components.switch import SwitchDevice, DOMAIN
from homeassistant.const import STATE_OFF, STATE_STANDBY, STATE_ON
from homeassistant.core import HomeAssistant
DEPENDENCIES = ['hdmi_cec']
@ -22,20 +21,23 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
"""Find and return HDMI devices as switches."""
if ATTR_NEW in discovery_info:
_LOGGER.info("Setting up HDMI devices %s", discovery_info[ATTR_NEW])
add_entities(CecSwitchDevice(hass, hass.data.get(device),
hass.data.get(device).logical_address) for
device in discovery_info[ATTR_NEW])
entities = []
for device in discovery_info[ATTR_NEW]:
hdmi_device = hass.data.get(device)
entities.append(CecSwitchDevice(
hdmi_device, hdmi_device.logical_address,
))
add_entities(entities, True)
class CecSwitchDevice(CecDevice, SwitchDevice):
"""Representation of a HDMI device as a Switch."""
def __init__(self, hass: HomeAssistant, device, logical) -> None:
def __init__(self, device, logical) -> None:
"""Initialize the HDMI device."""
CecDevice.__init__(self, hass, device, logical)
CecDevice.__init__(self, device, logical)
self.entity_id = "%s.%s_%s" % (
DOMAIN, 'hdmi', hex(self._logical_address)[2:])
self.update()
def turn_on(self, **kwargs) -> None:
"""Turn device on."""