@@ -690,6 +690,7 @@ def __init__(
690690 self .have_trigger = False
691691 self .setup_ok = False
692692 self .run_on_startup = False
693+ self .run_on_shutdown = False
693694
694695 if self .state_active is not None :
695696 self .active_expr = AstEval (
@@ -702,14 +703,17 @@ def __init__(
702703 self .active_expr .get_logger ().error (exc )
703704 return
704705
706+ if "time_trigger" in trig_cfg and self .time_trigger is None :
707+ self .run_on_startup = True
705708 if self .time_trigger is not None :
706709 while "startup" in self .time_trigger :
707710 self .run_on_startup = True
708711 self .time_trigger .remove ("startup" )
712+ while "shutdown" in self .time_trigger :
713+ self .run_on_shutdown = True
714+ self .time_trigger .remove ("shutdown" )
709715 if len (self .time_trigger ) == 0 :
710716 self .time_trigger = None
711- if "time_trigger" in trig_cfg and self .time_trigger is None :
712- self .run_on_startup = True
713717
714718 if self .state_trigger is not None :
715719 state_trig = []
@@ -783,7 +787,12 @@ def stop(self):
783787 if self .mqtt_trigger is not None :
784788 Mqtt .notify_del (self .mqtt_trigger [0 ], self .notify_q )
785789 if self .task :
786- Function .task_cancel (self .task )
790+ Function .reaper_cancel (self .task )
791+ if self .run_on_shutdown :
792+ notify_type = "shutdown"
793+ notify_info = {"trigger_type" : "shutdown" , "trigger_time" : None }
794+ action_future = self .call_action (notify_type , notify_info , run_task = False )
795+ Function .reaper_await (action_future )
787796
788797 def start (self ):
789798 """Start this trigger task."""
@@ -1000,30 +1009,6 @@ async def trigger_watch(self):
10001009 )
10011010 continue
10021011
1003- action_ast_ctx = AstEval (
1004- f"{ self .action .global_ctx_name } .{ self .action .name } " , self .action .global_ctx
1005- )
1006- Function .install_ast_funcs (action_ast_ctx )
1007- task_unique_func = None
1008- if self .task_unique is not None :
1009- task_unique_func = Function .task_unique_factory (action_ast_ctx )
1010-
1011- #
1012- # check for @task_unique with kill_me=True
1013- #
1014- if (
1015- self .task_unique is not None
1016- and self .task_unique_kwargs
1017- and self .task_unique_kwargs ["kill_me" ]
1018- and Function .unique_name_used (action_ast_ctx , self .task_unique )
1019- ):
1020- _LOGGER .debug (
1021- "trigger %s got %s trigger, @task_unique kill_me=True prevented new action" ,
1022- notify_type ,
1023- self .name ,
1024- )
1025- continue
1026-
10271012 if (
10281013 self .time_active_hold_off is not None
10291014 and last_trig_time is not None
@@ -1037,49 +1022,8 @@ async def trigger_watch(self):
10371022 )
10381023 continue
10391024
1040- # Create new HASS Context with incoming as parent
1041- if "context" in func_args and isinstance (func_args ["context" ], Context ):
1042- hass_context = Context (parent_id = func_args ["context" ].id )
1043- else :
1044- hass_context = Context ()
1045-
1046- # Fire an event indicating that pyscript is running
1047- # Note: the event must have an entity_id for logbook to work correctly.
1048- ev_name = self .name .replace ("." , "_" )
1049- ev_entity_id = f"pyscript.{ ev_name } "
1050-
1051- event_data = dict (name = ev_name , entity_id = ev_entity_id , func_args = func_args )
1052- Function .hass .bus .async_fire ("pyscript_running" , event_data , context = hass_context )
1053-
1054- _LOGGER .debug (
1055- "trigger %s got %s trigger, running action (kwargs = %s)" ,
1056- self .name ,
1057- notify_type ,
1058- func_args ,
1059- )
1060-
1061- async def do_func_call (func , ast_ctx , task_unique , task_unique_func , hass_context , ** kwargs ):
1062- # Store HASS Context for this Task
1063- Function .store_hass_context (hass_context )
1064-
1065- if task_unique and task_unique_func :
1066- await task_unique_func (task_unique )
1067- await func .call (ast_ctx , ** kwargs )
1068- if ast_ctx .get_exception_obj ():
1069- ast_ctx .get_logger ().error (ast_ctx .get_exception_long ())
1070-
1071- last_trig_time = time .monotonic ()
1072-
1073- Function .create_task (
1074- do_func_call (
1075- self .action ,
1076- action_ast_ctx ,
1077- self .task_unique ,
1078- task_unique_func ,
1079- hass_context ,
1080- ** func_args ,
1081- )
1082- )
1025+ if self .call_action (notify_type , func_args ):
1026+ last_trig_time = time .monotonic ()
10831027
10841028 except asyncio .CancelledError :
10851029 raise
@@ -1094,3 +1038,63 @@ async def do_func_call(func, ast_ctx, task_unique, task_unique_func, hass_contex
10941038 if self .mqtt_trigger is not None :
10951039 Mqtt .notify_del (self .mqtt_trigger [0 ], self .notify_q )
10961040 return
1041+
1042+ def call_action (self , notify_type , func_args , run_task = True ):
1043+ """Call the trigger action function."""
1044+ action_ast_ctx = AstEval (f"{ self .action .global_ctx_name } .{ self .action .name } " , self .action .global_ctx )
1045+ Function .install_ast_funcs (action_ast_ctx )
1046+ task_unique_func = None
1047+ if self .task_unique is not None :
1048+ task_unique_func = Function .task_unique_factory (action_ast_ctx )
1049+
1050+ #
1051+ # check for @task_unique with kill_me=True
1052+ #
1053+ if (
1054+ self .task_unique is not None
1055+ and self .task_unique_kwargs
1056+ and self .task_unique_kwargs ["kill_me" ]
1057+ and Function .unique_name_used (action_ast_ctx , self .task_unique )
1058+ ):
1059+ _LOGGER .debug (
1060+ "trigger %s got %s trigger, @task_unique kill_me=True prevented new action" ,
1061+ notify_type ,
1062+ self .name ,
1063+ )
1064+ return False
1065+
1066+ # Create new HASS Context with incoming as parent
1067+ if "context" in func_args and isinstance (func_args ["context" ], Context ):
1068+ hass_context = Context (parent_id = func_args ["context" ].id )
1069+ else :
1070+ hass_context = Context ()
1071+
1072+ # Fire an event indicating that pyscript is running
1073+ # Note: the event must have an entity_id for logbook to work correctly.
1074+ ev_name = self .name .replace ("." , "_" )
1075+ ev_entity_id = f"pyscript.{ ev_name } "
1076+
1077+ event_data = dict (name = ev_name , entity_id = ev_entity_id , func_args = func_args )
1078+ Function .hass .bus .async_fire ("pyscript_running" , event_data , context = hass_context )
1079+
1080+ _LOGGER .debug (
1081+ "trigger %s got %s trigger, running action (kwargs = %s)" , self .name , notify_type , func_args ,
1082+ )
1083+
1084+ async def do_func_call (func , ast_ctx , task_unique , task_unique_func , hass_context , ** kwargs ):
1085+ # Store HASS Context for this Task
1086+ Function .store_hass_context (hass_context )
1087+
1088+ if task_unique and task_unique_func :
1089+ await task_unique_func (task_unique )
1090+ await func .call (ast_ctx , ** kwargs )
1091+ if ast_ctx .get_exception_obj ():
1092+ ast_ctx .get_logger ().error (ast_ctx .get_exception_long ())
1093+
1094+ func = do_func_call (
1095+ self .action , action_ast_ctx , self .task_unique , task_unique_func , hass_context , ** func_args ,
1096+ )
1097+ if run_task :
1098+ Function .create_task (func )
1099+ return True
1100+ return func
0 commit comments