Why does run_in log immediately?

I have the following function:

  def night(self):
    self.cancel_timers()
    self.mode = "Night"
    self.log("Running Night mode tasks")
    self.select_option("input_select.holman_mode", "Night")
    self.common_off()
    self.hold_off()
    self.turn_off("switch.hot_water_tank")
    self.turn_off("switch.hot_water_loop")
    self.hvac_mode("off")
    self.run_in(self.difficult_off(), 60)

I would expect to see my difficult_off function run 60 seconds after the hvac_mode stuff but in the logs it happens immediately after, no pause at all. Why?

2018-12-16 10:06:19.776011 INFO modes: Received mode change request from HA: Night
2018-12-16 10:06:19.812473 INFO modes: Turning lights off
2018-12-16 10:06:20.909365 INFO modes: Turning hold switches off
2018-12-16 10:06:21.419795 INFO modes: Spam Rheem Mode: off
2018-12-16 10:06:21.464426 INFO modes: Spam Rheem Mode: off
2018-12-16 10:06:21.497216 INFO modes: Spam Rheem Mode: off
2018-12-16 10:06:21.814941 INFO modes: Turning difficult lights off

Because you have used parenthesis in the first parameter to run_in, which calls the function rather than using it as a reference. It should be

    self.run_in(self.difficult_off, 60)
1 Like

I wondered about that. What’s the difference between parentheses or not?

As I said, if you use parentheses, the function gets called, and the result of the function is used as the parameter to the run_in function.

You want the parameter to the run_in function to be the name of the difficult_off function, so that run_in will call that function at the appropriate time.

1 Like

TypeError: difficult_off() takes 1 positional argument but 2 were given

I didn’t pass it ANY positional arguments.

You need to make sure that the parameters for difficult_off match the callback defined here

Rene gave a good example in his tutorial
https://appdaemon.readthedocs.io/en/latest/HASS_TUTORIAL.html#sunrise-sunset-lighting

1 Like

so my function needs to be defined with (self, kwargs)? Alright that works finally.

thanks for getting this one @gpbenton

So it’s just a convention that you should create your functions as:

def my_func(self, kwargs):
  do something, maybe using muh kwargs

because this is what appDaemon functions like run_in expect?

From the larger python perspective, I’m still unclear why/when you pass things to a function using a parameter or using a kwargs dictionary. Why are things like entity, attribute, old, and new explicitly parameterized and not just kwargs?

most likely to make them easy available.

when they are parameterized you can use

self.log(new) or
if old == new:

instead of

self.log(kwargs["new]) or
if kwargs[“old”] == kwargs[“new”]:

yeah a callback in general is created in a specific way.
every lib that uses callbacks expects their callback to be setup in a certain way.

OK cool thx. I’m just trying to get the structure here organized in my head. Since I’m new to both AppDaemon and Python, I can’t quite tell what’s a required part of python, what’s a typical python convention, and what’s an AppDaemon convention.

You’re explanation makes sense as a line of demarcation between params and kwargs. It seems like a reasonable choice to me.

i never tried to learn things real “pythonic”

i use appdaemon and thats the only place where i use python.
so my programing is completely “appdaemonic”:wink:

i see a lot of python programmer saying stuff like:
but python does this or that, this or that way, why does AD do it that way?

and i am like:
AD expects me to do things in a certain way. so why think about how its like in other programs?

1 Like

Hey guys 2 quick questions. I’d ask on discord but I don’t see an appdaemon specific channel.

So first question, does one exist? Never used discord before.

Second, given the above, aka:

will the following work?

self.run_in(self.fire_event("MODE_CHANGE", mode = "Present"), 60)

I basically want to fire an event in the future, but I need to call the function with params in the future not just by name.

on the home assistant server from discord there is no appdaemon channel.
they did put that in the software channel.

but we have our own discord server that you can find here

about your second question.
no!
you need to give a callback. so for your example that means:

  self.run_in(self.callbackname, 60)

def callbackname(self,kwargs):
  self.fire_event("MODE_CHANGE", mode = "Present")