Custom component: On reload platform does not generate unique IDs

I’m developing a custom component to create time-weighted averages for sensors and I want to add a “reload” service to it.
I’ve followed examples of internal integrations implementing the reload service, however for mine, when I reload my integration I get the following errors:

2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID 4C474192-D82F-4B8A-B081-DAE64D39AFA1 is already used by sensor.average_voltage_house - ignoring sensor.average_voltage_house
2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID E5A4A70E-EAAA-4343-8A56-D8F4F5BAFEA4 is already used by sensor.average_power_lights - ignoring sensor.average_power_lights
2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID 834112F8-F527-47BB-B039-245B7EA8F062 is already used by sensor.average_total_energy_lights - ignoring sensor.average_total_energy_lights
2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID 857F18BC-ABBC-4D59-859C-B055BAE841C6 is already used by sensor.average_power_house - ignoring sensor.average_power_house
2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID 1A4B22F9-1948-446B-8102-FCF86AE1BB2A is already used by sensor.average_power_garden - ignoring sensor.average_power_garden
2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID E64E9086-D39C-45AB-81D1-9BD981EC1938 is already used by sensor.average_power_garden_lights - ignoring sensor.average_power_garden_lights
2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID D64AA081-BDD8-4884-9FE1-639BECC28934 is already used by sensor.average_power_rack - ignoring sensor.average_power_rack
2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID 124A9181-0136-479C-BD3C-CE8453EBC391 is already used by sensor.average_power_heater - ignoring sensor.average_power_heater
2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID 372D6073-AD9F-4FD9-9A5C-802A3DBF99F2 is already used by sensor.average_power_heat_pump - ignoring sensor.average_power_heat_pump
2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID 3AD5AA46-2862-4036-BC08-CB3E49DC59D2 is already used by sensor.average_power_washer - ignoring sensor.average_power_washer
2022-05-23 15:13:23 ERROR (MainThread) [homeassistant.components.sensor] Platform tw_average does not generate unique IDs. ID BD8FC531-30BD-400D-8C05-D3FE1EF9B51D is already used by sensor.average_power_bedroom_tv - ignoring sensor.average_power_bedroom_tv

Here’s the setup platform section of the code:

from homeassistant.helpers.reload import async_setup_reload_service

DOMAIN = "tw_average"
PLATFORMS = [Platform.SENSOR]

async def async_setup_platform(
    hass: HomeAssistant,
    config: ConfigType,
    async_add_entities: AddEntitiesCallback,
    discovery_info: DiscoveryInfoType = None,
) -> None:
    """Set up the time-weighted average sensors."""

    await async_setup_reload_service(hass, DOMAIN, PLATFORMS)

    platform_scan_interval = config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL)
    platform_unit_of_measurement = config.get(CONF_UNIT_OF_MEASUREMENT)
    platform_icon = config.get(CONF_ICON)
    platform_precision = config.get(CONF_PRECISION)
    platform_device_class = config.get(CONF_DEVICE_CLASS)
    platform_state_class = config.get(CONF_STATE_CLASS)
    platform_extremas = config.get(CONF_EXTREMAS)
    platform_method = config.get(CONF_METHOD)
    platform_total_method = config.get(CONF_TOTAL_METHOD)
    devices = config.get(CONF_SENSORS, {})
    sensors = []

    for object_id, device_config in devices.items():
        _LOGGER.info("Setting up %s with scan_interval %s", object_id, platform_scan_interval)
        sensors.append(
            TwAverageSensor(
                hass,
                platform_scan_interval,
                object_id,
                device_config.get(CONF_UNIQUE_ID),
                device_config.get(CONF_FRIENDLY_NAME, object_id),
                device_config.get(CONF_UNIT_OF_MEASUREMENT, platform_unit_of_measurement),
                device_config.get(CONF_ICON, platform_icon),
                device_config.get(CONF_ENTITIES),
                device_config.get(CONF_PRECISION, platform_precision),
                device_config.get(CONF_DEVICE_CLASS, platform_device_class),
                device_config.get(CONF_STATE_CLASS, platform_state_class),
                device_config.get(CONF_EXTREMAS, platform_extremas),
                device_config.get(CONF_METHOD, platform_method),
                device_config.get(CONF_TOTAL_METHOD, platform_total_method),
            )
        )

    if not sensors:
        _LOGGER.error("No sensors added")
        return

    async_add_entities(sensors)

