Trying to set various input booleans

So I’m working on getting this to work with appdaemon.

I don’t want to really pass in any args to the script kinda just want it to fire off on its own as time happens or presence changes. It passes the sanity checks when appdaemon loads it up but for the life of me I can’ get it to toggle the various input_booleans that I need it to toggle. My idea with these is to use them as I guess for lack of a better word a scene setter. Like if the night is active then we can do certain things or if sleep is active lets do this or that. I’m still no expert at python so a lot of this has been me studying other python examples to piece this together. The script makes sense to me it looks like it should work but I guess I’m missing something with it.

import appdaemon.appapi as appapi
import datetime

class set_modes(appapi.AppDaemon):

  def initialize(self):
    self.log("Set the boolean to the appropriate value")
    self.listen(self.someone_home_function, get_state.anyone_home)
    self.listen(self.set_mode_function, "input_boolean.notify_home")

# input booleans
    home = ['input_boolean.notify_home']
    day = ['input_boolean.notify_day']
    night = ['input_boolean.notify_night']
    sleep = ['input_boolean.notify_sleep']
# Days of the week
    WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
    WEEKEND = ['Saturday', 'Sunday']

  def someone_home_function (self, entity, attribute, old, new, kwargs):
    someone_home_function = self.get_state.anyone_home
    if self.someone_home_function == 'true':
       self.log("Setting the mode to home")
       self.turn_on("home")
    else:
       self.log("Setting the mode to away")
       self.turn_off("home")
       self.turn_off("day")
       self.turn_off("night")
       self.turn_off("sleep")


  def set_mode_function (self, entity, attribute, old, new, kwargs):
    set_mode_function = self.get_state()
    if home == 'on' and self.now_is_between("04:30:00","sunset") and day.strftime('%A') in WEEKDAYS:
      self.log("Setting mode to day")
      self.turn_on("day")
    elif home == 'on' and self.now_is_between("04:30:00","sunset") and day.strftime('%A') in WEEKEND:
      self.log("Setting mode to day")
      self.turn_on("day")
    elif home == 'on' and self.now_is_between("sunset","00:00:00"):
      self.log("Setting mode to night")
      self.turn_off("day")
      self.turn_on("night")
    elif home == 'on' and self.now_is_between("00:00:00","sunrise"):
      self.log("Setting mode to sleep")
      self.turn_off("night")
      self.turn_on("sleep")

I know once I get this figured out I can then go back to some of my other ones that I’m having issues with and probably fix them as well. I took a break from them since I thought this would be simpler. Guess I was wrong :slight_smile: thank you all for your help with this.

Rene must have gone AWOL, so I’ll try and answer this :grinning:

There are a couple of Python concepts that you have misunderstood. Firstly,

   home = ['input_boolean.notify_home']

This creates a variable called home, but it is only available (its scope) inside the function it is defined in. So it is not available elsewhere. Also, the [] around it make it an array, which is not what you want.

To make the variable available to other apps, you need to declare it as part of the class, which Python refers to as self. So this line should be

   self.home = 'input_boolean.notify_home'

Similarly with day night and sleep

