Skip to content

AppDaemon Add-on

Disclaimer

I have no official relationship to the add-on. These are just some notes over the mechanics of how it works.

Different Dockerfile

The AppDaemon add-on uses it's own Dockerfile, which inherits from a base image for Home Assistant add-ons.

One of the differences is that the add-on mounts the config directory at /config instead of /conf. It also wraps AppDaemon with some s6 stuff

Config

Pip can actually install directly from git repos, which can be used to replace the version of AppDaemon that runs in the add-on. The general syntax is pip install git+<url>@<branch>. Git has to be installed for this to work

URL for dev branch
git+https://github.com/AppDaemon/appdaemon@dev
Example screenshot

appdaemon add-on config

Secrets

The AppDaemon add-on gets the secrets from a file called secrets.yaml in the config directory.

Folder Structure
./addon_configs/a0d7b954_appdaemon/
├── appdaemon.yaml
├── apps
   ├── apps.yaml
   └── hello.py
├── compiled
   ├── css
   └── javascript
├── dashboards
   └── Hello.dash
├── namespaces
├── secrets.yaml
└── www
Example secrets.yaml
long_lived_token: eyJhbGciOiJIUzI1NiIsInR5cM68IkpXVCJ9.eyJpc3MiOiIzNzJiMjEzZTAzNzg0N2YzOTB2N2ZmMjYwYjk4NDY3MSIsImlhdCI7MTcyMjYxNDMzNiwiZXhwIjoyMDM3OTc0MzM2fQ.r57u-hcvk0HTq8jDSimQaX1AQ2fR6mkTBzNCwooJyXg
mqtt_password: NdO3@L6LXzqWbP!LorzANx7xV_4xTbZZ

These are not real tokens

Paths

Name Inside Container Samba Host
Home Assistant config /homeassistant /config /mnt/data/supervisor/homeassistant
AppDaemon config /config /addon_configs/a0d7b954_appdaemon /mnt/data/supervisor/addon_configs/a0d7b954_appdaemon
Home Assistant Media /media /media /mnt/data/supervisor/media
Home Assistant Share /share /share /mnt/data/supervisor/share

All run from the advanced terminal in Home Assistant, which needs Protection Mode turned off for access to the docker socket.

Show container ID and name
$ docker ps --format "table {{.ID}}\t{{.Names}}" | grep appdaemon
b27c64728b94   addon_a0d7b954_appdaemon
Store the container ID in a variable
CID=$(docker ps --format '{{.ID}} {{.Names}}' | awk '$2 ~ /appdaemon$/ {print $1}')
Show volume maps from the AppDaemon container
$ docker inspect --format='{{json .Mounts}}' $CID | jq -r '.[] | select(.Type == "bind") | [.Destination, .Source] | @tsv'
/ssl    /mnt/data/supervisor/ssl
/share  /mnt/data/supervisor/share
/media  /mnt/data/supervisor/media
/dev    /dev
/data   /mnt/data/supervisor/addons/data/a0d7b954_appdaemon
/config /mnt/data/supervisor/addon_configs/a0d7b954_appdaemon # (1)!
/homeassistant  /mnt/data/supervisor/homeassistant # (2)!
  1. This is the AppDaemon config directory
  2. This is the HomeAssistant config directory

/mnt/data/supervisor/addon_configs/a0d7b954_appdaemon is the directory on the host, outside of all the docker containers. This location is managed by HAOS, and it's not directly accessible.

/config is the where it will be mounted inside the AppDaemon container.

/mnt/data/supervisor/addon_configs is available as addon_configs when using the samba share add on

/config/apps/hello.py
from pathlib import Path

from appdaemon.plugins.hass.hassapi import Hass


class HelloWorld(Hass):
    def initialize(self):
        self.log('Hello from AppDaemon')
        self.log(f'Current file: {Path(__file__)}')
2024-08-04 22:43:21.003201 INFO hello_world: Hello from AppDaemon
2024-08-04 22:43:21.003866 INFO hello_world: Current file: /config/apps/hello.py

Custom Logging

appdaemon.yaml
...
logs:
  last_update_check: # (1)!
    name: lastUpdateCheckLog
    filename: /config/logs/last_update_check.log # (2)!
  1. This is what the app config file needs to refer to.
  2. This needs to be an absolute path and already be created.
apps.yaml
hello_world:
  module: hello
  class: HelloWorld
  log: last_update_check # (1)!
  1. This has to match the key under logs in appdaemon.yaml
hello.py
from pathlib import Path

from appdaemon.plugins.hass.hassapi import Hass


class HelloWorld(Hass):
    def initialize(self):
        self.log('Hello from AppDaemon')
        self.log(f'Current file: {Path(__file__)}')
        self.log(f'Logger name: {self.logger.name}')
/config/logs/last_update_check.log
2024-08-04 22:54:29.454083 INFO hello_world: Hello from AppDaemon
2024-08-04 22:54:29.454499 INFO hello_world: Current file: /config/apps/hello.py
2024-08-04 22:54:29.454913 INFO hello_world: Logger name: lastUpdateCheckLog.hello_world

This will be available at /addon_configs/a0d7b954_appdaemon/logs because /addon_configs/a0d7b954_appdaemon is /config inside the container.