Skip to content

Commit

Permalink
Restore states through a JSON store instead of recorder (#17270)
Browse files Browse the repository at this point in the history
* Restore states through a JSON store

* Accept entity_id directly in restore state helper

* Keep states stored between runs for a limited time

* Remove warning
  • Loading branch information
emlove authored and balloob committed Nov 28, 2018
1 parent a039c32 commit 5c3a4e3
Show file tree
Hide file tree
Showing 46 changed files with 488 additions and 417 deletions.
6 changes: 3 additions & 3 deletions homeassistant/components/alarm_control_panel/manual.py
Expand Up @@ -21,7 +21,7 @@
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import track_point_in_time
import homeassistant.util.dt as dt_util
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.restore_state import RestoreEntity

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -116,7 +116,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
)])


class ManualAlarm(alarm.AlarmControlPanel):
class ManualAlarm(alarm.AlarmControlPanel, RestoreEntity):
"""
Representation of an alarm status.
Expand Down Expand Up @@ -310,7 +310,7 @@ def device_state_attributes(self):

async def async_added_to_hass(self):
"""Run when entity about to be added to hass."""
state = await async_get_last_state(self.hass, self.entity_id)
state = await self.async_get_last_state()
if state:
self._state = state.state
self._state_ts = state.last_updated
3 changes: 1 addition & 2 deletions homeassistant/components/alarm_control_panel/mqtt.py
Expand Up @@ -108,8 +108,7 @@ def __init__(self, config, discovery_hash):

async def async_added_to_hass(self):
"""Subscribe mqtt events."""
await MqttAvailability.async_added_to_hass(self)
await MqttDiscoveryUpdate.async_added_to_hass(self)
await super().async_added_to_hass()
await self._subscribe_topics()

async def discovery_update(self, discovery_payload):
Expand Down
8 changes: 5 additions & 3 deletions homeassistant/components/automation/__init__.py
Expand Up @@ -21,7 +21,7 @@
from homeassistant.helpers import extract_domain_configs, script, condition
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.util.dt import utcnow
import homeassistant.helpers.config_validation as cv

Expand Down Expand Up @@ -182,7 +182,7 @@ async def reload_service_handler(service_call):
return True


class AutomationEntity(ToggleEntity):
class AutomationEntity(ToggleEntity, RestoreEntity):
"""Entity to show status of entity."""

def __init__(self, automation_id, name, async_attach_triggers, cond_func,
Expand Down Expand Up @@ -227,12 +227,13 @@ def is_on(self) -> bool:

async def async_added_to_hass(self) -> None:
"""Startup with initial state or previous state."""
await super().async_added_to_hass()
if self._initial_state is not None:
enable_automation = self._initial_state
_LOGGER.debug("Automation %s initial state %s from config "
"initial_state", self.entity_id, enable_automation)
else:
state = await async_get_last_state(self.hass, self.entity_id)
state = await self.async_get_last_state()
if state:
enable_automation = state.state == STATE_ON
self._last_triggered = state.attributes.get('last_triggered')
Expand Down Expand Up @@ -291,6 +292,7 @@ async def async_trigger(self, variables, skip_condition=False,

async def async_will_remove_from_hass(self):
"""Remove listeners when removing automation from HASS."""
await super().async_will_remove_from_hass()
await self.async_turn_off()

async def async_enable(self):
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/binary_sensor/mqtt.py
Expand Up @@ -102,8 +102,7 @@ def __init__(self, config, discovery_hash):

async def async_added_to_hass(self):
"""Subscribe mqtt events."""
await MqttAvailability.async_added_to_hass(self)
await MqttDiscoveryUpdate.async_added_to_hass(self)
await super().async_added_to_hass()
await self._subscribe_topics()

async def discovery_update(self, discovery_payload):
Expand Down
7 changes: 4 additions & 3 deletions homeassistant/components/climate/generic_thermostat.py
Expand Up @@ -23,7 +23,7 @@
from homeassistant.helpers.event import (
async_track_state_change, async_track_time_interval)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.restore_state import RestoreEntity

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -96,7 +96,7 @@ async def async_setup_platform(hass, config, async_add_entities,
precision)])


class GenericThermostat(ClimateDevice):
class GenericThermostat(ClimateDevice, RestoreEntity):
"""Representation of a Generic Thermostat device."""

def __init__(self, hass, name, heater_entity_id, sensor_entity_id,
Expand Down Expand Up @@ -155,8 +155,9 @@ def __init__(self, hass, name, heater_entity_id, sensor_entity_id,

async def async_added_to_hass(self):
"""Run when entity about to be added."""
await super().async_added_to_hass()
# Check If we have an old state
old_state = await async_get_last_state(self.hass, self.entity_id)
old_state = await self.async_get_last_state()
if old_state is not None:
# If we have no initial temperature, restore
if self._target_temp is None:
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/climate/mqtt.py
Expand Up @@ -221,8 +221,7 @@ def __init__(self, hass, config, discovery_hash):

async def async_added_to_hass(self):
"""Handle being added to home assistant."""
await MqttAvailability.async_added_to_hass(self)
await MqttDiscoveryUpdate.async_added_to_hass(self)
await super().async_added_to_hass()
await self._subscribe_topics()

async def discovery_update(self, discovery_payload):
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/counter/__init__.py
Expand Up @@ -10,9 +10,8 @@

from homeassistant.const import ATTR_ENTITY_ID, CONF_ICON, CONF_NAME
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.restore_state import RestoreEntity

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -86,7 +85,7 @@ async def async_setup(hass, config):
return True


class Counter(Entity):
class Counter(RestoreEntity):
"""Representation of a counter."""

def __init__(self, object_id, name, initial, restore, step, icon):
Expand Down Expand Up @@ -128,10 +127,11 @@ def state_attributes(self):

async def async_added_to_hass(self):
"""Call when entity about to be added to Home Assistant."""
await super().async_added_to_hass()
# __init__ will set self._state to self._initial, only override
# if needed.
if self._restore:
state = await async_get_last_state(self.hass, self.entity_id)
state = await self.async_get_last_state()
if state is not None:
self._state = int(state.state)

Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/cover/mqtt.py
Expand Up @@ -205,8 +205,7 @@ def __init__(self, config, discovery_hash):

async def async_added_to_hass(self):
"""Subscribe MQTT events."""
await MqttAvailability.async_added_to_hass(self)
await MqttDiscoveryUpdate.async_added_to_hass(self)
await super().async_added_to_hass()
await self._subscribe_topics()

async def discovery_update(self, discovery_payload):
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/device_tracker/__init__.py
Expand Up @@ -22,9 +22,8 @@
from homeassistant.config import load_yaml_config_file, async_log_exception
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_per_platform, discovery
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import GPSType, ConfigType, HomeAssistantType
import homeassistant.helpers.config_validation as cv
from homeassistant import util
Expand Down Expand Up @@ -396,7 +395,7 @@ async def async_init_single_device(dev):
await asyncio.wait(tasks, loop=self.hass.loop)


class Device(Entity):
class Device(RestoreEntity):
"""Represent a tracked device."""

host_name = None # type: str
Expand Down Expand Up @@ -564,7 +563,8 @@ async def async_update(self):

async def async_added_to_hass(self):
"""Add an entity."""
state = await async_get_last_state(self.hass, self.entity_id)
await super().async_added_to_hass()
state = await self.async_get_last_state()
if not state:
return
self._state = state.state
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/fan/mqtt.py
Expand Up @@ -151,8 +151,7 @@ def __init__(self, config, discovery_hash):

async def async_added_to_hass(self):
"""Subscribe to MQTT events."""
await MqttAvailability.async_added_to_hass(self)
await MqttDiscoveryUpdate.async_added_to_hass(self)
await super().async_added_to_hass()
await self._subscribe_topics()

async def discovery_update(self, discovery_payload):
Expand Down
14 changes: 0 additions & 14 deletions homeassistant/components/history.py
Expand Up @@ -38,20 +38,6 @@
IGNORE_DOMAINS = ('zone', 'scene',)


def last_recorder_run(hass):
"""Retrieve the last closed recorder run from the database."""
from homeassistant.components.recorder.models import RecorderRuns

with session_scope(hass=hass) as session:
res = (session.query(RecorderRuns)
.filter(RecorderRuns.end.isnot(None))
.order_by(RecorderRuns.end.desc()).first())
if res is None:
return None
session.expunge(res)
return res


def get_significant_states(hass, start_time, end_time=None, entity_ids=None,
filters=None, include_start_time_state=True):
"""
Expand Down
7 changes: 4 additions & 3 deletions homeassistant/components/input_boolean.py
Expand Up @@ -15,7 +15,7 @@
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.restore_state import RestoreEntity

