mirror of
https://github.com/home-assistant/core.git
synced 2025-09-07 05:41:32 +02:00
Ask user for Z-Wave RF region if country is missing (#150959)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com> Co-authored-by: TheJulianJES <TheJulianJES@users.noreply.github.com>
This commit is contained in:
committed by
Paulus Schoutsen
parent
2f4e29ba71
commit
2dad6fa298
@@ -35,6 +35,7 @@ from homeassistant.const import CONF_NAME, CONF_URL
|
|||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.data_entry_flow import AbortFlow
|
from homeassistant.data_entry_flow import AbortFlow
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers import selector
|
||||||
from homeassistant.helpers.hassio import is_hassio
|
from homeassistant.helpers.hassio import is_hassio
|
||||||
from homeassistant.helpers.service_info.hassio import HassioServiceInfo
|
from homeassistant.helpers.service_info.hassio import HassioServiceInfo
|
||||||
from homeassistant.helpers.service_info.usb import UsbServiceInfo
|
from homeassistant.helpers.service_info.usb import UsbServiceInfo
|
||||||
@@ -88,6 +89,8 @@ ADDON_USER_INPUT_MAP = {
|
|||||||
CONF_ADDON_LR_S2_AUTHENTICATED_KEY: CONF_LR_S2_AUTHENTICATED_KEY,
|
CONF_ADDON_LR_S2_AUTHENTICATED_KEY: CONF_LR_S2_AUTHENTICATED_KEY,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONF_ADDON_RF_REGION = "rf_region"
|
||||||
|
|
||||||
EXAMPLE_SERVER_URL = "ws://localhost:3000"
|
EXAMPLE_SERVER_URL = "ws://localhost:3000"
|
||||||
ON_SUPERVISOR_SCHEMA = vol.Schema({vol.Optional(CONF_USE_ADDON, default=True): bool})
|
ON_SUPERVISOR_SCHEMA = vol.Schema({vol.Optional(CONF_USE_ADDON, default=True): bool})
|
||||||
MIN_MIGRATION_SDK_VERSION = AwesomeVersion("6.61")
|
MIN_MIGRATION_SDK_VERSION = AwesomeVersion("6.61")
|
||||||
@@ -103,6 +106,19 @@ ZWAVE_JS_UI_MIGRATION_INSTRUCTIONS = (
|
|||||||
"#how-to-migrate-from-one-adapter-to-a-new-adapter-using-z-wave-js-ui"
|
"#how-to-migrate-from-one-adapter-to-a-new-adapter-using-z-wave-js-ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
RF_REGIONS = [
|
||||||
|
"Australia/New Zealand",
|
||||||
|
"China",
|
||||||
|
"Europe",
|
||||||
|
"Hong Kong",
|
||||||
|
"India",
|
||||||
|
"Israel",
|
||||||
|
"Japan",
|
||||||
|
"Korea",
|
||||||
|
"Russia",
|
||||||
|
"USA",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_manual_schema(user_input: dict[str, Any]) -> vol.Schema:
|
def get_manual_schema(user_input: dict[str, Any]) -> vol.Schema:
|
||||||
"""Return a schema for the manual step."""
|
"""Return a schema for the manual step."""
|
||||||
@@ -195,10 +211,12 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
self.backup_data: bytes | None = None
|
self.backup_data: bytes | None = None
|
||||||
self.backup_filepath: Path | None = None
|
self.backup_filepath: Path | None = None
|
||||||
self.use_addon = False
|
self.use_addon = False
|
||||||
|
self._addon_config_updates: dict[str, Any] = {}
|
||||||
self._migrating = False
|
self._migrating = False
|
||||||
self._reconfigure_config_entry: ZwaveJSConfigEntry | None = None
|
self._reconfigure_config_entry: ZwaveJSConfigEntry | None = None
|
||||||
self._usb_discovery = False
|
self._usb_discovery = False
|
||||||
self._recommended_install = False
|
self._recommended_install = False
|
||||||
|
self._rf_region: str | None = None
|
||||||
|
|
||||||
async def async_step_install_addon(
|
async def async_step_install_addon(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
@@ -236,6 +254,21 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
"""Start Z-Wave JS add-on."""
|
"""Start Z-Wave JS add-on."""
|
||||||
|
if self.hass.config.country is None and (
|
||||||
|
not self._rf_region or self._rf_region == "Automatic"
|
||||||
|
):
|
||||||
|
# If the country is not set, we need to check the RF region add-on config.
|
||||||
|
addon_info = await self._async_get_addon_info()
|
||||||
|
rf_region: str | None = addon_info.options.get(CONF_ADDON_RF_REGION)
|
||||||
|
self._rf_region = rf_region
|
||||||
|
if rf_region is None or rf_region == "Automatic":
|
||||||
|
# If the RF region is not set, we need to ask the user to select it.
|
||||||
|
return await self.async_step_rf_region()
|
||||||
|
if config_updates := self._addon_config_updates:
|
||||||
|
# If we have updates to the add-on config, set them before starting the add-on.
|
||||||
|
self._addon_config_updates = {}
|
||||||
|
await self._async_set_addon_config(config_updates)
|
||||||
|
|
||||||
if not self.start_task:
|
if not self.start_task:
|
||||||
self.start_task = self.hass.async_create_task(self._async_start_addon())
|
self.start_task = self.hass.async_create_task(self._async_start_addon())
|
||||||
|
|
||||||
@@ -629,6 +662,33 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
return await self.async_step_on_supervisor({CONF_USE_ADDON: True})
|
return await self.async_step_on_supervisor({CONF_USE_ADDON: True})
|
||||||
return await self.async_step_on_supervisor()
|
return await self.async_step_on_supervisor()
|
||||||
|
|
||||||
|
async def async_step_rf_region(
|
||||||
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
) -> ConfigFlowResult:
|
||||||
|
"""Handle RF region selection step."""
|
||||||
|
if user_input is not None:
|
||||||
|
# Store the selected RF region
|
||||||
|
self._addon_config_updates[CONF_ADDON_RF_REGION] = self._rf_region = (
|
||||||
|
user_input["rf_region"]
|
||||||
|
)
|
||||||
|
return await self.async_step_start_addon()
|
||||||
|
|
||||||
|
schema = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required("rf_region"): selector.SelectSelector(
|
||||||
|
selector.SelectSelectorConfig(
|
||||||
|
options=RF_REGIONS,
|
||||||
|
mode=selector.SelectSelectorMode.DROPDOWN,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="rf_region",
|
||||||
|
data_schema=schema,
|
||||||
|
)
|
||||||
|
|
||||||
async def async_step_on_supervisor(
|
async def async_step_on_supervisor(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
@@ -728,7 +788,7 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
CONF_ADDON_LR_S2_AUTHENTICATED_KEY: self.lr_s2_authenticated_key,
|
CONF_ADDON_LR_S2_AUTHENTICATED_KEY: self.lr_s2_authenticated_key,
|
||||||
}
|
}
|
||||||
|
|
||||||
await self._async_set_addon_config(addon_config_updates)
|
self._addon_config_updates = addon_config_updates
|
||||||
return await self.async_step_start_addon()
|
return await self.async_step_start_addon()
|
||||||
|
|
||||||
# Network already exists, go to security keys step
|
# Network already exists, go to security keys step
|
||||||
@@ -799,7 +859,7 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
CONF_ADDON_LR_S2_AUTHENTICATED_KEY: self.lr_s2_authenticated_key,
|
CONF_ADDON_LR_S2_AUTHENTICATED_KEY: self.lr_s2_authenticated_key,
|
||||||
}
|
}
|
||||||
|
|
||||||
await self._async_set_addon_config(addon_config_updates)
|
self._addon_config_updates = addon_config_updates
|
||||||
return await self.async_step_start_addon()
|
return await self.async_step_start_addon()
|
||||||
|
|
||||||
data_schema = vol.Schema(
|
data_schema = vol.Schema(
|
||||||
@@ -1004,7 +1064,7 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
if self.usb_path:
|
if self.usb_path:
|
||||||
# USB discovery was used, so the device is already known.
|
# USB discovery was used, so the device is already known.
|
||||||
await self._async_set_addon_config({CONF_ADDON_DEVICE: self.usb_path})
|
self._addon_config_updates[CONF_ADDON_DEVICE] = self.usb_path
|
||||||
return await self.async_step_start_addon()
|
return await self.async_step_start_addon()
|
||||||
# Now that the old controller is gone, we can scan for serial ports again
|
# Now that the old controller is gone, we can scan for serial ports again
|
||||||
return await self.async_step_choose_serial_port()
|
return await self.async_step_choose_serial_port()
|
||||||
@@ -1136,6 +1196,8 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
CONF_ADDON_LR_S2_AUTHENTICATED_KEY: self.lr_s2_authenticated_key,
|
CONF_ADDON_LR_S2_AUTHENTICATED_KEY: self.lr_s2_authenticated_key,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addon_config_updates = self._addon_config_updates | addon_config_updates
|
||||||
|
self._addon_config_updates = {}
|
||||||
await self._async_set_addon_config(addon_config_updates)
|
await self._async_set_addon_config(addon_config_updates)
|
||||||
|
|
||||||
if addon_info.state == AddonState.RUNNING and not self.restart_addon:
|
if addon_info.state == AddonState.RUNNING and not self.restart_addon:
|
||||||
@@ -1207,7 +1269,7 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
"""Choose a serial port."""
|
"""Choose a serial port."""
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
self.usb_path = user_input[CONF_USB_PATH]
|
self.usb_path = user_input[CONF_USB_PATH]
|
||||||
await self._async_set_addon_config({CONF_ADDON_DEVICE: self.usb_path})
|
self._addon_config_updates[CONF_ADDON_DEVICE] = self.usb_path
|
||||||
return await self.async_step_start_addon()
|
return await self.async_step_start_addon()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@@ -113,6 +113,16 @@
|
|||||||
"description": "[%key:component::zwave_js::config::step::on_supervisor::description%]",
|
"description": "[%key:component::zwave_js::config::step::on_supervisor::description%]",
|
||||||
"title": "[%key:component::zwave_js::config::step::on_supervisor::title%]"
|
"title": "[%key:component::zwave_js::config::step::on_supervisor::title%]"
|
||||||
},
|
},
|
||||||
|
"rf_region": {
|
||||||
|
"title": "Z-Wave region",
|
||||||
|
"description": "Select the RF region for your Z-Wave network.",
|
||||||
|
"data": {
|
||||||
|
"rf_region": "RF region"
|
||||||
|
},
|
||||||
|
"data_description": {
|
||||||
|
"rf_region": "The radio frequency region for your Z-Wave network. This must match the region of your Z-Wave devices."
|
||||||
|
}
|
||||||
|
},
|
||||||
"start_addon": {
|
"start_addon": {
|
||||||
"title": "Configuring add-on"
|
"title": "Configuring add-on"
|
||||||
},
|
},
|
||||||
|
@@ -198,6 +198,17 @@ def mock_sdk_version(client: MagicMock) -> Generator[None]:
|
|||||||
client.driver.controller.data["sdkVersion"] = original_sdk_version
|
client.driver.controller.data["sdkVersion"] = original_sdk_version
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="set_country", autouse=True)
|
||||||
|
def set_country_fixture(hass: HomeAssistant) -> Generator[None]:
|
||||||
|
"""Set the country for the test."""
|
||||||
|
original_country = hass.config.country
|
||||||
|
# Set a default country to avoid asking the user to select it.
|
||||||
|
hass.config.country = "US"
|
||||||
|
yield
|
||||||
|
# Reset the country after the test.
|
||||||
|
hass.config.country = original_country
|
||||||
|
|
||||||
|
|
||||||
async def test_manual(hass: HomeAssistant) -> None:
|
async def test_manual(hass: HomeAssistant) -> None:
|
||||||
"""Test we create an entry with manual step."""
|
"""Test we create an entry with manual step."""
|
||||||
|
|
||||||
@@ -4601,3 +4612,324 @@ async def test_recommended_usb_discovery(
|
|||||||
}
|
}
|
||||||
assert len(mock_setup.mock_calls) == 1
|
assert len(mock_setup.mock_calls) == 1
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("supervisor", "addon_installed", "addon_info", "unload_entry")
|
||||||
|
async def test_addon_rf_region_new_network(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
setup_entry: AsyncMock,
|
||||||
|
set_addon_options: AsyncMock,
|
||||||
|
start_addon: AsyncMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test RF region selection for new network when country is None."""
|
||||||
|
device = "/test"
|
||||||
|
hass.config.country = None
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.MENU
|
||||||
|
assert result["step_id"] == "installation_type"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], {"next_step_id": "intent_recommended"}
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{
|
||||||
|
"usb_path": device,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "rf_region"
|
||||||
|
|
||||||
|
# Check that all expected RF regions are available
|
||||||
|
|
||||||
|
data_schema = result["data_schema"]
|
||||||
|
assert data_schema is not None
|
||||||
|
schema = data_schema.schema
|
||||||
|
rf_region_field = schema["rf_region"]
|
||||||
|
selector_options = rf_region_field.config["options"]
|
||||||
|
|
||||||
|
expected_regions = [
|
||||||
|
"Australia/New Zealand",
|
||||||
|
"China",
|
||||||
|
"Europe",
|
||||||
|
"Hong Kong",
|
||||||
|
"India",
|
||||||
|
"Israel",
|
||||||
|
"Japan",
|
||||||
|
"Korea",
|
||||||
|
"Russia",
|
||||||
|
"USA",
|
||||||
|
]
|
||||||
|
|
||||||
|
assert selector_options == expected_regions
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], {"rf_region": "Europe"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
|
assert result["step_id"] == "start_addon"
|
||||||
|
|
||||||
|
# Verify RF region was set in addon config
|
||||||
|
assert set_addon_options.call_count == 1
|
||||||
|
assert set_addon_options.call_args == call(
|
||||||
|
"core_zwave_js",
|
||||||
|
AddonsOptions(
|
||||||
|
config={
|
||||||
|
"device": device,
|
||||||
|
"s0_legacy_key": "",
|
||||||
|
"s2_access_control_key": "",
|
||||||
|
"s2_authenticated_key": "",
|
||||||
|
"s2_unauthenticated_key": "",
|
||||||
|
"lr_s2_access_control_key": "",
|
||||||
|
"lr_s2_authenticated_key": "",
|
||||||
|
"rf_region": "Europe",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
assert start_addon.call_count == 1
|
||||||
|
assert start_addon.call_args == call("core_zwave_js")
|
||||||
|
assert setup_entry.call_count == 1
|
||||||
|
|
||||||
|
# avoid unload entry in teardown
|
||||||
|
entry = result["result"]
|
||||||
|
await hass.config_entries.async_unload(entry.entry_id)
|
||||||
|
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("supervisor", "addon_running")
|
||||||
|
async def test_addon_rf_region_migrate_network(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
client: MagicMock,
|
||||||
|
integration: MockConfigEntry,
|
||||||
|
restart_addon: AsyncMock,
|
||||||
|
addon_options: dict[str, Any],
|
||||||
|
set_addon_options: AsyncMock,
|
||||||
|
get_server_version: AsyncMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test migration flow with add-on."""
|
||||||
|
hass.config.country = None
|
||||||
|
version_info = get_server_version.return_value
|
||||||
|
entry = integration
|
||||||
|
assert client.connect.call_count == 1
|
||||||
|
assert client.driver.controller.home_id == 3245146787
|
||||||
|
assert entry.unique_id == "3245146787"
|
||||||
|
hass.config_entries.async_update_entry(
|
||||||
|
entry,
|
||||||
|
data={
|
||||||
|
"url": "ws://localhost:3000",
|
||||||
|
"use_addon": True,
|
||||||
|
"usb_path": "/dev/ttyUSB0",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
addon_options["device"] = "/dev/ttyUSB0"
|
||||||
|
|
||||||
|
async def mock_backup_nvm_raw():
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
client.driver.controller.emit(
|
||||||
|
"nvm backup progress", {"bytesRead": 100, "total": 200}
|
||||||
|
)
|
||||||
|
return b"test_nvm_data"
|
||||||
|
|
||||||
|
client.driver.controller.async_backup_nvm_raw = AsyncMock(
|
||||||
|
side_effect=mock_backup_nvm_raw
|
||||||
|
)
|
||||||
|
|
||||||
|
async def mock_restore_nvm(data: bytes, options: dict[str, bool] | None = None):
|
||||||
|
client.driver.controller.emit(
|
||||||
|
"nvm convert progress",
|
||||||
|
{"event": "nvm convert progress", "bytesRead": 100, "total": 200},
|
||||||
|
)
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
client.driver.controller.emit(
|
||||||
|
"nvm restore progress",
|
||||||
|
{"event": "nvm restore progress", "bytesWritten": 100, "total": 200},
|
||||||
|
)
|
||||||
|
client.driver.controller.data["homeId"] = 3245146787
|
||||||
|
client.driver.emit(
|
||||||
|
"driver ready", {"event": "driver ready", "source": "driver"}
|
||||||
|
)
|
||||||
|
|
||||||
|
client.driver.controller.async_restore_nvm = AsyncMock(side_effect=mock_restore_nvm)
|
||||||
|
|
||||||
|
events = async_capture_events(
|
||||||
|
hass, data_entry_flow.EVENT_DATA_ENTRY_FLOW_PROGRESS_UPDATE
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await entry.start_reconfigure_flow(hass)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.MENU
|
||||||
|
assert result["step_id"] == "reconfigure"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], {"next_step_id": "intent_migrate"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
|
assert result["step_id"] == "backup_nvm"
|
||||||
|
|
||||||
|
with patch("pathlib.Path.write_bytes") as mock_file:
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert client.driver.controller.async_backup_nvm_raw.call_count == 1
|
||||||
|
assert mock_file.call_count == 1
|
||||||
|
assert len(events) == 1
|
||||||
|
assert events[0].data["progress"] == 0.5
|
||||||
|
events.clear()
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "instruct_unplug"
|
||||||
|
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "choose_serial_port"
|
||||||
|
data_schema = result["data_schema"]
|
||||||
|
assert data_schema is not None
|
||||||
|
assert data_schema.schema[CONF_USB_PATH]
|
||||||
|
# Ensure the old usb path is not in the list of options
|
||||||
|
with pytest.raises(InInvalid):
|
||||||
|
data_schema.schema[CONF_USB_PATH](addon_options["device"])
|
||||||
|
|
||||||
|
version_info.home_id = 5678
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={
|
||||||
|
CONF_USB_PATH: "/test",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "rf_region"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], {"rf_region": "Europe"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
|
assert result["step_id"] == "start_addon"
|
||||||
|
assert set_addon_options.call_args == call(
|
||||||
|
"core_zwave_js",
|
||||||
|
AddonsOptions(
|
||||||
|
config={
|
||||||
|
"device": "/test",
|
||||||
|
"rf_region": "Europe",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert restart_addon.call_args == call("core_zwave_js")
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
|
||||||
|
assert entry.unique_id == "5678"
|
||||||
|
version_info.home_id = 3245146787
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
|
assert result["step_id"] == "restore_nvm"
|
||||||
|
assert client.connect.call_count == 2
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert client.connect.call_count == 4
|
||||||
|
assert entry.state is config_entries.ConfigEntryState.LOADED
|
||||||
|
assert client.driver.controller.async_restore_nvm.call_count == 1
|
||||||
|
assert len(events) == 2
|
||||||
|
assert events[0].data["progress"] == 0.25
|
||||||
|
assert events[1].data["progress"] == 0.75
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.ABORT
|
||||||
|
assert result["reason"] == "migration_successful"
|
||||||
|
assert entry.data["url"] == "ws://host1:3001"
|
||||||
|
assert entry.data["usb_path"] == "/test"
|
||||||
|
assert entry.data["use_addon"] is True
|
||||||
|
assert entry.unique_id == "3245146787"
|
||||||
|
assert client.driver.controller.home_id == 3245146787
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("supervisor", "addon_installed", "unload_entry")
|
||||||
|
@pytest.mark.parametrize(("country", "rf_region"), [("US", "Automatic"), (None, "USA")])
|
||||||
|
async def test_addon_skip_rf_region(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
setup_entry: AsyncMock,
|
||||||
|
addon_options: dict[str, Any],
|
||||||
|
set_addon_options: AsyncMock,
|
||||||
|
start_addon: AsyncMock,
|
||||||
|
country: str | None,
|
||||||
|
rf_region: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test RF region selection is skipped if not needed."""
|
||||||
|
device = "/test"
|
||||||
|
addon_options["rf_region"] = rf_region
|
||||||
|
hass.config.country = country
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.MENU
|
||||||
|
assert result["step_id"] == "installation_type"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], {"next_step_id": "intent_recommended"}
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{
|
||||||
|
"usb_path": device,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
|
assert result["step_id"] == "start_addon"
|
||||||
|
|
||||||
|
# Verify RF region was set in addon config
|
||||||
|
assert set_addon_options.call_count == 1
|
||||||
|
assert set_addon_options.call_args == call(
|
||||||
|
"core_zwave_js",
|
||||||
|
AddonsOptions(
|
||||||
|
config={
|
||||||
|
"device": device,
|
||||||
|
"s0_legacy_key": "",
|
||||||
|
"s2_access_control_key": "",
|
||||||
|
"s2_authenticated_key": "",
|
||||||
|
"s2_unauthenticated_key": "",
|
||||||
|
"lr_s2_access_control_key": "",
|
||||||
|
"lr_s2_authenticated_key": "",
|
||||||
|
"rf_region": rf_region,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
assert start_addon.call_count == 1
|
||||||
|
assert start_addon.call_args == call("core_zwave_js")
|
||||||
|
assert setup_entry.call_count == 1
|
||||||
|
|
||||||
|
# avoid unload entry in teardown
|
||||||
|
entry = result["result"]
|
||||||
|
await hass.config_entries.async_unload(entry.entry_id)
|
||||||
|
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
|
||||||
|
Reference in New Issue
Block a user