Internal Documentation

These notes are intended to assist anyone that wants to understand AppDaemon’s internals better. Most modules are used from within the AppDaemon object, which is a centralized depository of configuration information and references to the other objects and subsystems within AppDaemon.

appdaemon object

class appdaemon.appdaemon.AppDaemon(logging, loop, **kwargs)

Top-level container for the subsystem objects. This gets passed to the subsystem objects and stored in them as the self.AD attribute.

Subsystems:

Attribute

Object

services

Services

sequences

Sequences

state

State

events

Events

callbacks

Callbacks

futures

Futures

app_management

AppManagement

threading

Threading

executor

ThreadPoolExecutor

plugins

Plugins

utility

Utility

admin

admin_loop

app_management

class appdaemon.app_management.AppActions(init: ~typing.Dict[str, int] = <factory>, term: ~typing.Dict[str, int] = <factory>, total: int = 0, active: int = 0)

Stores which apps to initialize and terminate, as well as the total number of apps and the number of active apps.

init

Dictionary of apps to initialize, which ultimately happens in AppManagement._load_apps() as part of AppManagement.check_app_updates()

Type:

Dict[str, int]

term

Dictionary of apps to terminate, which ultimately happens in AppManagement._terminate_apps() as part of AppManagement.check_app_updates()

Type:

Dict[str, int]

total

Total number of apps

Type:

int

active

Number of active apps

Type:

int

class appdaemon.app_management.AppManagement(ad: AppDaemon, use_toml: bool)

Subsystem container for managing app lifecycles

monitored_files

Dictionary of the Python files that are being watched for changes and their last modified times

Type:

Dict[str | pathlib.Path, float]

filter_files

Dictionary of the modified times of the filter files and their paths.

Type:

Dict[str, float]

modules

Dictionary of the loaded modules and their names

Type:

Dict[str, module]

objects

Dictionary of dictionaries with the instantiated apps, plugins, and sequences along with some metadata

Type:

Dict[str, Dict]

apps_per_module(module_name: str)

Finds which apps came from a given module name

async check_app_updates(plugin: str = None, mode: UpdateMode = UpdateMode.NORMAL)

Checks the states of the Python files that define the apps, reloading when necessary.

Called as part of utility_loop.Utility.loop()

Parameters:
  • plugin (str, optional) – Plugin to restart, if necessary. Defaults to None.

  • mode (UpdateMode, optional) – Defaults to UpdateMode.NORMAL.

Check Process:
  • Refresh modified times of monitored files.

  • Checks for deleted files

  • Marks the apps for reloading or removal as necessary

  • Restarts the plugin, if specified

  • Terminates apps as necessary

  • Loads or reloads modules/pacakges as necessary

  • Loads apps from the modules/packages

create_app(app=None, **kwargs)

Used to create an app, which is written to a config file

edit_app(app, **kwargs)

Used to edit an app, which is already in Yaml. It is expecting the app’s name

get_app_deps_and_prios(applist: Iterable[str], mode: UpdateMode) Dict[str, float]

Gets the dependencies and priorities for the given apps

Parameters:
  • applist (Iterable[str]) – Iterable of app names

  • mode (UpdateMode) – UpdateMode

Returns:

_description_

Return type:

_type_

get_app_file(app)

Used to get the file an app is located

get_app_from_file(file)

Finds the apps that depend on a given file

get_file_from_module(module_name: str) Path | None

Gets the module __file__ based on the module name.

Parameters:

mod (str) – Module name

Returns:

Path of the __file__

Return type:

Optional[Path]

get_path_from_app(app_name: str) Path

Gets the module path based on the app_name

Used in self._terminate_apps

init_sequence_object(name, object)

Initialize the sequence

read_app(reload_cfg: ModuleLoad)

Reads an app into memory by importing or reloading the module it needs

remove_app(app, **kwargs)

Used to remove an app

Seems to be unreferenced?

async terminate_sequence(name: str) bool

Terminate the sequence

class appdaemon.app_management.ModuleLoad(path: Path, reload: bool = False)

Dataclass containing settings for calls to AppManagement.read_app()

path

Filepath of the module or path to the __init__.py of a package.

Type:

pathlib.Path

reload

Whether to reload the app using importlib.reload

Type:

bool

name

Importable name of the module/package

Type:

str

class appdaemon.app_management.UpdateMode(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)

