diff --git a/custom_components/pyscript/__init__.py b/custom_components/pyscript/__init__.py index b386ba1..8bb6dab 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 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 + + 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/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/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..69f959e 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(): @@ -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 #