From e5df78e2b9e9bf19cedf9f5238fde222af8b2184 Mon Sep 17 00:00:00 2001 From: Chris <1105672+firstof9@users.noreply.github.com> Date: Fri, 25 Sep 2026 12:56:19 -0700 Subject: [PATCH] Add common base entity to OpenEVSE (#183108) --- .../components/openevse/binary_sensor.py | 35 ++--------------- homeassistant/components/openevse/button.py | 33 ++-------------- homeassistant/components/openevse/entity.py | 37 ++++++++++++++++++ homeassistant/components/openevse/number.py | 38 ++----------------- homeassistant/components/openevse/select.py | 33 ++-------------- homeassistant/components/openevse/sensor.py | 32 ++-------------- homeassistant/components/openevse/switch.py | 32 ++-------------- 7 files changed, 59 insertions(+), 181 deletions(-) create mode 100644 homeassistant/components/openevse/entity.py diff --git a/homeassistant/components/openevse/binary_sensor.py b/homeassistant/components/openevse/binary_sensor.py index f27a558e371e..9e3d6818bd3d 100644 --- a/homeassistant/components/openevse/binary_sensor.py +++ b/homeassistant/components/openevse/binary_sensor.py @@ -11,14 +11,12 @@ from homeassistant.components.binary_sensor import ( BinarySensorEntity, BinarySensorEntityDescription, ) -from homeassistant.const import ATTR_CONNECTIONS, ATTR_SERIAL_NUMBER, EntityCategory +from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN -from .coordinator import OpenEVSEConfigEntry, OpenEVSEDataUpdateCoordinator +from .coordinator import OpenEVSEConfigEntry +from .entity import OpenEVSEEntity PARALLEL_UPDATES = 0 @@ -85,36 +83,11 @@ async def async_setup_entry( ) -class OpenEVSEBinarySensor( - CoordinatorEntity[OpenEVSEDataUpdateCoordinator], BinarySensorEntity -): +class OpenEVSEBinarySensor(OpenEVSEEntity, BinarySensorEntity): """Implementation of an OpenEVSE binary sensor.""" - _attr_has_entity_name = True entity_description: OpenEVSEBinarySensorDescription - def __init__( - self, - coordinator: OpenEVSEDataUpdateCoordinator, - description: OpenEVSEBinarySensorDescription, - identifier: str, - unique_id: str | None, - ) -> None: - """Initialize the binary sensor.""" - super().__init__(coordinator) - self.entity_description = description - self._attr_unique_id = f"{identifier}-{description.key}" - - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, identifier)}, - manufacturer="OpenEVSE", - ) - if unique_id: - self._attr_device_info[ATTR_CONNECTIONS] = { - (CONNECTION_NETWORK_MAC, unique_id) - } - self._attr_device_info[ATTR_SERIAL_NUMBER] = unique_id - @property @override def is_on(self) -> bool | None: diff --git a/homeassistant/components/openevse/button.py b/homeassistant/components/openevse/button.py index 44e76a8b2ca3..e14218ac2750 100644 --- a/homeassistant/components/openevse/button.py +++ b/homeassistant/components/openevse/button.py @@ -11,14 +11,12 @@ from homeassistant.components.button import ( ButtonEntity, ButtonEntityDescription, ) -from homeassistant.const import ATTR_CONNECTIONS, ATTR_SERIAL_NUMBER, EntityCategory +from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN -from .coordinator import OpenEVSEConfigEntry, OpenEVSEDataUpdateCoordinator +from .coordinator import OpenEVSEConfigEntry +from .entity import OpenEVSEEntity from .helpers import openevse_exception_handler PARALLEL_UPDATES = 0 @@ -63,34 +61,11 @@ async def async_setup_entry( ) -class OpenEVSEButton(CoordinatorEntity[OpenEVSEDataUpdateCoordinator], ButtonEntity): +class OpenEVSEButton(OpenEVSEEntity, ButtonEntity): """Implementation of an OpenEVSE button.""" - _attr_has_entity_name = True entity_description: OpenEVSEButtonDescription - def __init__( - self, - coordinator: OpenEVSEDataUpdateCoordinator, - description: OpenEVSEButtonDescription, - identifier: str, - unique_id: str | None, - ) -> None: - """Initialize the button.""" - super().__init__(coordinator) - self.entity_description = description - self._attr_unique_id = f"{identifier}-{description.key}" - - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, identifier)}, - manufacturer="OpenEVSE", - ) - if unique_id: - self._attr_device_info[ATTR_CONNECTIONS] = { - (CONNECTION_NETWORK_MAC, unique_id) - } - self._attr_device_info[ATTR_SERIAL_NUMBER] = unique_id - @override async def async_press(self) -> None: """Press the button.""" diff --git a/homeassistant/components/openevse/entity.py b/homeassistant/components/openevse/entity.py new file mode 100644 index 000000000000..dd196cecdf9f --- /dev/null +++ b/homeassistant/components/openevse/entity.py @@ -0,0 +1,37 @@ +"""Base entity for OpenEVSE.""" + +from homeassistant.const import ATTR_CONNECTIONS, ATTR_SERIAL_NUMBER +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo +from homeassistant.helpers.entity import EntityDescription +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import DOMAIN +from .coordinator import OpenEVSEDataUpdateCoordinator + + +class OpenEVSEEntity(CoordinatorEntity[OpenEVSEDataUpdateCoordinator]): + """Base implementation for OpenEVSE entities.""" + + _attr_has_entity_name = True + + def __init__( + self, + coordinator: OpenEVSEDataUpdateCoordinator, + description: EntityDescription, + identifier: str, + unique_id: str | None, + ) -> None: + """Initialize the OpenEVSE entity.""" + super().__init__(coordinator) + self.entity_description = description + self._attr_unique_id = f"{identifier}-{description.key}" + + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, identifier)}, + manufacturer="OpenEVSE", + ) + if unique_id: + self._attr_device_info[ATTR_CONNECTIONS] = { + (CONNECTION_NETWORK_MAC, unique_id) + } + self._attr_device_info[ATTR_SERIAL_NUMBER] = unique_id diff --git a/homeassistant/components/openevse/number.py b/homeassistant/components/openevse/number.py index 47da5f5db267..30656d7b8eba 100644 --- a/homeassistant/components/openevse/number.py +++ b/homeassistant/components/openevse/number.py @@ -11,19 +11,12 @@ from homeassistant.components.number import ( NumberEntity, NumberEntityDescription, ) -from homeassistant.const import ( - ATTR_CONNECTIONS, - ATTR_SERIAL_NUMBER, - EntityCategory, - UnitOfElectricCurrent, -) +from homeassistant.const import EntityCategory, UnitOfElectricCurrent from homeassistant.core import HomeAssistant -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN -from .coordinator import OpenEVSEConfigEntry, OpenEVSEDataUpdateCoordinator +from .coordinator import OpenEVSEConfigEntry +from .entity import OpenEVSEEntity from .helpers import openevse_exception_handler PARALLEL_UPDATES = 0 @@ -69,34 +62,11 @@ async def async_setup_entry( ) -class OpenEVSENumber(CoordinatorEntity[OpenEVSEDataUpdateCoordinator], NumberEntity): +class OpenEVSENumber(OpenEVSEEntity, NumberEntity): """Implementation of an OpenEVSE sensor.""" - _attr_has_entity_name = True entity_description: OpenEVSENumberDescription - def __init__( - self, - coordinator: OpenEVSEDataUpdateCoordinator, - description: OpenEVSENumberDescription, - identifier: str, - unique_id: str | None, - ) -> None: - """Initialize the sensor.""" - super().__init__(coordinator) - self.entity_description = description - self._attr_unique_id = f"{identifier}-{description.key}" - - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, identifier)}, - manufacturer="OpenEVSE", - ) - if unique_id: - self._attr_device_info[ATTR_CONNECTIONS] = { - (CONNECTION_NETWORK_MAC, unique_id) - } - self._attr_device_info[ATTR_SERIAL_NUMBER] = unique_id - @property @override def native_value(self) -> float: diff --git a/homeassistant/components/openevse/select.py b/homeassistant/components/openevse/select.py index 438e5ac9b54c..6a1f02ee2620 100644 --- a/homeassistant/components/openevse/select.py +++ b/homeassistant/components/openevse/select.py @@ -9,15 +9,13 @@ from typing import Any, override from openevsehttp import OpenEVSE from homeassistant.components.select import SelectEntity, SelectEntityDescription -from homeassistant.const import ATTR_CONNECTIONS, ATTR_SERIAL_NUMBER, EntityCategory +from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN -from .coordinator import OpenEVSEConfigEntry, OpenEVSEDataUpdateCoordinator +from .coordinator import OpenEVSEConfigEntry +from .entity import OpenEVSEEntity from .helpers import openevse_exception_handler PARALLEL_UPDATES = 0 @@ -67,36 +65,13 @@ async def async_setup_entry( ) -class OpenEVSESelect(CoordinatorEntity[OpenEVSEDataUpdateCoordinator], SelectEntity): +class OpenEVSESelect(OpenEVSEEntity, SelectEntity): """Implementation of an OpenEVSE select entity.""" - _attr_has_entity_name = True entity_description: OpenEVSESelectDescription _attr_current_option: str | None = None _update_task: asyncio.Task[None] | None = None - def __init__( - self, - coordinator: OpenEVSEDataUpdateCoordinator, - description: OpenEVSESelectDescription, - identifier: str, - unique_id: str | None, - ) -> None: - """Initialize the select.""" - super().__init__(coordinator) - self.entity_description = description - self._attr_unique_id = f"{identifier}-{description.key}" - - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, identifier)}, - manufacturer="OpenEVSE", - ) - if unique_id: - self._attr_device_info[ATTR_CONNECTIONS] = { - (CONNECTION_NETWORK_MAC, unique_id) - } - self._attr_device_info[ATTR_SERIAL_NUMBER] = unique_id - @property @override def available(self) -> bool: diff --git a/homeassistant/components/openevse/sensor.py b/homeassistant/components/openevse/sensor.py index 03d60ee10175..62e9f1f49bed 100644 --- a/homeassistant/components/openevse/sensor.py +++ b/homeassistant/components/openevse/sensor.py @@ -18,8 +18,6 @@ from homeassistant.components.sensor import ( ) from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import ( - ATTR_CONNECTIONS, - ATTR_SERIAL_NUMBER, CONF_HOST, CONF_MONITORED_VARIABLES, PERCENTAGE, @@ -37,17 +35,16 @@ from homeassistant.const import ( from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers import config_validation as cv, issue_registry as ir -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.entity_platform import ( AddConfigEntryEntitiesCallback, AddEntitiesCallback, ) from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType -from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.util import slugify from .const import DOMAIN, INTEGRATION_TITLE -from .coordinator import OpenEVSEConfigEntry, OpenEVSEDataUpdateCoordinator +from .coordinator import OpenEVSEConfigEntry +from .entity import OpenEVSEEntity _LOGGER = logging.getLogger(__name__) @@ -458,34 +455,11 @@ async def async_setup_entry( ) -class OpenEVSESensor(CoordinatorEntity[OpenEVSEDataUpdateCoordinator], SensorEntity): +class OpenEVSESensor(OpenEVSEEntity, SensorEntity): """Implementation of an OpenEVSE sensor.""" - _attr_has_entity_name = True entity_description: OpenEVSESensorDescription - def __init__( - self, - coordinator: OpenEVSEDataUpdateCoordinator, - description: OpenEVSESensorDescription, - identifier: str, - unique_id: str | None, - ) -> None: - """Initialize the sensor.""" - super().__init__(coordinator) - self.entity_description = description - self._attr_unique_id = f"{identifier}-{description.key}" - - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, identifier)}, - manufacturer="OpenEVSE", - ) - if unique_id: - self._attr_device_info[ATTR_CONNECTIONS] = { - (CONNECTION_NETWORK_MAC, unique_id) - } - self._attr_device_info[ATTR_SERIAL_NUMBER] = unique_id - @property @override def native_value(self) -> StateType | datetime: diff --git a/homeassistant/components/openevse/switch.py b/homeassistant/components/openevse/switch.py index a488465f96a7..a7cd45a6de80 100644 --- a/homeassistant/components/openevse/switch.py +++ b/homeassistant/components/openevse/switch.py @@ -7,14 +7,11 @@ from typing import Any, override from openevsehttp import OpenEVSE from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription -from homeassistant.const import ATTR_CONNECTIONS, ATTR_SERIAL_NUMBER from homeassistant.core import HomeAssistant -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN -from .coordinator import OpenEVSEConfigEntry, OpenEVSEDataUpdateCoordinator +from .coordinator import OpenEVSEConfigEntry +from .entity import OpenEVSEEntity from .helpers import openevse_exception_handler PARALLEL_UPDATES = 0 @@ -76,34 +73,11 @@ async def async_setup_entry( ) -class OpenEVSESwitch(CoordinatorEntity[OpenEVSEDataUpdateCoordinator], SwitchEntity): +class OpenEVSESwitch(OpenEVSEEntity, SwitchEntity): """Implementation of an OpenEVSE switch.""" - _attr_has_entity_name = True entity_description: OpenEVSESwitchDescription - def __init__( - self, - coordinator: OpenEVSEDataUpdateCoordinator, - description: OpenEVSESwitchDescription, - identifier: str, - unique_id: str | None, - ) -> None: - """Initialize the switch.""" - super().__init__(coordinator) - self.entity_description = description - self._attr_unique_id = f"{identifier}-{description.key}" - - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, identifier)}, - manufacturer="OpenEVSE", - ) - if unique_id: - self._attr_device_info[ATTR_CONNECTIONS] = { - (CONNECTION_NETWORK_MAC, unique_id) - } - self._attr_device_info[ATTR_SERIAL_NUMBER] = unique_id - @property @override def available(self) -> bool: