mirror of
https://github.com/home-assistant/core.git
synced 2026-04-19 16:09:06 +02:00
Expose async serial port scanning helper in USB integration (#167706)
This commit is contained in:
@@ -13,7 +13,7 @@ from homeassistant.components.homeassistant_hardware.util import guess_firmware_
|
||||
from homeassistant.components.usb import (
|
||||
USBDevice,
|
||||
async_register_port_event_callback,
|
||||
scan_serial_ports,
|
||||
async_scan_serial_ports,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -163,7 +163,7 @@ async def async_migrate_entry(
|
||||
key not in config_entry.data
|
||||
for key in (VID, PID, MANUFACTURER, PRODUCT, SERIAL_NUMBER)
|
||||
):
|
||||
serial_ports = await hass.async_add_executor_job(scan_serial_ports)
|
||||
serial_ports = await async_scan_serial_ports(hass)
|
||||
serial_ports_info = {port.device: port for port in serial_ports}
|
||||
device = config_entry.data[DEVICE]
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ from .models import (
|
||||
USBDevice,
|
||||
)
|
||||
from .utils import (
|
||||
scan_serial_ports,
|
||||
async_scan_serial_ports,
|
||||
scan_serial_ports, # noqa: F401
|
||||
usb_device_from_path, # noqa: F401
|
||||
usb_device_from_port, # noqa: F401
|
||||
usb_device_matches_matcher,
|
||||
@@ -433,7 +434,7 @@ class USBDiscovery:
|
||||
# Only consider USB-serial ports for discovery
|
||||
usb_ports = [
|
||||
p
|
||||
for p in await self.hass.async_add_executor_job(scan_serial_ports)
|
||||
for p in await async_scan_serial_ports(self.hass)
|
||||
if isinstance(p, USBDevice)
|
||||
]
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import os
|
||||
from serial.tools.list_ports import comports
|
||||
from serial.tools.list_ports_common import ListPortInfo
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.service_info.usb import UsbServiceInfo
|
||||
from homeassistant.loader import USBMatcher
|
||||
|
||||
@@ -76,6 +77,13 @@ def scan_serial_ports() -> Sequence[USBDevice | SerialDevice]:
|
||||
return serial_ports
|
||||
|
||||
|
||||
async def async_scan_serial_ports(
|
||||
hass: HomeAssistant,
|
||||
) -> Sequence[USBDevice | SerialDevice]:
|
||||
"""Scan serial ports and return USB and other serial devices, async."""
|
||||
return await hass.async_add_executor_job(scan_serial_ports)
|
||||
|
||||
|
||||
def usb_device_from_path(device_path: str) -> USBDevice | None:
|
||||
"""Get USB device info from a device path."""
|
||||
|
||||
|
||||
@@ -26,7 +26,11 @@ from homeassistant.components.homeassistant_hardware.firmware_config_flow import
|
||||
ZigbeeFlowStrategy,
|
||||
)
|
||||
from homeassistant.components.homeassistant_yellow import hardware as yellow_hardware
|
||||
from homeassistant.components.usb import SerialDevice, USBDevice, scan_serial_ports
|
||||
from homeassistant.components.usb import (
|
||||
SerialDevice,
|
||||
USBDevice,
|
||||
async_scan_serial_ports,
|
||||
)
|
||||
from homeassistant.config_entries import (
|
||||
SOURCE_IGNORE,
|
||||
SOURCE_ZEROCONF,
|
||||
@@ -155,7 +159,7 @@ def _format_serial_port_choice(
|
||||
async def list_serial_ports(hass: HomeAssistant) -> list[USBDevice | SerialDevice]:
|
||||
"""List all serial ports, including the Yellow radio and the multi-PAN addon."""
|
||||
ports: list[USBDevice | SerialDevice] = []
|
||||
ports.extend(await hass.async_add_executor_job(scan_serial_ports))
|
||||
ports.extend(await async_scan_serial_ports(hass))
|
||||
|
||||
# Add useful info to the Yellow's serial port selection screen
|
||||
try:
|
||||
|
||||
@@ -265,7 +265,7 @@ async def test_bad_config_entry_fixing(hass: HomeAssistant) -> None:
|
||||
fixable_entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.homeassistant_sky_connect.scan_serial_ports",
|
||||
"homeassistant.components.homeassistant_sky_connect.async_scan_serial_ports",
|
||||
return_value=[
|
||||
USBDevice(
|
||||
device="/dev/serial/by-id/usb-Nabu_Casa_SkyConnect_v1.0_4f5f3b26d59f8714a78b599690741999-if00-port0",
|
||||
|
||||
@@ -21,7 +21,7 @@ def force_usb_polling_watcher():
|
||||
|
||||
def patch_scanned_serial_ports(**kwargs) -> None:
|
||||
"""Patch the USB integration's list of scanned serial ports."""
|
||||
return patch("homeassistant.components.usb.scan_serial_ports", **kwargs)
|
||||
return patch("homeassistant.components.usb.utils.scan_serial_ports", **kwargs)
|
||||
|
||||
|
||||
async def async_request_scan(hass: HomeAssistant) -> None:
|
||||
|
||||
@@ -12,7 +12,10 @@ from homeassistant import config_entries
|
||||
from homeassistant.components import usb
|
||||
from homeassistant.components.usb import DOMAIN
|
||||
from homeassistant.components.usb.models import SerialDevice, USBDevice
|
||||
from homeassistant.components.usb.utils import scan_serial_ports, usb_device_from_path
|
||||
from homeassistant.components.usb.utils import (
|
||||
async_scan_serial_ports,
|
||||
usb_device_from_path,
|
||||
)
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
@@ -1293,8 +1296,10 @@ async def test_register_port_event_callback_failure(
|
||||
assert "Failure 2" in caplog.text
|
||||
|
||||
|
||||
def test_scan_serial_ports_with_unique_symlinks() -> None:
|
||||
"""Test scan_serial_ports returns devices with unique /dev/serial/by-id paths."""
|
||||
async def test_async_scan_serial_ports_with_unique_symlinks(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test async_scan_serial_ports returns devices with unique /dev/serial/by-id paths."""
|
||||
entry1 = MagicMock(spec_set=os.DirEntry)
|
||||
entry1.is_symlink.return_value = True
|
||||
entry1.path = "/dev/serial/by-id/usb-device1"
|
||||
@@ -1335,7 +1340,7 @@ def test_scan_serial_ports_with_unique_symlinks() -> None:
|
||||
return_value=[mock_port1, mock_port2],
|
||||
),
|
||||
):
|
||||
devices = scan_serial_ports()
|
||||
devices = await async_scan_serial_ports(hass)
|
||||
|
||||
assert len(devices) == 2
|
||||
assert devices[0].device == "/dev/serial/by-id/usb-device1"
|
||||
@@ -1344,8 +1349,10 @@ def test_scan_serial_ports_with_unique_symlinks() -> None:
|
||||
assert devices[1].vid == "ABCD"
|
||||
|
||||
|
||||
def test_scan_serial_ports_without_unique_symlinks() -> None:
|
||||
"""Test scan_serial_ports returns devices with original paths when no symlinks exist."""
|
||||
async def test_async_scan_serial_ports_without_unique_symlinks(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test async_scan_serial_ports returns devices with original paths when no symlinks exist."""
|
||||
mock_port = MagicMock()
|
||||
mock_port.device = "/dev/ttyUSB0"
|
||||
mock_port.vid = 0x1234
|
||||
@@ -1362,15 +1369,15 @@ def test_scan_serial_ports_without_unique_symlinks() -> None:
|
||||
return_value=[mock_port],
|
||||
),
|
||||
):
|
||||
devices = scan_serial_ports()
|
||||
devices = await async_scan_serial_ports(hass)
|
||||
|
||||
assert len(devices) == 1
|
||||
assert devices[0].device == "/dev/ttyUSB0"
|
||||
assert devices[0].vid == "1234"
|
||||
|
||||
|
||||
def test_scan_serial_ports_no_vid_pid() -> None:
|
||||
"""Test scan_serial_ports returns devices without VID:PID."""
|
||||
async def test_async_scan_serial_ports_no_vid_pid(hass: HomeAssistant) -> None:
|
||||
"""Test async_scan_serial_ports returns devices without VID:PID."""
|
||||
mock_port = MagicMock()
|
||||
mock_port.device = "/dev/ttyAMA1"
|
||||
mock_port.vid = None
|
||||
@@ -1387,7 +1394,7 @@ def test_scan_serial_ports_no_vid_pid() -> None:
|
||||
return_value=[mock_port],
|
||||
),
|
||||
):
|
||||
devices = scan_serial_ports()
|
||||
devices = await async_scan_serial_ports(hass)
|
||||
|
||||
assert len(devices) == 1
|
||||
assert isinstance(devices[0], SerialDevice)
|
||||
|
||||
@@ -2844,7 +2844,7 @@ async def test_config_flow_port_yellow_port_name(
|
||||
with (
|
||||
patch("homeassistant.components.zha.config_flow.yellow_hardware.async_info"),
|
||||
patch(
|
||||
"homeassistant.components.zha.config_flow.scan_serial_ports",
|
||||
"homeassistant.components.zha.config_flow.async_scan_serial_ports",
|
||||
return_value=[port],
|
||||
),
|
||||
):
|
||||
@@ -2866,7 +2866,7 @@ async def test_config_flow_ports_no_hassio(hass: HomeAssistant) -> None:
|
||||
with (
|
||||
patch("homeassistant.components.zha.config_flow.is_hassio", return_value=False),
|
||||
patch(
|
||||
"homeassistant.components.zha.config_flow.scan_serial_ports",
|
||||
"homeassistant.components.zha.config_flow.async_scan_serial_ports",
|
||||
return_value=[],
|
||||
),
|
||||
):
|
||||
@@ -2884,7 +2884,7 @@ async def test_config_flow_port_multiprotocol_port_name(hass: HomeAssistant) ->
|
||||
"homeassistant.components.hassio.addon_manager.AddonManager.async_get_addon_info"
|
||||
) as async_get_addon_info,
|
||||
patch(
|
||||
"homeassistant.components.zha.config_flow.scan_serial_ports",
|
||||
"homeassistant.components.zha.config_flow.async_scan_serial_ports",
|
||||
return_value=[],
|
||||
),
|
||||
):
|
||||
@@ -2909,7 +2909,7 @@ async def test_config_flow_port_no_multiprotocol(hass: HomeAssistant) -> None:
|
||||
side_effect=AddonError,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.zha.config_flow.scan_serial_ports",
|
||||
"homeassistant.components.zha.config_flow.async_scan_serial_ports",
|
||||
return_value=[],
|
||||
),
|
||||
):
|
||||
@@ -2974,7 +2974,7 @@ async def test_list_serial_ports_ignored_devices(hass: HomeAssistant) -> None:
|
||||
with (
|
||||
patch("homeassistant.components.zha.config_flow.is_hassio", return_value=False),
|
||||
patch(
|
||||
"homeassistant.components.zha.config_flow.scan_serial_ports",
|
||||
"homeassistant.components.zha.config_flow.async_scan_serial_ports",
|
||||
return_value=mock_ports,
|
||||
),
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user