Struggling with appdaemon time scheduler [SOLVED]

but also with run_once that can cause errors, because it must be a time in the past.

i hope i have given you stuff to create something even better :wink:

hmmm, yes I see your point. I have run it easily 100 times now, and have not seen an error. But in any case, does not hurt to add a second or two.

1 Like

A bit more awake now, and I can think through your feedback.

in your run_once you use nowtime and not onceDT

Yes, you are right. I have added a few seconds now.

you calculate your initialDT in your initialise and use it in your calback.
but if you use run_daily that initialDT will never change after you start the app.
that results in that the second day the time will be in the past and the app will stop working

My understanding is that if the time is in the past, run_daily will run the next day at that time so the program will work. The docs:

### run_daily()

Execute a callback at the same time every day. If the time has already passed, the function will not be invoked until the following day at the specified time.

in your norain CB you calculate the time and use run_once.
way more easy it is to use run_in. you dont need the date, just the amount of secs

What I need to avoid is the situation where two valves are on at once, as there is not enough water pressure in the system for that. I might be adding more calculations here, and can imagine cases where many run_ins would cause overlapping valves (I have read a nice article about irrigation, and that it is better to cycle through five minute intervals than to do each zone for thirty minutes). I think run_once with precise times gives me more control (indeed, making sure that it is not in the past. The first switchOff in the CB I will change to running immediately. I suppose I could put a check in for the first valve, but currently there will be a minute between calling the CB and turning on the first valve. That should be enough, I hope).

you dont want to use run_daily in your callback only in your initialise.

Yes, that is my plan. That and changing seconds to minutes are pretty much all I need to do to switch from run_once to run_daily.

thats true.
but thats not what i mean.
you calculate your time (initialDT) in your initialise
then you use kwargs to move the value to your callback.
in the callback you add seconds and valduration
then you start your run_once based on that time.

now you start your app today
the initialDT will be datetime object with the date from today.
rundaily will start on the time set in initialDT and every day after that.
so tommorow it wil start as wel.
but tommorow the date in initialDT wil still be the date from today.
so your run_once in the callback get the date from today and they wil never start.

so you have 2 options:

  1. you dont use kwargs, but you calculate initialDT inside the callback
  2. you add the amount of days running to the valvetime

many runins wouldnt be any different from many runonces, but thats your choice.
i think you better use a second app or create a part in this app that checks your valves to make sure.
like:

def initialise(self):
    for j in range (1, 1 + totalValves, 1):
        self.listen_state(self.checkvalves, "switch.in"+ str(j))
def checkvalves(self,enity,new,old,attributes,kwargs):
    if new == "on":
    for j in range (1, 1 + totalValves, 1):
        if str(j) != entity[:-1]:
            self.turn_off(entity[:-1] + str(j))

now you can never have more then 1 valve running
you even can forget about calculating the times to shut off the valvs (only the last one needs to be shut of)

Ah. Now you have told me the same thing three times, and I finally realize your point. :slight_smile:

Got, it. Thanks Rene.

1 Like

try not to overcomplicate things :wink:
thats why i suggested runin instead of runonce.

with runonce: (run_once(CB, now() + 90 seconds)

  1. get the time now
  2. calc amount of seconds to add to now
  3. add seconds to now
  4. use that for run once

with runin: (run_in(CB, 90 seconds)

  1. calc amount of seconds
  2. use that for run in

the result is the same. there is no more accuracy, only more calculation. (so more places where you can go wrong)

Now that I am home and look through the code in peace, I’m still not sure I agree with your point.

All of my callbacks are using times, not datetimes. My run_once in the callback uses the time only, so I believe it should start. Did you miss that I convert them to times, or am I still missing something?

oke i typed a whole lot and then i saw that you use a datetime as kwarg and then recalculate that to a time.
yeah it will work in that case but it could al be way more simple.

    dailyTime = datetime.time(self.args["onHour"], self.args["onMinute"], 0) 
    dailyDT = datetime.datetime.combine(now.date(), dailyTime)
    self.handle = self.run_daily(self.noRain, dailyDT)
  def noRain(self, kwargs):

    valveDuration = int(self.args["valveDuration"])
    totalValves = int(self.args["totalValves"])
    precipitation=float(self.entities.sensor.buienradar_precipitation.state)
    if precipitation == 0:
      self.switchOff(self)
      for j in range (1, 1 + totalValves, 1):
        valve_start = j + (j-1) * valveDuration
        valve_off = j + j * valveDuration
        self.run_in(self.switchOn, valve_start, j = j)
        self.run_once(self.switchOff, valve_off)

thats why i said that you are overcomplicating.
and even if its now still to get what you do, it will get more and more complicated.
so my experience in programming is to do it as simple as possible.

thanks, Rene. Yes, I already see that I am making the loops complicated. I’ll definitely work on simplifying it.

1 Like