Basic entity class for Imeon inverter integration (#145778)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: TheBushBoy <theodavid@icloud.com>
This commit is contained in:
Imeon-Energy 2025-06-09 20:04:25 +02:00 committed by GitHub
parent d58157ca9e
commit 7cc8f91bf9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 54 additions and 38 deletions

View File

@ -0,0 +1,40 @@
"""Imeon inverter base class for entities."""
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import InverterCoordinator
type InverterConfigEntry = ConfigEntry[InverterCoordinator]
class InverterEntity(CoordinatorEntity[InverterCoordinator]):
"""Common elements for all entities."""
_attr_has_entity_name = True
def __init__(
self,
coordinator: InverterCoordinator,
entry: InverterConfigEntry,
entity_description: EntityDescription,
) -> None:
"""Pass coordinator to CoordinatorEntity."""
super().__init__(coordinator)
self.entity_description = entity_description
self._inverter = coordinator.api.inverter
self.data_key = entity_description.key
assert entry.unique_id
self._attr_unique_id = f"{entry.unique_id}_{self.data_key}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, entry.unique_id)},
name="Imeon inverter",
manufacturer="Imeon Energy",
model=self._inverter.get("inverter"),
sw_version=self._inverter.get("software"),
serial_number=self._inverter.get("serial"),
configuration_url=self._inverter.get("url"),
)

View File

@ -21,20 +21,18 @@ from homeassistant.const import (
UnitOfTime, UnitOfTime,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
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 .const import DOMAIN
from .coordinator import InverterCoordinator from .coordinator import InverterCoordinator
from .entity import InverterEntity
type InverterConfigEntry = ConfigEntry[InverterCoordinator] type InverterConfigEntry = ConfigEntry[InverterCoordinator]
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ENTITY_DESCRIPTIONS = ( SENSOR_DESCRIPTIONS = (
# Battery # Battery
SensorEntityDescription( SensorEntityDescription(
key="battery_autonomy", key="battery_autonomy",
@ -423,42 +421,18 @@ async def async_setup_entry(
"""Create each sensor for a given config entry.""" """Create each sensor for a given config entry."""
coordinator = entry.runtime_data coordinator = entry.runtime_data
# Init sensor entities
async_add_entities( async_add_entities(
InverterSensor(coordinator, entry, description) InverterSensor(coordinator, entry, description)
for description in ENTITY_DESCRIPTIONS for description in SENSOR_DESCRIPTIONS
) )
class InverterSensor(CoordinatorEntity[InverterCoordinator], SensorEntity): class InverterSensor(InverterEntity, SensorEntity):
"""A sensor that returns numerical values with units.""" """Representation of an Imeon inverter sensor."""
_attr_has_entity_name = True
_attr_entity_category = EntityCategory.DIAGNOSTIC _attr_entity_category = EntityCategory.DIAGNOSTIC
def __init__(
self,
coordinator: InverterCoordinator,
entry: InverterConfigEntry,
description: SensorEntityDescription,
) -> None:
"""Pass coordinator to CoordinatorEntity."""
super().__init__(coordinator)
self.entity_description = description
self._inverter = coordinator.api.inverter
self.data_key = description.key
assert entry.unique_id
self._attr_unique_id = f"{entry.unique_id}_{self.data_key}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, entry.unique_id)},
name="Imeon inverter",
manufacturer="Imeon Energy",
model=self._inverter.get("inverter"),
sw_version=self._inverter.get("software"),
)
@property @property
def native_value(self) -> StateType | None: def native_value(self) -> StateType | None:
"""Value of the sensor.""" """Return the state of the entity."""
return self.coordinator.data.get(self.data_key) return self.coordinator.data.get(self.data_key)

View File

@ -60,7 +60,12 @@ def mock_imeon_inverter() -> Generator[MagicMock]:
inverter.__aenter__.return_value = inverter inverter.__aenter__.return_value = inverter
inverter.login.return_value = True inverter.login.return_value = True
inverter.get_serial.return_value = TEST_SERIAL inverter.get_serial.return_value = TEST_SERIAL
inverter.inverter.get.return_value = {"inverter": "blah", "software": "1.0"} inverter.inverter = {
"inverter": "3.6",
"software": "1.0",
"serial": TEST_SERIAL,
"url": f"http://{TEST_USER_INPUT[CONF_HOST]}",
}
inverter.storage = load_json_object_fixture("sensor_data.json", DOMAIN) inverter.storage = load_json_object_fixture("sensor_data.json", DOMAIN)
yield inverter yield inverter

View File

@ -1,6 +1,6 @@
"""Test the Imeon Inverter sensors.""" """Test the Imeon Inverter sensors."""
from unittest.mock import MagicMock, patch from unittest.mock import patch
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
@ -15,15 +15,12 @@ from tests.common import MockConfigEntry, snapshot_platform
async def test_sensors( async def test_sensors(
hass: HomeAssistant, hass: HomeAssistant,
mock_imeon_inverter: MagicMock,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
) -> None: ) -> None:
"""Test the Imeon Inverter sensors.""" """Test the Imeon Inverter sensors."""
with patch( with patch("homeassistant.components.imeon_inverter.PLATFORMS", [Platform.SENSOR]):
"homeassistant.components.imeon_inverter.const.PLATFORMS", [Platform.SENSOR]
):
await setup_integration(hass, mock_config_entry) await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)