Mastering Advanced Automations with AppDaemon in Home Assistant

0
0
  • #Home_Assistant
  • #AppDaemon
  • #Automation
  • #Python
  • #Smart_Home
Represent Mastering Advanced Automations with AppDaemon in Home Assistant article
6m read

Why AppDaemon for Home Assistant Automation?

Home Assistant provides powerful built-in automation tools, including the UI automation editor, YAML automations, Blueprints, and even Node-RED via an add-on. For many tasks, these are perfectly sufficient. However, sometimes you encounter scenarios that require more complex logic, state tracking over time, integration with external Python libraries, or simply prefer writing your automation logic in a structured programming language like Python.

This is where AppDaemon shines. It's a flexible, multi-threaded, and asynchronous automation framework for Home Assistant (and MQTT). Running as a separate process, AppDaemon allows you to write 'apps' in Python that interact with Home Assistant's state machine, call services, listen for events, and much more. Its strengths lie in:

  • Complex Logic: Easily implement intricate conditional logic, loops, and data manipulation that might be cumbersome in YAML or UI automations.
  • Statefulness: Apps can maintain state over time, remembering past events or conditions, which is difficult with stateless YAML automations.
  • Python Ecosystem: Leverage the vast collection of Python libraries for tasks like data analysis, external API interactions, complex calculations, etc.
  • Structured Code: Organize your automation logic into well-defined apps, making it easier to manage and debug larger smart home configurations.

Installation and Setup

The easiest way to get started with AppDaemon is by installing it as an Add-on directly from the Home Assistant Add-on Store (available under Settings -> Add-ons -> Add-on Store). This is the recommended method for most users.

Installation Steps (Add-on):

  1. Navigate to Settings -> Add-ons in Home Assistant.
  2. Click the Add-on Store button in the bottom right.
  3. Search for AppDaemon and select it.
  4. Click Install.
  5. Wait for the installation to complete.

Configuration:

Once installed, you need to configure AppDaemon to connect to your Home Assistant instance. Go to the AppDaemon add-on page and click the Configuration tab.

The basic configuration requires an appdaemon.yaml file. The add-on provides a default structure. You typically need to specify your Home Assistant URL and a Long-Lived Access Token.

appdaemon:
  latitude: XX.XXXX
  longitude: XX.XXXX
  elevation: XXX
  time_zone: Europe/London
hass:
  url: http://a0d7b954-appdaemon:8123  # Use this if running as Add-on
  # Or use your Home Assistant URL if not using the Add-on:
  # url: http://YOUR_HA_IP:8123
  token: YOUR_LONG_LIVED_ACCESS_TOKEN

logs:
  main_log:
    enabled: True
    filename: /config/appdaemon.log
  error_log:
    enabled: True
    filename: /config/appdaemon.err

app_dir: /config/appdaemon/apps

# Example app configuration (more on this later)
apps:
  hello_world:
    module: hello
    class: HelloWorld
    # Any specific parameters for this app go here
    # greeter: 'AppDaemon'

Replace YOUR_LONG_LIVED_ACCESS_TOKEN with a token generated in your Home Assistant user profile (bottom left, click your user name -> Create Token). Ensure the hass.url is correct for your setup (the example above is typical for the add-on).

The app_dir specifies where AppDaemon will look for your Python app files. Using the add-on, this is typically /config/appdaemon/apps within the Home Assistant configuration file structure.

After configuring, go to the Info tab and click Start. Check the Log tab to ensure AppDaemon starts without errors and successfully connects to Home Assistant.

Writing Your First App

AppDaemon apps are Python classes. Create a directory named apps inside your config/appdaemon directory (if using the add-on, this is typically /config/appdaemon/apps accessible via Samba, File Editor add-on, etc.). Inside the apps directory, create a Python file for your app (e.g., hello.py).

# hello.py
import hassapi as hass

