-
Notifications
You must be signed in to change notification settings - Fork 55
Persist pyscript.* states between home assistant restarts #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1865eca
fdfd291
ed39168
3fbf477
aa5fac1
83f6dc6
de9379f
aab1092
1bf67b7
656665b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ | |
|
||
import logging | ||
|
||
from homeassistant.helpers.restore_state import RestoreStateData | ||
|
||
from .const import LOGGER_PATH | ||
from .function import Function | ||
|
||
|
@@ -34,6 +36,11 @@ class State: | |
# | ||
pyscript_config = {} | ||
|
||
# | ||
# pyscript vars which have already been registered as persisted | ||
# | ||
persisted_vars = set() | ||
|
||
def __init__(self): | ||
"""Warn on State instantiation.""" | ||
_LOGGER.error("State class is not meant to be instantiated") | ||
|
@@ -44,7 +51,7 @@ def init(cls, hass): | |
cls.hass = hass | ||
|
||
@classmethod | ||
def notify_add(cls, var_names, queue): | ||
async def notify_add(cls, var_names, queue): | ||
"""Register to notify state variables changes to be sent to queue.""" | ||
|
||
for var_name in var_names if isinstance(var_names, set) else {var_names}: | ||
|
@@ -98,7 +105,7 @@ def notify_var_get(cls, var_names, new_vars): | |
return notify_vars | ||
|
||
@classmethod | ||
def set(cls, var_name, value, new_attributes=None, **kwargs): | ||
async def set(cls, var_name, value, new_attributes=None, **kwargs): | ||
"""Set a state variable and optional attributes in hass.""" | ||
if var_name.count(".") != 1: | ||
raise NameError(f"invalid name {var_name} (should be 'domain.entity')") | ||
|
@@ -113,8 +120,34 @@ def set(cls, var_name, value, new_attributes=None, **kwargs): | |
new_attributes.update(kwargs) | ||
_LOGGER.debug("setting %s = %s, attr = %s", var_name, value, new_attributes) | ||
cls.notify_var_last[var_name] = str(value) | ||
|
||
cls.hass.states.async_set(var_name, value, new_attributes) | ||
|
||
@classmethod | ||
async def register_persist(cls, var_name): | ||
"""Persists a pyscript state variable using RestoreState.""" | ||
if var_name.startswith("pyscript.") and var_name not in cls.persisted_vars: | ||
restore_data = await RestoreStateData.async_get_instance(cls.hass) | ||
restore_data.async_restore_entity_added(var_name) | ||
cls.persisted_vars.add(var_name) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How expensive is it to call these functions every time a pyscript state variable is set? Would it be better to only do it the first time each state variable is set? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not very experienced with the Home Assistant codebase or python async code. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've since introduced our own set to track persisted states, so this code block will only evaluate once. |
||
@classmethod | ||
async def persist(cls, var_name, default_value=None, default_attributes=None): | ||
"""Ensures a pyscript domain state variable is persisted.""" | ||
if var_name.count(".") != 1 or not var_name.startswith("pyscript."): | ||
raise NameError(f"invalid name {var_name} (should be 'pyscript.entity')") | ||
|
||
await cls.register_persist(var_name) | ||
exists = cls.exist(var_name) | ||
|
||
if not exists and default_value is not None: | ||
await cls.set(var_name, default_value, default_attributes) | ||
elif exists and default_attributes is not None: | ||
# Patch the attributes with new values if necessary | ||
current = cls.hass.states.get(var_name) | ||
new_attributes = {k: v for (k, v) in default_attributes.items() if k not in current.attributes} | ||
await cls.set(var_name, current.state, **new_attributes) | ||
|
||
@classmethod | ||
def exist(cls, var_name): | ||
"""Check if a state variable value or attribute exists in hass.""" | ||
|
@@ -125,7 +158,7 @@ def exist(cls, var_name): | |
return value and (len(parts) == 2 or parts[2] in value.attributes) | ||
|
||
@classmethod | ||
def get(cls, var_name): | ||
async def get(cls, var_name): | ||
"""Get a state variable value or attribute from hass.""" | ||
parts = var_name.split(".") | ||
if len(parts) != 2 and len(parts) != 3: | ||
|
@@ -140,7 +173,7 @@ def get(cls, var_name): | |
return value.attributes.get(parts[2]) | ||
|
||
@classmethod | ||
def get_attr(cls, var_name): | ||
async def get_attr(cls, var_name): | ||
"""Return a dict of attributes for a state variable.""" | ||
if var_name.count(".") != 1: | ||
raise NameError(f"invalid name {var_name} (should be 'domain.entity')") | ||
|
@@ -188,6 +221,7 @@ def register_functions(cls): | |
"state.set": cls.set, | ||
"state.names": cls.names, | ||
"state.get_attr": cls.get_attr, | ||
"state.persist": cls.persist, | ||
"pyscript.config": cls.pyscript_config, | ||
} | ||
Function.register(functions) | ||
|
Uh oh!
There was an error while loading. Please reload this page.