Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entity name not refreshing automatically in Lovelace UI for device-grouped entities #23420

Open
4 tasks done
virtualdj opened this issue Dec 23, 2024 · 0 comments
Open
4 tasks done

Comments

@virtualdj
Copy link

Checklist

  • I have updated to the latest available Home Assistant version.
  • I have cleared the cache of my browser.
  • I have tried a different browser to see if it is related to my browser.
  • I have tried reproducing the issue in safe mode to rule out problems with unsupported custom resources.

Describe the issue you are experiencing

When entities are grouped into a device, their names do not update in real-time in the Overview dashboard of the Lovelace UI, while their values do update correctly. The same entities update their names instantly when not grouped into a device, or when included in a custom dashboard (i.e. not the Overview).

This appears to be a Lovelace frontend issue since:

  • Entity values update correctly in real-time regardless of device grouping
  • Entity names update correctly in the More Info dialog
  • Entity names update instantly when not grouped in a device
  • Entity names only update in the UI for device-grouped entities after a page refresh/navigation
  • The issue happens only in the Overview dashboard where entities are added automatically

Describe the behavior you expected

The grouped entities should update their name instantly like the non-grouped entity does, or like they do when not in the Overview dashboard.

Steps to reproduce the issue

  1. Create a custom integration with this minimal example below
  2. Add the integration to the UI, so that three entities are added to the Overview dashboard: one standalone and two grouped in a device
  3. Wait for the coordinator to update the data (every 10 seconds) without switching page
  4. Observe the behavior in Lovelace UI using standard Entity cards: EntityOne gets its name refreshed automatically, while EntityTwo and EntityThree do not (as they're included in a device called Prefix)

Only the entity that doesn't belong to a device (i.e. EntityOne) gets its name refreshed automatically

Test Integration Code

File: manifest.json

{
  "domain": "entity_name_test",
  "name": "Entity Name Test",
  "config_flow": true,
  "dependencies": [],
  "import_executor": true,
  "integration_type": "hub",
  "iot_class": "cloud_polling",
  "loggers": ["entity_name_test"],
  "requirements": [],
  "single_config_entry": true,
  "version": "0.0.0"
}

File: __init__.py

"""Entity Names UI Refreshing Test."""

from datetime import timedelta
import logging

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

DOMAIN: str = "entity_name_test"

_LOGGER = logging.getLogger(__name__)

PLATFORMS: list[str] = ["sensor"]


async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry) -> bool:
    """Integration setup."""

    # Initialize the coordinator
    coordinator = TestCoordinator(hass, config)
    hass.data.setdefault(DOMAIN, {})[config.entry_id] = coordinator

    # Create the entities
    await hass.config_entries.async_forward_entry_setups(config, PLATFORMS)

    return True


async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool:
    """Integration removed."""

    # Unload the sensors
    unload_ok = await hass.config_entries.async_unload_platforms(config, PLATFORMS)
    if unload_ok:
        hass.data[DOMAIN].pop(config.entry_id)

    return unload_ok


class TestCoordinator(DataUpdateCoordinator):
    """Coordinator to update data."""

    def __init__(self, hass: HomeAssistant, config: ConfigEntry) -> None:
        """Initialization."""
        super().__init__(
            hass, _LOGGER, name=DOMAIN, update_interval=timedelta(seconds=10)
        )

        # Variables initialization
        self.value_counter: int = 1
        self.name_counter: int = 2
        _LOGGER.debug("Coordinator initialized.")

    async def _async_update_data(self):
        """Updates the data."""

        # Increment variables
        self.value_counter += 2
        self.name_counter += 2
        _LOGGER.debug(
            "Coordinator updated data (value counter: %d, name counter: %d).",
            self.value_counter,
            self.name_counter,
        )

        # Notify update
        self.async_set_updated_data({})

File: config_flow.py

"""Configuration UI."""

from homeassistant import config_entries

from . import DOMAIN


class EntityNameTestConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
    """Configuration."""

    async def async_step_user(self, user_input=None):
        """Home Assistant UI configuration."""
        # Avoid multiple instances
        await self.async_set_unique_id(DOMAIN)
        self._abort_if_unique_id_configured()

        if user_input is not None:
            return self.async_create_entry(title="Entity Name Test", data=user_input)
        return self.async_show_form(step_id="user")

File: sensor.py

"""Sensors implementation."""

from homeassistant.components.sensor import ENTITY_ID_FORMAT, SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import DiscoveryInfoType
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from . import DOMAIN, TestCoordinator


