mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Rfxtrx use previous received event to do complete restore (#37819)
* Add event attribute to display last received event * Restore state using event attribute * Allow empty dict for device config * Must also validate normal case * Do early return
This commit is contained in:
parent
f5b628c04f
commit
7c9be024bb
@ -24,7 +24,7 @@ from homeassistant.const import (
|
|||||||
UV_INDEX,
|
UV_INDEX,
|
||||||
)
|
)
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_EVENT,
|
ATTR_EVENT,
|
||||||
@ -92,9 +92,15 @@ def _bytearray_string(data):
|
|||||||
raise vol.Invalid("Data must be a hex string with multiple of two characters")
|
raise vol.Invalid("Data must be a hex string with multiple of two characters")
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_device(value):
|
||||||
|
if value is None:
|
||||||
|
return DEVICE_DATA_SCHEMA({})
|
||||||
|
return DEVICE_DATA_SCHEMA(value)
|
||||||
|
|
||||||
|
|
||||||
SERVICE_SEND_SCHEMA = vol.Schema({ATTR_EVENT: _bytearray_string})
|
SERVICE_SEND_SCHEMA = vol.Schema({ATTR_EVENT: _bytearray_string})
|
||||||
|
|
||||||
DEVICE_SCHEMA = vol.Schema(
|
DEVICE_DATA_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
||||||
vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
|
vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
|
||||||
@ -110,7 +116,7 @@ BASE_SCHEMA = vol.Schema(
|
|||||||
{
|
{
|
||||||
vol.Optional(CONF_DEBUG, default=False): cv.boolean,
|
vol.Optional(CONF_DEBUG, default=False): cv.boolean,
|
||||||
vol.Optional(CONF_AUTOMATIC_ADD, default=False): cv.boolean,
|
vol.Optional(CONF_AUTOMATIC_ADD, default=False): cv.boolean,
|
||||||
vol.Optional(CONF_DEVICES, default={}): {cv.string: DEVICE_SCHEMA},
|
vol.Optional(CONF_DEVICES, default={}): {cv.string: _ensure_device},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -337,7 +343,7 @@ def get_device_id(device, data_bits=None):
|
|||||||
return (f"{device.packettype:x}", f"{device.subtype:x}", id_string)
|
return (f"{device.packettype:x}", f"{device.subtype:x}", id_string)
|
||||||
|
|
||||||
|
|
||||||
class RfxtrxDevice(Entity):
|
class RfxtrxDevice(RestoreEntity):
|
||||||
"""Represents a Rfxtrx device.
|
"""Represents a Rfxtrx device.
|
||||||
|
|
||||||
Contains the common logic for Rfxtrx lights and switches.
|
Contains the common logic for Rfxtrx lights and switches.
|
||||||
@ -348,6 +354,7 @@ class RfxtrxDevice(Entity):
|
|||||||
self.signal_repetitions = signal_repetitions
|
self.signal_repetitions = signal_repetitions
|
||||||
self._name = f"{device.type_string} {device.id_string}"
|
self._name = f"{device.type_string} {device.id_string}"
|
||||||
self._device = device
|
self._device = device
|
||||||
|
self._event = None
|
||||||
self._state = None
|
self._state = None
|
||||||
self._device_id = device_id
|
self._device_id = device_id
|
||||||
self._unique_id = "_".join(x for x in self._device_id)
|
self._unique_id = "_".join(x for x in self._device_id)
|
||||||
@ -355,6 +362,17 @@ class RfxtrxDevice(Entity):
|
|||||||
if event:
|
if event:
|
||||||
self._apply_event(event)
|
self._apply_event(event)
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Restore RFXtrx device state (ON/OFF)."""
|
||||||
|
if self._event:
|
||||||
|
return
|
||||||
|
|
||||||
|
old_state = await self.async_get_last_state()
|
||||||
|
if old_state is not None:
|
||||||
|
event = old_state.attributes.get(ATTR_EVENT)
|
||||||
|
if event:
|
||||||
|
self._apply_event(get_rfx_object(event))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
"""No polling needed for a RFXtrx switch."""
|
"""No polling needed for a RFXtrx switch."""
|
||||||
@ -365,6 +383,13 @@ class RfxtrxDevice(Entity):
|
|||||||
"""Return the name of the device if any."""
|
"""Return the name of the device if any."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_state_attributes(self):
|
||||||
|
"""Return the device state attributes."""
|
||||||
|
if not self._event:
|
||||||
|
return None
|
||||||
|
return {ATTR_EVENT: "".join(f"{x:02x}" for x in self._event.data)}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if device is on."""
|
"""Return true if device is on."""
|
||||||
@ -391,6 +416,7 @@ class RfxtrxDevice(Entity):
|
|||||||
|
|
||||||
def _apply_event(self, event):
|
def _apply_event(self, event):
|
||||||
"""Apply a received event."""
|
"""Apply a received event."""
|
||||||
|
self._event = event
|
||||||
|
|
||||||
def _send_command(self, command, brightness=0):
|
def _send_command(self, command, brightness=0):
|
||||||
rfx_object = self.hass.data[DATA_RFXOBJECT]
|
rfx_object = self.hass.data[DATA_RFXOBJECT]
|
||||||
|
@ -12,6 +12,7 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import event as evt
|
from homeassistant.helpers import event as evt
|
||||||
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
CONF_AUTOMATIC_ADD,
|
CONF_AUTOMATIC_ADD,
|
||||||
@ -25,6 +26,7 @@ from . import (
|
|||||||
get_rfx_object,
|
get_rfx_object,
|
||||||
)
|
)
|
||||||
from .const import (
|
from .const import (
|
||||||
|
ATTR_EVENT,
|
||||||
COMMAND_OFF_LIST,
|
COMMAND_OFF_LIST,
|
||||||
COMMAND_ON_LIST,
|
COMMAND_ON_LIST,
|
||||||
DATA_RFXTRX_CONFIG,
|
DATA_RFXTRX_CONFIG,
|
||||||
@ -105,7 +107,7 @@ async def async_setup_entry(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RfxtrxBinarySensor(BinarySensorEntity):
|
class RfxtrxBinarySensor(BinarySensorEntity, RestoreEntity):
|
||||||
"""A representation of a RFXtrx binary sensor."""
|
"""A representation of a RFXtrx binary sensor."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -120,7 +122,7 @@ class RfxtrxBinarySensor(BinarySensorEntity):
|
|||||||
event=None,
|
event=None,
|
||||||
):
|
):
|
||||||
"""Initialize the RFXtrx sensor."""
|
"""Initialize the RFXtrx sensor."""
|
||||||
self.event = None
|
self._event = None
|
||||||
self._device = device
|
self._device = device
|
||||||
self._name = f"{device.type_string} {device.id_string}"
|
self._name = f"{device.type_string} {device.id_string}"
|
||||||
self._device_class = device_class
|
self._device_class = device_class
|
||||||
@ -141,6 +143,13 @@ class RfxtrxBinarySensor(BinarySensorEntity):
|
|||||||
"""Restore RFXtrx switch device state (ON/OFF)."""
|
"""Restore RFXtrx switch device state (ON/OFF)."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
|
|
||||||
|
if self._event is None:
|
||||||
|
old_state = await self.async_get_last_state()
|
||||||
|
if old_state is not None:
|
||||||
|
event = old_state.attributes.get(ATTR_EVENT)
|
||||||
|
if event:
|
||||||
|
self._apply_event(get_rfx_object(event))
|
||||||
|
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
||||||
SIGNAL_EVENT, self._handle_event
|
SIGNAL_EVENT, self._handle_event
|
||||||
@ -152,6 +161,13 @@ class RfxtrxBinarySensor(BinarySensorEntity):
|
|||||||
"""Return the device name."""
|
"""Return the device name."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_state_attributes(self):
|
||||||
|
"""Return the device state attributes."""
|
||||||
|
if not self._event:
|
||||||
|
return None
|
||||||
|
return {ATTR_EVENT: "".join(f"{x:02x}" for x in self._event.data)}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def data_bits(self):
|
def data_bits(self):
|
||||||
"""Return the number of data bits."""
|
"""Return the number of data bits."""
|
||||||
@ -221,6 +237,7 @@ class RfxtrxBinarySensor(BinarySensorEntity):
|
|||||||
|
|
||||||
def _apply_event(self, event):
|
def _apply_event(self, event):
|
||||||
"""Apply command from rfxtrx."""
|
"""Apply command from rfxtrx."""
|
||||||
|
self._event = event
|
||||||
if event.device.packettype == DEVICE_PACKET_TYPE_LIGHTING4:
|
if event.device.packettype == DEVICE_PACKET_TYPE_LIGHTING4:
|
||||||
self._apply_event_lighting4(event)
|
self._apply_event_lighting4(event)
|
||||||
else:
|
else:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.components.cover import CoverEntity
|
from homeassistant.components.cover import CoverEntity
|
||||||
from homeassistant.const import CONF_DEVICES, STATE_OPEN
|
from homeassistant.const import CONF_DEVICES
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.restore_state import RestoreEntity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
|
|
||||||
@ -86,10 +86,6 @@ class RfxtrxCover(RfxtrxDevice, CoverEntity, RestoreEntity):
|
|||||||
"""Restore RFXtrx cover device state (OPEN/CLOSE)."""
|
"""Restore RFXtrx cover device state (OPEN/CLOSE)."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
|
|
||||||
old_state = await self.async_get_last_state()
|
|
||||||
if old_state is not None:
|
|
||||||
self._state = old_state.state == STATE_OPEN
|
|
||||||
|
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
||||||
SIGNAL_EVENT, self._handle_event
|
SIGNAL_EVENT, self._handle_event
|
||||||
@ -120,6 +116,7 @@ class RfxtrxCover(RfxtrxDevice, CoverEntity, RestoreEntity):
|
|||||||
|
|
||||||
def _apply_event(self, event):
|
def _apply_event(self, event):
|
||||||
"""Apply command from rfxtrx."""
|
"""Apply command from rfxtrx."""
|
||||||
|
super()._apply_event(event)
|
||||||
if event.values["Command"] in COMMAND_ON_LIST:
|
if event.values["Command"] in COMMAND_ON_LIST:
|
||||||
self._state = True
|
self._state = True
|
||||||
elif event.values["Command"] in COMMAND_OFF_LIST:
|
elif event.values["Command"] in COMMAND_OFF_LIST:
|
||||||
|
@ -8,9 +8,8 @@ from homeassistant.components.light import (
|
|||||||
SUPPORT_BRIGHTNESS,
|
SUPPORT_BRIGHTNESS,
|
||||||
LightEntity,
|
LightEntity,
|
||||||
)
|
)
|
||||||
from homeassistant.const import CONF_DEVICES, STATE_ON
|
from homeassistant.const import CONF_DEVICES
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.restore_state import RestoreEntity
|
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
CONF_AUTOMATIC_ADD,
|
CONF_AUTOMATIC_ADD,
|
||||||
@ -93,7 +92,7 @@ async def async_setup_entry(
|
|||||||
hass.helpers.dispatcher.async_dispatcher_connect(SIGNAL_EVENT, light_update)
|
hass.helpers.dispatcher.async_dispatcher_connect(SIGNAL_EVENT, light_update)
|
||||||
|
|
||||||
|
|
||||||
class RfxtrxLight(RfxtrxDevice, LightEntity, RestoreEntity):
|
class RfxtrxLight(RfxtrxDevice, LightEntity):
|
||||||
"""Representation of a RFXtrx light."""
|
"""Representation of a RFXtrx light."""
|
||||||
|
|
||||||
_brightness = 0
|
_brightness = 0
|
||||||
@ -102,17 +101,6 @@ class RfxtrxLight(RfxtrxDevice, LightEntity, RestoreEntity):
|
|||||||
"""Restore RFXtrx device state (ON/OFF)."""
|
"""Restore RFXtrx device state (ON/OFF)."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
|
|
||||||
old_state = await self.async_get_last_state()
|
|
||||||
if old_state is not None:
|
|
||||||
self._state = old_state.state == STATE_ON
|
|
||||||
|
|
||||||
# Restore the brightness of dimmable devices
|
|
||||||
if (
|
|
||||||
old_state is not None
|
|
||||||
and old_state.attributes.get(ATTR_BRIGHTNESS) is not None
|
|
||||||
):
|
|
||||||
self._brightness = int(old_state.attributes[ATTR_BRIGHTNESS])
|
|
||||||
|
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
||||||
SIGNAL_EVENT, self._handle_event
|
SIGNAL_EVENT, self._handle_event
|
||||||
@ -147,6 +135,7 @@ class RfxtrxLight(RfxtrxDevice, LightEntity, RestoreEntity):
|
|||||||
|
|
||||||
def _apply_event(self, event):
|
def _apply_event(self, event):
|
||||||
"""Apply command from rfxtrx."""
|
"""Apply command from rfxtrx."""
|
||||||
|
super()._apply_event(event)
|
||||||
if event.values["Command"] in COMMAND_ON_LIST:
|
if event.values["Command"] in COMMAND_ON_LIST:
|
||||||
self._state = True
|
self._state = True
|
||||||
elif event.values["Command"] in COMMAND_OFF_LIST:
|
elif event.values["Command"] in COMMAND_OFF_LIST:
|
||||||
|
@ -11,7 +11,7 @@ from homeassistant.components.sensor import (
|
|||||||
)
|
)
|
||||||
from homeassistant.const import CONF_DEVICES
|
from homeassistant.const import CONF_DEVICES
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
CONF_AUTOMATIC_ADD,
|
CONF_AUTOMATIC_ADD,
|
||||||
@ -21,7 +21,7 @@ from . import (
|
|||||||
get_device_id,
|
get_device_id,
|
||||||
get_rfx_object,
|
get_rfx_object,
|
||||||
)
|
)
|
||||||
from .const import DATA_RFXTRX_CONFIG
|
from .const import ATTR_EVENT, DATA_RFXTRX_CONFIG
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -113,12 +113,12 @@ async def async_setup_entry(
|
|||||||
hass.helpers.dispatcher.async_dispatcher_connect(SIGNAL_EVENT, sensor_update)
|
hass.helpers.dispatcher.async_dispatcher_connect(SIGNAL_EVENT, sensor_update)
|
||||||
|
|
||||||
|
|
||||||
class RfxtrxSensor(Entity):
|
class RfxtrxSensor(RestoreEntity):
|
||||||
"""Representation of a RFXtrx sensor."""
|
"""Representation of a RFXtrx sensor."""
|
||||||
|
|
||||||
def __init__(self, device, device_id, data_type, event=None):
|
def __init__(self, device, device_id, data_type, event=None):
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
self.event = None
|
self._event = None
|
||||||
self._device = device
|
self._device = device
|
||||||
self._name = f"{device.type_string} {device.id_string} {data_type}"
|
self._name = f"{device.type_string} {device.id_string} {data_type}"
|
||||||
self.data_type = data_type
|
self.data_type = data_type
|
||||||
@ -136,6 +136,13 @@ class RfxtrxSensor(Entity):
|
|||||||
"""Restore RFXtrx switch device state (ON/OFF)."""
|
"""Restore RFXtrx switch device state (ON/OFF)."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
|
|
||||||
|
if self._event is None:
|
||||||
|
old_state = await self.async_get_last_state()
|
||||||
|
if old_state is not None:
|
||||||
|
event = old_state.attributes.get(ATTR_EVENT)
|
||||||
|
if event:
|
||||||
|
self._apply_event(get_rfx_object(event))
|
||||||
|
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
||||||
SIGNAL_EVENT, self._handle_event
|
SIGNAL_EVENT, self._handle_event
|
||||||
@ -149,9 +156,9 @@ class RfxtrxSensor(Entity):
|
|||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the state of the sensor."""
|
"""Return the state of the sensor."""
|
||||||
if not self.event:
|
if not self._event:
|
||||||
return None
|
return None
|
||||||
value = self.event.values.get(self.data_type)
|
value = self._event.values.get(self.data_type)
|
||||||
return self._convert_fun(value)
|
return self._convert_fun(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -162,9 +169,9 @@ class RfxtrxSensor(Entity):
|
|||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the device state attributes."""
|
"""Return the device state attributes."""
|
||||||
if not self.event:
|
if not self._event:
|
||||||
return None
|
return None
|
||||||
return self.event.values
|
return {ATTR_EVENT: "".join(f"{x:02x}" for x in self._event.data)}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self):
|
def unit_of_measurement(self):
|
||||||
@ -192,7 +199,7 @@ class RfxtrxSensor(Entity):
|
|||||||
|
|
||||||
def _apply_event(self, event):
|
def _apply_event(self, event):
|
||||||
"""Apply command from rfxtrx."""
|
"""Apply command from rfxtrx."""
|
||||||
self.event = event
|
self._event = event
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _handle_event(self, event, device_id):
|
def _handle_event(self, event, device_id):
|
||||||
|
@ -4,7 +4,7 @@ import logging
|
|||||||
import RFXtrx as rfxtrxmod
|
import RFXtrx as rfxtrxmod
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity
|
from homeassistant.components.switch import SwitchEntity
|
||||||
from homeassistant.const import CONF_DEVICES, STATE_ON
|
from homeassistant.const import CONF_DEVICES
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.restore_state import RestoreEntity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
|
|
||||||
@ -96,10 +96,6 @@ class RfxtrxSwitch(RfxtrxDevice, SwitchEntity, RestoreEntity):
|
|||||||
"""Restore RFXtrx switch device state (ON/OFF)."""
|
"""Restore RFXtrx switch device state (ON/OFF)."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
|
|
||||||
old_state = await self.async_get_last_state()
|
|
||||||
if old_state is not None:
|
|
||||||
self._state = old_state.state == STATE_ON
|
|
||||||
|
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
||||||
SIGNAL_EVENT, self._handle_event
|
SIGNAL_EVENT, self._handle_event
|
||||||
@ -108,6 +104,7 @@ class RfxtrxSwitch(RfxtrxDevice, SwitchEntity, RestoreEntity):
|
|||||||
|
|
||||||
def _apply_event(self, event):
|
def _apply_event(self, event):
|
||||||
"""Apply command from rfxtrx."""
|
"""Apply command from rfxtrx."""
|
||||||
|
super()._apply_event(event)
|
||||||
if event.values["Command"] in COMMAND_ON_LIST:
|
if event.values["Command"] in COMMAND_ON_LIST:
|
||||||
self._state = True
|
self._state = True
|
||||||
elif event.values["Command"] in COMMAND_OFF_LIST:
|
elif event.values["Command"] in COMMAND_OFF_LIST:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user