class HelloWorld(hass.Hass):

    def initialize(self):
        # This function is called when the app is started/reloaded
        self.log("Hello from AppDaemon!")
        # Schedule a message in 10 seconds
        self.run_in(self.delayed_message, 10)

    def delayed_message(self, kwargs):
        # This function is called by the scheduler
        self.log("This message appeared 10 seconds after startup.")

    def terminate(self):
        # This function is called when the app is stopped/reloaded
        self.log("AppDaemon is shutting down.")

Now, configure this app in your appdaemon.yaml (in the add-on configuration tab):

apps:
  hello_world:
    module: hello  # Name of the Python file (hello.py)
    class: HelloWorld # Name of the class within the file

Save the configuration, go back to the add-on's Info tab, and click Restart. Check the AppDaemon log. You should see the "Hello from AppDaemon!" message followed by the delayed message.

Interacting with Home Assistant

Your AppDaemon app (the HelloWorld class in the example) inherits from hass.Hass, which provides methods to interact with Home Assistant:

1. Logging:

self.log("Your message") writes messages to the AppDaemon log for debugging.

2. Getting State:

self.get_state("entity_id") retrieves the current state of an entity. You can also get attributes: self.get_state("light.living_room", attribute="brightness").

current_temp = self.get_state("sensor.outdoor_temperature")
self.log(f"Current outdoor temperature is: {current_temp}")

3. Calling Services:

self.call_service("domain/service", entity_id="entity_id", attribute=value, ...) allows you to trigger Home Assistant services.

# Turn on a light
self.call_service("light/turn_on", entity_id="light.living_room", brightness=200)

# Send a persistent notification
self.call_service("persistent_notification/create", message="Something happened!")

4. Listening for State Changes:

self.listen_state(callback, entity_id, attribute=None, new=None, old=None, duration=None, **kwargs) allows your app to react when an entity's state changes. The callback function will be called when the state changes.

# Listen for the front door sensor changing to 'on'
self.listen_state(self.door_opened, "binary_sensor.front_door", new="on")

# Callback function
def door_opened(self, entity, attribute, old, new, kwargs):
    self.log(f"{entity} changed from {old} to {new}")
    self.call_service("light/turn_on", entity_id="light.hallway")

5. Listening for Events:

self.listen_event(callback, event_name, **kwargs) allows your app to react to Home Assistant events (e.g., hass_event, zha_event, mqtt_event).

# Listen for ZHA events from a specific device
self.listen_event(self.button_pressed, "zha_event", device_ieee="xx:xx:xx:xx:xx:xx:xx:xx")

# Callback function
def button_pressed(self, event_name, data, kwargs):
    self.log(f"Received ZHA event: {data}")
    if data['command'] == 'toggle':
        self.call_service("light/toggle", entity_id="light.bedroom")

6. Schedulers:

AppDaemon provides methods to run functions at specific times or intervals: run_in(), run_at(), run_daily(), run_every(), etc. You can also cancel scheduled timers using the handle returned by these methods.

# Run a function every 5 minutes
self.run_every(self.check_temperature, "now", 5 * 60)

# Run a function tomorrow at 7:00 AM
self.run_daily(self.morning_routine, "07:00:00")

More Complex Examples

Example: Delayed Light Off with Presence Check

Turn off a light after it's been on for 5 minutes, but only if a presence sensor indicates no one is home.

# delayed_light_off.py
import hassapi as hass

class DelayedLightOff(hass.Hass):

    def initialize(self):
        # Listen for the light turning on
        self.listen_state(self.light_turned_on, "light.living_room", new="on")
        self.timer_handle = None

    def light_turned_on(self, entity, attribute, old, new, kwargs):
        self.log(f"{entity} turned on. Scheduling delayed off.")
        # Cancel any existing timer for this light
        if self.timer_handle:
            self.cancel_timer(self.timer_handle)
        # Schedule the off action in 300 seconds (5 minutes)
        self.timer_handle = self.run_in(self.turn_light_off, 300, entity_id=entity)

    def turn_light_off(self, kwargs):
        light_entity = kwargs['entity_id']
        presence_state = self.get_state("binary_sensor.house_occupied")

        if presence_state == "off":
            self.log(f"No one is home. Turning off {light_entity}.")
            self.call_service("light/turn_off", entity_id=light_entity)
        else:
            self.log(f"Someone is home. Keeping {light_entity} on.")

        self.timer_handle = None # Reset handle after action

    def terminate(self):
        # Clean up timer if app is stopped
        if self.timer_handle:
            self.cancel_timer(self.timer_handle)
        self.log("DelayedLightOff app terminated.")

