Skip to content

Commit 1efd3bd

Browse files
authored
Merge pull request #2340 from AppDaemon/websocket-hardening
hass plugin match/case structures
2 parents 86dc389 + a759720 commit 1efd3bd

File tree

4 files changed

+306
-251
lines changed

4 files changed

+306
-251
lines changed

appdaemon/models/config/plugin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ class HASSConfig(PluginConfig):
9292
enable_started_event: bool = True
9393
"""If true, the plugin will wait for the 'homeassistant_started' event before starting the plugin."""
9494
cert_path: CoercedPath | None = None
95-
cert_verify: bool | None = None
95+
cert_verify: bool = True
9696
commtype: str = "WS"
9797
q_timeout: int = 30
9898
ws_timeout: Annotated[

appdaemon/plugins/hass/hassapi.py

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,14 @@ def __init__(self, ad: AppDaemon, config_model: "AppConfig"):
5858
self.register_constraint("constrain_input_select")
5959

6060
@utils.sync_decorator
61-
async def ping(self) -> float:
61+
async def ping(self) -> float | None:
6262
"""Gets the number of seconds """
6363
if (plugin := self._plugin) is not None:
64-
return (await plugin.ping())['ad_duration']
64+
match await plugin.ping():
65+
case {"ad_status": "OK", "ad_duration": ad_duration}:
66+
return ad_duration
67+
case _:
68+
return None
6569

6670
@utils.sync_decorator
6771
async def check_for_entity(self, entity_id: str, namespace: str | None = None) -> bool:
@@ -539,16 +543,14 @@ def get_service_info(self, service: str) -> dict | None:
539543
Returns:
540544
Information about the service in a dict with the following keys: ``name``, ``description``, ``target``, and
541545
``fields``.
542-
543546
"""
544-
if (plugin := self._plugin) is not None:
545-
domain, service_name = service.split("/", 2)
546-
for service_def in plugin.services:
547-
if service_def.get("domain") == domain:
548-
if (services := service_def.get("services")) is not None:
549-
return deepcopy(services.get(service_name))
550-
else:
551-
self.logger.warning("Service info not found for domain '%s", domain)
547+
match self._plugin:
548+
case HassPlugin() as plugin:
549+
domain, service_name = service.split("/", 2)
550+
if info := plugin.services.get(domain, {}).get(service_name):
551+
# Return a copy of the info dict to prevent accidental modification
552+
return deepcopy(info)
553+
self.logger.warning("Service info not found for domain '%s", domain)
552554

553555
# Methods that use self.call_service
554556

@@ -680,7 +682,7 @@ async def get_history(
680682
significant_changes_only: bool | None = None,
681683
callback: Callable | None = None,
682684
namespace: str | None = None,
683-
) -> list[list[dict[str, Any]]]:
685+
) -> list[list[dict[str, Any]]] | None:
684686
"""Gets access to the HA Database.
685687
This is a convenience function that allows accessing the HA Database, so the
686688
history state of a device can be retrieved. It allows for a level of flexibility
@@ -755,31 +757,27 @@ async def get_history(
755757
end_time = end_time or await self.get_now()
756758
start_time = end_time - timedelta(days=days)
757759

758-
759-
plugin: "HassPlugin" = self.AD.plugins.get_plugin_object(
760-
namespace or self.namespace
761-
)
762-
763-
if plugin is not None:
764-
coro = plugin.get_history(
765-
filter_entity_id=entity_id,
766-
timestamp=start_time,
767-
end_time=end_time,
768-
minimal_response=minimal_response,
769-
no_attributes=no_attributes,
770-
significant_changes_only=significant_changes_only,
771-
)
772-
773-
if callback is not None and callable(callback):
774-
self.create_task(coro, callback)
775-
else:
776-
return await coro
777-
778-
else:
779-
self.logger.warning(
780-
"Wrong Namespace selected, as %s has no database plugin attached to it",
781-
namespace,
782-
)
760+
plugin = self.AD.plugins.get_plugin_object(namespace or self.namespace)
761+
match plugin:
762+
case HassPlugin():
763+
coro = plugin.get_history(
764+
filter_entity_id=entity_id,
765+
timestamp=start_time,
766+
end_time=end_time,
767+
minimal_response=minimal_response,
768+
no_attributes=no_attributes,
769+
significant_changes_only=significant_changes_only,
770+
)
771+
772+
if callback is not None and callable(callback):
773+
self.create_task(coro, callback)
774+
else:
775+
return await coro
776+
case _:
777+
self.logger.warning(
778+
"Wrong Namespace selected, as %s has no database plugin attached to it",
779+
namespace,
780+
)
783781

784782
@utils.sync_decorator
785783
async def get_logbook(

0 commit comments

Comments
 (0)