Skip to content

Commit 33b2600

Browse files
committed
Merge branch 'threading'
1 parent f0f7974 commit 33b2600

28 files changed

+1196
-936
lines changed

appdaemon/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
from . import models as cfg
12
from .adapi import ADAPI
23
from .appdaemon import AppDaemon
34
from .plugins.hass.hassapi import Hass
45
from .plugins.mqtt.mqttapi import Mqtt
5-
from . import models as cfg
66

77
__all__ = ["ADAPI", "AppDaemon", "Hass", "Mqtt", "cfg"]

appdaemon/__main__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@
2323
from pathlib import Path
2424
from time import perf_counter
2525

26-
2726
import appdaemon.appdaemon as ad
28-
from .dependency_manager import DependencyManager
2927
import appdaemon.utils as utils
3028
from appdaemon import exceptions as ade
3129
from appdaemon.app_management import UpdateMode
@@ -34,7 +32,9 @@
3432
from appdaemon.http import HTTP
3533
from appdaemon.logging import Logging
3634

35+
from .dependency_manager import DependencyManager
3736
from .models.config.yaml import MainConfig
37+
from .version import __version__, __version_comments__
3838

3939
logger = logging.getLogger(__name__)
4040
err_logger = logging.getLogger("bare")
@@ -137,7 +137,7 @@ def parse_arguments() -> argparse.Namespace:
137137
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
138138
)
139139
parser.add_argument("-m", "--moduledebug", nargs=2, action="append")
140-
parser.add_argument("-v", "--version", action="version", version="%(prog)s " + utils.__version__)
140+
parser.add_argument("-v", "--version", action="version", version="%(prog)s " + __version__)
141141
parser.add_argument("--profiledash", help=argparse.SUPPRESS, action="store_true")
142142
parser.add_argument("--write_toml", help="use TOML for creating new app configuration files", action="store_true")
143143
# TODO Implement --write_toml
@@ -355,7 +355,7 @@ def handle_sig(self, signum: int):
355355
case signal.SIGUSR1:
356356
self.AD.thread_async.call_async_no_wait(self.AD.sched.dump_schedule)
357357
self.AD.thread_async.call_async_no_wait(self.AD.callbacks.dump_callbacks)
358-
self.AD.thread_async.call_async_no_wait(self.AD.threading.dump_threads)
358+
self.AD.loop.call_soon_threadsafe(self.AD.threading.dump_threads)
359359
self.AD.thread_async.call_async_no_wait(self.AD.app_management.dump_objects)
360360
self.AD.thread_async.call_async_no_wait(self.AD.sched.dump_sun)
361361
case signal.SIGHUP:
@@ -479,10 +479,10 @@ def startup_text(self):
479479
try:
480480
# Startup message
481481
self.logger.info("-" * 60)
482-
self.logger.info("AppDaemon Version %s starting", utils.__version__)
482+
self.logger.info("AppDaemon Version %s starting", __version__)
483483

484-
if utils.__version_comments__ is not None and utils.__version_comments__ != "":
485-
self.logger.info("Additional version info: %s", utils.__version_comments__)
484+
if __version_comments__ is not None and __version_comments__ != "":
485+
self.logger.info("Additional version info: %s", __version_comments__)
486486

487487
self.logger.info("-" * 60)
488488
self.logger.info("Python version is %s.%s.%s", *sys.version_info[:3])

appdaemon/adapi.py

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@
1414
from pathlib import Path
1515
from typing import TYPE_CHECKING, Any, Literal, TypeVar, overload
1616

17-
from appdaemon import dependency
17+
from appdaemon import dependency, utils
1818
from appdaemon import exceptions as ade
19-
from appdaemon import utils
2019
from appdaemon.appdaemon import AppDaemon
2120
from appdaemon.entity import Entity
2221
from appdaemon.events import EventCallback
@@ -25,6 +24,8 @@
2524
from appdaemon.parse import resolve_time_str
2625
from appdaemon.state import StateCallbackType
2726

27+
from .version import __version__
28+
2829
T = TypeVar("T")
2930

3031

