Config Flow How to update an existing entity

Hello,

I am developing an integration which is configurable by the GUI (Config Flow).
All works fine and I can create a new integration and update an existing one without problems.

When I update an existing integration, I want to update (or recreate) the associated entity automatically without having to reload the integration (the case now).

My last configuration step in my OptionsFlow implementation is the following:

async def async_end(self):
        """Finalization of the ConfigEntry creation"""
        _LOGGER.debug(
            "CTOR ConfigFlow.async_finalize - updating entry with: %s", self._infos

        self.hass.config_entries.async_update_entry(self.config_entry, data=self._infos)
        return self.async_create_entry(title=None, data=None)

This only change the entry and I wanted to change the associated entity also.

Thank you in advance for you help.

1 Like

You can register an updatehandler for an optionsflow, see Options Flow | Home Assistant Developer Docs

Thank you for your reply.
I have already this but I don’t know how to get the entity to update in the method:

async def update_listener(hass, entry):

to call an entity.update_from_entry(entry.data)

Maybe I’m not in the right direction.

If you have an example, it would help me I guess.

Not sure what the exact problem you are facing is now. You created the entities yourself so you can just call functions in the entity?

I don’t have an example handy, but just search through the Home Assistant code for the update listeners and see if some integration does something like that.

Yes exactly I want to call a function on my entity. But How do i get the entity instance from the config flow ? All I have is an entry.entry_id

I don’t have an example handy, but just search through the Home Assistant code for the update listeners and see if some integration does something like that.

Yes, i will try that.

Thank you

I found something while looking at other integrations but it don’t work either:

async def async_end(self):
        """Finalization of the ConfigEntry creation"""
        _LOGGER.debug(
            "CTOR ConfigFlow.async_finalize - updating entry with: %s", self._infos
        )
        # Find eventual existing entity to update it
        # removing entities from registry (they will be recreated)
        ent_reg = entity_registry.async_get(self.hass)

        for entry in entity_registry.async_entries_for_config_entry(
            ent_reg, self.config_entry.entry_id
        ):
            entity: VersatileThermostat = ent_reg.async_get(entry.entity_id)
            _LOGGER.info("We found entity: %s for update", entity)
-> fails    entity.post_init(self._infos)                                               

        _LOGGER.debug(
            "We have found entities to update: %s", self.config_entry.entry_id
        )

        self.hass.config_entries.async_update_entry(self.config_entry, data=self._infos)
        return self.async_create_entry(title=None, data=None)

It fails at the line indicating with this error:

    return await self.generic_step(
  File "/config/custom_components/versatile_thermostat/config_flow.py", line 257, in generic_step
    return await next_step_function()
  File "/config/custom_components/versatile_thermostat/config_flow.py", line 500, in async_end
    entity.post_init(self._infos)
AttributeError: 'RegistryEntry' object has no attribute 'post_init'

So the EntityRegistry async_get doesn’t return my Entity but a RegistryEntity.
What I need in my Entity of type VersatileThermostat to be able to change attributes in it.

I hope it is more clear.

The entity registry returns an (Entity)RegistryEntry, not an entity instance.

The registry entry is just is a datastructure with info about the entity. I don’t think Home Assistant has a generic way to get access to “random” entity instance objects.

In cases where I needed access to my own entities at a later moment I then, next to adding them to Home Assistant, also stored them in a datastructure which was part of hass.data[MY_DOMAIN] which is practically available everywhere.
None of my current integrations have this mechanism anymore, so no examples unfortunately.

If you just want to delete entities you could have a look at this migration code, but that is almost like you have it already yamaha_ynca/migrations.py at d3fa53a07bf3b04903aced4ff90d7ec2e07b8a83 · mvdwetering/yamaha_ynca · GitHub

BTW, note that users can access the OptionsFlow of an integration even when loading of the integration failed, so there won’t be entity instances to talk to.

Thank you for your valuable answer.

After reading many integrations I found this code which seems to work as expected:

init.py

async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
...
    entry.async_on_unload(entry.add_update_listener(update_listener))

async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
    """Update listener."""
    await hass.config_entries.async_reload(entry.entry_id)

In my config_flow.yaml: (nothing special)

class VersatileThermostatOptionsFlowHandler(OptionsFlow):

    async def async_end(self):
        """Finalization of the ConfigEntry creation"""
        _LOGGER.info(
            "Recreating entry %s due to configuration change",
            self.config_entry.entry_id,
        )
        self.hass.config_entries.async_update_entry(self.config_entry, data=self._infos)
        return self.async_create_entry(title=None, data=None)

In my climate.yaml: nothing special

The magic is at this line: await hass.config_entries.async_reload(entry.entry_id) which remove and recreate the entity with the new configEntry.

That was very hard to find and I wonder why documentation don’t says a word about that.

Many thank’s for your answers which gives me the right way !

… and I remember your last idea:

add in hass.data[MY_DOMAIN] which is practically available everywhere.

2 Likes