Use ESPHome project info for serial device manufacturer and model (#180450)

This commit is contained in:
Jesse Hills
2026-08-27 16:48:44 -04:00
committed by GitHub
parent f6c1f1abdc
commit a06c462c68
3 changed files with 74 additions and 9 deletions
+5 -2
View File
@@ -27,6 +27,7 @@ from .manager import (
DEVICE_CONFLICT_ISSUE_FORMAT,
ESPHomeManager,
async_create_api_client,
async_get_manufacturer_model,
cleanup_instance,
)
from .websocket_api import async_setup as async_setup_websocket_api
@@ -52,14 +53,16 @@ def _async_scan_serial_ports(
if device_info is None:
continue
manufacturer, model = async_get_manufacturer_model(device_info)
ports.extend(
SerialDevice(
device=str(serial_proxy.build_url(entry.entry_id, proxy.name)),
serial_number=(
device_info.mac_address.replace(":", "") + "-" + slugify(proxy.name)
),
manufacturer=device_info.manufacturer,
description=f"{device_info.model} ({proxy.name})",
manufacturer=manufacturer,
description=f"{model} ({proxy.name})",
)
for proxy in device_info.serial_proxies
)
+10 -7
View File
@@ -1190,6 +1190,15 @@ class ESPHomeManager:
)
@callback
def async_get_manufacturer_model(device_info: EsphomeDeviceInfo) -> tuple[str, str]:
"""Return the manufacturer and model to use for a device."""
if device_info.project_name:
project_name = device_info.project_name.split(".")
return project_name[0], project_name[1]
return device_info.manufacturer or "espressif", device_info.model
@callback
def _async_setup_device_registry(
hass: HomeAssistant, entry: ESPHomeConfigEntry, entry_data: RuntimeEntryData
@@ -1236,14 +1245,8 @@ def _async_setup_device_registry(
):
configuration_url = f"homeassistant://app/{dashboard.addon_slug}"
manufacturer = "espressif"
if device_info.manufacturer:
manufacturer = device_info.manufacturer
model = device_info.model
manufacturer, model = async_get_manufacturer_model(device_info)
if device_info.project_name:
project_name = device_info.project_name.split(".")
manufacturer = project_name[0]
model = project_name[1]
sw_version = (
f"{device_info.project_version} (ESPHome {device_info.esphome_version})"
)
@@ -134,6 +134,65 @@ async def test_scan_serial_ports_happy_path(
]
@pytest.mark.usefixtures("mock_zeroconf")
async def test_scan_serial_ports_uses_project_info(
hass: HomeAssistant,
mock_client: APIClient,
mock_esphome_device: MockESPHomeDeviceType,
) -> None:
"""Project information takes precedence over manufacturer and model."""
device = await mock_esphome_device(
mock_client=mock_client,
device_info={
"mac_address": "AA:BB:CC:DD:EE:FF",
"manufacturer": "Espressif",
"model": "ESP32",
"project_name": "vendor.gadget",
"serial_proxies": [
SerialProxyInfo(name="uart0", port_type=SerialProxyPortType.TTL)
],
},
)
assert _async_scan_serial_ports(hass) == [
SerialDevice(
device=str(serial_proxy.build_url(device.entry.entry_id, "uart0")),
serial_number="AABBCCDDEEFF-uart0",
manufacturer="vendor",
description="gadget (uart0)",
)
]
@pytest.mark.usefixtures("mock_zeroconf")
async def test_scan_serial_ports_defaults_manufacturer(
hass: HomeAssistant,
mock_client: APIClient,
mock_esphome_device: MockESPHomeDeviceType,
) -> None:
"""A device without a manufacturer falls back to espressif."""
device = await mock_esphome_device(
mock_client=mock_client,
device_info={
"mac_address": "AA:BB:CC:DD:EE:FF",
"manufacturer": "",
"model": "ESP32",
"serial_proxies": [
SerialProxyInfo(name="uart0", port_type=SerialProxyPortType.TTL)
],
},
)
assert _async_scan_serial_ports(hass) == [
SerialDevice(
device=str(serial_proxy.build_url(device.entry.entry_id, "uart0")),
serial_number="AABBCCDDEEFF-uart0",
manufacturer="espressif",
description="ESP32 (uart0)",
)
]
@pytest.mark.usefixtures("mock_zeroconf")
async def test_scan_serial_ports_skips_unavailable(
hass: HomeAssistant,