Referring to these is done with the same code as they are created. So to turn on `input_boolean.notify_home’ you do

   self.turn_on(self.home)

To get the state of that item, you need to call self.get_state() so

  if home == 'on'

should be

  if self.get_state(self.home) == 'on'

but there are actually neater ways of doing that logic in appdaemon - more of that another time.

Going back to your initialize function, self.listen isn’t actually something defined in the api, so I’m surprised that isn’t giving an error. What you want is

self.listen_state(self.set_mode_function, "input_boolean.notify_home")

Although if you add some [callback constraints](http://callback constraints) you can make you functions much simpler.

I haven’t mentioned the someone_home_function because I’m not quite sure what you intend with that, but there is enough for you to fix for now.

Thank you very much for your help with this @gpbenton. Prior to HA I’ve really only done just bash so this has been a learning curve and I did do @ReneTode tutorials but that was with passing in the entity where with this I diddn’t want to pass in any entities and this is by far the most complex one I’ve done up so far where as other ones was a door opened turn on a light or its cold turn on an electric heater. This is my first attempt at the multiple functions and I hope where I stuck them at in the initialize was the correct location since prior to this I’ve only had 1 function.

The someone_home_function is just to set the main boolean of home to on or off. I intend to use this for setting various settings around the house such as thermostat temperature mainly.

So here we are now with the latest code fixes

import appdaemon.appapi as appapi
import datetime

class set_modes(appapi.AppDaemon):

  def initialize(self):
    self.log("Set the boolean to the appropriate value")
    self.listen_state(self.someone_home_function, get_state.anyone_home)
    self.listen_state(self.set_mode_function, "input_boolean.notify_home")

# Lets get all of our arguments defined now
# input booleans
    self.home = 'input_boolean.notify_home'
    self.day = 'input_boolean.notify_day'
    self.night = 'input_boolean.notify_night'
    self.sleep = 'input_boolean.notify_sleep'
# Days of the week
    WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
    WEEKEND = ['Saturday', 'Sunday']

  def someone_home_function (self, entity, attribute, old, new, kwargs):
    someone_home_function = self.get_state.anyone_home
    if self.someone_home_function == 'true':
       self.log("Setting the mode to home")
       self.turn_on(self.home)
    else:
       self.log("Setting the mode to away")
       self.turn_off(self.home)
       self.turn_off(self.day)
       self.turn_off(self.night)
       self.turn_off(self.sleep)


  def set_mode_function (self, entity, attribute, old, new, kwargs):
    set_mode_function = self.get_state()
    if self.get_state(self.home) == 'on' and self.now_is_between("04:30:00","sunset") and day.strftime('%A') in WEEKDAYS:
      self.log("Setting mode to day")
      self.turn_on(self.day)
    elif self.home == 'on' and self.now_is_between("04:30:00","sunset") and day.strftime('%A') in WEEKEND:
      self.log("Setting mode to day")
      self.turn_on(self.day)
    elif self.get_state(self.home) == 'on' and self.now_is_between("sunset","00:00:00"):
      self.log("Setting mode to night")
      self.turn_off(self.day)
      self.turn_on(self.night)
    elif self.get_state(self.home) == 'on' and self.now_is_between("00:00:00","sunrise"):
      self.log("Setting mode to sleep")
      self.turn_off(self.night)
      self.turn_on(self.sleep)

Edit over looked some things

This looks better, but a few more fixes

I take it that you want this to trigger when someone arrives home, or everyone has left. To do that, you have to trigger on the state of the group all_devices, so

    self.listen_state(self.someone_home_function, get_state.anyone_home)

should be

   self.listen_state(self.someone_home_function, "group.all_devices")

and with someone_home_function, AD provides convenience functions to determine if someone is home, so instead of

    someone_home_function = self.get_state.anyone_home
    if self.someone_home_function == 'true':

you can do

   if self.anyone_home():

and you missed one other self.get_state()

    elif self.home == 'on' and self.now_is_between("04:30:00","sunset") and day.strftime('%A') in WEEKEND:

Which, are all the bugs I can currently see. There are some optimizations I can see you could do with input constraints, but I think you should try and get this working before I make any more suggestions.

Thank you very very much for your help with this. At least I had the basic concept down of what I was trying to get done just the formatting. I am no programmer just an engineer so I take care of the app servers but I’m trying to advance more in my DevOps space that I work in and I know that having some python skills will greatly help me advance this and what better way to learn it than on something at home :slight_smile:

Oh and the changes are done and its currently running through my build process right now. Now if there was a way with Travis I could have it load appdaemon in the build so that Travis could check the sanity of my python it would save me a lot of merges with master :slight_smile:

This sounds way too elaborate. AD should work like you save the file, AD immediately loads the file and runs it.

Yeah I’ve thought about splitting my appdaemon stuff off to its own github repo and just have jenkins manage it by itself so that when I check in jenkins just logs in and does a pull

EDIT:

import appdaemon.appapi as appapi
import datetime

class set_modes(appapi.AppDaemon):

  def initialize(self):
    self.log("Set the boolean to the appropriate value")
    self.listen_state(self.someone_home_function, "group.all_devices")
    self.listen_state(self.set_mode_function, "input_boolean.notify_home")

# Lets get all of our arguments defined now
# input booleans
    self.home = 'input_boolean.notify_home'
    self.day = 'input_boolean.notify_day'
    self.night = 'input_boolean.notify_night'
    self.sleep = 'input_boolean.notify_sleep'
# Days of the week
    WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
    WEEKEND = ['Saturday', 'Sunday']

  def someone_home_function (self, entity, attribute, old, new, kwargs):
    someone_home_function = self.get_state.anyone_home
    if self.anyone_home():
       self.log("Setting the mode to home")
       self.turn_on(self.home)
    else:
       self.log("Setting the mode to away")
       self.turn_off(self.home)
       self.turn_off(self.day)
       self.turn_off(self.night)
       self.turn_off(self.sleep)


  def set_mode_function (self, entity, attribute, old, new, kwargs):
    set_mode_function = self.get_state()
    if self.get_state(self.home) == 'on' and self.now_is_between("04:30:00","sunset") and day.strftime('%A') in WEEKDAYS:
      self.log("Setting mode to day")
      self.turn_on(self.day)
    elif self.get_state(self.home) == 'on' and self.now_is_between("04:30:00","sunset") and day.strftime('%A') in WEEKEND:
      self.log("Setting mode to day")
      self.turn_on(self.day)
    elif self.get_state(self.home) == 'on' and self.now_is_between("sunset","00:00:00"):
      self.log("Setting mode to night")
      self.turn_off(self.day)
      self.turn_on(self.night)
    elif self.get_state(self.home) == 'on' and self.now_is_between("00:00:00","sunrise"):
      self.log("Setting mode to sleep")
      self.turn_off(self.night)
      self.turn_on(self.sleep)

Here is the latest rendition. Now if I understand correctly when it starts up shouldn’t it set the boolean? Right now I have the day turned on manually in hopes that HA will set the appropriate time of day switch.

You only have triggers for when the `input_boolean.notify_home’ changes, or when someone arrives home (or everyone has left). If you just sit and wait, you will be there forever.