Used as an argument for AppManagement.check_app_updates() to set the mode of the check.

INIT

Triggers AppManagement._init_update_mode to run during check_app_updates

NORMAL

Normal update mode, for when AppManagement.check_app_updates() is called by utility_loop.Utility.loop()

TERMINATE

Terminate all apps

callbacks

class appdaemon.callbacks.Callbacks(ad: AppDaemon)

Subsystem container for events

AD

Reference to the AppDaemon container object

dashboard

events

class appdaemon.events.Events(ad: AppDaemon)

Subsystem container for handling all events

AD

Reference to the AppDaemon container object

Type:

appdaemon.appdaemon.AppDaemon

async add_event_callback(name, namespace, cb, event, **kwargs)

Adds a callback for an event which is called internally by apps.

Parameters:
  • name (str) – Name of the app.

  • namespace (str) – Namespace of the event.

  • cb – Callback function.

  • event (str) – Name of the event.

  • **kwargs – List of values to filter on, and additional arguments to pass to the callback.

Returns:

None or the reference to the callback handle.

async cancel_event_callback(name, handle)

Cancels an event callback.

Parameters:
  • name (str) – Name of the app or module.

  • handle – Previously supplied callback handle for the callback.

Returns:

None.

async fire_event(namespace, event, **kwargs)

Fires an event.

If the namespace does not have a plugin associated with it, the event will be fired locally. If a plugin is associated, the firing of the event will be delegated to the plugin, under the understanding that when the event is fired, the plugin will notify appdaemon that it occurred, usually via the system the plugin is communicating with.

Parameters:
  • namespace (str) – Namespace for the event to be fired in.

  • event (str) – Name of the event.

  • **kwargs – Arguments to associate with the event.

Returns:

None.

async has_log_callback(name)

Returns True if the app has a log callback, False otherwise.

Used to prevent callback loops. In the calling logic, if this function returns True the resulting logging event will be suppressed.

Parameters:

name (str) – Name of the app.

async info_event_callback(name, handle)

Gets the information of an event callback.

Parameters:
  • name (str) – Name of the app or subsystem.

  • handle – Previously supplied handle for the callback.

Returns:

A dictionary of callback entries or rise a ValueError if an invalid handle is provided.

async process_event(namespace, data)

Processes an event that has been received either locally or from a plugin.

Parameters:
  • namespace (str) – Namespace the event was fired in.

  • data – Data associated with the event.

Returns:

None.

async process_event_callbacks(namespace, data)

Processes a pure event callback.

Locate any callbacks that may be registered for this event, check for filters and if appropriate, dispatch the event for further checking and eventual action.

Parameters:
  • namespace (str) – Namespace of the event.

  • data – Data associated with the event.

Returns:

None.

logging

class appdaemon.logging.AppNameFormatter(fmt=None, datefmt=None, style=None)

Logger formatter to add ‘appname’ as an interpolatable field.

format(record)

Format the specified record as text.

The record’s attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message.

class appdaemon.logging.DuplicateFilter(logger, threshold, delay, timeout)
filter(record)

Determine if the specified record is to be logged.

Returns True if the record should be logged, or False otherwise. If deemed appropriate, the record may be modified in-place.

class appdaemon.logging.LogSubscriptionHandler(ad: AppDaemon, type)

Handle apps that subscribe to logs.

This Handler requires that it’s formatter is an instance of AppNameFormatter.

emit(record)

Emit a record.

If a formatter is specified, it is used to format the record. The record is then written to the stream with a trailing newline. If exception information is present, it is formatted using traceback.print_exception and appended to the stream. If the stream has an ‘encoding’ attribute, it is used to determine how to do the output to the stream.

AppDaemon main() module.

AppDaemon module that contains main() along with argument parsing, instantiation of the AppDaemon and HTTP Objects, also creates the loop and kicks everything off

class appdaemon.__main__.ADMain

Class to encapsulate all main() functionality.

handle_sig(signum, frame)

Function to handle signals.

SIGUSR1 will result in internal info being dumped to the DIAG log SIGHUP will force a reload of all apps SIGINT and SIGTEM both result in AD shutting down

Parameters:
  • signum – Signal number being processed.

  • frame – frame - unused

Returns:

None.

init_signals()

Setup signal handling.

main()

Initial AppDaemon entry point.