DOMAIN = 'input_boolean'

Expand Down Expand Up @@ -84,7 +84,7 @@ async def async_setup(hass, config):
return True


class InputBoolean(ToggleEntity):
class InputBoolean(ToggleEntity, RestoreEntity):
"""Representation of a boolean input."""

def __init__(self, object_id, name, initial, icon):
Expand Down Expand Up @@ -117,10 +117,11 @@ def is_on(self):
async def async_added_to_hass(self):
"""Call when entity about to be added to hass."""
# If not None, we got an initial value.
await super().async_added_to_hass()
if self._state is not None:
return

state = await async_get_last_state(self.hass, self.entity_id)
state = await self.async_get_last_state()
self._state = state and state.state == STATE_ON

async def async_turn_on(self, **kwargs):
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/input_datetime.py
Expand Up @@ -11,9 +11,8 @@

from homeassistant.const import ATTR_ENTITY_ID, CONF_ICON, CONF_NAME
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.util import dt as dt_util


Expand Down Expand Up @@ -97,7 +96,7 @@ async def async_set_datetime_service(entity, call):
return True


class InputDatetime(Entity):
class InputDatetime(RestoreEntity):
"""Representation of a datetime input."""

def __init__(self, object_id, name, has_date, has_time, icon, initial):
Expand All @@ -112,6 +111,7 @@ def __init__(self, object_id, name, has_date, has_time, icon, initial):

