Configuration
This page covers how to migrate AppDaemon configuration files to Hassette's hassette.toml and typed AppConfig models.
Overview
AppDaemon uses two YAML files:
appdaemon.yaml— global settings (timezone, HA connection details)apps.yaml— per-app settings (module, class, arguments)
Hassette uses a single hassette.toml for everything. App arguments are defined as typed Pydantic models instead of raw dictionaries.
Global Configuration
AppDaemon (appdaemon.yaml)
appdaemon:
time_zone: America/Chicago
latitude: 51.725
longitude: 14.3434
elevation: 0
use_dictionary_unpacking: true
plugins:
HASS:
type: hass
ha_url: http://192.168.1.179:8123
token: !env_var HOME_ASSISTANT_TOKEN
Hassette (hassette.toml)
[hassette]
base_url = "http://192.168.1.179:8123"
# Token read from HASSETTE__TOKEN env var or .env file
[apps.my_app]
filename = "my_app.py"
class_name = "MyApp"
# [[double brackets]] = TOML array-of-tables; supports running the same app with multiple configs
[[apps.my_app.config]]
entity = "light.kitchen"
brightness = 200
The Home Assistant token is read from the HASSETTE__TOKEN environment variable or from a .env file — it is not stored in hassette.toml.
Per-App Configuration
AppDaemon (apps.yaml)
my_app:
module: my_app
class: MyApp
args:
entity: light.kitchen
brightness: 200
Arguments are accessible in the app via self.args["args"]["entity"] — a nested dictionary with no type information.
from appdaemon.plugins.hass import Hass
class MyApp(Hass):
def initialize(self):
self.log(f"{self.args=}")
entity = self.args["args"]["entity"]
brightness = self.args["args"]["brightness"]
self.log(f"My configured entity is {entity!r} (type {type(entity)})")
self.log(f"My configured brightness is {brightness!r} (type {type(brightness)})")
# 2025-10-13 18:59:04.820599 INFO my_app: self.args={'name': 'my_app', 'config_path': PosixPath('./apps.yaml'), 'module': 'my_app', 'class': 'MyApp', 'args': {'entity': 'light.kitchen', 'brightness': 200}}
# 2025-10-13 18:40:23.676650 INFO my_app: My configured entity is 'light.kitchen' (type <class 'str'>)
# 2025-10-13 18:40:23.677422 INFO my_app: My configured brightness is 200 (type <class 'int'>)
Hassette (hassette.toml + AppConfig)
[hassette]
base_url = "http://127.0.0.1:8123"
[apps.my_app]
filename = "my_app.py"
class_name = "MyApp"
[[apps.my_app.config]]
entity = "light.kitchen"
brightness = 200
In Hassette, you define a subclass of AppConfig to declare the expected parameters with types and defaults. You access configuration via the typed self.app_config attribute:
from pydantic import Field
from hassette import App, AppConfig
class MyAppConfig(AppConfig):
entity: str = Field(..., description="The entity to monitor")
brightness: int = Field(100, ge=0, le=255, description="Brightness level (0-255)")
class MyApp(App[MyAppConfig]):
async def on_initialize(self):
self.logger.info("app_manifest=%r", self.app_manifest)
self.logger.info("app_config=%r", self.app_config)
entity = self.app_config.entity
self.logger.info("My configured entity is %r (type %s)", entity, type(entity))
brightness = self.app_config.brightness
self.logger.info("My configured brightness is %r (type %s)", brightness, type(brightness))
# 2025-10-13 18:57:45.495 INFO hassette.MyApp.0.on_initialize:13 - self.app_manifest=<AppManifest MyApp (MyApp) - enabled=True file=my_app.py>
# 2025-10-13 18:57:45.495 INFO hassette.MyApp.0.on_initialize:14 - self.app_config=MyAppConfig(instance_name='MyApp.0', log_level='INFO', entity='light.kitchen', brightness=200)
# 2025-10-13 18:57:45.495 INFO hassette.MyApp.0.on_initialize:17 - My configured entity is 'light.kitchen' (type <class 'str'>)
# 2025-10-13 18:57:45.495 INFO hassette.MyApp.0.on_initialize:19 - My configured brightness is 200 (type <class 'int'>)
Migration Steps
Convert your appdaemon.yaml and apps.yaml to a single hassette.toml:
# appdaemon.yaml
appdaemon:
plugins:
HASS:
type: hass
ha_url: http://192.168.1.179:8123
token: !env_var HOME_ASSISTANT_TOKEN
# apps.yaml
my_app:
module: my_app
class: MyApp
args:
entity: light.kitchen
brightness: 200
[hassette]
base_url = "http://192.168.1.179:8123"
# Token read from HASSETTE__TOKEN env var or .env file
[apps.my_app]
filename = "my_app.py"
class_name = "MyApp"
# [[double brackets]] = TOML array-of-tables; supports running the same app with multiple configs
[[apps.my_app.config]]
entity = "light.kitchen"
brightness = 200
[[double brackets]] — TOML array-of-tables
The [[apps.my_app.config]] syntax uses TOML array-of-tables, which means you can repeat it to run the same app class with multiple independent configurations (for example, one instance per room). Change [[...]] to [...] and you get a single-item table — the double brackets signal a list.
Then replace dictionary access with typed config access:
def initialize(self):
entity = self.args["args"]["entity"]
brightness = self.args["args"]["brightness"]
from pydantic import Field
from hassette import App, AppConfig
class MyAppConfig(AppConfig):
entity: str = Field(..., description="The entity to monitor")
brightness: int = Field(100, ge=0, le=255)
class MyApp(App[MyAppConfig]):
async def on_initialize(self):
entity = self.app_config.entity
brightness = self.app_config.brightness
Benefits of Typed Configuration
- Validation at startup — missing required fields raise a clear error before your app runs, not at runtime when a handler fires
- IDE autocomplete —
self.app_config.entitygets type hints and autocomplete in any IDE with type-checking support - Default values — use
Field(default_value)to declare defaults; Hassette applies them if the toml omits the key - Constraints — Pydantic validators like
ge=0, le=255catch invalid values before your app starts
See Also
- App Configuration — full reference for defining
AppConfigmodels - Configuration Overview —
hassette.tomlstructure - Global Settings — all global Hassette settings
- Applications — app registration and toml syntax