Parse command line arguments, load configuration, set up logging.

run(appdaemon, hadashboard, admin, aui, api, http)

Start AppDaemon up after initial argument parsing.

Parameters:
  • appdaemon – Config for AppDaemon Object.

  • hadashboard – Config for HADashboard Object.

  • admin – Config for admin Object.

  • aui – Config for aui Object.

  • api – Config for API Object

  • http – Config for HTTP Object

Returns:

None.

stop()

Called by the signal handler to shut AD down.

Returns:

None.

appdaemon.__main__.main()

Called when run from the command line.

main

class appdaemon.plugin_management.PluginBase(ad: AppDaemon, name, args)

Base class for plugins to set up _logging

class appdaemon.plugin_management.Plugins(ad: AppDaemon, kwargs)

Subsystem container for managing plugins

AD

Reference to the AppDaemon container object

Type:

appdaemon.appdaemon.AppDaemon

plugin_meta

Dictionary storing the metadata for the loaded plugins

Type:

dict[str, dict]

plugin_objs

Dictionary storing the instantiated plugin objects

scheduler

services

class appdaemon.services.Services(ad: AppDaemon)

Subsystem container for handling services

AD

Reference to the AppDaemon container object

Type:

appdaemon.appdaemon.AppDaemon

clear_services(name: str) None

Used to clear services

deregister_service(namespace: str, domain: str, service: str, **kwargs: dict) bool

Used to unregister a service

async run_service(coro: Awaitable) Any

Used to process a service call

sequences

class appdaemon.sequences.Sequences(ad: AppDaemon)

Subsystem container for managing sequences

AD

Reference to the AppDaemon container object

Type:

appdaemon.appdaemon.AppDaemon

async loop_step(namespace: str, command: str, parameters: dict, loop_step: dict) None

Used to loop a step command

state

class appdaemon.state.State(ad: AppDaemon)

Subsystem container for tracking states

AD

Reference to the AppDaemon container object

async add_namespace(namespace, writeback, persist, name=None)

Used to Add Namespaces from Apps

add_persistent_namespace(namespace, writeback)

Used to add a database file for a created namespace

async remove_entity(namespace, entity)

Removes an entity.

If the namespace does not have a plugin associated with it, the entity will be removed locally only. If a plugin is associated, the entity will be removed via the plugin and locally.

Parameters:
  • namespace (str) – Namespace for the event to be fired in.

  • entity (str) – Name of the entity.

Returns:

None.

async remove_entity_simple(namespace: str, entity_id: str) None

Used to remove an internal AD entity

async remove_namespace(namespace)

Used to Remove Namespaces from Apps

remove_persistent_namespace(namespace)

Used to remove the file for a created namespace

stream

thread_async

class appdaemon.thread_async.ThreadAsync(ad: AppDaemon)

Module to translate from the thread world to the async world via queues

threading

utility_loop

Module to handle utility functions within AppDaemon.

class appdaemon.utility_loop.Utility(ad: AppDaemon)

Subsystem container for managing the utility loop

Checks for file changes, overdue threads, thread starvation, and schedules regular state refreshes.

async loop()

The main utility loop.

Loops until stop() is called, checks for file changes, overdue threads, thread starvation, and schedules regular state refreshes.

stop()

Called by the AppDaemon object to terminate the loop cleanly

Returns:

None

utils

class appdaemon.utils.AttrDict(*args, **kwargs)

Dictionary subclass whose entries can be accessed by attributes (as well as normally).

static from_nested_dict(data)

Construct nested AttrDicts from nested dictionaries.

class appdaemon.utils.EntityStateAttrs(dict)
class appdaemon.utils.PersistentDict(filename, safe, *args, **kwargs)

Dict-like object that uses a Shelf to persist its contents.

update([E, ]**F) None.  Update D from mapping/iterable E and F.

If E present and has a .keys() method, does: for k in E: D[k] = E[k] If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v

class appdaemon.utils.StateAttrs(dict)
appdaemon.utils.get_object_size(obj, seen=None)

Recursively finds size of objects

appdaemon.utils.recursive_reload(module: module, reloaded: set = None)

Recursive reload function that does a depth-first search through all sub-modules and reloads them in the correct order of dependence.

Adapted from https://gist.github.com/KristianHolsheimer/f139646259056c1dffbf79169f84c5de