async def async_setup_entry(
    hass: HomeAssistant,
    config: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
    discovery_info: DiscoveryInfoType | None = None,
) -> None:
    """Initializes and creates the sensors."""

    # Get the coordinator
    coordinator = hass.data[DOMAIN][config.entry_id]

    # Create the entitites
    entities: list[SensorEntity] = []
    entities.append(EntityOne(coordinator))
    entities.append(EntityTwo(coordinator))
    entities.append(EntityThree(coordinator))
    async_add_entities(entities, update_before_add=False)


class EntityOne(CoordinatorEntity, SensorEntity):
    """Sensor with name and value changing, NOT in a device."""

    def __init__(self, coordinator: TestCoordinator) -> None:
        super().__init__(coordinator)

        self.coordinator: TestCoordinator = coordinator
        self.entity_id = ENTITY_ID_FORMAT.format("entity_one")
        self._attr_unique_id = self.entity_id
        self._attr_has_entity_name = True
        self._attr_name = "Entity One"
        self._attr_available = False
        self._attr_native_value: int = 0
        self._attr_should_poll = False

    def _handle_coordinator_update(self) -> None:
        """Receives data from coordinator."""

        if self.coordinator.value_counter > 0:
            self._attr_native_value = self.coordinator.value_counter
            self._attr_name = f"Entity One ({self.coordinator.name_counter})"
            self._attr_available = True
        else:
            self._attr_name = "Entity One"
            self._attr_available = False

        # Update Home Assistant status
        self.async_write_ha_state()


class EntityTwo(CoordinatorEntity, SensorEntity):
    """Sensor with name and value changing inside a device."""

    def __init__(self, coordinator: TestCoordinator) -> None:
        super().__init__(coordinator)

        self.coordinator: TestCoordinator = coordinator
        self.entity_id = ENTITY_ID_FORMAT.format("entity_two")
        self._attr_unique_id = self.entity_id
        self._attr_has_entity_name = True
        self._attr_name = "Entity Two in a device"
        self._attr_available = False
        self._attr_native_value: int = 0
        self._attr_should_poll = False

        # This belongs to a device
        self._attr_device_info: DeviceInfo = {
            "identifiers": {(DOMAIN, "")},
            "manufacturer": "Me, a developer",
            "name": "Prefix",
        }

    def _handle_coordinator_update(self) -> None:
        """Receives data from coordinator."""

        if self.coordinator.value_counter > 0:
            self._attr_native_value = self.coordinator.value_counter
            self._attr_name = (
                f"Entity Two in a device ({self.coordinator.name_counter})"
            )
            self._attr_available = True
        else:
            self._attr_name = "Entity Two in a device"
            self._attr_available = False

        # Update Home Assistant status
        self.async_write_ha_state()


class EntityThree(CoordinatorEntity, SensorEntity):
    """Another Sensor with name and value changing inside a device."""

    def __init__(self, coordinator: TestCoordinator) -> None:
        super().__init__(coordinator)

        self.coordinator: TestCoordinator = coordinator
        self.entity_id = ENTITY_ID_FORMAT.format("entity_three")
        self._attr_unique_id = self.entity_id
        self._attr_has_entity_name = True
        self._attr_name = "Entity Three in a device"
        self._attr_available = False
        self._attr_native_value: int = 0
        self._attr_should_poll = False

        # This belongs to a device
        self._attr_device_info: DeviceInfo = {
            "identifiers": {(DOMAIN, "")},
            "manufacturer": "Me, a developer",
            "name": "Prefix",
        }

    def _handle_coordinator_update(self) -> None:
        """Receives data from coordinator."""

        if self.coordinator.value_counter > 0:
            self._attr_native_value = self.coordinator.value_counter
            self._attr_name = (
                f"Entity Three in a device ({self.coordinator.name_counter})"
            )
            self._attr_available = True
        else:
            self._attr_name = "Entity Three in a device"
            self._attr_available = False

        # Update Home Assistant status (different method)
        self.async_schedule_update_ha_state()

What version of Home Assistant Core has the issue?

core-2024.11.1

What was the last working version of Home Assistant Core?

No response

In which browser are you experiencing the issue with?

Microsoft Edge 131.0.2903.112

Which operating system are you using to run this browser?

Windows 10 22H2 19045.5247

State of relevant entities

No response

Problem-relevant frontend configuration

No response

Javascript errors shown in your browser console/inspector

No response

Additional information

Adding the three entities to a custom dashboard does not result in any issue. The name is refreshed instantly, like the value does.

Custom dashboard with the same entities

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant