Skip to content

Commit a98f979

Browse files
committed
editing
1 parent 4125938 commit a98f979

File tree

1 file changed

+59
-58
lines changed

1 file changed

+59
-58
lines changed

docs/APPGUIDE.rst

Lines changed: 59 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -466,81 +466,46 @@ In the App, the app_users can be accessed like every other argument the App can
466466
App 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-
534497
Apps in AppDaemon can import from other python files in the apps directory, and it's a common pattern to have a single
535498
file 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

632633
The 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,
636637
or 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

639640
To add a priority to an app, simply add a ``priority`` entry to its configuration. e.g.:
640641

0 commit comments

Comments
 (0)