AppDaemon Q&A

@aimc daemonize needs fcntl. and if i read it correctly that cant work on windows because that is the Linux equivalent from winapi 32.

there is a programm which uses both, cq translates the one to the other. but i wouldnt have a clue how and what to change.

it could be worthwile to check it out, because this part can be a hugh extra for HA. and it would be a shame if HA loses its platform independance.

i am really said :frowning: i installed everything (had to figure out how and what goes where in windows) made the config like it should be, and then i cant even start it :frowning:

I am working on Docker support - maybe that will be another approach? I am not sure if Docker will get around the issue but if it does it would be a lot easier than rewriting it to support windows.

Another possibility is creating a version that doesn’t use the daemonize function - then you would be able to run it from the command line and probably set it up as a windows service. You could try this idea in a quick and dirty way by commenting out the import in appdaemon.py and just make sure to run it without the -d option.

Let me know if that works and I could perhaps refactor to make a windows version that runs without that edit.

i really have now idea what docker support is :wink:

i commented the import deamonize out.
at least it does something, but then comes another error.

i ran from the commandline: /bin/appdaemon.py conf/appdaemon.cfg

and get:

Traceback (most recent call last):
  File "C:\Users\rene\appdaemon\bin\appdaemon.py", line 782, in <module>
    main()
  File "C:\Users\rene\appdaemon\bin\appdaemon.py", line 695, in main
    signal.signal(signal.SIGUSR1, handle_sig)
AttributeError: 'module' object has no attribute 'SIGUSR1'

Hmm, seems like we will have to strip a number of functions out to get this to work on Windows.

The signals are not essential, they are there for troubleshooting so you can comment that line out and the line following and give it another go.

My choice would be to try and get this running under the new BASH environment in windows 10 - that is probably a lot easier than getting it to run under native windows, so I may have a look at that at the weekend.

Thanks for the detailed answer, @aimc! I don’t disagree with any of your points, and it makes sense to me. I think it may be easier/quicker to make changes and improve AppDaemon in the short-term as a separate entity anyway, since hass itself doesn’t need to be released each time.

You can probably expect a PR from me tonight to fix some documentation after I get another chance to just make sure I wasn’t doing something wrong :wink:

Thanks - I’ll take all the help I can get :slight_smile:

HA, in python, in Linux, in windows?
dont think that would be the way.
the overload would be to much.

i have read a small bit about BASH now, but i dont think i want to go that way.
i rather install a new machine then do such a thing.

to me it feels like that microsoft tries to hijack the competition.
and the thing that annoys me the most is that there is no communication between windows and BASH except through files or network.

oke i’ll start to take out lines, 1 by 1 in the hope i get to something that works :stuck_out_tongue:

oke it seems like all it took was to take out the import daemonize and the 2 signal lines.

i havent made any app yet but i’m going to try something simple now. and see how it goes.
right now all he sais is:

2016-08-17 22:00:32,958 INFO Got initial state

That’s a good sign :slight_smile:

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.