Skip to content

Commit 04e2167

Browse files
committed
Merge branch 'dev'
2 parents 69434f9 + 5ad17ff commit 04e2167

File tree

6 files changed

+37
-38
lines changed

6 files changed

+37
-38
lines changed

appdaemon/__main__.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ def main(self): # noqa: C901
227227
"-D",
228228
"--debug",
229229
help="global debug level",
230-
default="INFO",
230+
# default="INFO",
231231
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
232232
)
233233
parser.add_argument("-m", "--moduledebug", nargs=2, action="append")
@@ -283,7 +283,7 @@ def main(self): # noqa: C901
283283
config = {
284284
k: v if v is not None else {}
285285
for k, v in config.items()
286-
} # fmt: skip
286+
} # fmt: skip
287287

288288
ad_kwargs = config["appdaemon"]
289289

@@ -299,7 +299,13 @@ def main(self): # noqa: C901
299299
ad_kwargs["endtime"] = args.endtime
300300

301301
ad_kwargs["stop_function"] = self.stop
302-
ad_kwargs["loglevel"] = args.debug
302+
303+
if args.debug is not None:
304+
ad_kwargs["loglevel"] = args.debug
305+
elif "loglevel" in ad_kwargs:
306+
pass
307+
else:
308+
ad_kwargs["loglevel"] = "INFO"
303309

304310
if args.moduledebug is not None:
305311
module_debug_cli = {arg[0]: arg[1] for arg in args.moduledebug}
@@ -319,9 +325,9 @@ def main(self): # noqa: C901
319325

320326
model = MainConfig.model_validate(config)
321327

322-
if args.debug.upper() == "DEBUG":
328+
if ad_kwargs["loglevel"] == "DEBUG":
323329
# need to dump as python types or serializing the timezone object will fail
324-
model_json = model.model_dump(mode='python', by_alias=True)
330+
model_json = model.model_dump(mode="python", by_alias=True)
325331
print(json.dumps(model_json, indent=4, default=str, sort_keys=True))
326332
except ValidationError as e:
327333
print(f"Configuration error in: {config_file}")
@@ -335,7 +341,7 @@ def main(self): # noqa: C901
335341
print(e)
336342
sys.exit(1)
337343

338-
log_cfg = model.model_dump(mode='python', by_alias=True)['logs']
344+
log_cfg = model.model_dump(mode="python", by_alias=True)["logs"]
339345
self.logging = Logging(log_cfg, args.debug)
340346
self.logger = self.logging.get_logger()
341347

@@ -365,7 +371,7 @@ def main(self): # noqa: C901
365371
self.logger.debug("AppDaemon Section: %s", config.get("appdaemon"))
366372
self.logger.debug("HADashboard Section: %s", config.get("hadashboard"))
367373

368-
dump_kwargs = dict(mode='json', by_alias=True, exclude_unset=True)
374+
dump_kwargs = dict(mode="json", by_alias=True, exclude_unset=True)
369375

370376
if (hadashboard := model.hadashboard) is not None:
371377
hadashboard = hadashboard.model_dump(**dump_kwargs)

appdaemon/events.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ async def info_event_callback(self, name: str, handle: str):
171171
else:
172172
raise ValueError(f"Invalid handle: {handle}")
173173

174-
async def fire_event(self, namespace: str, event: str, **kwargs):
174+
async def fire_event(self, namespace: str, event: str, **kwargs: Any) -> dict[str, Any] | None:
175175
"""Fires an event.
176176
177177
If the namespace does not have a plugin associated with it, the event will be fired locally.
@@ -190,15 +190,18 @@ async def fire_event(self, namespace: str, event: str, **kwargs):
190190
"""
191191

192192
self.logger.debug("fire_plugin_event() %s %s %s", namespace, event, kwargs)
193-
plugin = self.AD.plugins.get_plugin_object(namespace)
194-
match plugin:
195-
case PluginBase() as plugin:
196-
if hasattr(plugin, "fire_plugin_event"):
197-
# We assume that the event will come back to us via the plugin
198-
return await plugin.fire_plugin_event(event, namespace, **kwargs)
199-
else:
200-
# Just fire the event locally
201-
await self.AD.events.process_event(namespace, {"event_type": event, "data": kwargs})
193+
match self.AD.plugins.get_plugin_object(namespace):
194+
case PluginBase() as plugin if hasattr(plugin, "fire_plugin_event"):
195+
# In the case that the namespace has a PluginBase associated (both Hass and MQTT plugins do), we check
196+
# that the plugin actually has a method called `fire_plugin_event`. If both of these conditions are met,
197+
# we call that method to fire the event, and assume that the plugin when the plugin fires the event, it
198+
# will make it back to AppDaemon via the normal plugin event processing mechanism.
199+
return await plugin.fire_plugin_event(event, namespace, **kwargs)
200+
case _:
201+
# If anything else comes out of get_plugin_object, we assume that the namespace does not have a plugin
202+
# associated with it, and we can fire the event locally.
203+
# This is the case for the admin namespace, and any other namespaces that do not have a plugin.
204+
return await self.AD.events.process_event(namespace, {"event_type": event, "data": kwargs})
202205

203206
async def process_event(self, namespace: str, data: dict[str, Any]):
204207
"""Processes an event that has been received either locally or from a plugin.

appdaemon/state.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,9 @@ async def add_entity(
538538
) -> None:
539539
"""Adds an entity to the internal state registry and fires the ``__AD_ENTITY_ADDED`` event"""
540540
if self.entity_exists(namespace, entity):
541-
self.logger.warning("%s already exists, will not be adding it", entity)
541+
# No warning is necessary because this method gets called twice for the app entities because of
542+
# create_initial_threads and then again during start_app
543+
# self.logger.warning("%s already exists, will not be adding it", entity)
542544
return
543545

544546
state = {

appdaemon/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version__ = "4.5.9"
1+
__version__ = "4.5.10"
22
__version_comments__ = ""

docs/CONFIGURE.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,11 @@ The following settings provide a high level of control over AppDaemon's internal
272272
Setting this to a specific value will turn off automatic thread management.
273273
-
274274

275+
* - loglevel
276+
- The global log level for AppDaemon's main log. This can be set to ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` or ``CRITICAL``.
277+
The default is ``INFO``. Note that this value will be overridden by the `-D` command line flag, if it is set.
278+
- ``INFO``
279+
275280
* - pin_apps
276281
- If ``true``, AppDaemon apps will be pinned to a particular thread.
277282
This should avoids complications around re-entrant code and locking of instance variables.

docs/HISTORY.md

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Change Log
22

3-
## 4.5.9
3+
## 4.5.10
44

55
**Features**
66

7-
None
7+
- Added "log_level" directive to `appdaemon'yaml` to allow global log level setting
88

99
**Fixes**
1010

@@ -54,23 +54,6 @@ None
5454
**Fixes**
5555

5656
- Fixed issue with getter that prevented app initialization
57-
58-
**Breaking Changes**
59-
60-
None
61-
62-
**Changes in Behavior**
63-
64-
None
65-
66-
## 4.5.6 (2025-06-01)
67-
68-
**Features**
69-
70-
None
71-
72-
**Fixes**
73-
7457
- Fixed an async issue with `firendly_name()`
7558
- Added missing setter for global_vars
7659

0 commit comments

Comments
 (0)