Add heat meter to Powerfox integration (#134799)

pull/134890/head
Klaas Schoute 2025-01-06 15:23:47 +01:00 committed by GitHub
parent 67e2379d2b
commit 99d7f462a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 302 additions and 4 deletions

View File

@ -5,7 +5,7 @@ from __future__ import annotations
from datetime import datetime
from typing import Any
from powerfox import PowerMeter, WaterMeter
from powerfox import HeatMeter, PowerMeter, WaterMeter
from homeassistant.core import HomeAssistant
@ -52,6 +52,22 @@ async def async_get_config_entry_diagnostics(
if isinstance(coordinator.data, WaterMeter)
else {}
),
**(
{
"heat_meter": {
"outdated": coordinator.data.outdated,
"timestamp": datetime.strftime(
coordinator.data.timestamp, "%Y-%m-%d %H:%M:%S"
),
"total_energy": coordinator.data.total_energy,
"delta_energy": coordinator.data.delta_energy,
"total_volume": coordinator.data.total_volume,
"delta_volume": coordinator.data.delta_volume,
}
}
if isinstance(coordinator.data, HeatMeter)
else {}
),
}
for coordinator in powerfox_data
],

View File

@ -5,7 +5,7 @@ from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from powerfox import Device, PowerMeter, WaterMeter
from powerfox import Device, HeatMeter, PowerMeter, WaterMeter
from homeassistant.components.sensor import (
SensorDeviceClass,
@ -23,7 +23,7 @@ from .entity import PowerfoxEntity
@dataclass(frozen=True, kw_only=True)
class PowerfoxSensorEntityDescription[T: (PowerMeter, WaterMeter)](
class PowerfoxSensorEntityDescription[T: (PowerMeter, WaterMeter, HeatMeter)](
SensorEntityDescription
):
"""Describes Poweropti sensor entity."""
@ -93,6 +93,40 @@ SENSORS_WATER: tuple[PowerfoxSensorEntityDescription[WaterMeter], ...] = (
),
)
SENSORS_HEAT: tuple[PowerfoxSensorEntityDescription[HeatMeter], ...] = (
PowerfoxSensorEntityDescription[HeatMeter](
key="heat_total_energy",
translation_key="heat_total_energy",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda meter: meter.total_energy,
),
PowerfoxSensorEntityDescription[HeatMeter](
key="heat_delta_energy",
translation_key="heat_delta_energy",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
value_fn=lambda meter: meter.delta_energy,
),
PowerfoxSensorEntityDescription[HeatMeter](
key="heat_total_volume",
translation_key="heat_total_volume",
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
device_class=SensorDeviceClass.WATER,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda meter: meter.total_volume,
),
PowerfoxSensorEntityDescription[HeatMeter](
key="heat_delta_volume",
translation_key="heat_delta_volume",
suggested_display_precision=2,
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
device_class=SensorDeviceClass.WATER,
value_fn=lambda meter: meter.delta_volume,
),
)
async def async_setup_entry(
hass: HomeAssistant,
@ -121,6 +155,15 @@ async def async_setup_entry(
)
for description in SENSORS_WATER
)
if isinstance(coordinator.data, HeatMeter):
entities.extend(
PowerfoxSensorEntity(
coordinator=coordinator,
description=description,
device=coordinator.device,
)
for description in SENSORS_HEAT
)
async_add_entities(entities)

View File

@ -64,6 +64,18 @@
},
"warm_water": {
"name": "Warm water"
},
"heat_total_energy": {
"name": "Total energy"
},
"heat_delta_energy": {
"name": "Delta energy"
},
"heat_total_volume": {
"name": "Total volume"
},
"heat_delta_volume": {
"name": "Delta volume"
}
}
}

View File

