Added ToggleEntity save and restore state mechanism
parent
b3e66ad42f
commit
0e275014a9
|
@ -6,10 +6,13 @@ import logging
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import group
|
||||
from homeassistant.const import (SERVICE_TURN_ON, SERVICE_TOGGLE,
|
||||
SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
||||
from homeassistant.const import (
|
||||
SERVICE_CANCEL_RESTORE_STATE, SERVICE_RESTORE_STATE, SERVICE_SAVE_STATE,
|
||||
SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON, ATTR_ENTITY_ID)
|
||||
from homeassistant.loader import bind_hass
|
||||
from homeassistant.helpers.entity import ToggleEntity
|
||||
from homeassistant.helpers.entity import (
|
||||
ToggleEntity, ENTITY_SAVE_STATE_SCHEMA,
|
||||
ENTITY_RESTORE_STATE_SCHEMA, ENTITY_CANCEL_RESTORE_STATE_SCHEMA)
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.config_validation import ( # noqa
|
||||
PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE)
|
||||
|
@ -123,6 +126,21 @@ async def async_setup(hass, config: dict):
|
|||
'async_set_direction'
|
||||
)
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_SAVE_STATE, ENTITY_SAVE_STATE_SCHEMA,
|
||||
'async_save_state'
|
||||
)
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_RESTORE_STATE, ENTITY_RESTORE_STATE_SCHEMA,
|
||||
'async_restore_state'
|
||||
)
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_CANCEL_RESTORE_STATE, ENTITY_CANCEL_RESTORE_STATE_SCHEMA,
|
||||
'async_cancel_restore_state'
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
@ -54,6 +54,33 @@ set_direction:
|
|||
description: The direction to rotate. Either 'forward' or 'reverse'
|
||||
example: 'forward'
|
||||
|
||||
save_state:
|
||||
description: Saves a state of the entity.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities to save state of.
|
||||
example: 'fan.attic'
|
||||
rewrite:
|
||||
description: Should it rewrite already saved state fo the entity (default False).
|
||||
example: True
|
||||
|
||||
restore_state:
|
||||
description: Restores a state of the entity.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities to restore state of.
|
||||
example: 'fan.attic'
|
||||
delay:
|
||||
description: Time period before restore.
|
||||
example: "5, '0:05', {'minutes': 5}"
|
||||
|
||||
cancel_restore_state:
|
||||
description: Cancels scheduled state restore of the entity.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities to cancel restoring state of.
|
||||
example: 'fan.attic'
|
||||
|
||||
xiaomi_miio_set_buzzer_on:
|
||||
description: Turn the buzzer on.
|
||||
fields:
|
||||
|
|
|
@ -11,13 +11,16 @@ from homeassistant.auth.permissions.const import POLICY_CONTROL
|
|||
from homeassistant.components.group import \
|
||||
ENTITY_ID_FORMAT as GROUP_ENTITY_ID_FORMAT
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON,
|
||||
ATTR_ENTITY_ID, SERVICE_CANCEL_RESTORE_STATE, SERVICE_RESTORE_STATE,
|
||||
SERVICE_SAVE_STATE, SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON,
|
||||
STATE_ON)
|
||||
from homeassistant.exceptions import UnknownUser, Unauthorized
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.config_validation import ( # noqa
|
||||
PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE)
|
||||
from homeassistant.helpers.entity import ToggleEntity
|
||||
from homeassistant.helpers.entity import (
|
||||
ToggleEntity, ENTITY_SAVE_STATE_SCHEMA, ENTITY_RESTORE_STATE_SCHEMA,
|
||||
ENTITY_CANCEL_RESTORE_STATE_SCHEMA)
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers import intent
|
||||
from homeassistant.loader import bind_hass
|
||||
|
@ -320,6 +323,21 @@ async def async_setup(hass, config):
|
|||
'async_toggle'
|
||||
)
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_SAVE_STATE, ENTITY_SAVE_STATE_SCHEMA,
|
||||
'async_save_state'
|
||||
)
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_RESTORE_STATE, ENTITY_RESTORE_STATE_SCHEMA,
|
||||
'async_restore_state'
|
||||
)
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_CANCEL_RESTORE_STATE, ENTITY_CANCEL_RESTORE_STATE_SCHEMA,
|
||||
'async_cancel_restore_state'
|
||||
)
|
||||
|
||||
hass.helpers.intent.async_register(SetIntentHandler())
|
||||
|
||||
return True
|
||||
|
|
|
@ -71,6 +71,33 @@ toggle:
|
|||
'...':
|
||||
description: All turn_on parameters can be used.
|
||||
|
||||
save_state:
|
||||
description: Saves a state of the entity.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities to save state of.
|
||||
example: 'light.attic'
|
||||
rewrite:
|
||||
description: Should it rewrite already saved state fo the entity (default False).
|
||||
example: True
|
||||
|
||||
restore_state:
|
||||
description: Restores a state of the entity.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities to restore state of.
|
||||
example: 'light.attic'
|
||||
delay:
|
||||
description: Time period before restore.
|
||||
example: "5, '0:05', {'minutes': 5}"
|
||||
|
||||
cancel_restore_state:
|
||||
description: Cancels scheduled state restore of the entity.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities to cancel restoring state of.
|
||||
example: 'light.attic'
|
||||
|
||||
lifx_set_state:
|
||||
description: Set a color/brightness and possibliy turn the light on/off.
|
||||
fields:
|
||||
|
|
|
@ -6,12 +6,15 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.loader import bind_hass
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.entity import ToggleEntity
|
||||
from homeassistant.helpers.entity import (
|
||||
ToggleEntity, ENTITY_SAVE_STATE_SCHEMA,
|
||||
ENTITY_RESTORE_STATE_SCHEMA, ENTITY_CANCEL_RESTORE_STATE_SCHEMA)
|
||||
from homeassistant.helpers.config_validation import ( # noqa
|
||||
PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.const import (
|
||||
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE,
|
||||
STATE_ON, SERVICE_CANCEL_RESTORE_STATE, SERVICE_RESTORE_STATE,
|
||||
SERVICE_SAVE_STATE, SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON,
|
||||
ATTR_ENTITY_ID)
|
||||
from homeassistant.components import group
|
||||
|
||||
|
@ -81,6 +84,22 @@ async def async_setup(hass, config):
|
|||
'async_toggle'
|
||||
)
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_SAVE_STATE, ENTITY_SAVE_STATE_SCHEMA,
|
||||
'async_save_state'
|
||||
)
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_RESTORE_STATE, ENTITY_RESTORE_STATE_SCHEMA,
|
||||
'async_restore_state'
|
||||
)
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_CANCEL_RESTORE_STATE, ENTITY_CANCEL_RESTORE_STATE_SCHEMA,
|
||||
'async_cancel_restore_state'
|
||||
)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,33 @@ toggle:
|
|||
description: Name(s) of entities to toggle.
|
||||
example: 'switch.living_room'
|
||||
|
||||
save_state:
|
||||
description: Saves a state of the entity.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities to save state of.
|
||||
example: 'switch.attic'
|
||||
rewrite:
|
||||
description: Should it rewrite already saved state fo the entity (default False).
|
||||
example: True
|
||||
|
||||
restore_state:
|
||||
description: Restores a state of the entity.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities to restore state of.
|
||||
example: 'switch.attic'
|
||||
delay:
|
||||
description: Time period before restore.
|
||||
example: "5, '0:05', {'minutes': 5}"
|
||||
|
||||
cancel_restore_state:
|
||||
description: Cancels scheduled state restore of the entity.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities to cancel restoring state of.
|
||||
example: 'switch.attic'
|
||||
|
||||
mysensors_send_ir_code:
|
||||
description: Set an IR code as a state attribute for a MySensors IR device switch and turn the switch on.
|
||||
fields:
|
||||
|
|
|
@ -371,6 +371,9 @@ SERVICE_HOMEASSISTANT_RESTART = 'restart'
|
|||
SERVICE_TURN_ON = 'turn_on'
|
||||
SERVICE_TURN_OFF = 'turn_off'
|
||||
SERVICE_TOGGLE = 'toggle'
|
||||
SERVICE_SAVE_STATE = 'save_state'
|
||||
SERVICE_RESTORE_STATE = 'restore_state'
|
||||
SERVICE_CANCEL_RESTORE_STATE = 'cancel_restore_state'
|
||||
SERVICE_RELOAD = 'reload'
|
||||
|
||||
SERVICE_VOLUME_UP = 'volume_up'
|
||||
|
|
|
@ -5,21 +5,45 @@ import functools as ft
|
|||
from timeit import default_timer as timer
|
||||
from typing import Optional, List, Iterable
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
ATTR_ASSUMED_STATE, ATTR_FRIENDLY_NAME, ATTR_HIDDEN, ATTR_ICON,
|
||||
ATTR_UNIT_OF_MEASUREMENT, DEVICE_DEFAULT_NAME, STATE_OFF, STATE_ON,
|
||||
STATE_UNAVAILABLE, STATE_UNKNOWN, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
||||
ATTR_ENTITY_PICTURE, ATTR_SUPPORTED_FEATURES, ATTR_DEVICE_CLASS)
|
||||
ATTR_ENTITY_ID, ATTR_ENTITY_PICTURE, ATTR_SUPPORTED_FEATURES,
|
||||
ATTR_DEVICE_CLASS)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.config import DATA_CUSTOMIZE
|
||||
from homeassistant.exceptions import NoEntitySpecifiedError
|
||||
from homeassistant.util import ensure_unique_string, slugify
|
||||
from homeassistant.util.async_ import run_callback_threadsafe
|
||||
from homeassistant.util import dt as dt_util
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
import homeassistant.helpers.event as evt
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
SLOW_UPDATE_WARNING = 10
|
||||
|
||||
ATTR_REWRITE = "rewrite"
|
||||
ATTR_DELAY = "delay"
|
||||
|
||||
ENTITY_SAVE_STATE_SCHEMA = vol.Schema({
|
||||
ATTR_ENTITY_ID: cv.comp_entity_ids,
|
||||
ATTR_REWRITE: cv.boolean,
|
||||
})
|
||||
|
||||
ENTITY_RESTORE_STATE_SCHEMA = vol.Schema({
|
||||
ATTR_ENTITY_ID: cv.comp_entity_ids,
|
||||
ATTR_DELAY: vol.All(cv.time_period, cv.positive_timedelta),
|
||||
})
|
||||
|
||||
ENTITY_CANCEL_RESTORE_STATE_SCHEMA = vol.Schema({
|
||||
ATTR_ENTITY_ID: cv.comp_entity_ids,
|
||||
})
|
||||
|
||||
SAVED_STATE_ID_FORMAT = "saved_{}"
|
||||
|
||||
|
||||
def generate_entity_id(entity_id_format: str, name: Optional[str],
|
||||
current_ids: Optional[List[str]] = None,
|
||||
|
@ -448,6 +472,8 @@ class Entity:
|
|||
class ToggleEntity(Entity):
|
||||
"""An abstract class for entities that can be turned on and off."""
|
||||
|
||||
_restore_state_listener = None
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""Return the state."""
|
||||
|
@ -458,6 +484,11 @@ class ToggleEntity(Entity):
|
|||
"""Return True if entity is on."""
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def saved_state_id(self):
|
||||
"""Return the id of state to save"""
|
||||
return SAVED_STATE_ID_FORMAT.format(self.entity_id)
|
||||
|
||||
def turn_on(self, **kwargs) -> None:
|
||||
"""Turn the entity on."""
|
||||
raise NotImplementedError()
|
||||
|
@ -497,3 +528,45 @@ class ToggleEntity(Entity):
|
|||
if self.is_on:
|
||||
return self.async_turn_off(**kwargs)
|
||||
return self.async_turn_on(**kwargs)
|
||||
|
||||
async def async_cancel_restore_state(self):
|
||||
"""Cancel scheduled entity state restore."""
|
||||
if self._restore_state_listener:
|
||||
self._restore_state_listener()
|
||||
self._restore_state_listener = None
|
||||
|
||||
async def async_save_state(self, rewrite=False):
|
||||
"""Save entity state."""
|
||||
if rewrite:
|
||||
await self.async_cancel_restore_state()
|
||||
|
||||
if rewrite or not self.hass.states.get(self.saved_state_id):
|
||||
self.hass.states.async_set(
|
||||
self.saved_state_id,
|
||||
self.state,
|
||||
self.hass.states.get(self.entity_id).attributes
|
||||
)
|
||||
|
||||
@callback
|
||||
async def async_restore_state_listener(self, *args):
|
||||
"""Restore entity state after a delay."""
|
||||
await self.async_cancel_restore_state()
|
||||
saved_state = self.hass.states.get(self.saved_state_id)
|
||||
if saved_state:
|
||||
if saved_state.state == STATE_ON:
|
||||
await self.async_turn_on(**saved_state.attributes)
|
||||
else:
|
||||
await self.async_turn_off()
|
||||
self.hass.states.async_remove(self.saved_state_id)
|
||||
|
||||
async def async_restore_state(self, delay=None):
|
||||
"""Restore previously saved entity state."""
|
||||
if delay:
|
||||
await self.async_cancel_restore_state()
|
||||
self._restore_state_listener = evt.async_call_later(
|
||||
self.hass,
|
||||
delay.total_seconds(),
|
||||
self.async_restore_state_listener()
|
||||
)
|
||||
else:
|
||||
await self.async_restore_state_listener()
|
||||
|
|
Loading…
Reference in New Issue