From d905b23c023636b6b86fb97ceb033e821f80aad3 Mon Sep 17 00:00:00 2001 From: Daniel Lashua Date: Tue, 3 Nov 2020 11:11:56 -0600 Subject: [PATCH 1/4] detect old attribute values --- custom_components/pyscript/__init__.py | 33 ++++++++++++++++++++++++++ custom_components/pyscript/state.py | 8 +++++-- custom_components/pyscript/trigger.py | 2 +- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/custom_components/pyscript/__init__.py b/custom_components/pyscript/__init__.py index b386ba1..9bdde8d 100644 --- a/custom_components/pyscript/__init__.py +++ b/custom_components/pyscript/__init__.py @@ -210,16 +210,49 @@ async def state_changed(event): else: new_val = event.data["new_state"].state old_val = event.data["old_state"].state if event.data["old_state"] else None + + if old_val != new_val: + val_change = False + else: + val_change = True + new_vars = {var_name: new_val, f"{var_name}.old": old_val} func_args = { "trigger_type": "state", "var_name": var_name, "value": new_val, "old_value": old_val, + "change": val_change, "context": event.context, } await State.update(new_vars, func_args) + if "new_state" not in event.data or event.data["new_state"] is None: + return + + for attribute in event.data["new_state"].attributes: + new_val = event.data["new_state"].attributes[attribute] + if "old_state" in event.data and attribute in event.data["old_state"].attributes: + old_val = event.data["old_state"].attributes[attribute] + else: + old_val = None + + if old_val != new_val: + val_change = False + else: + val_change = True + + new_vars = {f"{var_name}.{attribute}": new_val, f"{var_name}.old.{attribute}": old_val} + func_args = { + "trigger_type": "state", + "var_name": f"{var_name}.{attribute}", + "value": new_val, + "old_value": old_val, + "change": val_change, + "context": event.context, + } + await State.update(new_vars, func_args) + async def hass_started(event): _LOGGER.debug("adding state changed listener and starting global contexts") await State.get_service_params() diff --git a/custom_components/pyscript/state.py b/custom_components/pyscript/state.py index ea4c3a5..95a1e50 100644 --- a/custom_components/pyscript/state.py +++ b/custom_components/pyscript/state.py @@ -77,9 +77,13 @@ async def notify_add(cls, var_names, queue): for var_name in var_names if isinstance(var_names, set) else {var_names}: parts = var_name.split(".") - if len(parts) != 2 and len(parts) != 3: + if len(parts) == 2: + state_var_name = f"{parts[0]}.{parts[1]}" + elif len(parts) == 3: + state_var_name = f"{parts[0]}.{parts[1]}.{parts[2]}" + else: continue - state_var_name = f"{parts[0]}.{parts[1]}" + if state_var_name not in cls.notify: cls.notify[state_var_name] = {} cls.notify[state_var_name][queue] = var_names diff --git a/custom_components/pyscript/trigger.py b/custom_components/pyscript/trigger.py index bbc6689..5f8bd0f 100644 --- a/custom_components/pyscript/trigger.py +++ b/custom_components/pyscript/trigger.py @@ -22,7 +22,7 @@ _LOGGER = logging.getLogger(LOGGER_PATH + ".trigger") -STATE_RE = re.compile(r"[a-zA-Z]\w*\.[a-zA-Z]\w*$") +STATE_RE = re.compile(r"[a-zA-Z]\w*\.[a-zA-Z]\w*(\.[a-zA-Z]\w*)?$") def dt_now(): From d6c51eff23eb87e61d598b18f1b669a7fc738aa7 Mon Sep 17 00:00:00 2001 From: Daniel Lashua Date: Tue, 3 Nov 2020 11:33:05 -0600 Subject: [PATCH 2/4] val_change logic correction --- custom_components/pyscript/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/pyscript/__init__.py b/custom_components/pyscript/__init__.py index 9bdde8d..c2c1478 100644 --- a/custom_components/pyscript/__init__.py +++ b/custom_components/pyscript/__init__.py @@ -211,7 +211,7 @@ async def state_changed(event): new_val = event.data["new_state"].state old_val = event.data["old_state"].state if event.data["old_state"] else None - if old_val != new_val: + if old_val == new_val: val_change = False else: val_change = True @@ -237,7 +237,7 @@ async def state_changed(event): else: old_val = None - if old_val != new_val: + if old_val == new_val: val_change = False else: val_change = True From 54b1e892305744c5b815008f17b38d2eb8f71616 Mon Sep 17 00:00:00 2001 From: Daniel Lashua Date: Tue, 3 Nov 2020 11:43:57 -0600 Subject: [PATCH 3/4] add support for only_on_change in state_trigger --- custom_components/pyscript/eval.py | 2 +- custom_components/pyscript/trigger.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/custom_components/pyscript/eval.py b/custom_components/pyscript/eval.py index daee320..b4ba0ee 100644 --- a/custom_components/pyscript/eval.py +++ b/custom_components/pyscript/eval.py @@ -455,7 +455,7 @@ async def do_service_call(func, ast_ctx, data): kwarg_check = { "task_unique": {"kill_me"}, "time_active": {"hold_off"}, - "state_trigger": {"state_hold", "state_check_now"}, + "state_trigger": {"state_hold", "state_check_now", "only_on_change"}, } for dec_name in trig_args: if dec_name not in kwarg_check and "kwargs" in trig_args[dec_name]: diff --git a/custom_components/pyscript/trigger.py b/custom_components/pyscript/trigger.py index 5f8bd0f..69f959e 100644 --- a/custom_components/pyscript/trigger.py +++ b/custom_components/pyscript/trigger.py @@ -538,6 +538,7 @@ def __init__( self.state_trigger_kwargs = trig_cfg.get("state_trigger", {}).get("kwargs", {}) self.state_hold_dur = self.state_trigger_kwargs.get("state_hold", None) self.state_check_now = self.state_trigger_kwargs.get("state_check_now", False) + self.only_on_change = self.state_trigger_kwargs.get("only_on_change", True) self.time_trigger = trig_cfg.get("time_trigger", {}).get("args", None) self.event_trigger = trig_cfg.get("event_trigger", {}).get("args", None) self.state_active = trig_cfg.get("state_active", {}).get("args", None) @@ -785,6 +786,12 @@ async def trigger_watch(self): else: func_args = notify_info + # + # check if our value changed and if we want to trigger on non changes + # + if self.only_on_change and "change" in func_args and not func_args['change']: + continue + # # now check the state and time active expressions # From 1ddf19d728eaff79385427903641a9ce13edec02 Mon Sep 17 00:00:00 2001 From: Daniel Lashua Date: Tue, 3 Nov 2020 14:26:27 -0600 Subject: [PATCH 4/4] catch None old_state --- custom_components/pyscript/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/pyscript/__init__.py b/custom_components/pyscript/__init__.py index c2c1478..8bb6dab 100644 --- a/custom_components/pyscript/__init__.py +++ b/custom_components/pyscript/__init__.py @@ -232,7 +232,7 @@ async def state_changed(event): for attribute in event.data["new_state"].attributes: new_val = event.data["new_state"].attributes[attribute] - if "old_state" in event.data and attribute in event.data["old_state"].attributes: + if "old_state" in event.data and event.data['old_state'] is not None and attribute in event.data["old_state"].attributes: old_val = event.data["old_state"].attributes[attribute] else: old_val = None