Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion custom_components/power_group_monitor/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"domain": "power_group_monitor",
"name": "PowerGroupMonitor",
"version": "0.3.0",
"version": "0.4.0",
"documentation": "https://github.com/mephdrac/PowerGroupMonitor",
"issue_tracker": "https://github.com/mephdrac/PowerGroupMonitor/issues",
"requirements": [],
Expand Down
14 changes: 13 additions & 1 deletion custom_components/power_group_monitor/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@
from .sensors.power_total_sensor import PowerTotalSensor
from .sensors.power_peak_total_sensor import PowerPeakTotalSensor
from .sensors.power_standby_total_sensor import PowerStandbyTotalSensor

from .sensors.energy_today_sensor import EnergyTodaySensor
from .sensors.energy_total_sensor import EnergyTotalSensor

from .sensors.energy_total_all_sensor import EnergyTotalAllSensor
from .sensors.energy_today_all_sensor import EnergyTodayAllSensor

from .sensors.average_power_sensor import AveragePowerSensor
from .sensors.average_power_all_sensor import AveragePowerAllSensor

from .const import (
CONF_GROUP_NAME,
CONF_GROUP_ENTITIES,
Expand Down Expand Up @@ -73,6 +76,8 @@ async def async_setup_entry( # pylint: disable=too-many-locals, too-many-statem
entity_list = []
energy_total_list = []
energy_today_list = []
power_average_list = []

total_standby_threshold = float(0)

for group in groups:
Expand All @@ -93,6 +98,9 @@ async def async_setup_entry( # pylint: disable=too-many-locals, too-many-statem
standby_threshold=float(standby_threshold), # konfigurierbarer Wert?
)

# Durchschnittswert
average_power = AveragePowerSensor(entry, group_name, power_sensor)

# Energie pro Gruppe heute
energie_heute_gruppe = EnergyTodaySensor(
hass, entry, group_id, group_name, power_sensor
Expand All @@ -109,11 +117,13 @@ async def async_setup_entry( # pylint: disable=too-many-locals, too-many-statem
standby_sensor,
energie_heute_gruppe,
energie_gesamt_gruppe,
average_power,
]
)

energy_total_list.extend([energie_gesamt_gruppe])
energy_today_list.extend([energie_heute_gruppe])
power_average_list.extend([average_power])

async_add_entities(entity_list, update_before_add=True)

Expand All @@ -128,6 +138,7 @@ async def async_setup_entry( # pylint: disable=too-many-locals, too-many-statem

all_energy_total = EnergyTotalAllSensor(entry, energy_total_list)
all_energy_today = EnergyTodayAllSensor(entry, energy_today_list)
all_power_average = AveragePowerAllSensor(entry, power_average_list)

async_add_entities(
[
Expand All @@ -136,5 +147,6 @@ async def async_setup_entry( # pylint: disable=too-many-locals, too-many-statem
power_standby_total_sensor,
all_energy_total,
all_energy_today,
all_power_average
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""Sensor für Gesamtenergie pro Gruppe.

Dieses Modul definiert einen Sensor für Home Assistant,
der die gesamte Energie gruppenübergreifent berechnet.
Dazu werden einfach die Gruppensensoren addiert.
"""
import logging

from homeassistant.components.sensor import SensorEntity, SensorStateClass
from homeassistant.const import UnitOfPower
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.event import async_track_state_change_event

from ..const import DEVICE_INFO, DOMAIN

_LOGGER = logging.getLogger(__name__)


class AveragePowerAllSensor(SensorEntity):
"""Addiert alle Gruppen-Gesamtsummen"""
_attr_translation_key = "AveragePowerAllSensor"
_attr_has_entity_name = True

def __init__(self, entry: ConfigEntry, obj_entities) -> None:
"""Initialisiert den Sensor.

Args:
entry (ConfigEntry): Die Konfigurationseintrag-Instanz für diese Integration.

"""
self._attr_suggested_display_precision = 3
self._entry = entry
self._obj_entities = obj_entities
self._entities = [entity.entity_id for entity in self._obj_entities]
self._unsub = None

self._attr_unique_id = f"{entry.entry_id}_avg_all_power"
# self._attr_device_class = SensorDeviceClass.M
self._attr_state_class = SensorStateClass.MEASUREMENT
self._attr_native_unit_of_measurement = UnitOfPower.WATT

self.my_icon = "mdi:counter"
self._attr_native_value = None

async def async_added_to_hass(self):
"""Wird beim Hinzufügen zur Home Assistant-Instanz aufgerufen."""

for entity in self._obj_entities:

if entity.entity_id is None:
_LOGGER.warning("Sensor entity_id is None during standby setup!")
return

self._entities = [entity.entity_id for entity in self._obj_entities]
self._unsub = async_track_state_change_event(self.hass, self._entities,
self._async_state_changed)

await self._async_update_value()

# pylint: disable=unused-argument
async def _async_state_changed(self, event):
# Wird aufgerufen, wenn sich eine Entity im Set ändert
await self._async_update_value()

async def _async_update_value(self):
total = 0.0
for entity_id in self._entities:
state = self.hass.states.get(entity_id)
if state is None:
continue
try:
value = float(state.state)

total += value
except ValueError:
continue
self._attr_native_value = round(total, 3)
self.async_write_ha_state()

@property
def device_info(self):
"""Liefert die Geräteinformationen für diese Sensor-Entity.

Returns:
dict: Ein Dictionary mit Informationen zur Identifikation
des Geräts in Home Assistant, einschließlich:
- identifiers: Eindeutige Identifikatoren (Domain und Entry ID)
- name: Anzeigename des Geräts
- manufacturer: Herstellername
- model: Modellbezeichnung

"""

return {
"identifiers": {(DOMAIN, self._entry.entry_id)},
"name": self._entry.title,
**DEVICE_INFO,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""Modul definiert einen 15 Minuten Durchschnittsleistungssensor für Home Assistant.
Dazu wird die History der letzten 15 Minuten ausgewertet."""
import logging
from datetime import timedelta

from homeassistant.components import recorder
from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfPower
from homeassistant.util import dt as dt_util

from ..const import DEVICE_INFO, DOMAIN # noqa: TID252
from .power_sensor import PowerSensor

_LOGGER = logging.getLogger(__name__)


class AveragePowerSensor(SensorEntity):
"""Durchschnittliche Leistung über 15 Minuten."""

_attr_translation_key = "AveragePowerSensor"
_attr_has_entity_name = True

def __init__(self, entry: ConfigEntry, group_name: str, source: PowerSensor):
self._entry = entry
self._group_name = group_name
self._attr_translation_placeholders = {"index": self._group_name}
self._source = source
self._attr_unique_id = f"{entry.entry_id}_{self._group_name}_avg_power"
self._attr_native_unit_of_measurement = UnitOfPower.WATT
self._attr_suggested_display_precision = 3
self._source_entity_id = source.entity_id
self._statistics_sensor = None

async def async_added_to_hass(self):
"""Wird aufgerufen, wenn die Entity zu HA hinzugefügt wird."""

source_entity_id = self._source.entity_id
if source_entity_id is None:
_LOGGER.warning("Sensor entity_id is None during avg setup!")
return

await super().async_added_to_hass()

async def async_update(self):
"""Wird aufgerufen, wenn die Entity aktualisiert wird."""
self._attr_native_value = await self.async_calculate_average()

async def async_calculate_average(self):
"""Berechne den Durchschnitt der letzten 15 Minuten aus der History."""
now = dt_util.utcnow()
start = now - timedelta(minutes=15)

def _fetch():
return recorder.history.state_changes_during_period(
self.hass,
start_time=start,
end_time=now,
entity_id=self._source.entity_id,
no_attributes=True,
)

instance = recorder.get_instance(self.hass)
states = await instance.async_add_executor_job(_fetch)

values = []
for state in states.get(self._source.entity_id, []):
try:
values.append(float(state.state))
except (ValueError, TypeError):
continue

if values:
return sum(values) / len(values)
return None

@property
def device_info(self):
"""Liefert die Geräteinformationen für diese Sensor-Entity."""
return {
"identifiers": {(DOMAIN, self._entry.entry_id)},
"name": self._entry.title,
**DEVICE_INFO,
}
3 changes: 3 additions & 0 deletions custom_components/power_group_monitor/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
},
"EnergyTodayAllSensor":{
"name": "Gesamt - Energie heute"
},
"AveragePowerSensor":{
"name": "{index} - 15 Min. Durchschnitt"
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions custom_components/power_group_monitor/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
},
"EnergyTodayAllSensor":{
"name": "Total - Energy today"
},
"AveragePowerSensor":{
"name": "{index} - 15 Min. Average"
}
}
}
Expand Down
Loading