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: Logging, loop: BaseEventLoop, **kwargs)
Top-level container for the subsystem objects. This gets passed to the subsystem objects and stored in them as the
self.AD
attribute.Asyncio:
Subsystems:
Attribute
Object
app_management
callbacks
events
futures
http
plugins
scheduler
Scheduler
services
sequences
state
threading
utility
- config_dir: str | Path
Path to the AppDaemon configuration files. Defaults to the first folder that has
./apps
~/.homeassistant
/etc/appdaemon
- executor: ThreadPoolExecutor
Executes functions from a pool of async threads. Configured with the
threadpool_workers
key. Defaults to 10.
- loop: BaseEventLoop
Main asyncio event loop
- register_http(http: HTTP)
Sets the
self.http
attribute with aHTTP
object and starts the admin loop.
- stop()
Called by the signal handler to shut AD down.
Also stops
Scheduler
admin
admin_loop
- class appdaemon.admin_loop.AdminLoop(ad: AppDaemon)
Called by
register_http()
. Loop timed withadmin_delay
- async loop()
Handles calling
get_callback_update()
andget_q_update()
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 ofAppManagement.check_app_updates()
- term
Dictionary of apps to terminate, which ultimately happens in
AppManagement._terminate_apps()
as part ofAppManagement.check_app_updates()
- class appdaemon.app_management.AppManagement(ad: AppDaemon, use_toml: bool)
Subsystem container for managing app lifecycles
- app_config: Dict[str, Dict[str, Dict[str, bool]]]
Keeps track of which module and class each app comes from, along with any associated global modules. Gets set at the end of
check_config()
.
- 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
- async check_config(silent: bool = False, add_threads: bool = True) AppActions | None
Wraps
read_config()
- 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
- filter_files: Dict[str, float]
Dictionary of the modified times of the filter files and their paths.
- 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
- async init_object(app_name: str)
Instantiates an app by name and stores it in
self.objects
- Parameters:
app_name (str) – Name of the app, as defined in a config file
- init_sequence_object(name, object)
Initialize the sequence
- modules: Dict[str, ModuleType]
Dictionary of the loaded modules and their names
- monitored_files: Dict[str | Path, float]
Dictionary of the Python files that are being watched for changes and their last modified times
- objects: Dict[str, Dict[str, Any]]
Dictionary of dictionaries with the instantiated apps, plugins, and sequences along with some metadata. Gets populated by
self.init_object
, which instantiates the app classesself.init_plugin_object
self.init_sequence_object
- read_app(reload_cfg: ModuleLoad)
Reads an app into memory by importing or reloading the module it needs
- async read_config() Dict[str, Dict[str, Any]]
Walks the apps directory and reads all the config files with
read_config_file()
, which reads individual config files and runs in theexecutor
.
- remove_app(app, **kwargs)
Used to remove an app
Seems to be unreferenced?
- 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:
- 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 byutility_loop.Utility.loop()
- TERMINATE
Terminate all apps
callbacks
dashboard
events
- class appdaemon.events.Events(ad: AppDaemon)
Subsystem container for handling all events
- async add_event_callback(name, namespace, cb, event, **kwargs)
Adds a callback for an event which is called internally by apps.
- 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: str, event: str, **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.
- async has_log_callback(name: str)
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: str, handle: str)
Gets the information of an event callback.
- Parameters:
- Raises:
ValueError – an invalid name or handle was provided
- Returns:
A dictionary of callback entries or rise a
ValueError
if an invalid handle is provided.
- async process_event(namespace: str, data: Dict[str, Any])
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.
futures
http
- class appdaemon.http.HTTP(ad: AppDaemon, loop, logging, appdaemon, dashboard, old_admin, admin, api, http)
Handles serving the web UI
- appdaemon.http.route_secure(myfunc)
Take care of streams and service calls
- appdaemon.http.secure(myfunc)
Take care of screen based security
- appdaemon.http.securedata(myfunc)
Take care of streams and service calls
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: Logger, threshold: float, delay: float, timeout: float)
logging.Filter
that filters duplicate messages
- 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.
- class appdaemon.logging.Logging(config: Dict | None = None, log_level: str = 'INFO')
Creates and configures the Python logging. The top-level logger is called
AppDaemon
. Child loggers are created withget_child()
.- async add_log_callback(namespace: str, name: str, cb: Callable, level, **kwargs)
Adds a callback for log which is called internally by apps.
- get_child(name: str) Logger
Creates a logger with the name
AppDaemon.<name>
. Automatically adds aDuplicateFilter
with the config options frommain_log
:filter_threshold
filter_repeat_delay
filter_timeout
- Parameters:
name (str) – Child name for the logger.
- Returns:
Child logger
- Return type:
Logger
- get_error() Logger
Gets the top-level error log
- Returns:
Python logger named
Error
- Return type:
Logger
- get_logger() Logger
Gets the top-level log
- Returns:
Python logger named
AppDaemon
- Return type:
Logger
- async process_log_callbacks(namespace, log_data)
Process Log callbacks
main
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: 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.
plugins
- class appdaemon.plugin_management.PluginBase(ad: AppDaemon, name, args)
Base class for plugins to set up _logging
scheduler
services
sequences
state
- class appdaemon.state.State(ad: AppDaemon)
Subsystem container for tracking states
- 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.
- 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
threading
- class appdaemon.threading.Threading(ad: AppDaemon, kwargs)
Subsystem container for managing
Thread
objects- async check_constraint(key, value, app)
Used to check Constraint
- async check_days_constraint(args, name)
Used to check days Constraint
- async check_state_constraint(args, new_state, name)
Used to check state Constraint
- async check_time_constraint(args, name)
Used to check time Constraint
- async get_callback_update()
Updates the sensors with information about how many callbacks have been fired. Called by the
AdminLoop
sensor.callbacks_average_fired
sensor.callbacks_average_executed
- async get_q_update()
Updates queue sizes
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: ModuleType, 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
- async appdaemon.utils.run_in_executor(self, fn, *args, **kwargs) Any
Runs the function with the given arguments in the instance of
ThreadPoolExecutor
in the top-levelAppDaemon
object.- Parameters:
self – Needs to have an
AD
attribute with theAppDaemon
objectfn (function) – Function to run in the executor
*args – Any positional arguments to use with the function
**kwargs – Any keyword arguments to use with the function
- Returns:
Whatever the function returns