1
mirror of https://github.com/home-assistant/core synced 2024-10-07 10:13:38 +02:00

Added ToggleEntity save and restore state mechanism

This commit is contained in:
lufton 2019-05-18 22:24:23 +03:00
parent b3e66ad42f
commit 0e275014a9
8 changed files with 220 additions and 8 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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