That makes sense. So I manually triggered the home boolean to see if anything would fire off but nada. Nothing was written to the error log or my stdout log. Hmm

In case its relevant this is what I have in my config to call the module/class

set_modes:
  module: set_modes
  class: set_modes

Was this written when the file was saved, just to make sure the app is starting up correctly.

Ok I resaved the file to force appdaemon to reload it and

----------
2018-03-02 08:35:28.208449 WARNING Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/appdaemon/appdaemon.py", line 775, in process_message
    process_state_change(data)
  File "/usr/lib/python3.6/site-packages/appdaemon/appdaemon.py", line 726, in process_state_change
    callback["kwargs"]
  File "/usr/lib/python3.6/site-packages/appdaemon/appdaemon.py", line 664, in check_and_disapatch
    "kwargs": kwargs
  File "/usr/lib/python3.6/site-packages/appdaemon/appdaemon.py", line 255, in dispatch_worker
    for arg in config[name].keys():
KeyError: 'set_modes'

2018-03-02 08:35:28.209771 WARNING ------------------------------------------------------------

So it doesn’t like the kwargs in there.

Is that because I"m not actually passing in an argument to it like where you specify an arg in the appdaemon.yaml?

EDIT: Correction that error is being thrown when I toggle the home boolean so its attempting to get in there

I just pasted your code into my test box, and it runs without that error.

I don’t think it does what you expect it to - nothing much at all even when the input boolean is switched - but there are no errors.

The KeyError is not something I have not seen before. Can you paste all your apps.yaml? The trouble with naming them all the same is that you cannot tell whether it is referring to the app, the module or the class.

Here is the full config

AppDaemon:
  cert_verify: False
  disable_apps: 1
  logfile: /config/hadaemon/appdaemon.log
  errorfile: /config/hadaemon/error.log
  threads: 10
  app_dir: /config/hadaemon/apps
HASS:
  ha_url: http://172.17.0.1:8123
  ha_key: password
HADashboard:
  dash_url: http://cp.local.io
  dash_dir: /config/hadaemon/dashboards
#Apps
sun_down_turn_on_outside_lights:
  module: sun_lights
  class: sun_down_lights
  sunset_offset: 1200
  sunrise_offset: 0
  lightID: light.outside_lights

sun_down_turn_on_living_room_lights:
  module: sun_lights
  class: sun_down_lights
  sunset_offset: 0
  sunrise_offset: 0
  lightID: light.living_room_lights

sun_up_turn_off_boys_night_light:
  module: sun_lights
  class: sun_down_lights
  sunset_offset: 0
  sunrise_offset: 0
  constrain_start_time: sunrise
  constrain_end_time: sunrise +02:00:00
  lightID: light.boys_night_light

east_side_motion_lights:
  module: motion_lights
  class: motion_lights
  lightID: light.east_wall_light
  motionID: sensor.east_side_motion
  constrain_start_time: sunset + 00:20:00
  constrain_end_time: sunrise

