Mixing run_in() and call_service()

Hello guys,

I have a Welcome and a Goodbye routines, that are turning on or off lights in my apartment. (AppDeamon)

Tonight I tried to add some “sequentiality” to the routines, so that the lights are either turning on or off in a nicely timed sequence…

In order to do so I tried to write some code that is trying to achieve (functionally) this :
“Call this particular service in that amount of delay”

So I tried to mix run_in and call_service… and I never managed…
I am debugging my code since one hour now and I am starting to get desperate :slight_smile:

I ended up creating an intermediate callback function and I find my solution really ugly.
It is working but I am not really proud of the execution.

See for yourself :

  """
  Helper method:
  Does : Turn on the lights of the entry, living room and kitchen
  Returns :  Nothing
  """
  def act_on_arriving_home(self, bom):
    if bom["action"]:
      self.say_something("greeting")
      self.run_in(self.helper_call_service, 1 , service = 'light/turn_on', entity_id = "light.entry_lights", transition = 3, brightness_pct = 100)
      self.run_in(self.helper_call_service, 3 , service = 'light/turn_on', entity_id = "light.living_room_lights", transition = 3, brightness_pct = 100)
      self.run_in(self.helper_call_service, 5 , service = 'light/turn_on', entity_id = "light.kitchen_lights", transition = 3, brightness_pct = 100)

  """
  Helper method:
  Method present mostly because I am too dumb and did not managed to bundle the run_in and the call_service in one shot :)
  """
  def helper_call_service(self, kwargs):
    service = kwargs["service"]
    kwargs.pop("service")
    self.call_service(service, **kwargs)

I saw a reply in this post that seems to indicate that run_in() has been designed to be called with an external callback… But still I am interested in seeing a way to achieve what I want in one function…

If you find a more elegant solution and I all ears :slight_smile:
Honestly I think it’ s my understanding of python that is the limiting factor here !

Regards,
Jenova70

There is no way to do this in one function, run_in needs a callback function.

1 Like

To achieve this in one function you would need “sleep” functionality.

If you are using AD version 3, the only option is time.sleep() which is not recommended.

If you are using AD version 4 (in beta), you have several options. The easiest is to run a sequence. It looks like this:

seq = [
 {"light/turn_on": {
    "entity_id": "light.entry_lights",
    "transition": 3,
    "brightness_pct": 100 }},
  {"sleep": 2},
 {"light/turn_on": {
    "entity_id": "light.living_room_lights",
    "transition": 3,
    "brightness_pct": 100 }},
  {"sleep": 2},
 {"light/turn_on": {
    "entity_id": "light.kitchen_lights",
    "transition": 3,
    "brightness_pct": 100 }}
]
self.run_sequence(seq)

A second option, a little more advanced, but more readable, in my opinion, is to use the newly supported async syntax:

async def act_on_arriving_home(self, bom):
   await self.call_service('light/turn_on', entity_id="light.entry_lights", transition=3, brightness_pct=100)
   await self.sleep(2)
   await self.call_service('light/turn_on', entity_id="light.living_room_lights", transition=3, brightness_pct=100)
   await self.sleep(2)
   await self.call_service('light/turn_on', entity_id="light.kitchen_lights", transition=3, brightness_pct=100)
1 Like

Hello @swiftlyfalling,

Happy new year !
with some delay, I migrate to AppDemaon 4.0.0, and took the time to implement the sequence.

Everything worked as expected.

Thank you very much.
Jenova