AppDaemon Q&A

and my app is up and running!

i see that he reacts to changing a boolean!
and i even can see which boolean.

but he tells me that he doesnt know what args are.

NameError: name ‘args’ is not defined

My bad - it should be “self.args”

after trying to put args in several places and looking in the blog i figured that out. :wink:

but it gives the next error:

2016-08-17 22:48:12,731 WARNING Traceback (most recent call last):
  File "C:\Users\rene\appdaemon\bin\appdaemon.py", line 361, in worker
    function(entity, attr, old_state, new_state, args["kwargs"])
  File "C:\Users\rene\appdaemon\apps\RFSwitch.py", line 13, in switch
    self.call_service("switch.mysensors_send_ir_code", entity_id = self.args["switch"], V_IR_SEND="P02f")
  File "C:\Users\rene\appdaemon\bin\appapi.py", line 153, in call_service
    self._check_service(service)
  File "C:\Users\rene\appdaemon\bin\appapi.py", line 28, in _check_service
    raise ValueError("Invalid Service Name: {}".format(service))
ValueError: Invalid Service Name: switch.mysensors_send_ir_code

and now im in a loss what i should change :wink:

My bad again, I was typing from memory last night - always a mistake!

In the service name replace the period with a /

E,g, switch/mysensors_send_ir_code

somehow i already wondered why there was a / in the servicelist, but i wasnt bold enough to try it out :wink:

i can tell you that it workt.

i used an app to switch the light on and off.

the only thing is that i now have 2 things running. command line and powershell.
dont think that that will go right after a few days. (just a feeling)

but i have enough info to start making a real app.
so thats what i am going to do now.

and i did it and it works!!

my app:

###########################################################################################
#  Home Assistant App for switching Mysensors (mysensors.org) 433 Mhz switch              #
#  If you have klik-aan-klik_uit, ELRO, Blokker or Action 433 Mhz switches,               #
#  all you have to do is to install a general mysensors sketch on an arduino              #
#  with a cheap 433 mhz sender. you can connect an infinitiv amount of switches with      #
#  up to 99 arduino nodes.                                                                #
#                                                                                         #
#  the sketch can be found here:                                                          #
#  https://community.home-assistant.io/t/general-mysensors-433-mhz-switch/2588/3          #
#  this is an example from an appdaemon.cfg app part:                                     #
#                                                                                         #
#  [RFSwitch1]                                                                            #
#  module = RFSwitch                                                                      #
#  class = RFSwitch                                                                       #
#  switch01 = switch.remote_2_4                                                           #
#  switch02 = switch.remote_2_5                                                           #
#  switch03 = switch.remote_2_6                                                           #
#  switch04 = switch.remote_2_7                                                           #
#  total_switches = 3                                                                     #
#  switchcode1 = rfaa02P01                                                                #
#  switchcode2 = rfab02P02                                                                #
#  switchcode3 = rfac02P03                                                                #
#                                                                                         #
#  explanation:                                                                           #
#  switch 01 to 04 are the 4 switches that the mysensors node create.                     #
#  you can use more nodes just add 05, 06, 07, ...                                        #
#  total_switches is the amount you have in use. in this case P01,P02 and P03             #
#  switchcode is build up from 3 parts.                                                   #
#  1) rfaa, rfab, rfac, ... the start from the name of the input_boolean you made         #
#  2) 01, 02, 03, ..., 99 the number from the arduinoswitch you want to send the code to. #
#  3) P01, A31, M16, ... code to send                                                     #
#  ELROcode => (A/E) buttoncode, (01/31) dipswitchcode                                    #
#  KAKUcode => (A/P) groupcode(dipswitch), (01/16) buttoncode                             #
#  Blokkercode => (A) to keep the code unified, (01/16) buttoncode                        #
#  Actioncode =>  (A/D) buttoncode, (01/?) dipswitchcode                                  #
#                                                                                         #
#  Rene Tode ( [email protected] )                                                            #
#  ( with a lot off help from Andrew Cockburn (aimc) )                                    #
#  2016/08/16 Germany                                                                     #
#                                                                                         #
###########################################################################################

