mirror of
https://github.com/home-assistant/core.git
synced 2026-09-03 03:51:51 +01:00
Ignore static add-on devices when attributing serial ports (#181074)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Paulus Schoutsen
Claude Fable 5.1
parent
2a92f8bb3a
commit
0dbe35ec4a
@@ -1,6 +1,6 @@
|
||||
"""Attribution of serial ports to the integrations and apps using them."""
|
||||
|
||||
from collections.abc import Mapping, Sequence
|
||||
from collections.abc import Iterator, Mapping, Sequence
|
||||
import os
|
||||
import re
|
||||
from typing import Any
|
||||
@@ -156,14 +156,29 @@ async def _async_get_config_entry_consumers(
|
||||
return consumers
|
||||
|
||||
|
||||
def _iter_option_device_paths(value: Any) -> Iterator[str]:
|
||||
"""Yield device paths configured anywhere in the options of an app."""
|
||||
if isinstance(value, str):
|
||||
if value.startswith("/dev/"):
|
||||
yield value
|
||||
elif isinstance(value, Mapping):
|
||||
for item in value.values():
|
||||
yield from _iter_option_device_paths(item)
|
||||
elif isinstance(value, list):
|
||||
for item in value:
|
||||
yield from _iter_option_device_paths(item)
|
||||
|
||||
|
||||
@callback
|
||||
def _async_get_app_consumers(
|
||||
hass: HomeAssistant,
|
||||
) -> dict[str, list[SerialPortConsumer]]:
|
||||
"""Return devices mapped into apps, either statically or through options.
|
||||
"""Return devices configured in the options of apps.
|
||||
|
||||
Supervisor resolves `device(subsystem=tty)` options into real devices, so device
|
||||
paths that no longer exist are missing and non-serial devices are included.
|
||||
The `devices` field of an app also lists the static devices of its manifest,
|
||||
which are mapped into the container whether the app uses them or not, so only
|
||||
options are evidence of a device being used. Options can refer to devices
|
||||
that no longer exist or are not serial ports.
|
||||
"""
|
||||
if not is_hassio(hass):
|
||||
return {}
|
||||
@@ -179,7 +194,7 @@ def _async_get_app_consumers(
|
||||
if info is None:
|
||||
continue
|
||||
|
||||
for device in info["devices"]:
|
||||
for device in _iter_option_device_paths(info["options"]):
|
||||
consumers.setdefault(device, []).append(
|
||||
SerialPortConsumer(
|
||||
kind="app",
|
||||
@@ -224,7 +239,7 @@ async def async_get_serial_port_consumers(
|
||||
consumers.setdefault(device, []).extend(path_consumers)
|
||||
|
||||
for path, path_consumers in app_consumers.items():
|
||||
# Apps also map non-serial devices, only scanned ports are of interest
|
||||
# Options can name non-serial devices, only scanned ports are of interest
|
||||
resolved_path = resolved[path]
|
||||
|
||||
if resolved_path not in aliases:
|
||||
|
||||
@@ -439,17 +439,26 @@ async def test_app_consumers(
|
||||
hass: HomeAssistant,
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
) -> None:
|
||||
"""Test detecting serial ports mapped into apps."""
|
||||
"""Test detecting serial ports configured in the options of apps."""
|
||||
apps_info = {
|
||||
"core_zwave_js": {
|
||||
"name": "Z-Wave JS",
|
||||
"state": "started",
|
||||
"devices": [TTY_USB0_BY_ID, "/dev/dri/card0"],
|
||||
"devices": [TTY_USB0],
|
||||
"options": {"device": TTY_USB0_BY_ID, "gpu": "/dev/dri/card0"},
|
||||
},
|
||||
"some_app": {
|
||||
"name": "Some App",
|
||||
"state": "stopped",
|
||||
"devices": [TTY_USB1],
|
||||
"options": {"serial": [{"port": TTY_USB0}]},
|
||||
},
|
||||
# Static devices of the manifest are mapped regardless of being used
|
||||
"wmbusmeters": {
|
||||
"name": "Wmbusmeters",
|
||||
"state": "started",
|
||||
"devices": [TTY_USB0, TTY_USB1],
|
||||
"options": {"reset_config": False},
|
||||
},
|
||||
"uninstalled_app": None,
|
||||
}
|
||||
@@ -478,7 +487,15 @@ async def test_app_consumers(
|
||||
"domain": None,
|
||||
"config_entry_id": None,
|
||||
"slug": "core_zwave_js",
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "app",
|
||||
"title": "Some App",
|
||||
"active": False,
|
||||
"domain": None,
|
||||
"config_entry_id": None,
|
||||
"slug": "some_app",
|
||||
},
|
||||
],
|
||||
),
|
||||
(ESPHOME_PORT, []),
|
||||
@@ -531,7 +548,12 @@ async def test_multiple_consumers(
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
apps_info = {
|
||||
"some_app": {"name": "Some App", "state": "started", "devices": [TTY_USB0]}
|
||||
"some_app": {
|
||||
"name": "Some App",
|
||||
"state": "started",
|
||||
"devices": [TTY_USB0],
|
||||
"options": {"device": TTY_USB0},
|
||||
}
|
||||
}
|
||||
|
||||
with (
|
||||
|
||||
Reference in New Issue
Block a user