Appdaemon's run_daily issue

Hi there,

I’m new to AppDaemon and Python and I’m experimenting with an App.

I want to turn my lights on slowly every morning at a set time that I can modify via the frontend.

import appdaemon.plugins.hass.hassapi as hass
from datetime import datetime

class WakeUp(hass.Hass):

  def initialize(self):
     self.log("initializing wake up app")
     
     time_str = self.get_state("input_datetime.set_wake_up_light")
     time_dt = datetime.strptime(time_str, '%H:%M:%S').time()

     self.bedroom_light = self.get_entity("light.the_bedroom_light")
     self.listen_state(self.time_change, "input_datetime.set_wake_up_light")
     self.run_daily(self.wake_up_light, time_dt) 
     
     self.log("end initialize")
  
  def wake_up_light(self, kwargs):
     self.log("in wake up light callback now")
     self.bedroom_light.turn_on(transition = 60)

  def time_change(self, entity, attribute, old, new, kwargs):
     time_str = self.get_state("input_datetime.set_wake_up_light")
     time_dt = datetime.strptime(time_str, '%H:%M:%S').time()
     self.log("wake up light time now {}".format(time_str))

I begin by getting the datetime from an input_date helper on my front end, then I convert it to a datetime time, then I both listen for changes to the datetime helper, and I set a run_daily callback to run at time_dt.

When I add

self.log(type(time_dt)

I get the output:

<class 'datetime.time'>

which seems like the correct type since I don’t get any errors from the run_daily callback like I did when I put in the full datetime.
I do not get errors in the initialize, and my time_change callback works fine, I just can’t get the run_daily callback to trigger.

Any help? What else might you need to know?

Hi, for my alarm clock this works just fine:

weckzeit = datetime.datetime.strptime(self.get_state("input_datetime.weckzeit"), "%H:%M:%S") - datetime.timedelta(minutes=30)
self._weckzeitListener = self.run_daily(self.startAufwecken, weckzeit.strftime('%H:%M:%S'))

I want to start the lights fade 30 minutes before the set time. So startAufwecken looks like this:

self.turn_on("light.lightstrip_bett_intern", brightness = 255, rgb_color = [255, 255, 255], transition = 1800)

So the parameter appears to be a string, in your case just this should work:

self.run_daily(self.wake_up_light, self.get_state("input_datetime.set_wake_up_light"))
1 Like

so it turns out I had some logic problems and my appdaemon time_zone config was wrong, which was preventing me from debugging the problem.

I changed my time zone in the appdaemon.yaml.

Your advice inspired me to think about why I got all wrapped up in using datetime, then I realized I needed to reinitialize the app if I want the wake up light callback to reinitialize with the new time set in the front end. I also added in a switch to turn on and off the wake up light. Here is what I ended up with

import appdaemon.plugins.hass.hassapi as hass
import time

class WakeUp(hass.Hass):

  def initialize(self):
     self.log("wake up light initializing ...")
          
     self.listen_state(self.time_change, "input_datetime.set_wake_up_light")
     self.run_daily(self.turn_on_light, (self.get_state("input_datetime.set_wake_up_light"))) 

  def turn_on_light(self, kwargs):
     self.switch = self.get_entity("input_boolean.wake_up_light_switch")
     self.bedroom_light = self.get_entity("light.the_bedroom_light")
    
     if self.switch.is_state("on"):
        self.bedroom_light.turn_on(transition = 600)
     else:
        self.log("wake up ilght switch is off")

  def time_change(self, entity, attribute, old, new, kwargs):
     time.sleep(3)
     self.restart_app("wakeup")

thanks for taking a look and replying!

I’ll throw out a few suggestions. Instead of having time_change() restart the app, you’ll want it to cancel the run_daily() scheduler and re-create it. You can do this easily by storing the handle ID of run_daily() in a class variable. Also, you never want your callbacks to include time.sleep() because it is a blocking call.

1 Like

awesome, thank you for the suggestions, I’ll work on implementing them.

The reason I added the sleep was because when you change a single digit on the input datetime helper, it triggers the callback to restart, so I wanted to prevent the restart until I finished editing the input datetime and I figured a delay would allow me to do that. I’ll take your advice though, thanks again.

Just add a duration argument with the desired amount of seconds to the listen_state callback and it wont fire until you stop editing the helper entity.

I implemented self.handle and recreated the callback and I added the duration argument.

I realize this is all pretty basic stuff, I appreciate the time you took to help me out!

No problem, glad you got it working.