Skip to content
Permalink
Browse files

Added ToggleEntity save and restore state mechanism

  • Loading branch information...
lufton committed May 18, 2019
1 parent b3e66ad commit 0e275014a9eb0dd783b47e85ef894cd6c47889ff
@@ -6,10 +6,13 @@
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 @@ def is_on(hass, entity_id: str = None) -> bool:
'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.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 @@ class SetIntentHandler(intent.IntentHandler):
'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 @@

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 @@ def is_on(hass, entity_id=None):
'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_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 @@
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 @@ def __repr__(self):
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 @@ def is_on(self) -> bool:
"""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 @@ def async_toggle(self, **kwargs):
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()

0 comments on commit 0e27501

Please sign in to comment.
You can’t perform that action at this time.