west_side_motion_lights:
  module: motion_lights
  class: motion_lights
  lightID: light.west_wall_light
  motionID: sensor.west_side_motion
  constrain_start_time: sunset + 00:20:00
  constrain_end_time: sunrise

chicken_coop_motion_lights:
  module: motion_lights
  class: motion_lights
  lightID: light.chicken_run_light
  motionID: sensor.chicken_coop_motion
  constrain_start_time: sunset + 01:00:00
  constrain_end_time: sunrise

living_room_motion_lights:
  module: motion_lights
  class: motion_lights
  lightID: light.living_room_lights
  motionID: sensor.living_room_motion
  constrain_start_time: 00:00:00
  constrain_end_time: sunrise

garage_door_opens_night:
  module: door_opens
  class: lights_after_sunset
  lightID: light.garage_light
  DoorSensorID: sensor.garage_door_contact
  constrain_start_time: sunset + 00:20:00
  constrain_end_time: sunrise

back_door_opens_night:
  module: door_opens
  class: lights_after_sunset
  lightID: light.back_porch_light
  DoorSensorID: sensor.back_door_contact
  constrain_start_time: sunset + 00:20:00
  constrain_end_time: sunrise
  constrain_presence: anyone

cold_outside_turn_on_chicken_water_heater:
  module: heaters
  class: heaters
  tempID: sensor.average_outside_temp
  switchID: switch.chicken_water_heater_switch

crawlspace_hot_turn_on_fan:
  module: crawlspace_cooling
  class: crawlspace_cooling
  tempID: sensor.crawlspace_temp
  switchID: switch.crawlspace_fan

cameras_activation:
  module: cameras
  class: cameras

set_modes:
  module: set_modes
  class: set_modes

grandfather_clock:
  module: grandfather_clock.py
  class: Grandfather
  constrain_start_time: 08:00:00
  constrain_end_time: 22:00:00

The grandfather clock module is broken right now and I"m trying to find the original post of that code to compare my changes against the original because there is something I screwed up in it. But I wouldn’t think that would effect this

EDIT: Didn’t think about the naming the same problem. That is a really good point so I’ll make a change to that so I can differentiate between the 2

Which version of appdaemon are you running? The organization of configuration files has changed for the various versions, and it looks like you have an old setup.

FYI, the stable version (v2) is described here, with separate appdaemon.yaml and apps.yaml files.

Ok so the plot thickens I removed my broken Grandfather clock stuff from appdaemon for now so that it will stop throwing errors. Now when I toggle my switch I get

2018-03-02 11:26:52.881129 WARNING ------------------------------------------------------------
2018-03-02 11:26:52.882597 WARNING ------------------------------------------------------------
2018-03-02 11:26:52.883932 WARNING Unexpected error in worker for App set_modes:
2018-03-02 11:26:52.889140 WARNING Unexpected error in worker for App set_modes:
2018-03-02 11:26:52.891392 WARNING Worker Ags: {'name': 'set_modes', 'id': UUID('48680582-4cc6-4a6a-bce8-8bc2b03c1b11'), 'type': 'attr', 'function': <bound method set_modes_boolean.set_mode_function of <set_modes.set_modes_boolean object at 0x75721490>>, 'attribute': 'state', 'entity': 'input_boolean.notify_home', 'new_state': 'off', 'old_state': 'on', 'kwargs': {}}
2018-03-02 11:26:52.896865 WARNING Worker Ags: {'name': 'set_modes', 'id': UUID('48680582-4cc6-4a6a-bce8-8bc2b03c1b11'), 'type': 'attr', 'function': <bound method set_modes_boolean.set_mode_function of <set_modes.set_modes_boolean object at 0x7570ed10>>, 'attribute': 'state', 'entity': 'input_boolean.notify_home', 'new_state': 'off', 'old_state': 'on', 'kwargs': {}}
2018-03-02 11:26:52.901278 WARNING ------------------------------------------------------------
2018-03-02 11:26:52.906108 WARNING ------------------------------------------------------------
2018-03-02 11:26:52.908799 WARNING Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/appdaemon/appdaemon.py", line 525, in worker
    ha.sanitize_state_kwargs(args["kwargs"]))
TypeError: set_mode_function() takes 1 positional argument but 6 were given

2018-03-02 11:26:52.911404 WARNING Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/appdaemon/appdaemon.py", line 525, in worker
    ha.sanitize_state_kwargs(args["kwargs"]))