async def async_added_to_hass(self):
"""Run when entity about to be added."""
await super().async_added_to_hass()
restore_val = None

# Priority 1: Initial State
Expand All @@ -120,7 +120,7 @@ async def async_added_to_hass(self):

# Priority 2: Old state
if restore_val is None:
old_state = await async_get_last_state(self.hass, self.entity_id)
old_state = await self.async_get_last_state()
if old_state is not None:
restore_val = old_state.state

Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/input_number.py
Expand Up @@ -11,9 +11,8 @@
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_UNIT_OF_MEASUREMENT, CONF_ICON, CONF_NAME, CONF_MODE)
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.restore_state import RestoreEntity

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -123,7 +122,7 @@ async def async_setup(hass, config):
return True


class InputNumber(Entity):
class InputNumber(RestoreEntity):
"""Representation of a slider."""

def __init__(self, object_id, name, initial, minimum, maximum, step, icon,
Expand Down Expand Up @@ -178,10 +177,11 @@ def state_attributes(self):

async def async_added_to_hass(self):
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
if self._current_value is not None:
return

state = await async_get_last_state(self.hass, self.entity_id)
state = await self.async_get_last_state()
value = state and float(state.state)

# Check against None because value can be 0
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/input_select.py
Expand Up @@ -10,9 +10,8 @@

from homeassistant.const import ATTR_ENTITY_ID, CONF_ICON, CONF_NAME
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.restore_state import RestoreEntity

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -116,7 +115,7 @@ async def async_setup(hass, config):
return True


class InputSelect(Entity):
class InputSelect(RestoreEntity):
"""Representation of a select input."""

def __init__(self, object_id, name, initial, options, icon):
Expand All @@ -129,10 +128,11 @@ def __init__(self, object_id, name, initial, options, icon):

async def async_added_to_hass(self):
"""Run when entity about to be added."""
await super().async_added_to_hass()
if self._current_option is not None:
return

state = await async_get_last_state(self.hass, self.entity_id)
state = await self.async_get_last_state()
if not state or state.state not in self._options:
self._current_option = self._options[0]
else:
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/input_text.py
Expand Up @@ -11,9 +11,8 @@
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_UNIT_OF_MEASUREMENT, CONF_ICON, CONF_NAME, CONF_MODE)
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.restore_state import RestoreEntity

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -104,7 +103,7 @@ async def async_setup(hass, config):
return True


class InputText(Entity):
class InputText(RestoreEntity):
"""Represent a text box."""

def __init__(self, object_id, name, initial, minimum, maximum, icon,
Expand Down Expand Up @@ -157,10 +156,11 @@ def state_attributes(self):

async def async_added_to_hass(self):
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
if self._current_value is not None:
return

state = await async_get_last_state(self.hass, self.entity_id)
state = await self.async_get_last_state()
value = state and state.state

# Check against None because value can be 0
Expand Down

0 comments on commit 5c3a4e3

Please sign in to comment.