Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion homeassistant/components/zha/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@
extra=vol.ALLOW_EXTRA,
)

# USB devices to ignore in serial port selection (non-Zigbee devices)
# Format: (manufacturer, description)
IGNORED_USB_DEVICES = {
("Nabu Casa", "ZWA-2"),
}


class OptionsMigrationIntent(StrEnum):
"""Zigbee options flow intents."""
Expand Down Expand Up @@ -165,7 +171,12 @@ async def list_serial_ports(hass: HomeAssistant) -> list[ListPortInfo]:
addon_port.manufacturer = "Nabu Casa"
ports.append(addon_port)

return ports
# Filter out ignored USB devices
return [
port
for port in ports
if (port.manufacturer, port.description) not in IGNORED_USB_DEVICES
]


class BaseZhaFlow(ConfigEntryBaseFlow):
Expand Down
65 changes: 65 additions & 0 deletions tests/components/zha/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2643,6 +2643,71 @@ async def test_config_flow_port_no_multiprotocol(hass: HomeAssistant) -> None:
assert ports == []


async def test_list_serial_ports_ignored_devices(hass: HomeAssistant) -> None:
"""Test that list_serial_ports filters out ignored non-Zigbee devices."""
mock_ports = [
ListPortInfo("/dev/ttyUSB0"),
ListPortInfo("/dev/ttyUSB1"),
ListPortInfo("/dev/ttyUSB2"),
ListPortInfo("/dev/ttyUSB3"),
ListPortInfo("/dev/ttyUSB4"),
ListPortInfo("/dev/ttyUSB5"),
]

# ZWA-2, should be filtered
mock_ports[0].manufacturer = "Nabu Casa"
mock_ports[0].description = "ZWA-2"

# ZBT-2, should be shown
mock_ports[1].manufacturer = "Nabu Casa"
mock_ports[1].description = "ZBT-2"

# ZBT-1, should be shown
mock_ports[2].manufacturer = "Nabu Casa"
mock_ports[2].description = "Home Assistant Connect ZBT-1"

# SkyConnect, should be shown
mock_ports[3].manufacturer = "Nabu Casa"
mock_ports[3].description = "SkyConnect v1.0"

# unknown device with manufacturer/description, should be shown
mock_ports[4].manufacturer = "Another Manufacturer"
mock_ports[4].description = "Zigbee USB Adapter"

# unknown device with no manufacturer/description, should be shown
mock_ports[5].manufacturer = None
mock_ports[5].description = None

with (
patch("homeassistant.components.zha.config_flow.is_hassio", return_value=False),
patch("serial.tools.list_ports.comports", return_value=mock_ports),
):
ports = await config_flow.list_serial_ports(hass)

# ZWA-2 should be filtered out, others should remain
assert len(ports) == 5

assert ports[0].device == "/dev/ttyUSB1"
assert ports[0].manufacturer == "Nabu Casa"
assert ports[0].description == "ZBT-2"

assert ports[1].device == "/dev/ttyUSB2"
assert ports[1].manufacturer == "Nabu Casa"
assert ports[1].description == "Home Assistant Connect ZBT-1"

assert ports[2].device == "/dev/ttyUSB3"
assert ports[2].manufacturer == "Nabu Casa"
assert ports[2].description == "SkyConnect v1.0"

assert ports[3].device == "/dev/ttyUSB4"
assert ports[3].manufacturer == "Another Manufacturer"
assert ports[3].description == "Zigbee USB Adapter"

assert ports[4].device == "/dev/ttyUSB5"
assert ports[4].manufacturer is None
assert ports[4].description is None


@patch("serial.tools.list_ports.comports", MagicMock(return_value=[com_port()]))
async def test_probe_wrong_firmware_installed(hass: HomeAssistant) -> None:
"""Test auto-probing failing because the wrong firmware is installed."""
Expand Down
Loading