Use entity base class for NextDNS entities (#146934)

* Add entity module

* Add NextDnsEntityDescription class

* Remove NextDnsEntityDescription

* Create DeviceInfo in entity module

* Use property
This commit is contained in:
Maciej Bieniek 2025-06-16 16:58:47 +02:00 committed by GitHub
parent 421251308f
commit 4add783108
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 54 additions and 85 deletions

View File

@ -13,12 +13,11 @@ from homeassistant.components.binary_sensor import (
BinarySensorEntityDescription, BinarySensorEntityDescription,
) )
from homeassistant.const import EntityCategory from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import NextDnsConfigEntry from . import NextDnsConfigEntry
from .coordinator import NextDnsUpdateCoordinator from .entity import NextDnsEntity
PARALLEL_UPDATES = 0 PARALLEL_UPDATES = 0
@ -61,30 +60,14 @@ async def async_setup_entry(
) )
class NextDnsBinarySensor( class NextDnsBinarySensor(NextDnsEntity, BinarySensorEntity):
CoordinatorEntity[NextDnsUpdateCoordinator[ConnectionStatus]], BinarySensorEntity
):
"""Define an NextDNS binary sensor.""" """Define an NextDNS binary sensor."""
_attr_has_entity_name = True
entity_description: NextDnsBinarySensorEntityDescription entity_description: NextDnsBinarySensorEntityDescription
def __init__( @property
self, def is_on(self) -> bool:
coordinator: NextDnsUpdateCoordinator[ConnectionStatus], """Return True if the binary sensor is on."""
description: NextDnsBinarySensorEntityDescription, return self.entity_description.state(
) -> None:
"""Initialize."""
super().__init__(coordinator)
self._attr_device_info = coordinator.device_info
self._attr_unique_id = f"{coordinator.profile_id}_{description.key}"
self._attr_is_on = description.state(coordinator.data, coordinator.profile_id)
self.entity_description = description
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._attr_is_on = self.entity_description.state(
self.coordinator.data, self.coordinator.profile_id self.coordinator.data, self.coordinator.profile_id
) )
self.async_write_ha_state()

View File