Add this to appdaemon.yaml:

apps:
  ...
  delayed_light_off:
    module: delayed_light_off
    class: DelayedLightOff

Best Practices for Reliability

  • Use Logging Extensively: Log app startups, state changes, service calls, and any potential issues. This is invaluable for debugging. AppDaemon logs are separate from Home Assistant logs.
  • Handle State Changes Properly: Be mindful of what triggers your listeners. Specify old and new state constraints when possible (e.g., new="on") to avoid triggering on irrelevant state updates (like attribute changes).
  • Manage Timers: If an action schedules a timer, consider if a new event should cancel the previous timer (like the delayed light off example). Use the handle returned by the scheduler methods.
  • Error Handling: Use Python's try...except blocks, especially around service calls or interactions with potentially unavailable entities, to prevent your app from crashing.
  • Modularize Your Code: Break down complex logic into smaller, reusable functions or even separate apps.
  • Configuration vs. Code: Use parameters in your appdaemon.yaml to configure apps (e.g., which light or sensor to monitor) rather than hardcoding values in the Python file. Pass these parameters via kwargs in the initialize function.
  • Version Control: Keep your AppDaemon app files under version control (like Git) just like your Home Assistant configuration.
  • Monitor AppDaemon: Check the AppDaemon add-on logs regularly for errors. Ensure the add-on is set to auto-start with Home Assistant.
  • Graceful Shutdown: Implement the terminate() function to clean up resources, cancel timers, or save state if necessary.

Device Integration Tips

AppDaemon integrates with devices by interacting with their corresponding entities and services within Home Assistant. Any device integrated into Home Assistant (via official integrations, HACS, MQTT, ZHA, Z-Wave, etc.) can be controlled and monitored from AppDaemon.

  • Know Your Entities and Services: Use the Home Assistant Developer Tools -> States and Developer Tools -> Services tabs to find the exact entity IDs, service calls, and required parameters for your devices.
  • Use Attributes: Don't just rely on the main state. Device attributes often contain crucial information (battery level, signal strength, specific sensor readings, current track on a media player, etc.) that can be retrieved using self.get_state("entity_id", attribute="attribute_name").
  • Listen for Specific Events: Some device integrations or protocols (like ZHA, Z-Wave JS, MQTT, Zigbee2MQTT) fire specific events that contain rich data (e.g., button presses with different click types). Use self.listen_event() to capture these. Inspect the event data in Home Assistant's Developer Tools -> Events tab.
  • Handle Device Unavailability: Devices can go offline. Your AppDaemon apps should ideally check if an entity exists or its state is 'unavailable' or 'unknown' before attempting to interact with it, especially in long-running loops or critical automations.

Conclusion

AppDaemon is a powerful tool in the Home Assistant ecosystem for those who need more flexibility and complexity than standard automation methods provide. By allowing you to write Python code, it opens up possibilities for sophisticated state management, data processing, and integration with external systems or logic. While it has a steeper learning curve than UI or YAML automations, the ability to leverage a full programming language for your smart home's brain can be incredibly rewarding, enabling truly custom and intelligent behaviors.

Start with simple apps, utilize logging, and gradually build up complexity. The AppDaemon documentation is an excellent resource for exploring its full capabilities.

Avatar picture of NGC 224
Written by:

NGC 224

Author bio:

There are no comments yet
loading...