diff --git a/homeassistant/components/trafikverket_train/__init__.py b/homeassistant/components/trafikverket_train/__init__.py index 3e807df9301..23aee50d816 100644 --- a/homeassistant/components/trafikverket_train/__init__.py +++ b/homeassistant/components/trafikverket_train/__init__.py @@ -2,6 +2,8 @@ from __future__ import annotations +import logging + from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er @@ -11,6 +13,8 @@ from .coordinator import TVDataUpdateCoordinator TVTrainConfigEntry = ConfigEntry[TVDataUpdateCoordinator] +_LOGGER = logging.getLogger(__name__) + async def async_setup_entry(hass: HomeAssistant, entry: TVTrainConfigEntry) -> bool: """Set up Trafikverket Train from a config entry.""" @@ -42,3 +46,24 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: """Handle options update.""" await hass.config_entries.async_reload(entry.entry_id) + + +async def async_migrate_entry(hass: HomeAssistant, entry: TVTrainConfigEntry) -> bool: + """Migrate config entry.""" + _LOGGER.debug("Migrating from version %s", entry.version) + + if entry.version > 1: + # This means the user has downgraded from a future version + return False + + if entry.version == 1 and entry.minor_version == 1: + # Remove unique id + hass.config_entries.async_update_entry(entry, unique_id=None, minor_version=2) + + _LOGGER.debug( + "Migration to version %s.%s successful", + entry.version, + entry.minor_version, + ) + + return True diff --git a/homeassistant/components/trafikverket_train/config_flow.py b/homeassistant/components/trafikverket_train/config_flow.py index f498a7b0d0e..298e6a44f2d 100644 --- a/homeassistant/components/trafikverket_train/config_flow.py +++ b/homeassistant/components/trafikverket_train/config_flow.py @@ -37,7 +37,7 @@ from homeassistant.helpers.selector import ( import homeassistant.util.dt as dt_util from .const import CONF_FILTER_PRODUCT, CONF_FROM, CONF_TIME, CONF_TO, DOMAIN -from .util import create_unique_id, next_departuredate +from .util import next_departuredate _LOGGER = logging.getLogger(__name__) @@ -125,6 +125,7 @@ class TVTrainConfigFlow(ConfigFlow, domain=DOMAIN): """Handle a config flow for Trafikverket Train integration.""" VERSION = 1 + MINOR_VERSION = 2 @staticmethod @callback @@ -202,11 +203,16 @@ class TVTrainConfigFlow(ConfigFlow, domain=DOMAIN): filter_product, ) if not errors: - unique_id = create_unique_id( - train_from, train_to, train_time, train_days + self._async_abort_entries_match( + { + CONF_API_KEY: api_key, + CONF_FROM: train_from, + CONF_TO: train_to, + CONF_TIME: train_time, + CONF_WEEKDAY: train_days, + CONF_FILTER_PRODUCT: filter_product, + } ) - await self.async_set_unique_id(unique_id) - self._abort_if_unique_id_configured() return self.async_create_entry( title=name, data={ diff --git a/homeassistant/components/trafikverket_train/util.py b/homeassistant/components/trafikverket_train/util.py index 9648436f1e5..9a8dd9ea237 100644 --- a/homeassistant/components/trafikverket_train/util.py +++ b/homeassistant/components/trafikverket_train/util.py @@ -2,22 +2,11 @@ from __future__ import annotations -from datetime import date, time, timedelta +from datetime import date, timedelta from homeassistant.const import WEEKDAYS -def create_unique_id( - from_station: str, to_station: str, depart_time: time | str | None, weekdays: list -) -> str: - """Create unique id.""" - timestr = str(depart_time) if depart_time else "" - return ( - f"{from_station.casefold().replace(' ', '')}-{to_station.casefold().replace(' ', '')}" - f"-{timestr.casefold().replace(' ', '')}-{weekdays!s}" - ) - - def next_weekday(fromdate: date, weekday: int) -> date: """Return the date of the next time a specific weekday happen.""" days_ahead = weekday - fromdate.weekday() diff --git a/tests/components/trafikverket_train/conftest.py b/tests/components/trafikverket_train/conftest.py index 14671d27252..2fa5d099ee9 100644 --- a/tests/components/trafikverket_train/conftest.py +++ b/tests/components/trafikverket_train/conftest.py @@ -50,7 +50,8 @@ async def load_integration_from_entry( data=ENTRY_CONFIG, options=OPTIONS_CONFIG, entry_id="1", - unique_id="stockholmc-uppsalac--['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']", + version=1, + minor_version=2, ) config_entry.add_to_hass(hass) await setup_config_entry_with_mocked_data(config_entry.entry_id) @@ -60,7 +61,8 @@ async def load_integration_from_entry( source=SOURCE_USER, data=ENTRY_CONFIG2, entry_id="2", - unique_id="stockholmc-uppsalac-1100-['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']", + version=1, + minor_version=2, ) config_entry2.add_to_hass(hass) await setup_config_entry_with_mocked_data(config_entry2.entry_id) diff --git a/tests/components/trafikverket_train/snapshots/test_init.ambr b/tests/components/trafikverket_train/snapshots/test_init.ambr index c32995fdb76..2b3693eddc1 100644 --- a/tests/components/trafikverket_train/snapshots/test_init.ambr +++ b/tests/components/trafikverket_train/snapshots/test_init.ambr @@ -7,7 +7,7 @@ 'title_placeholders': dict({ 'name': 'Mock Title', }), - 'unique_id': '321', + 'unique_id': None, }), 'flow_id': , 'handler': 'trafikverket_train', diff --git a/tests/components/trafikverket_train/snapshots/test_sensor.ambr b/tests/components/trafikverket_train/snapshots/test_sensor.ambr index cae0457bbff..6caf1f86b51 100644 --- a/tests/components/trafikverket_train/snapshots/test_sensor.ambr +++ b/tests/components/trafikverket_train/snapshots/test_sensor.ambr @@ -222,7 +222,7 @@ 'title_placeholders': dict({ 'name': 'Mock Title', }), - 'unique_id': "stockholmc-uppsalac--['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']", + 'unique_id': None, }), 'flow_id': , 'handler': 'trafikverket_train', diff --git a/tests/components/trafikverket_train/test_config_flow.py b/tests/components/trafikverket_train/test_config_flow.py index 9fe02994f05..d75ad5d1b46 100644 --- a/tests/components/trafikverket_train/test_config_flow.py +++ b/tests/components/trafikverket_train/test_config_flow.py @@ -16,6 +16,7 @@ from pytrafikverket.models import TrainStopModel from homeassistant import config_entries from homeassistant.components.trafikverket_train.const import ( + CONF_FILTER_PRODUCT, CONF_FROM, CONF_TIME, CONF_TO, @@ -73,7 +74,6 @@ async def test_form(hass: HomeAssistant) -> None: } assert result["options"] == {"filter_product": None} assert len(mock_setup_entry.mock_calls) == 1 - assert result["result"].unique_id == "stockholmc-uppsalac-10:00-['mon', 'fri']" async def test_form_entry_already_exist(hass: HomeAssistant) -> None: @@ -88,8 +88,10 @@ async def test_form_entry_already_exist(hass: HomeAssistant) -> None: CONF_TO: "Uppsala C", CONF_TIME: "10:00", CONF_WEEKDAY: WEEKDAYS, + CONF_FILTER_PRODUCT: None, }, - unique_id=f"stockholmc-uppsalac-10:00-{WEEKDAYS}", + version=1, + minor_version=2, ) entry.add_to_hass(hass) @@ -240,7 +242,8 @@ async def test_reauth_flow(hass: HomeAssistant) -> None: CONF_TIME: "10:00", CONF_WEEKDAY: WEEKDAYS, }, - unique_id=f"stockholmc-uppsalac-10:00-{WEEKDAYS}", + version=1, + minor_version=2, ) entry.add_to_hass(hass) @@ -314,7 +317,8 @@ async def test_reauth_flow_error( CONF_TIME: "10:00", CONF_WEEKDAY: WEEKDAYS, }, - unique_id=f"stockholmc-uppsalac-10:00-{WEEKDAYS}", + version=1, + minor_version=2, ) entry.add_to_hass(hass) @@ -396,7 +400,8 @@ async def test_reauth_flow_error_departures( CONF_TIME: "10:00", CONF_WEEKDAY: WEEKDAYS, }, - unique_id=f"stockholmc-uppsalac-10:00-{WEEKDAYS}", + version=1, + minor_version=2, ) entry.add_to_hass(hass) @@ -467,7 +472,8 @@ async def test_options_flow( CONF_TIME: "10:00", CONF_WEEKDAY: WEEKDAYS, }, - unique_id=f"stockholmc-uppsalac-10:00-{WEEKDAYS}", + version=1, + minor_version=2, ) entry.add_to_hass(hass) diff --git a/tests/components/trafikverket_train/test_init.py b/tests/components/trafikverket_train/test_init.py index c8fea174e83..972e6bffbb4 100644 --- a/tests/components/trafikverket_train/test_init.py +++ b/tests/components/trafikverket_train/test_init.py @@ -28,7 +28,8 @@ async def test_unload_entry( data=ENTRY_CONFIG, options=OPTIONS_CONFIG, entry_id="1", - unique_id="321", + version=1, + minor_version=2, ) entry.add_to_hass(hass) @@ -64,7 +65,8 @@ async def test_auth_failed( data=ENTRY_CONFIG, options=OPTIONS_CONFIG, entry_id="1", - unique_id="321", + version=1, + minor_version=2, ) entry.add_to_hass(hass) @@ -94,7 +96,8 @@ async def test_no_stations( data=ENTRY_CONFIG, options=OPTIONS_CONFIG, entry_id="1", - unique_id="321", + version=1, + minor_version=2, ) entry.add_to_hass(hass) @@ -121,7 +124,8 @@ async def test_migrate_entity_unique_id( data=ENTRY_CONFIG, options=OPTIONS_CONFIG, entry_id="1", - unique_id="321", + version=1, + minor_version=2, ) entry.add_to_hass(hass) @@ -149,3 +153,69 @@ async def test_migrate_entity_unique_id( entity = entity_registry.async_get(entity.entity_id) assert entity.unique_id == f"{entry.entry_id}-departure_time" + + +async def test_migrate_entry( + hass: HomeAssistant, + get_trains: list[TrainStopModel], +) -> None: + """Test migrate entry unique id.""" + entry = MockConfigEntry( + domain=DOMAIN, + source=SOURCE_USER, + data=ENTRY_CONFIG, + options=OPTIONS_CONFIG, + version=1, + minor_version=1, + entry_id="1", + unique_id="321", + ) + entry.add_to_hass(hass) + + with ( + patch( + "homeassistant.components.trafikverket_train.coordinator.TrafikverketTrain.async_get_train_station", + ), + patch( + "homeassistant.components.trafikverket_train.coordinator.TrafikverketTrain.async_get_next_train_stops", + return_value=get_trains, + ), + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.state is ConfigEntryState.LOADED + + assert entry.version == 1 + assert entry.minor_version == 2 + assert entry.unique_id is None + + +async def test_migrate_entry_from_future_version_fails( + hass: HomeAssistant, + get_trains: list[TrainStopModel], +) -> None: + """Test migrate entry from future version fails.""" + entry = MockConfigEntry( + domain=DOMAIN, + source=SOURCE_USER, + data=ENTRY_CONFIG, + options=OPTIONS_CONFIG, + version=2, + entry_id="1", + ) + entry.add_to_hass(hass) + + with ( + patch( + "homeassistant.components.trafikverket_train.coordinator.TrafikverketTrain.async_get_train_station", + ), + patch( + "homeassistant.components.trafikverket_train.coordinator.TrafikverketTrain.async_get_next_train_stops", + return_value=get_trains, + ), + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.state is ConfigEntryState.MIGRATION_ERROR