mirror of
https://github.com/home-assistant/core.git
synced 2025-07-29 08:07:45 +00:00
Use a unique ID for the Yellow ZHA hardware discovery (#81523)
* Set unique ID for hardware discovery * Use the provided `name` for discovered hardware
This commit is contained in:
parent
604cd46ec9
commit
74357bef15
@ -76,6 +76,14 @@ ESPHOME_API_PORT = 6053
|
|||||||
|
|
||||||
CONNECT_DELAY_S = 1.0
|
CONNECT_DELAY_S = 1.0
|
||||||
|
|
||||||
|
HARDWARE_DISCOVERY_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required("name"): str,
|
||||||
|
vol.Required("port"): dict,
|
||||||
|
vol.Required("radio_type"): str,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -182,6 +190,13 @@ class BaseZhaFlow(FlowHandler):
|
|||||||
async with self._connect_zigpy_app() as app:
|
async with self._connect_zigpy_app() as app:
|
||||||
await app.backups.restore_backup(backup, **kwargs)
|
await app.backups.restore_backup(backup, **kwargs)
|
||||||
|
|
||||||
|
def _parse_radio_type(self, radio_type: str) -> RadioType:
|
||||||
|
"""Parse a radio type name, accounting for past aliases."""
|
||||||
|
if radio_type == "efr32":
|
||||||
|
return RadioType.ezsp
|
||||||
|
|
||||||
|
return RadioType[radio_type]
|
||||||
|
|
||||||
async def _detect_radio_type(self) -> bool:
|
async def _detect_radio_type(self) -> bool:
|
||||||
"""Probe all radio types on the current port."""
|
"""Probe all radio types on the current port."""
|
||||||
for radio in AUTOPROBE_RADIOS:
|
for radio in AUTOPROBE_RADIOS:
|
||||||
@ -544,6 +559,24 @@ class ZhaConfigFlowHandler(BaseZhaFlow, config_entries.ConfigFlow, domain=DOMAIN
|
|||||||
|
|
||||||
VERSION = 3
|
VERSION = 3
|
||||||
|
|
||||||
|
async def _set_unique_id_or_update_path(
|
||||||
|
self, unique_id: str, device_path: str
|
||||||
|
) -> None:
|
||||||
|
"""Set the flow's unique ID and update the device path if it isn't unique."""
|
||||||
|
current_entry = await self.async_set_unique_id(unique_id)
|
||||||
|
|
||||||
|
if not current_entry:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._abort_if_unique_id_configured(
|
||||||
|
updates={
|
||||||
|
CONF_DEVICE: {
|
||||||
|
**current_entry.data.get(CONF_DEVICE, {}),
|
||||||
|
CONF_DEVICE_PATH: device_path,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@callback
|
@callback
|
||||||
def async_get_options_flow(
|
def async_get_options_flow(
|
||||||
@ -600,16 +633,11 @@ class ZhaConfigFlowHandler(BaseZhaFlow, config_entries.ConfigFlow, domain=DOMAIN
|
|||||||
manufacturer = discovery_info.manufacturer
|
manufacturer = discovery_info.manufacturer
|
||||||
description = discovery_info.description
|
description = discovery_info.description
|
||||||
dev_path = await self.hass.async_add_executor_job(usb.get_serial_by_id, device)
|
dev_path = await self.hass.async_add_executor_job(usb.get_serial_by_id, device)
|
||||||
unique_id = f"{vid}:{pid}_{serial_number}_{manufacturer}_{description}"
|
|
||||||
if current_entry := await self.async_set_unique_id(unique_id):
|
await self._set_unique_id_or_update_path(
|
||||||
self._abort_if_unique_id_configured(
|
unique_id=f"{vid}:{pid}_{serial_number}_{manufacturer}_{description}",
|
||||||
updates={
|
device_path=dev_path,
|
||||||
CONF_DEVICE: {
|
)
|
||||||
**current_entry.data.get(CONF_DEVICE, {}),
|
|
||||||
CONF_DEVICE_PATH: dev_path,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# If they already have a discovery for deconz we ignore the usb discovery as
|
# If they already have a discovery for deconz we ignore the usb discovery as
|
||||||
# they probably want to use it there instead
|
# they probably want to use it there instead
|
||||||
@ -645,7 +673,9 @@ class ZhaConfigFlowHandler(BaseZhaFlow, config_entries.ConfigFlow, domain=DOMAIN
|
|||||||
port = DEFAULT_ZHA_ZEROCONF_PORT
|
port = DEFAULT_ZHA_ZEROCONF_PORT
|
||||||
|
|
||||||
if "radio_type" in discovery_info.properties:
|
if "radio_type" in discovery_info.properties:
|
||||||
self._radio_type = RadioType[discovery_info.properties["radio_type"]]
|
self._radio_type = self._parse_radio_type(
|
||||||
|
discovery_info.properties["radio_type"]
|
||||||
|
)
|
||||||
elif "efr32" in local_name:
|
elif "efr32" in local_name:
|
||||||
self._radio_type = RadioType.ezsp
|
self._radio_type = RadioType.ezsp
|
||||||
else:
|
else:
|
||||||
@ -654,15 +684,10 @@ class ZhaConfigFlowHandler(BaseZhaFlow, config_entries.ConfigFlow, domain=DOMAIN
|
|||||||
node_name = local_name[: -len(".local")]
|
node_name = local_name[: -len(".local")]
|
||||||
device_path = f"socket://{discovery_info.host}:{port}"
|
device_path = f"socket://{discovery_info.host}:{port}"
|
||||||
|
|
||||||
if current_entry := await self.async_set_unique_id(node_name):
|
await self._set_unique_id_or_update_path(
|
||||||
self._abort_if_unique_id_configured(
|
unique_id=node_name,
|
||||||
updates={
|
device_path=device_path,
|
||||||
CONF_DEVICE: {
|
)
|
||||||
**current_entry.data.get(CONF_DEVICE, {}),
|
|
||||||
CONF_DEVICE_PATH: device_path,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
self.context["title_placeholders"] = {CONF_NAME: node_name}
|
self.context["title_placeholders"] = {CONF_NAME: node_name}
|
||||||
self._title = device_path
|
self._title = device_path
|
||||||
@ -674,34 +699,31 @@ class ZhaConfigFlowHandler(BaseZhaFlow, config_entries.ConfigFlow, domain=DOMAIN
|
|||||||
self, data: dict[str, Any] | None = None
|
self, data: dict[str, Any] | None = None
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
"""Handle hardware flow."""
|
"""Handle hardware flow."""
|
||||||
if not data:
|
|
||||||
return self.async_abort(reason="invalid_hardware_data")
|
|
||||||
if data.get("radio_type") != "efr32":
|
|
||||||
return self.async_abort(reason="invalid_hardware_data")
|
|
||||||
|
|
||||||
self._radio_type = RadioType.ezsp
|
|
||||||
|
|
||||||
schema = {
|
|
||||||
vol.Required(
|
|
||||||
CONF_DEVICE_PATH, default=self._device_path or vol.UNDEFINED
|
|
||||||
): str
|
|
||||||
}
|
|
||||||
|
|
||||||
radio_schema = self._radio_type.controller.SCHEMA_DEVICE.schema
|
|
||||||
assert not isinstance(radio_schema, vol.Schema)
|
|
||||||
|
|
||||||
for param, value in radio_schema.items():
|
|
||||||
if param in SUPPORTED_PORT_SETTINGS:
|
|
||||||
schema[param] = value
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
device_settings = vol.Schema(schema)(data.get("port"))
|
discovery_data = HARDWARE_DISCOVERY_SCHEMA(data)
|
||||||
except vol.Invalid:
|
except vol.Invalid:
|
||||||
return self.async_abort(reason="invalid_hardware_data")
|
return self.async_abort(reason="invalid_hardware_data")
|
||||||
|
|
||||||
self._title = data.get("name", data["port"]["path"])
|
name = discovery_data["name"]
|
||||||
|
radio_type = self._parse_radio_type(discovery_data["radio_type"])
|
||||||
|
|
||||||
|
try:
|
||||||
|
device_settings = radio_type.controller.SCHEMA_DEVICE(
|
||||||
|
discovery_data["port"]
|
||||||
|
)
|
||||||
|
except vol.Invalid:
|
||||||
|
return self.async_abort(reason="invalid_hardware_data")
|
||||||
|
|
||||||
|
await self._set_unique_id_or_update_path(
|
||||||
|
unique_id=f"{name}_{radio_type.name}_{device_settings[CONF_DEVICE_PATH]}",
|
||||||
|
device_path=device_settings[CONF_DEVICE_PATH],
|
||||||
|
)
|
||||||
|
|
||||||
|
self._title = name
|
||||||
|
self._radio_type = radio_type
|
||||||
self._device_path = device_settings[CONF_DEVICE_PATH]
|
self._device_path = device_settings[CONF_DEVICE_PATH]
|
||||||
self._device_settings = device_settings
|
self._device_settings = device_settings
|
||||||
|
self.context["title_placeholders"] = {CONF_NAME: name}
|
||||||
|
|
||||||
return await self.async_step_confirm()
|
return await self.async_step_confirm()
|
||||||
|
|
||||||
|
@ -987,6 +987,7 @@ async def test_hardware_already_setup(hass):
|
|||||||
).add_to_hass(hass)
|
).add_to_hass(hass)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
|
"name": "Yellow",
|
||||||
"radio_type": "efr32",
|
"radio_type": "efr32",
|
||||||
"port": {
|
"port": {
|
||||||
"path": "/dev/ttyAMA1",
|
"path": "/dev/ttyAMA1",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user