And the YAML configuration for the entities in the log:

sensor:
  - platform: tw_average
    scan_interval: 10
    precision: 0
    unit_of_measurement: V
    sensors:
      average_voltage_house:
        unique_id: 4C474192-D82F-4B8A-B081-DAE64D39AFA1
        friendly_name: Average House Voltage
        entities: sensor.em_house_voltage

  - platform: tw_average
    scan_interval: 60
    precision: 0
    unit_of_measurement: W
    device_class: power
    sensors:
      average_power_lights:
        unique_id: E5A4A70E-EAAA-4343-8A56-D8F4F5BAFEA4
        friendly_name: Average Lights Power
        entities: group.energy_lights_power

      average_total_energy_lights:
        unique_id: 834112F8-F527-47BB-B039-245B7EA8F062
        friendly_name: Average Lights Total Energy
        unit_of_measurement: kWh
        state_class: total_increasing
        device_class: energy
        precision: 3
        entities: group.energy_lights_total_energy

      average_power_house:
        unique_id: 857F18BC-ABBC-4D59-859C-B055BAE841C6
        friendly_name: Average House Power
        entities: sensor.em_house_power

      average_power_garden:
        unique_id: 1A4B22F9-1948-446B-8102-FCF86AE1BB2A
        friendly_name: Average Garden Power
        entities: sensor.em_garden_power

      average_power_garden_lights:
        unique_id: E64E9086-D39C-45AB-81D1-9BD981EC1938
        friendly_name: Average Garden Lights Power
        entities: sensor.garden_power

      average_power_rack:
        unique_id: D64AA081-BDD8-4884-9FE1-639BECC28934
        friendly_name: Average Rack Power
        entities: sensor.rack_power

      average_power_heater:
        unique_id: 124A9181-0136-479C-BD3C-CE8453EBC391
        friendly_name: Average Heater Power
        entities: sensor.heater_power

      average_power_heat_pump:
        unique_id: 372D6073-AD9F-4FD9-9A5C-802A3DBF99F2
        friendly_name: Average Heat Pump Power
        entities: sensor.heat_pump_power

      average_power_washer:
        unique_id: 3AD5AA46-2862-4036-BC08-CB3E49DC59D2
        friendly_name: Average Washer Power
        entities: sensor.washer_power

      average_power_bedroom_tv:
        unique_id: BD8FC531-30BD-400D-8C05-D3FE1EF9B51D
        friendly_name: Average Bedroom TV Power
        entities: sensor.bedroom_tv_socket_energy_power

I’m using separate platforms in YAML to specify different platform level options for different set of sensors (like scan interval).

The complete code is here: GitHub - clau-bucur/ha-tw-average: Time-weighted average custom component sensor for Home Assistant

Can anyone point out what is the issue that the reload is not working as expected? Thanks!

On reload you first have to unload all the existing sensors.

Thanks for the reply.
How do I do that? I don’t see the other integrations, I looked at, do that. Eg.: history_stats.

I’m not sure how to do it for your scenario. I use the config entries for my integration. There is a callback like this that calls async_unload_platforms. I’d search the code base for this, see if there is a variation for non config entry based integrations.


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Unload a config entry."""
    _LOGGER.debug(f"async_unload_entry entry [{entry.unique_id}]")
    unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
    if unload_ok == True:
        entry_data = hass.data[DOMAIN].pop(entry.unique_id)
        manager: Manager = entry_data[MANAGER]
        try:
            await manager.async_shutdown(None)
        except S30Exception as e:
            _LOGGER.error(
                f"async_unload_entry entry [{entry.unique_id}] error [{e.as_string()}]"
            )
        except Exception as e:
            _LOGGER.exception(f"async_unload_entry entry [{entry.unique_id}]")
        return True
    else:
        _LOGGER.error(
            f"async_unload_entry call to hass.config_entries.async_unload_platforms returned False"
        )
        return False

Indeed, that’s the case I suspected and looks like it’s not applying in my case.
Can’t find any variation for the non-config entry based integrations.