@@ -777,18 +778,17 @@ def get_ad_version() -> str:
777778
>>> version = self.get_ad_version()
778779
779780
"""
780-
return utils.__version__
781+
return __version__
781782

782783
#
783784
# Entity
784785
#
785786

786-
@utils.sync_decorator
787-
async def add_entity(
787+
def add_entity(
788788
self,
789789
entity_id: str,
790790
state: Any,
791-
attributes: dict | None = None,
791+
attributes: dict[str, Any] | None = None,
792792
namespace: str | None = None,
793793
) -> None:
794794
"""Adds a non-existent entity, by creating it within a namespaces.
@@ -817,11 +817,10 @@ async def add_entity(
817817
>>> self.add_entity('mqtt.living_room_temperature', namespace='mqtt')
818818
819819
"""
820-
namespace = namespace or self.namespace
821-
return await self.AD.state.add_entity(namespace, entity_id, state, attributes)
820+
namespace = namespace if namespace is not None else self.namespace
821+
return self.AD.state.add_entity(namespace, entity_id, state, attributes)
822822

823-
@utils.sync_decorator
824-
async def entity_exists(self, entity_id: str, namespace: str | None = None) -> bool:
823+
def entity_exists(self, entity_id: str, namespace: str | None = None) -> bool:
825824
"""Checks the existence of an entity in AD.
826825
827826
When working with multiple AD namespaces, it is possible to specify the
@@ -850,7 +849,7 @@ async def entity_exists(self, entity_id: str, namespace: str | None = None) -> b
850849
>>> if self.entity_exists("mqtt.security_settings", namespace = "mqtt"):
851850
>>> #do something
852851
"""
853-
namespace = namespace or self.namespace
852+
namespace = namespace if namespace is not None else self.namespace
854853
return self.AD.state.entity_exists(namespace, entity_id)
855854

856855
@utils.sync_decorator
@@ -1724,7 +1723,7 @@ async def get_state(
17241723
if kwargs:
17251724
self.logger.warning(f"Extra kwargs passed to get_state, will be ignored: {kwargs}")
17261725

1727-
return await self.AD.state.get_state(
1726+
return self.AD.state.get_state(
17281727
name=self.name,
17291728
namespace=namespace or self.namespace,
17301729
entity_id=entity_id,
@@ -2364,14 +2363,14 @@ async def sun_up(self) -> bool:
23642363
"""Determines if the sun is currently up.
23652364
23662365
Returns:
2367-
bool: ``True`` if the sun is up, ``False`` otherwise.
2366+
bool: ``True`` if the sun is up, ``False`` otherwise.
23682367
23692368
Examples:
23702369
>>> if self.sun_up():
2371-
>>> #do something
2370+
>>> # do something
23722371
23732372
"""
2374-
return await self.AD.sched.sun_up()
2373+
return self.AD.sched.sun_up()
23752374

23762375
@utils.sync_decorator
23772376
async def sun_down(self) -> bool:
@@ -2382,10 +2381,10 @@ async def sun_down(self) -> bool:
23822381
23832382
Examples:
23842383
>>> if self.sun_down():
2385-
>>> #do something
2384+
>>> # do something
23862385
23872386
"""
2388-
return await self.AD.sched.sun_down()
2387+
return self.AD.sched.sun_down()
23892388

23902389
@utils.sync_decorator
23912390
async def parse_time(
@@ -2442,7 +2441,7 @@ async def parse_time(
24422441
05:33:17
24432442
24442443
"""
2445-
return await self.AD.sched.parse_time(
2444+
return self.AD.sched.parse_time(
24462445
time_str=time_str,
24472446
aware=aware,
24482447
today=today,
@@ -2506,7 +2505,7 @@ async def parse_datetime(
25062505
>>> self.parse_datetime("sunrise + 01:00:00")
25072506
2019-08-16 06:33:17
25082507
"""
2509-
return await self.AD.sched.parse_datetime(
2508+
return self.AD.sched.parse_datetime(
25102509
input_=time_str,
25112510
aware=aware,
25122511
today=today,
@@ -2522,8 +2521,7 @@ async def get_now(self, aware: bool = True) -> dt.datetime:
25222521
2019-08-16 21:17:41.098813-04:00
25232522
25242523
"""
2525-
now = await self.AD.sched.get_now()
2526-
return now.astimezone(self.AD.tz) if aware else self.AD.sched.make_naive(now)
2524+
return self.AD.sched.get_now_sync(_tz=None if aware else False)
25272525

25282526
@utils.sync_decorator
25292527
async def get_now_ts(self, aware: bool = False) -> float:
@@ -2578,7 +2576,7 @@ async def now_is_between(
25782576
>>> #do something
25792577
25802578
"""
2581-
return await self.AD.sched.now_is_between(start_time=start_time, end_time=end_time, now=now)
2579+
return self.AD.sched.now_is_between(start_time=start_time, end_time=end_time, now=now)
25822580

25832581
@utils.sync_decorator
25842582
async def sunrise(self, aware: bool = False, today: bool = False, days_offset: int = 0) -> dt.datetime:
@@ -2600,7 +2598,7 @@ async def sunrise(self, aware: bool = False, today: bool = False, days_offset: i
26002598
2023-02-01 07:12:20.272403
26012599
26022600
"""
2603-
return await self.AD.sched.sunrise(aware, today, days_offset)
2601+
return self.AD.sched.sunrise(aware, today, days_offset)
26042602

26052603
@utils.sync_decorator
26062604
async def sunset(self, aware: bool = False, today: bool = False, days_offset: int = 0) -> dt.datetime:
@@ -2622,7 +2620,7 @@ async def sunset(self, aware: bool = False, today: bool = False, days_offset: in
26222620
2023-02-02 18:09:46.252314
26232621
26242622
"""
2625-
return await self.AD.sched.sunset(aware, today, days_offset)
2623+
return self.AD.sched.sunset(aware, today, days_offset)
26262624

26272625
@utils.sync_decorator
26282626
async def datetime(self, aware: bool = False) -> dt.datetime:
@@ -2639,7 +2637,7 @@ async def datetime(self, aware: bool = False) -> dt.datetime:
26392637
2019-08-15 20:15:55.549379
26402638
26412639
"""
2642-
return await self.get_now(aware=aware)
2640+
return self.get_now(aware=aware)
26432641

26442642
@utils.sync_decorator
26452643
async def time(self) -> dt.time:
@@ -2653,7 +2651,7 @@ async def time(self) -> dt.time:
26532651
20:15:31.295751
26542652
26552653
"""
2656-
return (await self.get_now(aware=True)).time()
2654+
return self.get_now(aware=True).time()
26572655

26582656
@utils.sync_decorator
26592657
async def date(self) -> dt.date:
@@ -2667,11 +2665,11 @@ async def date(self) -> dt.date:
26672665
2019-08-15
26682666
26692667
"""
2670-
return (await self.get_now(aware=True)).date()
2668+
return self.get_now(aware=True).date()
26712669

2672-
def get_timezone(self) -> str:
2670+
def get_timezone(self) -> str | None:
26732671
"""Returns the current time zone."""
2674-
return self.AD.time_zone
2672+
return self.AD.time_zone.zone
26752673

26762674
#
26772675
# Scheduler
@@ -2967,7 +2965,7 @@ async def run_at(
29672965
_, offset = resolve_time_str(start_str, now=now, location=self.AD.sched.location)
29682966
func = functools.partial(func, *args, repeat=True, offset=offset)
29692967
case _:
2970-
start = await self.AD.sched.parse_datetime(start, aware=True)
2968+
start = self.AD.sched.parse_datetime(start, aware=True)
29712969
func = functools.partial(
29722970
self.AD.sched.insert_schedule,
29732971
name=self.name,
@@ -3371,7 +3369,7 @@ async def run_at_sunset(
33713369
>>> self.run_at_sunset(self.sun, random_start = -60*60, random_end = 30*60)
33723370
33733371
"""
3374-
sunset = await self.AD.sched.next_sunset()
3372+
sunset = self.AD.sched.next_sunset()
33753373
td = utils.parse_timedelta(offset)
33763374
self.logger.debug(f"Registering run_at_sunset at {sunset + td} with {args}, {kwargs}")
33773375
return await self.AD.sched.insert_schedule(
@@ -3444,7 +3442,7 @@ async def run_at_sunrise(
34443442
>>> self.run_at_sunrise(self.sun, random_start = -60*60, random_end = 30*60)
34453443
34463444
"""
3447-
sunrise = await self.AD.sched.next_sunrise()
3445+
sunrise = self.AD.sched.next_sunrise()
34483446
td = utils.parse_timedelta(offset)
34493447
self.logger.debug(f"Registering run_at_sunrise at {sunrise + td} with {args}, {kwargs}")
34503448
return await self.AD.sched.insert_schedule(

appdaemon/admin_loop.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ async def loop(self):
2929
and self.AD.sched is not None
3030
): # fmt: skip
3131
await self.AD.threading.get_callback_update()
32-
await self.AD.threading.get_q_update()
32+
await self.AD.threading.update_queue_sizes()
3333

3434
await self.AD.utility.sleep(self.AD.admin_delay, timeout_ok=True)

appdaemon/app_management.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
from pydantic import ValidationError
2323

24-
2524
from appdaemon.dependency import DependencyResolutionFail, get_full_module_name
2625
from appdaemon.dependency_manager import DependencyManager
2726
from appdaemon.models.config import AllAppConfig, AppConfig, GlobalModule
@@ -33,9 +32,9 @@
3332
from .models.internal.app_management import LoadingActions, ManagedObject, UpdateActions, UpdateMode
3433

3534
if TYPE_CHECKING:
36-
from .appdaemon import AppDaemon
37-
from .adbase import ADBase
3835
from .adapi import ADAPI
36+
from .adbase import ADBase
37+
from .appdaemon import AppDaemon
3938
from .plugin_management import PluginBase
4039

4140
T = TypeVar("T")
@@ -213,7 +212,7 @@ async def get_state(self, name: str, **kwargs):
213212
else:
214213
entity_id = name
215214

216-
return await self.AD.state.get_state("_app_management", "admin", entity_id, **kwargs)
215+
return self.AD.state.get_state("_app_management", "admin", entity_id, **kwargs)
217216

218217
async def init_admin_entities(self):
219218
for app_name, cfg in self.app_config.root.items():
@@ -237,7 +236,7 @@ async def add_entity(self, name: str, state, attributes):
237236
else:
238237
entity_id = name
239238

240-
await self.AD.state.add_entity("admin", entity_id, state, attributes)
239+
self.AD.state.add_entity("admin", entity_id, state, attributes)
241240

242241
async def remove_entity(self, name: str):
243242
await self.AD.state.remove_entity("admin", f"app.{name}")
@@ -291,12 +290,13 @@ def get_app(self, name: str):
291290
if obj := self.objects.get(name):
292291
return obj.object
293292

294-
def get_app_info(self, name: str):
293+
def get_managed_object(self, name: str) -> ManagedObject | None:
295294
return self.objects.get(name)
296295

297-
def get_app_instance(self, name: str, id):
298-
if (obj := self.objects.get(name)) and obj.id == id:
299-
return obj.object
296+
def get_app_instance(self, name: str, id: str) -> Any | None:
297+
match self.get_managed_object(name):
298+
case ManagedObject(object=obj, id=_id) if _id == id:
299+
return obj
300300

301301
def get_app_pin(self, name: str) -> bool:
302302
return self.objects[name].pin_app
@@ -1556,3 +1556,27 @@ async def manage_services(
15561556
return result
15571557
case _:
15581558
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1559+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1560+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1561+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1562+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1563+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1564+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1565+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1566+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1567+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1568+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1569+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1570+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1571+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1572+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1573+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1574+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1575+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1576+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1577+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1578+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1579+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1580+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1581+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)
1582+
self.logger.warning("Invalid app service call '%s' with app '%s' from app %s.", service, app, __name)

appdaemon/appdaemon.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from appdaemon.threads import Threading
2424
from appdaemon.utility_loop import Utility
2525

26-
2726
if TYPE_CHECKING:
2827
from appdaemon.http import HTTP
2928
from appdaemon.logging import Logging
@@ -373,11 +372,11 @@ def use_stream(self):
373372
return self.config.use_stream
374373

375374
@property
376-
def write_toml(self):
375+
def write_toml(self) -> bool:
377376
return self.config.write_toml
378377

379378
@property
380-
def utility_delay(self):
379+
def utility_delay(self) -> int:
381380
return self.config.utility_delay
382381

383382
def start(self) -> None:

0 commit comments

Comments
 (0)