@@ -466,81 +466,46 @@ In the App, the app_users can be accessed like every other argument the App can
466466App Dependencies
467467----------------
468468
469- AppDaemon is designed for low coupling between apps, which means that apps can interact without any explicit references
470- to each other. For example, an app can register a service which can be called by another app. The calling app only needs
471- to know the service name ``<domain>/<service> `` to be able to use :py:meth: `~appdaemon.adapi.ADAPI.call_service ` to
472- call the service. It doesn't need to reference or know anything about the app that provides the service. See
469+ Apps can interact without any explicit references to each other by using because the calling app only needs
470+ to know the service name ``<domain>/<service> `` to be able to use :py:meth: `~appdaemon.adapi.ADAPI.call_service `. It
471+ doesn't need to reference or know anything about the app that provides the service. See
473472`service registration <#service-registration >`__ for more details on how to register services.
474473
475- Low coupling is generally desirable, but sometimes in development it's useful to intentionally create a dependency so
476- that apps get reloaded together as files change. This can be done with the ``dependencies `` direction in the app
477- configuration.
474+ Sometimes in development it's useful to intentionally create a dependency so that apps get reloaded together as files
475+ change. This can be done with the ``dependencies `` direction in the app configuration.
478476
479477.. code-block :: yaml
480478 :emphasize-lines : 9
481479
482480 # conf/apps/apps.yaml
483- Provider :
481+ my_provider :
484482 module : provider
485483 class : Provider
486484
487- Consumer :
485+ my_consumer :
488486 module : consumer
489487 class : Consumer
490488 dependencies :
491- - Provider
489+ - my_provider
492490
493- In this example, both apps would get reloaded if anything in ``provider.py `` changes, and the ``Consumer `` app is
494- guaranteed to be loaded after the ``Provider `` app. This guarantees that the services registered by the ``Provider `` app
495- will be available by the time the ``Consumer `` app tries to use them.
491+ In this example, both apps would get reloaded if anything in `provider.py ` changes, and the ``my_provider `` app is
492+ guaranteed to be loaded after the ``my_provider `` app.
496493
497- As of AppDaemon v4.5, apps that import other modules or packages from somewhere in the ``conf/apps `` directory will have
498- dependencies created for them automatically.
499-
500- For example, an App ``Consumer ``, uses another App ``Sound `` to play
501- sound files. ``Sound `` in turn uses ``Global `` to store some global
502- values. We can represent these dependencies as follows:
503-
504- .. code :: yaml
505-
506- Global :
507- module : global
508- class : Global
509-
510- Sound :
511- module : sound
512- class : Sound
513- dependencies : Global
514-
515- Consumer :
516- module : sound
517- class : Sound
518- dependencies : Sound
519-
520- AppDaemon will write errors to the log if a dependency is missing and it
521- will also detect circular dependencies.
522-
523- Dependencies can also be set using the ``register_dependency() `` api call.
524-
525- Globals
494+ Imports
526495~~~~~~~
527496
528- .. admonition :: Global Modules
529- :class: warning
530-
531- Global modules are deprecated and will be removed in a future release. AppDaemon now automatically tracks and
532- resolves dependencies by parsing files using the :py:mod: `ast <ast> ` package from the standard library.
533-
534497Apps in AppDaemon can import from other python files in the apps directory, and it's a common pattern to have a single
535498file containing global data that gets imported by multiple other apps.
536499
500+ This shows a complete example of defining some things in a single file `globals.py ` that are used by both apps defined
501+ in `app_a.py ` and `app_b.py `.
502+
537503.. code-block :: text
538504 :caption: Example App Directory Structure with Globals
539505
540506 conf/apps
541507 ├── apps.yaml
542508 ├── globals.py
543- ├── hello.py
544509 └── my_apps
545510 ├── app_a.py
546511 └── app_b.py
@@ -580,7 +545,6 @@ file containing global data that gets imported by multiple other apps.
580545
581546 # conf/apps/app_a.py
582547 from appdaemon.adapi import ADAPI
583-
584548 from globals import GLOBAL_MODE , GLOBAL_VAR
585549
586550
@@ -589,11 +553,12 @@ file containing global data that gets imported by multiple other apps.
589553 self .log(GLOBAL_VAR )
590554 self .log(f ' Global mode is set to: { GLOBAL_MODE .value} ' )
591555
556+ def terminate (self ) -> None : ...
557+
592558 .. code-block :: python
593559
594560 # conf/apps/app_b.py
595561 from appdaemon.adapi import ADAPI
596-
597562 from globals import GLOBAL_MODE , GLOBAL_VAR
598563
599564
@@ -602,9 +567,14 @@ file containing global data that gets imported by multiple other apps.
602567 self .log(GLOBAL_VAR )
603568 self .log(f ' Global mode is set to: { GLOBAL_MODE .value} ' )
604569
605- In this example, AppDaemon understands that both `app_a.py ` and `app_b.py ` depend on `globals.py `, so any changes to
606- `globals.py ` will effectively trigger a reload of both ``AppA `` and ``AppB ``. Just for the example, ``AppA `` was given
607- a dependency on ``AppB ``, which will cause it to always stopped before ``AppB `` and always started after ``AppB ``.
570+ def terminate (self ) -> None : ...
571+
572+ AppDaemon understands that both `app_a.py ` and `app_b.py ` depend on `globals.py ` because of the import statement, so any
573+ changes to `globals.py ` will effectively trigger a reload of both ``AppA `` and ``AppB ``. Just for the example, ``AppA ``
574+ was given a dependency on ``AppB ``, which will cause it to always stopped before ``AppB `` and always started after
575+ ``AppB ``.
576+
577+ For example, if ``GLOBAL_MODE `` is set to ``ModeSelect.MODE_C `` in `globals.py `, the log output would look like this:
608578
609579.. code-block :: log
610580
@@ -626,15 +596,46 @@ a dependency on ``AppB``, which will cause it to always stopped before ``AppB``
626596 INFO AppA: Hello, World!
627597 INFO AppA: Global mode is set to: mode_c
628598
599+ Globals
600+ ~~~~~~~
601+
602+ .. admonition :: Global Modules
603+ :class: warning
604+
605+ Global modules are deprecated and will be removed in a future release. AppDaemon now automatically tracks and
606+ resolves dependencies by parsing files using the :py:mod: `ast <ast> ` package from the standard library.
607+
608+ This is a legacy feature, but apps still have the ability to access a variable that's shared globally across all apps in
609+ their ``self.global_vars `` attribute. Accessing this variable is wrapped with a the global lock, so it is safe to read
610+ and write between threads, although it's advised to lock entire methods with the ``global_lock `` decorator.
611+
612+ In this example, the ``global_vars `` would remain locked throughout the duration of the ``do_something `` method.
613+
614+ .. code-block :: python
615+
616+ # conf/apps/simple.py
617+ from appdaemon import adbase as ad
618+ from appdaemon.adapi import ADAPI
619+
620+ class SimpleApp (ADAPI ):
621+ def initialize (self ) -> None :
622+ self .do_something()
623+
624+ @ad.global_lock
625+ def do_something (self ):
626+ vars = self .global_vars
627+ ... # do some operations
628+ self .global_vars = vars
629+
629630 App Priorities
630631~~~~~~~~~~~~~~
631632
632633The priority system is complementary to the dependency system, but they are trying to solve different problems.
633- Dependencies should be used when an App literally depends upon another, for instance, it is using variables stored in it
634- with the ``get_app() `` call. Priorities should be used when an App does some setup for other apps but doesn't provide
635- variables or code for the dependent App . An example of this might be an App that sets up some sensors in Home Assistant,
634+ Dependencies should be used when an app literally depends upon another, for instance, it is using variables stored in it
635+ with the ``get_app() `` call. Priorities should be used when an app does some setup for other apps but doesn't provide
636+ variables or code for the dependent app . An example of this might be an app that sets up some sensors in Home Assistant,
636637or sets some switch or input_slider to a specific value. It may be necessary for that setup to be performed before other
637- apps are started, but there is no requirement to reload those apps if the first App changes.
638+ apps are started, but there is no requirement to reload those apps if the first app changes.
638639
639640To add a priority to an app, simply add a ``priority `` entry to its configuration. e.g.:
640641
0 commit comments