AppDaemon and when to use it

I’ve mentioned AppDaemon in passing and used it for my ZoneMinder camera automations, but what is it and why would you use it? AppDaemon is described as “a loosely coupled, multi-threaded, sandboxed python execution environment for writing automation apps for home automation projects.

What does that mean in practice?

AppDaemon integrates with Home Assistant to allow you to write automations in Python. Anything that you can with native Home Assistant automations you can also do with AppDaemon.

For example, imagine you have a motion sensor and want to turn a light on when motion is detected. You only need it to run when it’s dark, so let’s say between sunset and sunrise. The easy way to do that is to check for the sun being below the horizon.

In the user interface, you first set the trigger:

Then add the condition:


And finally an action:


To do the same thing in AppDaemon:

import appdaemon.plugins.hass.hassapi as hass

class SunsetLight(hass.Hass):
    def initialize(self):
        self.listen_state(self.light_on, "binary_sensor.kitchen_motion")

    def light_on(self, light, attribute, old, new, kwargs):       
        if new == "on" and self.get_state("sun.sun") == "below_horizon":
            self.turn_on("light.kitchen_light")

Note that although the UI text for motion sensors is “Detected” or “Clear”, these map to the values “on” and “off” for the actual entity state.

Obviously that’s such a trivial example that you’d be unlikely to use AppDaemon. Now say you wanted to extend the automation to set the brightness of the light according to the time – 100% if it’s before midnight and 50% if it’s after midnight.

You can still do that through the UI with two automations with different conditions – one that runs after sunset and one that runs before sunrise.

To do the same in AppDaemon, you just need to change the code:

import appdaemon.plugins.hass.hassapi as hass

class SunsetLight(hass.Hass):
    def initialize(self):
        self.listen_state(self.light_on, "binary_sensor.kitchen_motion")

    def light_on(self, light, attribute, old, new, kwargs):       
        if new == "on":
            if self.now_is_between("sunset", "00:00:00"):
                self.turn_on("light.kitchen_light", brightness = 100)
            elif self.now_is_between("00:00:00", "sunrise"):
                self.turn_on("light.kitchen_light", brightness = 50)

The AppDaemon version is already, arguably, simpler. The UI method involves some duplication – you need two automations. It should also be possible to do it in a single automation with a data template to determine brightness, but then you’d be duplicating the condition logic in the data template for the action.

It’s still not a use case that really needs AppDaemon – I’d probably opt for two separate automations for this one.

The more complex the conditions and actions get, the more AppDaemon comes into its own. If you want to use a complex formula for the light brightness based on the time, or the value of a light sensor, it can be easier to write the logic in Python than by using data templates.  I’ll be honest here and say I’m not a fan of complex data templates. The Jinja2 templating engine that Home Assistant uses is very powerful, but I find it fiddly to use and you have to be very careful to get the spacing right.

Every AppDaemon app can have a configuration file. For the first example, the configuration file could contain a mapping between motion sensors and lights, so if you had multiple sensors you’d still only need a single app. You could also use configuration parameters for the brightness levels.

My rule of thumb is that if the configuration is pretty much fixed, it goes into the configuration file. If it’s something that I might want to control, either directly or through automations, I use an input helper. For example, in my Zoneminder automation I have a number of boolean switches and a couple of numeric inputs that manage how the automation works.

It’s worth noting that there is also a Python script integration in Home Assistant that can do a lot of the same things. It’s better integrated, so it’s simpler to use and is another option.

There are, though, some things that AppDaemon can do that the native Python script integration can’t. It supports imports, which greatly increases the flexibility, giving you access to anything that you can install via Python’s pip. For example, I use the JSON module in my Zoneminder automation to extract data from the state of an MQTT sensor.

AppDaemon apps are Python classes that are instantiated when AppDaemon starts. That means that you can also have persistent variables to keep track of data between calls to the automation. It’s possible to do the same thing in Home Assistant, using the various automation helpers such as input_text, but with Python code you can use data structures such as lists, dictionaries and arbitrarily complex combinations of both.

Native automations do have one big advantage over AppDaemon apps – you can switch them on and off through the user interface. There is a way to have the best of both worlds. In the example above, the AppDaemon app replicated the UI automation by listening for the same event – the change of state of the automation sensor. You can also write AppDaemon apps that respond to events that you fire from within normal automations.

Using the same example, you’d have an automation that triggers on the motion sensor and has an action to fire an event:

The automation wouldn’t need  a condition. In AppDaemon you’d then listen for the event and act on it. Since the automation is triggered by motion, you’d only need to do the time check in AppDaemon:

import appdaemon.plugins.hass.hassapi as hass

class SunsetLight(hass.Hass):
    def initialize(self):
        self.listen_event(self.light_on, "KITCHENMOTIONLIGHT")

    def light_on(self, light, attribute, old, new, kwargs):       
        if self.now_is_between("sunset", "00:00:00"):
            self.turn_on("light.kitchen_light", brightness = 100)
        elif self.now_is_between("00:00:00", "sunrise"):
            self.turn_on("light.kitchen_light", brightness = 50)

It’s an approach that allows you to manage your automations through Home Assistant while still having access to all of the power of AppDaemon.

AppDaemon is rarely essential, as most things can be done with native automations, but it’s a useful tool to have in the box. If you have a programming background, in particular, you may find it easier to write your automations in Python code than to figure out how to do them natively.

in Home Automation

One Comment

  1. H Wings 5th January 2021

Add a Comment

Your email address will not be published. All comments will be reviewed.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Related Posts