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(*args, **kwargs)
Top-level container for the subsystem objects. This gets passed to the subsystem objects and stored in them as the
self.ADattribute.Asyncio:
Subsystems:
Attribute
Object
app_managementcallbackseventsfutureshttppluginsPluginsschedulerSchedulerservicessequencesstatethreadingThreadingutility- property app_dir
Defined in the main YAML config under
appdaemon.app_dir. Defaults to./apps
- property apps
Flag for whether
disable_appswas set in the AppDaemon config
- property config_dir
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_workerskey. Defaults to 10.
- loop: BaseEventLoop
Main asyncio event loop
- register_http(http: HTTP)
Sets the
self.httpattribute with aHTTPobject and starts the admin loop.
- stop()
Called by the signal handler to shut AD down.
Also stops
SchedulerPlugins
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.AppManagement(ad: AppDaemon)
Subsystem container for managing app lifecycles
- add_plugin_object(name: str, object: PluginBase, use_dictionary_unpacking: bool = False) None
Add the plugin object to the internal dictionary of
ManagedObjects
- property app_config: AllAppConfig
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_config_files(update_actions: UpdateActions)
Updates self.mtimes_config and self.app_config
- async check_app_python_files(update_actions: UpdateActions)
Checks the python files in the app directory. Part of self.check_app_updates sequence
- async check_app_updates(plugin_ns: 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_ns (str, optional) – Namespace of a plugin to restart, if necessary. Defaults to None.
mode (UpdateMode, optional) – Defaults to UpdateMode.NORMAL.
- property config_filecheck: FileCheck
Property that aliases the
FileCheckinstance for the app config files
- async create_app(app: str = None, **kwargs)
Used to create an app, which is written to a config file
- async create_app_object(app_name: str) None
Instantiates an app by name and stores it in
self.objects.This does not work on global module apps.
- Parameters:
app_name (str) – Name of the app, as defined in a config file
- Raises:
PinOutofRange – Caused by passing in an invalid value for pin_thread
MissingAppClass – When there’s a problem getting the class definition from the loaded module
AppClassSignatureError – When the class has the wrong number of inputs on its __init__ method
AppInstantiationError – When there’s another, unknown error creating the class from its definition
- async edit_app(app: str, **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.
- async get_app_config_files() Iterable[Path]
Iterates through config files in the config directory. Excludes directory names defined in exclude_dirs and files with a “.” character. Also excludes files that aren’t readable.
- async get_python_files() Iterable[Path]
Iterates through
*.pyin the app directory. Excludes directory names defined in exclude_dirs and with a “.” character. Also excludes files that aren’t readable.
- async import_module(module_name: str) int
Reads an app into memory by importing or reloading the module it needs
- async increase_active_apps(name: str)
Marks an app as active and updates the sensors for active/inactive apps.
- async increase_inactive_apps(name: str)
Marks an app as inactive and updates the sensors for active/inactive apps.
- objects: dict[str, ManagedObject]
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_objectself.init_sequence_object
- property python_filecheck: FileCheck
Property that aliases the
FileCheckinstance for the app python files
- async read_config_file(file: Path) AllAppConfig
Reads a single YAML or TOML file into a pydantic model. This also sets the
config_pathattribute of any AppConfigs.This function is primarily used by the create/edit/remove app methods that write yaml files.
- reversed_graph: dict[str, set[str]] = {}
Dictionary that maps full module names to sets of those that depend on them
- async start_app(app_name: str)
Initializes a new object and runs the initialize function of the app.
This does not work on global module apps because they only exist as imported modules.
- Parameters:
app (str) – Name of the app to start
callbacks
dashboard
events
- class appdaemon.events.Events(ad: AppDaemon)
Subsystem container for handling all events
- async add_event_callback(name: str, namespace: str, cb: Callable, event: str | Iterable[str], timeout: int, oneshot: bool, pin: bool, pin_thread: int, **kwargs) str | list[str]
Adds a callback for an event which is called internally by apps.
- Parameters:
- Returns:
Noneor 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: 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
Trueif the app has a log callback,Falseotherwise.Used to prevent callback loops. In the calling logic, if this function returns
Truethe 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
ValueErrorif 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, 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.Filterthat 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(*args, **kwargs)
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, callback: Callable, level: str | int, pin: bool | None = None, pin_thread: int | None = None, **kwargs) list[str] | None
Adds a callback for log which is called internally by apps.
- Parameters:
- Returns:
Noneor a list of the callback handles, 1 for each logging level above the one given
- get_child(name: str) Logger
Creates a logger with the name
AppDaemon.<name>. Automatically adds aDuplicateFilterwith 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: int)
Function to handle signals.
- 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
- main()
Initial AppDaemon entry point.
Parse command line arguments, load configuration, set up logging.
- run(ad_config_model: AppDaemonConfig, *args, http)
Start AppDaemon up after initial argument parsing.
- Parameters:
ad_config_model – Config for AppDaemon Object.
*args – Gets used to create the HTTP object.
http – Main HTTP config
- stop()
Called by the signal handler to shut AD down.
- Returns:
None.
- exception appdaemon.__main__.NoADConfig
- appdaemon.__main__.main()
Called when run from the command line.
plugins
- class appdaemon.plugin_management.PluginBase(ad: AppDaemon, name: str, config: PluginConfig)
Base class for plugins to set up _logging
- property all_namespaces: list[str]
A list of namespaces that includes the main namespace as well as any extra ones.
- first_time: bool = True
Flag for this being the first time the plugin has made a connection.
The first connection a plugin makes is handled a little differently because it’ll be at startup and it’ll be before any apps have been loaded.
- class appdaemon.plugin_management.PluginManagement(ad: AppDaemon, config: dict[str, PluginConfig])
Subsystem container for managing plugins
- config: dict[str, PluginConfig]
Config as defined in the appdaemon.plugins section of appdaemon.yaml
- get_plugin_from_namespace(namespace: str) str
Gets the name of the plugin that’s associated with the given namespace.
This function is needed because plugins can have multiple namespaces associated with them.
- plugin_meta: Dict[str, dict[str, Any]]
Dictionary storing the metadata for the loaded plugins. {<namespace>: <metadata dict>}
- plugin_objs: Dict[str, PluginBase]
Dictionary storing the instantiated plugin objects. {<namespace>: { “object”: <PluginBase>, “active”: <bool>, “name”: <str> }}
- process_meta(meta: dict, name: str)
Looks for certain keys in the metadata dict to override ones in the original AD config. For example, latitude and longitude from a Hass plugin
scheduler
services
- class appdaemon.services.DomainServices(_services: dict[str, appdaemon.services.ServiceDefinition])
- class appdaemon.services.NamespaceServices(_services: dict[str, appdaemon.services.DomainServices])
- class appdaemon.services.ServiceCollection(_services: dict[str, appdaemon.services.NamespaceServices])
- class appdaemon.services.ServiceDefinition(_ServiceDefinition__name: str | None = None, callback: str | None = None)
sequences
state
- class appdaemon.state.State(ad: AppDaemon)
Subsystem container for tracking states
- async add_entity(namespace: str, entity: str, state: str | dict, attributes: dict | None = None)
Adds an entity to the internal state registry and fires the
__AD_ENTITY_ADDEDevent
- async add_namespace(namespace: str, writeback: str, persist: bool, name: str = None) bool | Path
Used to Add Namespaces from Apps
- async add_persistent_namespace(namespace: str, writeback: str) Path
Used to add a database file for a created namespace.
Needs to be an async method to make sure it gets run from the event loop in the main thread. Otherwise, the DbfilenameShelf can get messed up because it’s not thread-safe. In some systems, it’ll complain about being accessed from multiple threads.
- async remove_entity(namespace: str, entity: str) None
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
Fires the
__AD_ENTITY_REMOVEDevent in a new task
- async remove_namespace(namespace: str) dict[str, Any] | None
Used to Remove Namespaces from Apps
Fires an
__AD_NAMESPACE_REMOVEDevent in theadminnamespace if it’s actually removed.
- async remove_persistent_namespace(namespace: str) Path
Used to remove the file for a created namespace
- async set_state(name: str, namespace: str, entity: str, _silent: bool, state: Any, attributes: dict, replace: bool, **kwargs) None
Sets the internal state of an entity. Uses relevant plugin objects based on namespace.
Fires the
state_changedevent under the namespace- Parameters:
name – Only used for a log message
namespace
entity
__silent
state
attributes
replace
stream
thread_async
threading
- class appdaemon.threads.Threading(ad: AppDaemon)
Subsystem container for managing
Threadobjects- async calculate_pin_threads()
Assigns thread numbers to apps that are supposed to be pinned
- async check_constraint(key, value, app: ADBase)
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
AdminLoopsensor.callbacks_average_firedsensor.callbacks_average_executed
- async get_q_update()
Updates queue sizes
- log_lock: allocate_lock
Threadsafe lock that helps prevent blocks of log output from different threads being mixed together
- property pin_apps
Whether each app should be pinned to a thread
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 get_uptime() timedelta
Utility function to return the uptime of AppDaemon
- Returns:
The uptime of AppDaemon
- Return type:
- 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.PersistentDict(filename, safe: bool, *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
- appdaemon.utils.clean_kwargs(**kwargs)
Converts to datetimes when necessary and filters None values
- appdaemon.utils.deep_compare(check: dict, data: dict) bool
Compares 2 nested dictionaries of values
- appdaemon.utils.executor_decorator(func)
Use this decorator on synchronous class methods to have them run in the AD executor asynchronously
- appdaemon.utils.get_object_size(obj, seen=None)
Recursively finds size of objects
- appdaemon.utils.has_expanded_kwargs(func)
Determines whether or not to use keyword argument expansion on this function by finding if there’s a
**kwargsexpansion somewhere.Handles unwrapping (removing decorators) if necessary.
- appdaemon.utils.make_endpoint(base: str, endpoint: str) str
Formats a URL appropriately with slashes
- appdaemon.utils.read_config_file(file: Path, app_config: bool = False) dict[str, dict | list]
Reads a single YAML or TOML file.
This includes all the mechanics for including secrets and environment variables.
- Parameters:
app_config – Flag for whether to add the config_path key to the loaded dictionaries
- appdaemon.utils.run_coroutine_threadsafe(self: ADBase, coro: Coroutine, timeout: float | None = None) Any
This runs an instantiated coroutine (async) from sync code. This handles the logic for cancelling coroutines that run too long.
- Parameters:
self (ADBase) – Needs to have a
self.ADattribute with theAppDaemonobject.coro (Coroutine) – An instantiated coroutine that hasn’t been awaited.
timeout (float | None, optional) – Optional timeout. Defaults to None, which will block indefinitely
- Returns:
Result from the coroutine
- async appdaemon.utils.run_in_executor(self, fn, *args, **kwargs) Any
Runs the function with the given arguments in the instance of
ThreadPoolExecutorin the top-levelAppDaemonobject.- Parameters:
self – Needs to have an
ADattribute with theAppDaemonobjectfn (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
- appdaemon.utils.warning_decorator(start_text: str | None = None, success_text: str | None = None, error_text: str | None = None, finally_text: str | None = None, reraise: bool = False)
Creates a decorator for a function that logs custom text before and after, depending on whether it succeeds.
By default this does not reraise any exceptions that occur during the execution of the wrapped function.
- Only works on methods of AppDaemon subsystems because it uses the attributes:
self.logger
self.AD