diff --git a/homeassistant/components/vizio/config_flow.py b/homeassistant/components/vizio/config_flow.py index 5500ec3db94..04f70da4a8c 100644 --- a/homeassistant/components/vizio/config_flow.py +++ b/homeassistant/components/vizio/config_flow.py @@ -53,6 +53,11 @@ def _get_config_flow_schema(input_dict: Dict[str, Any] = None) -> vol.Schema: ) +def _host_is_same(host1: str, host2: str) -> bool: + """Check if host1 and host2 are the same.""" + return host1.split(":")[0] == host2.split(":")[0] + + class VizioOptionsConfigFlow(config_entries.OptionsFlow): """Handle Transmission client options.""" @@ -108,7 +113,7 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): # Check if new config entry matches any existing config entries for entry in self.hass.config_entries.async_entries(DOMAIN): - if entry.data[CONF_HOST] == user_input[CONF_HOST]: + if _host_is_same(entry.data[CONF_HOST], user_input[CONF_HOST]): errors[CONF_HOST] = "host_exists" break @@ -165,24 +170,31 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Import a config entry from configuration.yaml.""" # Check if new config entry matches any existing config entries for entry in self.hass.config_entries.async_entries(DOMAIN): - if entry.data[CONF_HOST] == import_config[CONF_HOST] and entry.data[ - CONF_NAME - ] == import_config.get(CONF_NAME): + if _host_is_same(entry.data[CONF_HOST], import_config[CONF_HOST]): updated_options = {} + updated_name = {} + + if entry.data[CONF_NAME] != import_config[CONF_NAME]: + updated_name[CONF_NAME] = import_config[CONF_NAME] if entry.data[CONF_VOLUME_STEP] != import_config[CONF_VOLUME_STEP]: updated_options[CONF_VOLUME_STEP] = import_config[CONF_VOLUME_STEP] - if updated_options: + if updated_options or updated_name: new_data = entry.data.copy() - new_data.update(updated_options) new_options = entry.options.copy() - new_options.update(updated_options) + + if updated_name: + new_data.update(updated_name) + + if updated_options: + new_data.update(updated_options) + new_options.update(updated_options) self.hass.config_entries.async_update_entry( entry=entry, data=new_data, options=new_options, ) - return self.async_abort(reason="updated_options") + return self.async_abort(reason="updated_entry") return self.async_abort(reason="already_setup") @@ -199,7 +211,7 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): # Check if new config entry matches any existing config entries and abort if so for entry in self.hass.config_entries.async_entries(DOMAIN): - if entry.data[CONF_HOST] == discovery_info[CONF_HOST]: + if _host_is_same(entry.data[CONF_HOST], discovery_info[CONF_HOST]): return self.async_abort(reason="already_setup") # Set default name to discovered device name by stripping zeroconf service diff --git a/homeassistant/components/vizio/strings.json b/homeassistant/components/vizio/strings.json index 305e49d56f8..64b2fb5f936 100644 --- a/homeassistant/components/vizio/strings.json +++ b/homeassistant/components/vizio/strings.json @@ -21,7 +21,7 @@ "abort": { "already_setup": "This entry has already been setup.", "already_setup_with_diff_host_and_name": "This entry appears to have already been setup with a different host and name based on its serial number. Please remove any old entries from your configuration.yaml and from the Integrations menu before reattempting to add this device.", - "updated_options": "This entry has already been setup but the options defined in the config do not match the previously imported options values so the config entry has been updated accordingly." + "updated_entry": "This entry has already been setup but the name and/or options defined in the config do not match the previously imported config so the config entry has been updated accordingly." } }, "options": { @@ -35,4 +35,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/components/vizio/test_config_flow.py b/tests/components/vizio/test_config_flow.py index 41da5c0267b..069c00bf6b2 100644 --- a/tests/components/vizio/test_config_flow.py +++ b/tests/components/vizio/test_config_flow.py @@ -130,6 +130,30 @@ async def test_user_host_already_configured( assert result["errors"] == {CONF_HOST: "host_exists"} +async def test_user_host_already_configured_no_port( + hass: HomeAssistantType, + vizio_connect: pytest.fixture, + vizio_bypass_setup: pytest.fixture, +) -> None: + """Test host is already configured during user setup when existing entry has no port.""" + # Mock entry without port so we can test that the same entry WITH a port will fail + no_port_entry = MOCK_SPEAKER_CONFIG.copy() + no_port_entry[CONF_HOST] = no_port_entry[CONF_HOST].split(":")[0] + entry = MockConfigEntry( + domain=DOMAIN, data=no_port_entry, options={CONF_VOLUME_STEP: VOLUME_STEP} + ) + entry.add_to_hass(hass) + fail_entry = MOCK_SPEAKER_CONFIG.copy() + fail_entry[CONF_NAME] = "newtestname" + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data=fail_entry + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["errors"] == {CONF_HOST: "host_exists"} + + async def test_user_name_already_configured( hass: HomeAssistantType, vizio_connect: pytest.fixture, @@ -293,13 +317,43 @@ async def test_import_flow_update_options( ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT - assert result["reason"] == "updated_options" + assert result["reason"] == "updated_entry" assert ( hass.config_entries.async_get_entry(entry_id).options[CONF_VOLUME_STEP] == VOLUME_STEP + 1 ) +async def test_import_flow_update_name( + hass: HomeAssistantType, + vizio_connect: pytest.fixture, + vizio_bypass_update: pytest.fixture, +) -> None: + """Test import config flow with updated name.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data=vol.Schema(VIZIO_SCHEMA)(MOCK_IMPORT_VALID_TV_CONFIG), + ) + await hass.async_block_till_done() + + assert result["result"].data[CONF_NAME] == NAME + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + entry_id = result["result"].entry_id + + updated_config = MOCK_IMPORT_VALID_TV_CONFIG.copy() + updated_config[CONF_NAME] = NAME2 + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data=vol.Schema(VIZIO_SCHEMA)(updated_config), + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "updated_entry" + assert hass.config_entries.async_get_entry(entry_id).data[CONF_NAME] == NAME2 + + async def test_zeroconf_flow( hass: HomeAssistantType, vizio_connect: pytest.fixture,