Sure! Let me know how it works out for you. Iād love to hear feedback on what you think could be explained better. The complex example is more flexible of an approach to the problem, but doesnāt have all the accompanying explanation. If youād like me to expand on any of it, let me know and I certainly can!
I should caveat that currently, if youāre going to use the complex example for light notifications, any time you change the brightness, youāll get a āThis light has been on for more than X seconds!ā notification. Thatās not necessarily what you want in that case, so youād need to modify it to pull out the brightness level and format your message accordingly. I just used it as an example because I donāt have any door/window/garage sensors! ha ha
Thanks for this. I found the tutorial very useful.
Could you give me any pointers about how one goes about debugging an AppDaemon python scripts? There must be an easier way than checking the output of the error and appdaemon log files. Iām new to Python so any advice would be appreciated.
Can you give me an example of an error youāre seeing or what youāre expecting to see? The easiest (maybe not the simplest) way would be to periodically check your error log. This does give me a great idea for my next tutorial though, one that would solve this need for the āsimplestā way!
Hint
Weāll simply write an app to notify us any time there is a ānewā error!
I just keep three or four terminal sessions open. I use one as a unix prompt to edit various files. I use the second to keep a running tail of my appdaemon.log file, and the third is to keep a running tail of my appdaemon.err file. It does make for a busy screen if you have them all open at once, but it also gives a good feeling of satisfaction to look over and see that your err windowās last error was a few hours ago. You do have to close and reopen them periodically though because AD does log swaps so if your log tail doesnāt change for a while, you probably arenāt watching the live file anymore.
Now, you might not need to clutter up your screen so much.
Tutorial #2 is up and rockinā! Check it out. Thanks for the awesome idea for an app, @awitty! Iām actually going to be using the complex version in my own setup.
Thanks, i managed to figure out how to debug the code. Iām sure itās second nature to most people on this forum, and perhaps thereās an easier way. But for anybody struggling like me this is what i did;
edit your .py file and add the following line near the top;
import pdb # this is the python debugger
now add a breakpoint somewhere in your code where you want to start debugging by inserting;
pdb.set_trace()
now stop your appdaemon service (i.e. sudo service appdaemon stop)
and run appdaemon in the foreground. (i.e. appdaemon -c āpath to your config fileā)
appdaemon will now stop at your breakpoint and you can step through the code and inspect variables etc.
Thereās a good tutoral on how to use the debugger here
Just started using appdaemon today. Got everything set up and running. Just so I could get my bearings on how things work I tried to copy the simple script and run that. But I canāt seem to get it to work. I realize that this tutorial is probably not meant to be copied and pasted but to breakdown and explain the parts of the script but just getting it working will help me step through the parts.
First issue i ran into is initialize is spelled incorrectly. Once i realized and fixed that I started getting the following error.
import appdaemon.appapi as appapi
#
# App to send notification when a door left open for too long
#
# Args: (set these in appdaemon.cfg)
# ttl = # of seconds to wait until notified
#
#
# EXAMPLE appdaemon.cfg entry below
#
# # Apps
#
# [door_notifications]
# module = door_notifications
# class = DoorMonitor
# ttl = 15
#
class test(appapi.AppDaemon):
def initialize(self):
self.log("test")
self.door_entities = ['input_boolean.spot']
self.door_timer_library = {}
for door in self.door_entities:
self.listen_state(self.tracker, entity=door)
def tracker(self, entity, attribute, old, new, kwargs):
try:
self.cancel_timer(self.door_timer_library[entity])
except KeyError:
self.log('Tried to cancel a timer for {}, but none existed!'.format(entity),
level='DEBUG')
if new == 'on':
self.door_timer_library[entity] = self.run_in(self.notifier,
int(self.args['ttl']),
e=entity)
def notifier(self, kwargs):
friendly_name = self.get_state(kwargs['e'], 'friendly_name')
title = "Message from HASS!"
message = "{} has been open for more than {} seconds.".format(friendly_name,
self.args['ttl'])
self.log('notify/notify, title={}, message={}'.format(title,message))
I think the problem is that sometimes entity especially if passed in through kwargs interferes with it if itās used in the library code. So I changed where we passed entity=entity into the callback function through kwargs to e=entity and that got rid of the error you were seeing. I also simplified it to look at just one input_boolean (since I donāt have any door sensors like that), and to just dump out a log message instead of sending a notification which I donāt have setup in my config.
Thanks for the info. Trying to test this from work by just setting the state of the door sensor to on in the states-dev tool (since I canāt manually open the door) Iām trying to add the json for the friendly_name but I canāt for the life of me figure out the syntax. Iāve tried a ton of variations on basically {"Friendly_name" : "Front Door Opened"} but I keep getting various errors along the lines of Error parsing JSON: SyntaxError: JSON.parse: unexpected character at line 1 column 20 of the JSON data (the error changes depending what i change in the syntax). Iāve tried single quotes outside of the curly brackets, inside instead of double quotes, spaces, no spaces, etc.
EDIT: nevermind. This { "friendly_name" : "Front Door Opened" } worked, which i swear i had already tried.
Sweet. Got it running. Changing the entity variable to e did the trick. Now to start practicing trying to understand and write some code on my own. Thanks again for the help.
Youāre both totally right about entity erroring out. I updated the easy version! Youāll see the complex version of the app (the one I actually testedā¦) uses entity_name instead of entity. Thereās a lesson in here that you shouldnāt use these so-called āreservedā keywords as your variable names, otherwise it can cause some headache when trying to debug. In AppDaemon, entity is one of those such keywords!
While we have you Aimc,
In SupahNoobās code there is a run_in(self.callback,seconds=ttl) or something like that. Is seconds being recognized as being the second named arguement, or is it somehow coming across as a kwarg because of the ā=ā? Iām thinking itās being seen as the second named arguement since there isnāt a default for it in the appapi code and itās not erroring out.