import appapi

class RFSwitch(appapi.AppDaemon):

  def initialize(self):
    self.listen_state(self.switch, "input_boolean")
  
  def switch(self, entity, attribute, old, new, kwargs):
    for counter in range(1,int(self.args["total_switches"])+1):
        boolean_name_start= self.args["switchcode" + str(counter)][0:4]
        switch_type = self.args["switchcode" + str(counter)][4:6]
        switch_code = self.args["switchcode" + str(counter)][6:]
        switch=self.args["switch" + switch_type]
        if entity[14:18] == boolean_name_start:
          if new == "on":
            self.call_service("switch/mysensors_send_ir_code", entity_id = switch, V_IR_SEND=switch_code + "t")
          else:
            self.call_service("switch/mysensors_send_ir_code", entity_id = switch, V_IR_SEND=switch_code + "f")

this made my configuration.yaml already over 300 lines shorter.

Great!! Glad you managed to work through the the issues.

1 Like

i hope it will help others in the future too :wink:

Do you have an example of triggering something after it has been set to a certain state for a certain amount of time?

I’d like to take this:

trigger:
  platform: state
  entity_id: binary_sensor.garage_door_sensor_3
  from: 'off'
  to: 'on'
  for:
    minutes: 5

and turn it into something like this:

self.listen_state(self.activate, "binary_sensor.garage_door_sensor_3", new='on', for=300)

Maybe that should be a feature request… Otherwise, should I have self.activate use self.run_in to call a 2nd function after 5 minutes, and then have that function check to see if the state is still set to whatever value? I’m not sure if that’s the best way to do it or not.

edit: This is what I have now, and it seems to work:

class GarageOpenTooLong(appapi.AppDaemon):

  def initialize(self):
      self.listen_state(self.garage_opened, "binary_sensor.garage_door_sensor_3", new='on')
      self.listen_state(self.garage_closed, "binary_sensor.garage_door_sensor_3", new='off')

  def garage_opened(self, *args, **kwargs):
      self.log("Garage door opened!")
      self.still_open_timer = self.run_in(self.garage_still_open, 10)

  def garage_closed(self, *args, **kwargs):
      self.log("Garage door closed!")
      self.cancel_timer(self.still_open_timer)

  def garage_still_open(self, *args, **kwargs):
      if self.get_state('binary_sensor.garage_door_sensor_3') == 'on':
          self.log("Garage open for too long!  Notifying.")
          self.call_service("notify/pushbullet",
                            message='Garage door has been open for 5 minutes!',
                            target='xxx')

Just curious, but why have you not separated your configuration.yaml out to separate files? I see a lot of people stuffing all of their scripts, automations, scenes, etc, etc inside of their configuration.yaml, so I have to wonder if they aren’t aware that you can have different files for each automation, script, scene etc so they are easier to find and edit.

Why are there only constraints for input_boolean and input_select but no constraints for switch, light, sensor, etc? What if I want to have an app callback only if the living room light is off, or the front door is closed? Do I have to create an input_boolean in home assistant for every one of my contacts sensors, switches and lights that match the state of the actual device in order to have constraints? I have 37 z-wave door/window sensors, 18 z-wave light switches as well as a slew of other z-wave devices, but it doesn’t look like I can use their current state as a constraint. This would make it impossible for me to use appdaemon for any of my automations.

Or am I misunderstanding constraints? Aren’t they equivalent to conditions in home assistant? Home Assistant conditions can be based on the state of any item as well as AND and OR, but it appears that appdaemon constraints are only based on AND

yeah, i have it splitt out.
but i still count the lines together as 1 config :wink:

as i see it, with the little bit i have done you can listen to everything and set everything.

its py, so off course there is also OR.

