@@ -644,6 +644,55 @@ def start(self):
644644 self .task = Function .create_task (self .trigger_watch ())
645645 _LOGGER .debug ("trigger %s is active" , self .name )
646646
647+ def ident_any_values_changed (self , func_args ):
648+ """Check for changes to state or attributes on ident any vars"""
649+ value = func_args ['value' ]
650+ old_value = func_args ['old_value' ]
651+ var_name = func_args ['var_name' ]
652+
653+ if var_name is None :
654+ return False
655+
656+ for check_var in self .state_trig_ident_any :
657+ if check_var == var_name and old_value != value :
658+ return True
659+
660+ if check_var .startswith (f"{ var_name } ." ):
661+ var_pieces = check_var .split ('.' )
662+ if len (var_pieces ) == 3 and f"{ var_pieces [0 ]} .{ var_pieces [1 ]} " == var_name :
663+ if var_pieces [2 ] == "*" :
664+ # catch all has been requested, check all attributes for change
665+ all_attributes = (set (value .__dict__ .keys ()) | set (old_value .__dict__ .keys ())) - {"last_updated" , "last_changed" }
666+ for attribute in all_attributes :
667+ attrib_val = getattr (value , attribute , None )
668+ attrib_old_val = getattr (old_value , attribute , None )
669+ if attrib_old_val != attrib_val :
670+ return True
671+ else :
672+ attrib_val = getattr (value , var_pieces [2 ], None )
673+ attrib_old_val = getattr (old_value , var_pieces [2 ], None )
674+ if attrib_old_val != attrib_val :
675+ return True
676+ return False
677+
678+ def ident_values_changed (self , func_args ):
679+ """Check for changes to state or attributes on ident vars"""
680+ value = func_args ['value' ]
681+ old_value = func_args ['old_value' ]
682+ var_name = func_args ['var_name' ]
683+ for check_var in self .state_trig_ident :
684+ var_pieces = check_var .split ('.' )
685+ if len (var_pieces ) == 2 and check_var == var_name :
686+ if value != old_value :
687+ return True
688+ elif len (var_pieces ) == 3 and f"{ var_pieces [0 ]} .{ var_pieces [1 ]} " == var_name :
689+ attrib_val = getattr (value , var_pieces [2 ], None )
690+ attrib_old_val = getattr (old_value , var_pieces [2 ], None )
691+ if attrib_old_val != attrib_val :
692+ return True
693+
694+ return False
695+
647696 async def trigger_watch (self ):
648697 """Task that runs for each trigger, waiting for the next trigger and calling the function."""
649698
@@ -739,25 +788,22 @@ async def trigger_watch(self):
739788 elif notify_type == "state" :
740789 new_vars , func_args = notify_info
741790
742- # check if any state_trig_ident_any starts with var_name
743- any_match = False
744- if "var_name" in func_args :
745- for check_var in self .state_trig_ident_any :
746- if check_var == func_args ['var_name' ]:
747- any_match = True
748- break
749- if check_var .startswith (f"{ func_args ['var_name' ]} ." ):
750- any_match = True
751- break
752- if not any_match :
753- if self .state_trig_eval :
754- trig_ok = await self .state_trig_eval .eval (new_vars )
755- exc = self .state_trig_eval .get_exception_long ()
756- if exc is not None :
757- self .state_trig_eval .get_logger ().error (exc )
758- trig_ok = False
759- else :
791+ # if func_args is not fully populated, then we are state_check_now so skip changed check
792+ if all ([(x in func_args ) for x in ['value' , 'old_value' , 'var_name' ]]):
793+ # check for changes to ident vars
794+ if not self .ident_any_values_changed (func_args ) and not self .ident_values_changed (func_args ):
795+ # nothing changed so no need to evaluate trigger
796+ continue
797+
798+ if self .state_trig_eval :
799+ trig_ok = await self .state_trig_eval .eval (new_vars )
800+ exc = self .state_trig_eval .get_exception_long ()
801+ if exc is not None :
802+ self .state_trig_eval .get_logger ().error (exc )
760803 trig_ok = False
804+ else :
805+ trig_ok = False
806+
761807 if self .state_hold_dur is not None :
762808 if trig_ok :
763809 if not state_trig_waiting :
@@ -822,42 +868,7 @@ async def trigger_watch(self):
822868 if self .task_unique is not None :
823869 task_unique_func = Function .task_unique_factory (action_ast_ctx )
824870
825- #
826- # check for changes to state or attributes
827- #
828-
829- # if "value" not in func_args, then we are state_check_now
830- if notify_type == 'state' and all ([(x in func_args ) for x in ['value' , 'old_value' , 'var_name' ]]):
831- trig_ident_change = False
832871
833- value = func_args ['value' ]
834- old_value = func_args ['old_value' ]
835- var_name = func_args ['var_name' ]
836- # determine if the catchall has been requested in state_trig_ident_any
837- catch_all_entity = f"{ var_name } .*"
838- if catch_all_entity in self .state_trig_ident_any :
839- # catch all has been requested, check all attributes for change
840- all_attributes = (set (value .__dict__ .keys ()) | set (old_value .__dict__ .keys ())) - {"last_updated" , "last_changed" }
841- for attribute in all_attributes :
842- attrib_val = getattr (value , attribute , None )
843- attrib_old_val = getattr (old_value , attribute , None )
844- if attrib_old_val != attrib_val :
845- trig_ident_change = True
846-
847- if not trig_ident_change :
848- for var in self .state_trig_ident :
849- var_pieces = var .split ('.' )
850- if len (var_pieces ) == 2 and var == var_name :
851- if value != old_value :
852- trig_ident_change = True
853- elif len (var_pieces ) == 3 and f"{ var_pieces [0 ]} .{ var_pieces [1 ]} " == var_name :
854- attrib_val = getattr (value , var_pieces [2 ], None )
855- attrib_old_val = getattr (old_value , var_pieces [2 ], None )
856- if attrib_old_val != attrib_val :
857- trig_ident_change = True
858-
859- if not trig_ident_change :
860- continue
861872
862873 #
863874 # check for @task_unique with kill_me=True
0 commit comments