TypeError: set_mode_function() takes 1 positional argument but 6 were given

2018-03-02 11:26:52.923354 WARNING ------------------------------------------------------------
2018-03-02 11:26:52.924446 WARNING ------------------------------------------------------------
2018-03-02 11:26:54.504320 WARNING ------------------------------------------------------------
2018-03-02 11:26:54.505306 WARNING ------------------------------------------------------------
2018-03-02 11:26:54.506749 WARNING Unexpected error in worker for App set_modes:
2018-03-02 11:26:54.506058 WARNING Unexpected error in worker for App set_modes:
2018-03-02 11:26:54.507331 WARNING Worker Ags: {'name': 'set_modes', 'id': UUID('48680582-4cc6-4a6a-bce8-8bc2b03c1b11'), 'type': 'attr', 'function': <bound method set_modes_boolean.set_mode_function of <set_modes.set_modes_boolean object at 0x75721490>>, 'attribute': 'state', 'entity': 'input_boolean.notify_home', 'new_state': 'on', 'old_state': 'off', 'kwargs': {}}
2018-03-02 11:26:54.505749 WARNING ------------------------------------------------------------
2018-03-02 11:26:54.507909 WARNING Worker Ags: {'name': 'set_modes', 'id': UUID('48680582-4cc6-4a6a-bce8-8bc2b03c1b11'), 'type': 'attr', 'function': <bound method set_modes.set_mode_function of <set_modes.set_modes object at 0x75a76850>>, 'attribute': 'state', 'entity': 'input_boolean.notify_home', 'new_state': 'on', 'old_state': 'off', 'kwargs': {}}
2018-03-02 11:26:54.508544 WARNING ------------------------------------------------------------
2018-03-02 11:26:54.509218 WARNING Unexpected error in worker for App set_modes:
2018-03-02 11:26:54.509887 WARNING ------------------------------------------------------------
2018-03-02 11:26:54.510967 WARNING Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/appdaemon/appdaemon.py", line 525, in worker
    ha.sanitize_state_kwargs(args["kwargs"]))
TypeError: set_mode_function() takes 1 positional argument but 6 were given

2018-03-02 11:26:54.511948 WARNING Worker Ags: {'name': 'set_modes', 'id': UUID('48680582-4cc6-4a6a-bce8-8bc2b03c1b11'), 'type': 'attr', 'function': <bound method set_modes_boolean.set_mode_function of <set_modes.set_modes_boolean object at 0x7570ed10>>, 'attribute': 'state', 'entity': 'input_boolean.notify_home', 'new_state': 'on', 'old_state': 'off', 'kwargs': {}}
2018-03-02 11:26:54.513102 WARNING ------------------------------------------------------------
2018-03-02 11:26:54.513700 WARNING Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/appdaemon/appdaemon.py", line 525, in worker
    ha.sanitize_state_kwargs(args["kwargs"]))
  File "/config/hadaemon/apps/set_modes.py", line 36, in set_mode_function
    if self.get_state(self.home) == 'on' and self.now_is_between("04:30:00","sunset") and day.strftime('%A') in WEEKDAYS:
NameError: name 'day' is not defined

2018-03-02 11:26:54.514301 WARNING ------------------------------------------------------------
2018-03-02 11:26:54.515254 WARNING ------------------------------------------------------------
2018-03-02 11:26:54.516618 WARNING Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/appdaemon/appdaemon.py", line 525, in worker
    ha.sanitize_state_kwargs(args["kwargs"]))
TypeError: set_mode_function() takes 1 positional argument but 6 were given

2018-03-02 11:26:54.517564 WARNING ------------------------------------------------------------

So I’m running Hassio and this is what got installed from the app store for appdaemon 0.0.13
its from Vlad’s repository

I don’t use hassio, so I have no idea what this is. Does it say what version of appdaemon it is running?

Yeah I just restarted the addon and it comes up with starting version 3.2.2. I built this out on a pi and was just following the guides for a pi install which led me to hassio

Edit: Ok its now running with no errors had to remove all the additional arguments passed in and only send it the self one but you’re right. It doesn’t do what I thought it would do. Time to dig into it some more and see what I can figure out.

I’m still a bit confused about what version you are running. Version 3.0 is still in beta, so 3.2.2 isn’t correct.

It should print something like

2018-02-18 12:19:54.753974 INFO AppDaemon Version 2.1.12 starting

In the appdaemon log when it starts (I don’t know where this will be in hassio)