diff --git a/homeassistant/components/flux_led/__init__.py b/homeassistant/components/flux_led/__init__.py index 56f0f371d60..17dc28a5edf 100644 --- a/homeassistant/components/flux_led/__init__.py +++ b/homeassistant/components/flux_led/__init__.py @@ -122,6 +122,13 @@ async def _async_migrate_unique_ids(hass: HomeAssistant, entry: ConfigEntry) -> await er.async_migrate_entries(hass, entry.entry_id, _async_migrator) +async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Handle options update.""" + coordinator: FluxLedUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] + if entry.title != coordinator.title: + await hass.config_entries.async_reload(entry.entry_id) + + async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Flux LED/MagicLight from a config entry.""" host = entry.data[CONF_HOST] @@ -185,6 +192,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: await _async_sync_time() # set at startup entry.async_on_unload(async_track_time_change(hass, _async_sync_time, 2, 40, 30)) + # There must not be any awaits between here and the return + # to avoid a race condition where the add_update_listener is not + # in place in time for the check in async_update_entry_from_discovery + entry.async_on_unload(entry.add_update_listener(_async_update_listener)) return True diff --git a/homeassistant/components/flux_led/coordinator.py b/homeassistant/components/flux_led/coordinator.py index 0a285518c66..5f2c3c097c0 100644 --- a/homeassistant/components/flux_led/coordinator.py +++ b/homeassistant/components/flux_led/coordinator.py @@ -28,6 +28,7 @@ class FluxLedUpdateCoordinator(DataUpdateCoordinator): ) -> None: """Initialize DataUpdateCoordinator to gather data for specific device.""" self.device = device + self.title = entry.title self.entry = entry super().__init__( hass, diff --git a/homeassistant/components/flux_led/discovery.py b/homeassistant/components/flux_led/discovery.py index 34e8b4b0667..70ab8cb3fa5 100644 --- a/homeassistant/components/flux_led/discovery.py +++ b/homeassistant/components/flux_led/discovery.py @@ -24,7 +24,7 @@ from flux_led.scanner import FluxLEDDiscovery from homeassistant import config_entries from homeassistant.components import network -from homeassistant.config_entries import ConfigEntry +from homeassistant.config_entries import ConfigEntry, ConfigEntryState from homeassistant.const import CONF_HOST, CONF_NAME from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import device_registry as dr @@ -142,7 +142,9 @@ def async_update_entry_from_discovery( updates["data"] = {**entry.data, **data_updates} if title_matches_name: del updates["data"][CONF_NAME] - if updates: + # If the title has changed and the config entry is loaded, a listener is + # in place, and we should not reload + if updates and not ("title" in updates and entry.state is ConfigEntryState.LOADED): return hass.config_entries.async_update_entry(entry, **updates) return False diff --git a/tests/components/flux_led/test_init.py b/tests/components/flux_led/test_init.py index 89c5aee73d9..b0a2c5dd33b 100644 --- a/tests/components/flux_led/test_init.py +++ b/tests/components/flux_led/test_init.py @@ -14,7 +14,12 @@ from homeassistant.components.flux_led.const import ( DOMAIN, ) from homeassistant.config_entries import ConfigEntryState -from homeassistant.const import CONF_HOST, CONF_NAME, EVENT_HOMEASSISTANT_STARTED +from homeassistant.const import ( + ATTR_FRIENDLY_NAME, + CONF_HOST, + CONF_NAME, + EVENT_HOMEASSISTANT_STARTED, +) from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from homeassistant.setup import async_setup_component @@ -278,3 +283,30 @@ async def test_name_removed_when_it_matches_entry_title(hass: HomeAssistant) -> await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}}) await hass.async_block_till_done() assert CONF_NAME not in config_entry.data + + +async def test_entry_is_reloaded_when_title_changes(hass: HomeAssistant) -> None: + """Test the entry gets reloaded when the title changes.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + data={ + CONF_REMOTE_ACCESS_HOST: "any", + CONF_REMOTE_ACCESS_ENABLED: True, + CONF_REMOTE_ACCESS_PORT: 1234, + CONF_HOST: IP_ADDRESS, + }, + title=DEFAULT_ENTRY_TITLE, + ) + config_entry.add_to_hass(hass) + with _patch_discovery(), _patch_wifibulb(): + await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}}) + await hass.async_block_till_done() + + hass.config_entries.async_update_entry(config_entry, title="Shop Light") + assert config_entry.title == "Shop Light" + await hass.async_block_till_done() + + assert ( + hass.states.get("light.bulb_rgbcw_ddeeff").attributes[ATTR_FRIENDLY_NAME] + == "Shop Light" + )