Add base entity to Peblar Rocksolid EV Chargers integration (#133794)

This commit is contained in:
Franck Nijhof 2024-12-22 14:01:31 +01:00 committed by GitHub
parent 1e68ae1bb8
commit 075f95b9c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 111 additions and 174 deletions

View File

@ -16,10 +16,8 @@ from peblar import (
from homeassistant.const import CONF_HOST, CONF_PASSWORD, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from .const import DOMAIN
from .coordinator import (
PeblarConfigEntry,
PeblarDataUpdateCoordinator,
@ -76,29 +74,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: PeblarConfigEntry) -> bo
entry.runtime_data = PeblarRuntimeData(
data_coordinator=meter_coordinator,
system_information=system_information,
user_configuraton_coordinator=user_configuration_coordinator,
user_configuration_coordinator=user_configuration_coordinator,
version_coordinator=version_coordinator,
)
# Peblar is a single device integration. Setting up the device directly
# during setup. This way we only have to reference it in all entities.
device_registry = dr.async_get(hass)
device_registry.async_get_or_create(
config_entry_id=entry.entry_id,
configuration_url=f"http://{entry.data[CONF_HOST]}",
connections={
(dr.CONNECTION_NETWORK_MAC, system_information.ethernet_mac_address),
(dr.CONNECTION_NETWORK_MAC, system_information.wlan_mac_address),
},
identifiers={(DOMAIN, system_information.product_serial_number)},
manufacturer=system_information.product_vendor_name,
model_id=system_information.product_number,
model=system_information.product_model_name,
name="Peblar EV Charger",
serial_number=system_information.product_serial_number,
sw_version=version_coordinator.data.current.firmware,
)
# Forward the setup to the platforms
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

View File

@ -12,12 +12,10 @@ from homeassistant.components.binary_sensor import (
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import PeblarConfigEntry, PeblarData, PeblarDataUpdateCoordinator
from .entity import PeblarEntity
PARALLEL_UPDATES = 0
@ -56,35 +54,23 @@ async def async_setup_entry(
) -> None:
"""Set up Peblar binary sensor based on a config entry."""
async_add_entities(
PeblarBinarySensorEntity(entry=entry, description=description)
PeblarBinarySensorEntity(
entry=entry,
coordinator=entry.runtime_data.data_coordinator,
description=description,
)
for description in DESCRIPTIONS
)
class PeblarBinarySensorEntity(
CoordinatorEntity[PeblarDataUpdateCoordinator], BinarySensorEntity
PeblarEntity[PeblarDataUpdateCoordinator],
BinarySensorEntity,
):
"""Defines a Peblar binary sensor entity."""
entity_description: PeblarBinarySensorEntityDescription
_attr_has_entity_name = True
def __init__(
self,
entry: PeblarConfigEntry,
description: PeblarBinarySensorEntityDescription,
) -> None:
"""Initialize the binary sensor entity."""
super().__init__(entry.runtime_data.data_coordinator)
self.entity_description = description
self._attr_unique_id = f"{entry.unique_id}-{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={
(DOMAIN, entry.runtime_data.system_information.product_serial_number)
},
)
@property
def is_on(self) -> bool:
"""Return state of the binary sensor."""

View File

@ -15,12 +15,10 @@ from homeassistant.components.button import (
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import PeblarConfigEntry, PeblarUserConfigurationDataUpdateCoordinator
from .entity import PeblarEntity
PARALLEL_UPDATES = 1
@ -59,6 +57,7 @@ async def async_setup_entry(
async_add_entities(
PeblarButtonEntity(
entry=entry,
coordinator=entry.runtime_data.user_configuration_coordinator,
description=description,
)
for description in DESCRIPTIONS
@ -66,29 +65,13 @@ async def async_setup_entry(
class PeblarButtonEntity(
CoordinatorEntity[PeblarUserConfigurationDataUpdateCoordinator], ButtonEntity
PeblarEntity[PeblarUserConfigurationDataUpdateCoordinator],
ButtonEntity,
):
"""Defines an Peblar button."""
entity_description: PeblarButtonEntityDescription
_attr_has_entity_name = True
def __init__(
self,
entry: PeblarConfigEntry,
description: PeblarButtonEntityDescription,
) -> None:
"""Initialize the button entity."""
super().__init__(coordinator=entry.runtime_data.user_configuraton_coordinator)
self.entity_description = description
self._attr_unique_id = f"{entry.unique_id}_{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={
(DOMAIN, entry.runtime_data.system_information.product_serial_number)
},
)
async def async_press(self) -> None:
"""Trigger button press on the Peblar device."""
await self.entity_description.press_fn(self.coordinator.peblar)

View File

@ -30,7 +30,7 @@ class PeblarRuntimeData:
data_coordinator: PeblarDataUpdateCoordinator
system_information: PeblarSystemInformation
user_configuraton_coordinator: PeblarUserConfigurationDataUpdateCoordinator
user_configuration_coordinator: PeblarUserConfigurationDataUpdateCoordinator
version_coordinator: PeblarVersionDataUpdateCoordinator

View File

@ -15,7 +15,7 @@ async def async_get_config_entry_diagnostics(
"""Return diagnostics for a config entry."""
return {
"system_information": entry.runtime_data.system_information.to_dict(),
"user_configuration": entry.runtime_data.user_configuraton_coordinator.data.to_dict(),
"user_configuration": entry.runtime_data.user_configuration_coordinator.data.to_dict(),
"ev": entry.runtime_data.data_coordinator.data.ev.to_dict(),
"meter": entry.runtime_data.data_coordinator.data.meter.to_dict(),
"system": entry.runtime_data.data_coordinator.data.system.to_dict(),

View File

@ -0,0 +1,55 @@
"""Base entity for the Peblar integration."""
from __future__ import annotations
from typing import Any
from homeassistant.const import CONF_HOST
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)
from .const import DOMAIN
from .coordinator import PeblarConfigEntry
class PeblarEntity[_DataUpdateCoordinatorT: DataUpdateCoordinator[Any]](
CoordinatorEntity[_DataUpdateCoordinatorT]
):
"""Defines a Peblar entity."""
_attr_has_entity_name = True
def __init__(
self,
*,
entry: PeblarConfigEntry,
coordinator: _DataUpdateCoordinatorT,
description: EntityDescription,
) -> None:
"""Initialize the Peblar entity."""
super().__init__(coordinator=coordinator)
self.entity_description = description
self._attr_unique_id = f"{entry.unique_id}_{description.key}"
system_information = entry.runtime_data.system_information
self._attr_device_info = DeviceInfo(
configuration_url=f"http://{entry.data[CONF_HOST]}",
connections={
(dr.CONNECTION_NETWORK_MAC, system_information.ethernet_mac_address),
(dr.CONNECTION_NETWORK_MAC, system_information.wlan_mac_address),
},
identifiers={
(DOMAIN, entry.runtime_data.system_information.product_serial_number)
},
manufacturer=system_information.product_vendor_name,
model=system_information.product_model_name,
model_id=system_information.product_number,
name="Peblar EV Charger",
serial_number=system_information.product_serial_number,
sw_version=entry.runtime_data.version_coordinator.data.current.firmware,
)

View File

@ -15,17 +15,15 @@ from homeassistant.components.number import (
)
from homeassistant.const import EntityCategory, UnitOfElectricCurrent
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import (
PeblarConfigEntry,
PeblarData,
PeblarDataUpdateCoordinator,
PeblarRuntimeData,
)
from .entity import PeblarEntity
PARALLEL_UPDATES = 1
@ -64,33 +62,29 @@ async def async_setup_entry(
async_add_entities(
PeblarNumberEntity(
entry=entry,
coordinator=entry.runtime_data.data_coordinator,
description=description,
)
for description in DESCRIPTIONS
)
class PeblarNumberEntity(CoordinatorEntity[PeblarDataUpdateCoordinator], NumberEntity):
class PeblarNumberEntity(
PeblarEntity[PeblarDataUpdateCoordinator],
NumberEntity,
):
"""Defines a Peblar number."""
entity_description: PeblarNumberEntityDescription
_attr_has_entity_name = True
def __init__(
self,
entry: PeblarConfigEntry,
coordinator: PeblarDataUpdateCoordinator,
description: PeblarNumberEntityDescription,
) -> None:
"""Initialize the Peblar entity."""
super().__init__(entry.runtime_data.data_coordinator)
self.entity_description = description
self._attr_unique_id = f"{entry.unique_id}_{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={
(DOMAIN, entry.runtime_data.system_information.product_serial_number)
},
)
super().__init__(entry=entry, coordinator=coordinator, description=description)
self._attr_native_max_value = description.native_max_value_fn(
entry.runtime_data
)

View File

@ -11,12 +11,10 @@ from peblar import Peblar, PeblarUserConfiguration, SmartChargingMode
from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import PeblarConfigEntry, PeblarUserConfigurationDataUpdateCoordinator
from .entity import PeblarEntity
PARALLEL_UPDATES = 1
@ -56,6 +54,7 @@ async def async_setup_entry(
async_add_entities(
PeblarSelectEntity(
entry=entry,
coordinator=entry.runtime_data.user_configuration_coordinator,
description=description,
)
for description in DESCRIPTIONS
@ -63,29 +62,13 @@ async def async_setup_entry(
class PeblarSelectEntity(
CoordinatorEntity[PeblarUserConfigurationDataUpdateCoordinator], SelectEntity
PeblarEntity[PeblarUserConfigurationDataUpdateCoordinator],
SelectEntity,
):
"""Defines a peblar select entity."""
"""Defines a Peblar select entity."""
entity_description: PeblarSelectEntityDescription
_attr_has_entity_name = True
def __init__(
self,
entry: PeblarConfigEntry,
description: PeblarSelectEntityDescription,
) -> None:
"""Initialize the select entity."""
super().__init__(entry.runtime_data.user_configuraton_coordinator)
self.entity_description = description
self._attr_unique_id = f"{entry.unique_id}-{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={
(DOMAIN, entry.runtime_data.system_information.product_serial_number)
},
)
@property
def current_option(self) -> str | None:
"""Return the selected entity option to represent the entity state."""

View File

@ -22,17 +22,15 @@ from homeassistant.const import (
UnitOfPower,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.dt import utcnow
from .const import (
DOMAIN,
PEBLAR_CHARGE_LIMITER_TO_HOME_ASSISTANT,
PEBLAR_CP_STATE_TO_HOME_ASSISTANT,
)
from .coordinator import PeblarConfigEntry, PeblarData, PeblarDataUpdateCoordinator
from .entity import PeblarEntity
PARALLEL_UPDATES = 0
@ -237,34 +235,21 @@ async def async_setup_entry(
) -> None:
"""Set up Peblar sensors based on a config entry."""
async_add_entities(
PeblarSensorEntity(entry, description)
PeblarSensorEntity(
entry=entry,
coordinator=entry.runtime_data.data_coordinator,
description=description,
)
for description in DESCRIPTIONS
if description.has_fn(entry.runtime_data.user_configuraton_coordinator.data)
if description.has_fn(entry.runtime_data.user_configuration_coordinator.data)
)
class PeblarSensorEntity(CoordinatorEntity[PeblarDataUpdateCoordinator], SensorEntity):
class PeblarSensorEntity(PeblarEntity[PeblarDataUpdateCoordinator], SensorEntity):
"""Defines a Peblar sensor."""
entity_description: PeblarSensorDescription
_attr_has_entity_name = True
def __init__(
self,
entry: PeblarConfigEntry,
description: PeblarSensorDescription,
) -> None:
"""Initialize the Peblar entity."""
super().__init__(entry.runtime_data.data_coordinator)
self.entity_description = description
self._attr_unique_id = f"{entry.unique_id}_{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={
(DOMAIN, entry.runtime_data.system_information.product_serial_number)
},
)
@property
def native_value(self) -> datetime | int | str | None:
"""Return the state of the sensor."""

View File

@ -11,17 +11,15 @@ from peblar import PeblarApi
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import (
PeblarConfigEntry,
PeblarData,
PeblarDataUpdateCoordinator,
PeblarRuntimeData,
)
from .entity import PeblarEntity
PARALLEL_UPDATES = 1
@ -42,7 +40,7 @@ DESCRIPTIONS = [
entity_category=EntityCategory.CONFIG,
has_fn=lambda x: (
x.data_coordinator.data.system.force_single_phase_allowed
and x.user_configuraton_coordinator.data.connected_phases > 1
and x.user_configuration_coordinator.data.connected_phases > 1
),
is_on_fn=lambda x: x.ev.force_single_phase,
set_fn=lambda x, on: x.ev_interface(force_single_phase=on),
@ -59,6 +57,7 @@ async def async_setup_entry(
async_add_entities(
PeblarSwitchEntity(
entry=entry,
coordinator=entry.runtime_data.data_coordinator,
description=description,
)
for description in DESCRIPTIONS
@ -66,28 +65,14 @@ async def async_setup_entry(
)
class PeblarSwitchEntity(CoordinatorEntity[PeblarDataUpdateCoordinator], SwitchEntity):
class PeblarSwitchEntity(
PeblarEntity[PeblarDataUpdateCoordinator],
SwitchEntity,
):
"""Defines a Peblar switch entity."""
entity_description: PeblarSwitchEntityDescription
_attr_has_entity_name = True
def __init__(
self,
entry: PeblarConfigEntry,
description: PeblarSwitchEntityDescription,
) -> None:
"""Initialize the select entity."""
super().__init__(entry.runtime_data.data_coordinator)
self.entity_description = description
self._attr_unique_id = f"{entry.unique_id}-{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={
(DOMAIN, entry.runtime_data.system_information.product_serial_number)
},
)
@property
def is_on(self) -> bool:
"""Return state of the switch."""

View File

@ -11,16 +11,14 @@ from homeassistant.components.update import (
UpdateEntityDescription,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import (
PeblarConfigEntry,
PeblarVersionDataUpdateCoordinator,
PeblarVersionInformation,
)
from .entity import PeblarEntity
PARALLEL_UPDATES = 1
@ -56,34 +54,23 @@ async def async_setup_entry(
) -> None:
"""Set up Peblar update based on a config entry."""
async_add_entities(
PeblarUpdateEntity(entry, description) for description in DESCRIPTIONS
PeblarUpdateEntity(
entry=entry,
coordinator=entry.runtime_data.version_coordinator,
description=description,
)
for description in DESCRIPTIONS
)
class PeblarUpdateEntity(
CoordinatorEntity[PeblarVersionDataUpdateCoordinator], UpdateEntity
PeblarEntity[PeblarVersionDataUpdateCoordinator],
UpdateEntity,
):
"""Defines a Peblar update entity."""
entity_description: PeblarUpdateEntityDescription
_attr_has_entity_name = True
def __init__(
self,
entry: PeblarConfigEntry,
description: PeblarUpdateEntityDescription,
) -> None:
"""Initialize the update entity."""
super().__init__(entry.runtime_data.version_coordinator)
self.entity_description = description
self._attr_unique_id = f"{entry.unique_id}_{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={
(DOMAIN, entry.runtime_data.system_information.product_serial_number)
},
)
@property
def installed_version(self) -> str | None:
"""Version currently installed and in use."""

View File

@ -28,7 +28,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'active_error_codes',
'unique_id': '23-45-A4O-MOF-active_error_codes',
'unique_id': '23-45-A4O-MOF_active_error_codes',
'unit_of_measurement': None,
})
# ---
@ -75,7 +75,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'active_warning_codes',
'unique_id': '23-45-A4O-MOF-active_warning_codes',
'unique_id': '23-45-A4O-MOF_active_warning_codes',
'unit_of_measurement': None,
})
# ---

View File

@ -36,7 +36,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'smart_charging',
'unique_id': '23-45-A4O-MOF-smart_charging',
'unique_id': '23-45-A4O-MOF_smart_charging',
'unit_of_measurement': None,
})
# ---

View File

@ -28,7 +28,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'force_single_phase',
'unique_id': '23-45-A4O-MOF-force_single_phase',
'unique_id': '23-45-A4O-MOF_force_single_phase',
'unit_of_measurement': None,
})
# ---