@ -4,21 +4,21 @@ from __future__ import annotations
from aiohttp import ClientError from aiohttp import ClientError
from aiohttp.client_exceptions import ClientConnectorError from aiohttp.client_exceptions import ClientConnectorError
from nextdns import AnalyticsStatus, ApiError, InvalidApiKeyError from nextdns import ApiError, InvalidApiKeyError
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.const import EntityCategory from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import NextDnsConfigEntry from . import NextDnsConfigEntry
from .const import DOMAIN from .const import DOMAIN
from .coordinator import NextDnsUpdateCoordinator from .entity import NextDnsEntity
PARALLEL_UPDATES = 1 PARALLEL_UPDATES = 1
CLEAR_LOGS_BUTTON = ButtonEntityDescription( CLEAR_LOGS_BUTTON = ButtonEntityDescription(
key="clear_logs", key="clear_logs",
translation_key="clear_logs", translation_key="clear_logs",
@ -37,24 +37,9 @@ async def async_setup_entry(
async_add_entities([NextDnsButton(coordinator, CLEAR_LOGS_BUTTON)]) async_add_entities([NextDnsButton(coordinator, CLEAR_LOGS_BUTTON)])
class NextDnsButton( class NextDnsButton(NextDnsEntity, ButtonEntity):
CoordinatorEntity[NextDnsUpdateCoordinator[AnalyticsStatus]], ButtonEntity
):
"""Define an NextDNS button.""" """Define an NextDNS button."""
_attr_has_entity_name = True
def __init__(
self,
coordinator: NextDnsUpdateCoordinator[AnalyticsStatus],
description: ButtonEntityDescription,
) -> None:
"""Initialize."""
super().__init__(coordinator)
self._attr_device_info = coordinator.device_info
self._attr_unique_id = f"{coordinator.profile_id}_{description.key}"
self.entity_description = description
async def async_press(self) -> None: async def async_press(self) -> None:
"""Trigger cleaning logs.""" """Trigger cleaning logs."""
try: try:

View File

@ -24,7 +24,6 @@ from tenacity import RetryError
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
if TYPE_CHECKING: if TYPE_CHECKING:
@ -53,14 +52,6 @@ class NextDnsUpdateCoordinator(DataUpdateCoordinator[CoordinatorDataT]):
"""Initialize.""" """Initialize."""
self.nextdns = nextdns self.nextdns = nextdns
self.profile_id = profile_id self.profile_id = profile_id
self.profile_name = nextdns.get_profile_name(profile_id)
self.device_info = DeviceInfo(
configuration_url=f"https://my.nextdns.io/{profile_id}/setup",
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, str(profile_id))},
manufacturer="NextDNS Inc.",
name=self.profile_name,
)
super().__init__( super().__init__(
hass, hass,

View File

@ -0,0 +1,31 @@
"""Define NextDNS entities."""
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import CoordinatorDataT, NextDnsUpdateCoordinator
class NextDnsEntity(CoordinatorEntity[NextDnsUpdateCoordinator[CoordinatorDataT]]):
"""Define NextDNS entity."""
_attr_has_entity_name = True
def __init__(
self,
coordinator: NextDnsUpdateCoordinator[CoordinatorDataT],
description: EntityDescription,
) -> None:
"""Initialize."""
super().__init__(coordinator)
self._attr_device_info = DeviceInfo(
configuration_url=f"https://my.nextdns.io/{coordinator.profile_id}/setup",
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, str(coordinator.profile_id))},
manufacturer="NextDNS Inc.",
name=coordinator.nextdns.get_profile_name(coordinator.profile_id),
)
self._attr_unique_id = f"{coordinator.profile_id}_{description.key}"
self.entity_description = description

View File

@ -20,10 +20,9 @@ from homeassistant.components.sensor import (
SensorStateClass, SensorStateClass,
) )
from homeassistant.const import PERCENTAGE, EntityCategory from homeassistant.const import PERCENTAGE, EntityCategory
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import NextDnsConfigEntry from . import NextDnsConfigEntry
from .const import ( from .const import (
@ -33,7 +32,8 @@ from .const import (
ATTR_PROTOCOLS, ATTR_PROTOCOLS,
ATTR_STATUS, ATTR_STATUS,
) )
from .coordinator import CoordinatorDataT, NextDnsUpdateCoordinator from .coordinator import CoordinatorDataT
from .entity import NextDnsEntity
PARALLEL_UPDATES = 0 PARALLEL_UPDATES = 0
@ -297,27 +297,12 @@ async def async_setup_entry(
) )
class NextDnsSensor( class NextDnsSensor(NextDnsEntity, SensorEntity):
CoordinatorEntity[NextDnsUpdateCoordinator[CoordinatorDataT]], SensorEntity
):
"""Define an NextDNS sensor.""" """Define an NextDNS sensor."""
_attr_has_entity_name = True entity_description: NextDnsSensorEntityDescription
def __init__( @property
self, def native_value(self) -> StateType:
coordinator: NextDnsUpdateCoordinator[CoordinatorDataT], """Return the state of the sensor."""
description: NextDnsSensorEntityDescription, return self.entity_description.value(self.coordinator.data)
) -> None:
"""Initialize."""
super().__init__(coordinator)
self._attr_device_info = coordinator.device_info
self._attr_unique_id = f"{coordinator.profile_id}_{description.key}"
self._attr_native_value = description.value(coordinator.data)
self.entity_description: NextDnsSensorEntityDescription = description
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._attr_native_value = self.entity_description.value(self.coordinator.data)
self.async_write_ha_state()

View File

@ -15,11 +15,11 @@ from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import NextDnsConfigEntry from . import NextDnsConfigEntry
from .const import DOMAIN from .const import DOMAIN
from .coordinator import NextDnsUpdateCoordinator from .coordinator import NextDnsUpdateCoordinator
from .entity import NextDnsEntity
PARALLEL_UPDATES = 1 PARALLEL_UPDATES = 1
@ -536,12 +536,9 @@ async def async_setup_entry(
) )
class NextDnsSwitch( class NextDnsSwitch(NextDnsEntity, SwitchEntity):
CoordinatorEntity[NextDnsUpdateCoordinator[Settings]], SwitchEntity
):
"""Define an NextDNS switch.""" """Define an NextDNS switch."""
_attr_has_entity_name = True
entity_description: NextDnsSwitchEntityDescription entity_description: NextDnsSwitchEntityDescription
def __init__( def __init__(
@ -550,11 +547,8 @@ class NextDnsSwitch(
description: NextDnsSwitchEntityDescription, description: NextDnsSwitchEntityDescription,
) -> None: ) -> None:
"""Initialize.""" """Initialize."""
super().__init__(coordinator) super().__init__(coordinator, description)
self._attr_device_info = coordinator.device_info
self._attr_unique_id = f"{coordinator.profile_id}_{description.key}"
self._attr_is_on = description.state(coordinator.data) self._attr_is_on = description.state(coordinator.data)
self.entity_description = description
@callback @callback
def _handle_coordinator_update(self) -> None: def _handle_coordinator_update(self) -> None: