mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Clean up Z-Wave config flow (#143670)
This commit is contained in:
parent
4adf5ce826
commit
5b1e32f51d
@ -25,6 +25,7 @@ from homeassistant.components.hassio import (
|
||||
)
|
||||
from homeassistant.config_entries import (
|
||||
SOURCE_USB,
|
||||
ConfigEntry,
|
||||
ConfigEntryState,
|
||||
ConfigFlow,
|
||||
ConfigFlowResult,
|
||||
@ -77,9 +78,6 @@ CONF_EMULATE_HARDWARE = "emulate_hardware"
|
||||
CONF_LOG_LEVEL = "log_level"
|
||||
SERVER_VERSION_TIMEOUT = 10
|
||||
|
||||
OPTIONS_INTENT_MIGRATE = "intent_migrate"
|
||||
OPTIONS_INTENT_RECONFIGURE = "intent_reconfigure"
|
||||
|
||||
ADDON_LOG_LEVELS = {
|
||||
"error": "Error",
|
||||
"warn": "Warn",
|
||||
@ -203,7 +201,7 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self.backup_data: bytes | None = None
|
||||
self.backup_filepath: str | None = None
|
||||
self.use_addon = False
|
||||
self._reconfiguring = False
|
||||
self._reconfigure_config_entry: ConfigEntry | None = None
|
||||
self._usb_discovery = False
|
||||
|
||||
async def async_step_install_addon(
|
||||
@ -266,8 +264,8 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Add-on start failed."""
|
||||
if self._reconfiguring:
|
||||
return await self.async_step_start_failed_reconfigure()
|
||||
if self._reconfigure_config_entry:
|
||||
return await self.async_revert_addon_config(reason="addon_start_failed")
|
||||
return self.async_abort(reason="addon_start_failed")
|
||||
|
||||
async def _async_start_addon(self) -> None:
|
||||
@ -305,7 +303,7 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Ask for config for Z-Wave JS add-on."""
|
||||
if self._reconfiguring:
|
||||
if self._reconfigure_config_entry:
|
||||
return await self.async_step_configure_addon_reconfigure(user_input)
|
||||
return await self.async_step_configure_addon_user(user_input)
|
||||
|
||||
@ -317,7 +315,7 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
Get add-on discovery info and server version info.
|
||||
Set unique id and abort if already configured.
|
||||
"""
|
||||
if self._reconfiguring:
|
||||
if self._reconfigure_config_entry:
|
||||
return await self.async_step_finish_addon_setup_reconfigure(user_input)
|
||||
return await self.async_step_finish_addon_setup_user(user_input)
|
||||
|
||||
@ -332,11 +330,25 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
return addon_info
|
||||
|
||||
async def _async_set_addon_config(self, config: dict) -> None:
|
||||
async def _async_set_addon_config(self, config_updates: dict) -> None:
|
||||
"""Set Z-Wave JS add-on config."""
|
||||
addon_info = await self._async_get_addon_info()
|
||||
addon_config = addon_info.options
|
||||
|
||||
new_addon_config = addon_config | config_updates
|
||||
|
||||
if new_addon_config == addon_config:
|
||||
return
|
||||
|
||||
if addon_info.state == AddonState.RUNNING:
|
||||
self.restart_addon = True
|
||||
# Copy the add-on config to keep the objects separate.
|
||||
self.original_addon_config = dict(addon_config)
|
||||
# Remove legacy network_key
|
||||
new_addon_config.pop(CONF_ADDON_NETWORK_KEY, None)
|
||||
addon_manager: AddonManager = get_addon_manager(self.hass)
|
||||
try:
|
||||
await addon_manager.async_set_addon_options(config)
|
||||
await addon_manager.async_set_addon_options(new_addon_config)
|
||||
except AddonError as err:
|
||||
_LOGGER.error(err)
|
||||
raise AbortFlow("addon_set_config_failed") from err
|
||||
@ -370,12 +382,12 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Confirm if we are migrating adapters or just re-configuring."""
|
||||
self._reconfiguring = True
|
||||
self._reconfigure_config_entry = self._get_reconfigure_entry()
|
||||
return self.async_show_menu(
|
||||
step_id="reconfigure",
|
||||
menu_options=[
|
||||
OPTIONS_INTENT_RECONFIGURE,
|
||||
OPTIONS_INTENT_MIGRATE,
|
||||
"intent_reconfigure",
|
||||
"intent_migrate",
|
||||
],
|
||||
)
|
||||
|
||||
@ -432,7 +444,10 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
await self.async_set_unique_id(
|
||||
f"{vid}:{pid}_{serial_number}_{manufacturer}_{description}"
|
||||
)
|
||||
self._abort_if_unique_id_configured()
|
||||
# We don't need to check if the unique_id is already configured
|
||||
# since we will update the unique_id before finishing the flow.
|
||||
# The unique_id set above is just a temporary value to avoid
|
||||
# duplicate discovery flows.
|
||||
dev_path = discovery_info.device
|
||||
self.usb_path = dev_path
|
||||
if manufacturer == "Nabu Casa" and description == "ZWA-2 - Nabu Casa ZWA-2":
|
||||
@ -598,8 +613,7 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
if not self._usb_discovery:
|
||||
self.usb_path = user_input[CONF_USB_PATH]
|
||||
|
||||
new_addon_config = {
|
||||
**addon_config,
|
||||
addon_config_updates = {
|
||||
CONF_ADDON_DEVICE: self.usb_path,
|
||||
CONF_ADDON_S0_LEGACY_KEY: self.s0_legacy_key,
|
||||
CONF_ADDON_S2_ACCESS_CONTROL_KEY: self.s2_access_control_key,
|
||||
@ -609,8 +623,7 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
CONF_ADDON_LR_S2_AUTHENTICATED_KEY: self.lr_s2_authenticated_key,
|
||||
}
|
||||
|
||||
if new_addon_config != addon_config:
|
||||
await self._async_set_addon_config(new_addon_config)
|
||||
await self._async_set_addon_config(addon_config_updates)
|
||||
|
||||
return await self.async_step_start_addon()
|
||||
|
||||
@ -730,11 +743,17 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_update_entry(self, data: dict[str, Any]) -> None:
|
||||
def _async_update_entry(
|
||||
self, updates: dict[str, Any], *, schedule_reload: bool = True
|
||||
) -> None:
|
||||
"""Update the config entry with new data."""
|
||||
config_entry = self._reconfigure_config_entry
|
||||
assert config_entry is not None
|
||||
self.hass.config_entries.async_update_entry(
|
||||
self._get_reconfigure_entry(), data=data
|
||||
config_entry, data=config_entry.data | updates
|
||||
)
|
||||
if schedule_reload:
|
||||
self.hass.config_entries.async_schedule_reload(config_entry.entry_id)
|
||||
|
||||
async def async_step_intent_reconfigure(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
@ -749,7 +768,9 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Confirm the user wants to reset their current controller."""
|
||||
if not self._get_reconfigure_entry().data.get(CONF_USE_ADDON):
|
||||
config_entry = self._reconfigure_config_entry
|
||||
assert config_entry is not None
|
||||
if not self._usb_discovery and not config_entry.data.get(CONF_USE_ADDON):
|
||||
return self.async_abort(reason="addon_required")
|
||||
|
||||
if user_input is not None:
|
||||
@ -834,7 +855,8 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle a manual configuration."""
|
||||
config_entry = self._get_reconfigure_entry()
|
||||
config_entry = self._reconfigure_config_entry
|
||||
assert config_entry is not None
|
||||
if user_input is None:
|
||||
return self.async_show_form(
|
||||
step_id="manual_reconfigure",
|
||||
@ -858,14 +880,12 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
# if the controller is reconfigured in a manual step.
|
||||
self._async_update_entry(
|
||||
{
|
||||
**config_entry.data,
|
||||
**user_input,
|
||||
CONF_USE_ADDON: False,
|
||||
CONF_INTEGRATION_CREATED_ADDON: False,
|
||||
}
|
||||
)
|
||||
|
||||
self.hass.config_entries.async_schedule_reload(config_entry.entry_id)
|
||||
return self.async_abort(reason="reconfigure_successful")
|
||||
|
||||
return self.async_show_form(
|
||||
@ -878,7 +898,8 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle logic when on Supervisor host."""
|
||||
config_entry = self._get_reconfigure_entry()
|
||||
config_entry = self._reconfigure_config_entry
|
||||
assert config_entry is not None
|
||||
if user_input is None:
|
||||
return self.async_show_form(
|
||||
step_id="on_supervisor_reconfigure",
|
||||
@ -914,7 +935,6 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Ask for config for Z-Wave JS add-on."""
|
||||
config_entry = self._get_reconfigure_entry()
|
||||
addon_info = await self._async_get_addon_info()
|
||||
addon_config = addon_info.options
|
||||
|
||||
@ -927,8 +947,7 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self.lr_s2_authenticated_key = user_input[CONF_LR_S2_AUTHENTICATED_KEY]
|
||||
self.usb_path = user_input[CONF_USB_PATH]
|
||||
|
||||
new_addon_config = {
|
||||
**addon_config,
|
||||
addon_config_updates = {
|
||||
CONF_ADDON_DEVICE: self.usb_path,
|
||||
CONF_ADDON_S0_LEGACY_KEY: self.s0_legacy_key,
|
||||
CONF_ADDON_S2_ACCESS_CONTROL_KEY: self.s2_access_control_key,
|
||||
@ -942,19 +961,14 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
),
|
||||
}
|
||||
|
||||
if new_addon_config != addon_config:
|
||||
if addon_info.state == AddonState.RUNNING:
|
||||
self.restart_addon = True
|
||||
# Copy the add-on config to keep the objects separate.
|
||||
self.original_addon_config = dict(addon_config)
|
||||
# Remove legacy network_key
|
||||
new_addon_config.pop(CONF_ADDON_NETWORK_KEY, None)
|
||||
await self._async_set_addon_config(new_addon_config)
|
||||
await self._async_set_addon_config(addon_config_updates)
|
||||
|
||||
if addon_info.state == AddonState.RUNNING and not self.restart_addon:
|
||||
return await self.async_step_finish_addon_setup_reconfigure()
|
||||
|
||||
if config_entry.data.get(CONF_USE_ADDON):
|
||||
if (
|
||||
config_entry := self._reconfigure_config_entry
|
||||
) and config_entry.data.get(CONF_USE_ADDON):
|
||||
# Disconnect integration before restarting add-on.
|
||||
await self.hass.config_entries.async_unload(config_entry.entry_id)
|
||||
|
||||
@ -1021,18 +1035,8 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
) -> ConfigFlowResult:
|
||||
"""Choose a serial port."""
|
||||
if user_input is not None:
|
||||
addon_info = await self._async_get_addon_info()
|
||||
addon_config = addon_info.options
|
||||
self.usb_path = user_input[CONF_USB_PATH]
|
||||
new_addon_config = {
|
||||
**addon_config,
|
||||
CONF_ADDON_DEVICE: self.usb_path,
|
||||
}
|
||||
if addon_info.state == AddonState.RUNNING:
|
||||
self.restart_addon = True
|
||||
# Copy the add-on config to keep the objects separate.
|
||||
self.original_addon_config = dict(addon_config)
|
||||
await self._async_set_addon_config(new_addon_config)
|
||||
await self._async_set_addon_config({CONF_ADDON_DEVICE: self.usb_path})
|
||||
return await self.async_step_start_addon()
|
||||
|
||||
try:
|
||||
@ -1050,12 +1054,6 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
step_id="choose_serial_port", data_schema=data_schema
|
||||
)
|
||||
|
||||
async def async_step_start_failed_reconfigure(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Add-on start failed."""
|
||||
return await self.async_revert_addon_config(reason="addon_start_failed")
|
||||
|
||||
async def async_step_backup_failed(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
@ -1082,7 +1080,8 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
Get add-on discovery info and server version info.
|
||||
Check for same unique id and abort if not the same unique id.
|
||||
"""
|
||||
config_entry = self._get_reconfigure_entry()
|
||||
config_entry = self._reconfigure_config_entry
|
||||
assert config_entry is not None
|
||||
if self.revert_reason:
|
||||
self.original_addon_config = None
|
||||
reason = self.revert_reason
|
||||
@ -1108,9 +1107,6 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
self._async_update_entry(
|
||||
{
|
||||
**config_entry.data,
|
||||
# this will only be different in a migration flow
|
||||
"unique_id": str(self.version_info.home_id),
|
||||
CONF_URL: self.ws_address,
|
||||
CONF_USB_PATH: self.usb_path,
|
||||
CONF_S0_LEGACY_KEY: self.s0_legacy_key,
|
||||
@ -1126,8 +1122,6 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
if self.backup_data:
|
||||
return await self.async_step_restore_nvm()
|
||||
|
||||
# Always reload entry since we may have disconnected the client.
|
||||
self.hass.config_entries.async_schedule_reload(config_entry.entry_id)
|
||||
return self.async_abort(reason="reconfigure_successful")
|
||||
|
||||
async def async_revert_addon_config(self, reason: str) -> ConfigFlowResult:
|
||||
@ -1143,9 +1137,9 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
)
|
||||
|
||||
if self.revert_reason or not self.original_addon_config:
|
||||
self.hass.config_entries.async_schedule_reload(
|
||||
self._get_reconfigure_entry().entry_id
|
||||
)
|
||||
config_entry = self._reconfigure_config_entry
|
||||
assert config_entry is not None
|
||||
self.hass.config_entries.async_schedule_reload(config_entry.entry_id)
|
||||
return self.async_abort(reason=reason)
|
||||
|
||||
self.revert_reason = reason
|
||||
@ -1189,11 +1183,11 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
async def _async_restore_network_backup(self) -> None:
|
||||
"""Restore the backup."""
|
||||
assert self.backup_data is not None
|
||||
config_entry = self._reconfigure_config_entry
|
||||
assert config_entry is not None
|
||||
|
||||
# Reload the config entry to reconnect the client after the addon restart
|
||||
await self.hass.config_entries.async_reload(
|
||||
self._get_reconfigure_entry().entry_id
|
||||
)
|
||||
await self.hass.config_entries.async_reload(config_entry.entry_id)
|
||||
|
||||
@callback
|
||||
def forward_progress(event: dict) -> None:
|
||||
@ -1222,7 +1216,8 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
def _get_driver(self) -> Driver:
|
||||
"""Get the driver from the config entry."""
|
||||
config_entry = self._get_reconfigure_entry()
|
||||
config_entry = self._reconfigure_config_entry
|
||||
assert config_entry is not None
|
||||
if config_entry.state != ConfigEntryState.LOADED:
|
||||
raise AbortFlow("Configuration entry is not loaded")
|
||||
client: Client = config_entry.runtime_data[DATA_CLIENT]
|
||||
|
Loading…
x
Reference in New Issue
Block a user