@ -4,7 +4,7 @@ from collections.abc import Generator
from datetime import UTC, datetime
from unittest.mock import AsyncMock, patch
from powerfox import Device, DeviceType, PowerMeter, WaterMeter
from powerfox import Device, DeviceType, HeatMeter, PowerMeter, WaterMeter
import pytest
from homeassistant.components.powerfox.const import DOMAIN
@ -53,6 +53,14 @@ def mock_powerfox_client() -> Generator[AsyncMock]:
type=DeviceType.COLD_WATER_METER,
name="Wateropti",
),
Device(
id="9x9x1f12xx5x",
date_added=datetime(2024, 11, 26, 9, 22, 35, tzinfo=UTC),
main_device=False,
bidirectional=False,
type=DeviceType.HEAT_METER,
name="Heatopti",
),
]
client.device.side_effect = [
PowerMeter(
@ -70,6 +78,14 @@ def mock_powerfox_client() -> Generator[AsyncMock]:
cold_water=1111.111,
warm_water=0.0,
),
HeatMeter(
outdated=False,
timestamp=datetime(2024, 11, 26, 10, 48, 51, tzinfo=UTC),
total_energy=1111.111,
delta_energy=111,
total_volume=1111.111,
delta_volume=0.111,
),
]
yield client

View File

@ -21,6 +21,16 @@
'warm_water': 0.0,
}),
}),
dict({
'heat_meter': dict({
'delta_energy': 111,
'delta_volume': 0.111,
'outdated': False,
'timestamp': '2024-11-26 10:48:51',
'total_energy': 1111.111,
'total_volume': 1111.111,
}),
}),
]),
})
# ---

View File

@ -1,4 +1,205 @@
# serializer version: 1
# name: test_all_sensors[sensor.heatopti_delta_energy-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.heatopti_delta_energy',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Delta energy',
'platform': 'powerfox',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'heat_delta_energy',
'unique_id': '9x9x1f12xx5x_heat_delta_energy',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
})
# ---
# name: test_all_sensors[sensor.heatopti_delta_energy-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Heatopti Delta energy',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.heatopti_delta_energy',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '111',
})
# ---
# name: test_all_sensors[sensor.heatopti_delta_volume-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.heatopti_delta_volume',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': 'Delta volume',
'platform': 'powerfox',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'heat_delta_volume',
'unique_id': '9x9x1f12xx5x_heat_delta_volume',
'unit_of_measurement': <UnitOfVolume.CUBIC_METERS: 'm³'>,
})
# ---
# name: test_all_sensors[sensor.heatopti_delta_volume-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'water',
'friendly_name': 'Heatopti Delta volume',
'unit_of_measurement': <UnitOfVolume.CUBIC_METERS: 'm³'>,
}),
'context': <ANY>,
'entity_id': 'sensor.heatopti_delta_volume',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.111',
})
# ---
# name: test_all_sensors[sensor.heatopti_total_energy-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.heatopti_total_energy',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Total energy',
'platform': 'powerfox',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'heat_total_energy',
'unique_id': '9x9x1f12xx5x_heat_total_energy',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
})
# ---
# name: test_all_sensors[sensor.heatopti_total_energy-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Heatopti Total energy',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.heatopti_total_energy',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1111.111',
})
# ---
# name: test_all_sensors[sensor.heatopti_total_volume-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.heatopti_total_volume',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': 'Total volume',
'platform': 'powerfox',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'heat_total_volume',
'unique_id': '9x9x1f12xx5x_heat_total_volume',
'unit_of_measurement': <UnitOfVolume.CUBIC_METERS: 'm³'>,
})
# ---
# name: test_all_sensors[sensor.heatopti_total_volume-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'water',
'friendly_name': 'Heatopti Total volume',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfVolume.CUBIC_METERS: 'm³'>,
}),
'context': <ANY>,
'entity_id': 'sensor.heatopti_total_volume',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1111.111',
})
# ---
# name: test_all_sensors[sensor.poweropti_energy_return-entry]
EntityRegistryEntrySnapshot({
'aliases': set({