somthing like:

if (self.sun_down or self.sun_rise):
       self.toggle("light.living_room")

in a case like this:

  def initialize(self):
    self.listen_state(self.motion, "switch.livingroom")
    self.listen_state(self.motion, "switch.diningroom")
    self.listen_state(self.motion, "switch.hallway")
  
  def motion(self, entity, attribute, old, new, kwargs):
    if (entity=="switch.hallway"):
      self.turn_on("switch_bathroom")
    else:
      self.turn_off("switchbathroom")

so in this case if livingroom OR diningroom OR hallway is toggled an action is taken
if someone is in the hallway the bathroomlights go on
if someone is in the diningroom or livingroom the bathroomlights go out.

@justyns - that is how I would have done it too. I will put some thought into a more concise way but however it looks it will end up doing the same as you did under the covers - it’s a good idea though. It is also an example of something I mentioned in the blog - you can pretty much do anything with AppDaemon already, but there is scope for making things easier for sure.

@jbardi - Constraints are just a convenience. As @ReneTode explained above, you can check for state on any entity and use it for conditions using the get_state() call. For instance, to check if a light is on:

if self.get_state("light.bedroom") == "on":
  do something ...

To use this in an automation you would simply perform this and other checks in the first lines of the callback to determine if you wanted to do anything. You have all the power of Python here to set the conditions and you can use AND/OR in any combination, nested to any degree using Python If/Else which I think is a lot easier to understand and more powerful than nested YAML.

What I found was that some tests like this were so common - time of day, use of an input_boolean to activate or deactivate, whether or not anyone was home etc. that I added constraints to save on lines of code to check them explicitly but you don’t have to use them if you need more complex logic.

You can think of the callback as the trigger, and the python checks on state as the conditions, and constraints as a built-in simplified type of condition that will save you coding if it matches what you want to do.

Also, this piece is wrong (it was a typo in the blog post so my bad) - the signature for state callbacks should be:

garage_closed(self, **kwargs):

I think I fixed it in the docs but I’ll check when I get home. In this case it doesn’t probably doesn’t matter because AppDaemon will never supply additional positional args but just wanted to let you know.

Andrew, 1 question:

when i was looking at the device_tracker parts, i saw that IP adress is used in the code.
do you know if there is an easy way to get the IP adress out off HA with apps?

Hi -

Not sure what you mean by “IP address is used in the code” ? Are you talking about IP addresses used by the trackers or something else?

in the known devices, devices are only listed by name and MAC.
but if i look at the pycode from nmap i see that devices are searched by IP.

and this part tells me that the IP from a device must be known to HA:

out off nmap_tracker.py

            last_results.append(Device(mac.upper(), name, ipv4, now))

i cant find the part where things are written to the knowndevices yaml, but then i find it Always hard to understand code from other people when it is splitt up in lotts off small part.

so i thought that maybe there would be an easy way to get the IP out off HA with apps.

Awesome, thanks for the explanation… I have to divorce my mind from the standard trigger/condition/action layout of HA YAML and realize I have all of Python at my disposal… do’h :smiley:

2 Likes

This is specific to the NMAP device tracker and not part of the state machine of HA, you can prove this by grepping through the logfile and looking for a specific IP address within a state change message. (Caveat - I don’t use NMAP so I might be wrong, in which case you can prove me wrong with the same technique!)

The basic principle here is that no matter what is happening under the covers, device trackers have a state of “home”, “not_home” or a specific location, it doesn’t matter how that works under the covers it doesn’t make it to Home Assistant’s internal state.

What use did you have in mind for the IP address?

I already searched at different places for IP adress, without luck, so youre probably right.
with a registered ip adress it would be easy to check with which router a device is connected.
i dont want an exact pinpoint in the house but it would be nice to know in which part off the house our devices are at a specific time.
i know that it is possible to work around it, but i was hoping on a easy way around, without rewriting parts or making changes to devices :wink: