Skip to content

Commit

Permalink
Merge pull request #17 from StephanU/feature/panel_metrics
Browse files Browse the repository at this point in the history
Added entities for panel and grid metrics.
  • Loading branch information
StephanU authored Jun 18, 2024
2 parents 094943a + efde9e3 commit a3b91c4
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 31 deletions.
190 changes: 164 additions & 26 deletions custom_components/talent_monitor/sensor.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
"""Sensor platform for TalentMonitor."""

from datetime import datetime
import logging
from custom_components.talent_monitor.entity import TalentMonitorEntity, TalentMonitorInverterEntity
import re
from custom_components.talent_monitor.entity import (
TalentMonitorEntity,
TalentMonitorInverterEntity,
)
from custom_components.talent_monitor.pyTalentMonitor.data_provider import Entity
from custom_components.talent_monitor.pyTalentMonitor.inverter import Inverter
from custom_components.talent_monitor.pyTalentMonitor.power_station import PowerStation
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.components.sensor import SensorEntity
from homeassistant.components.sensor import SensorEntityDescription
from homeassistant.components.sensor import SensorStateClass
from homeassistant.const import UnitOfElectricCurrent
from homeassistant.const import UnitOfElectricPotential
from homeassistant.const import UnitOfEnergy
from homeassistant.const import UnitOfFrequency
from homeassistant.const import UnitOfTemperature
from homeassistant.const import UnitOfPower
from homeassistant.core import callback
Expand All @@ -19,48 +27,71 @@

_LOGGER: logging.Logger = logging.getLogger(__name__)

camel_case_to_snake_case = re.compile(r'(?<!^)(?=[A-Z])')

SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key="totalActivePower",
translation_key="talentmonitor_powerstation_total_active_power",
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.POWER,
),
SensorEntityDescription(
key="ratedPower",
translation_key="talentmonitor_powerstation_rated_power",
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.POWER,
),
SensorEntityDescription(
key="dayEnergy",
translation_key="talentmonitor_powerstation_day_energy",
state_class=SensorStateClass.TOTAL_INCREASING,
device_class=SensorDeviceClass.ENERGY,
),
SensorEntityDescription(
key="monthEnergy",
translation_key="talentmonitor_powerstation_month_energy",
state_class=SensorStateClass.TOTAL_INCREASING,
device_class=SensorDeviceClass.ENERGY,
),
SensorEntityDescription(
key="yearEnergy",
translation_key="talentmonitor_powerstation_year_energy",
state_class=SensorStateClass.TOTAL_INCREASING,
device_class=SensorDeviceClass.ENERGY,
),
SensorEntityDescription(
key="lastDataUpdateTime",
translation_key="talentmonitor_powerstation_last_data_update_time",
device_class=SensorDeviceClass.DATE,
),
SensorEntityDescription(
key="inverterTemp",
translation_key="talentmonitor_inverter_temp",
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
),
SensorEntityDescription(
key="activePower",
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.POWER,
),
SensorEntityDescription(
key="power",
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.POWER,
),
SensorEntityDescription(
key="current",
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
),
SensorEntityDescription(
key="voltage",
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.VOLTAGE,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
),
SensorEntityDescription(
key="frequency",
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.FREQUENCY,
native_unit_of_measurement=UnitOfFrequency.HERTZ,
),
)

Expand Down Expand Up @@ -106,6 +137,47 @@ async def async_setup_entry(hass, entry, async_add_devices):
)
]
)
if value == "pv" and "pvCount" in inverter.data:
for index, pv in enumerate(inverter.data[value]):
if index < inverter.data["pvCount"] - 1 and index < len(
inverter.data[value]
): # it seems pvCount is not set correctly as it is set to 3 when there are only 2 panels, subtracting 1 is a solution for now but might result in a problem at some point
for _, pv_value in enumerate(pv):
_LOGGER.debug(
"Iterate pv %d for inverter %s", index, pv_value
)
if pv_value and pv_value in SENSORS:
async_add_devices(
[
TalentMonitorInverterPanelSensor(
coordinator,
inverter,
SENSORS[pv_value],
index,
)
]
)

if value == "phase" and "acPhaseCount" in inverter.data:
for index, phase in enumerate(inverter.data[value]):
if index < inverter.data["acPhaseCount"] and index < len(
inverter.data[value]
):
for _, phase_value in enumerate(phase):
_LOGGER.debug(
"Iterate phase %d for inverter %s", index, phase_value
)
if phase_value and phase_value in SENSORS:
async_add_devices(
[
TalentMonitorInverterPhaseSensor(
coordinator,
inverter,
SENSORS[phase_value],
index,
)
]
)


class TalentMonitorSensor(SensorEntity):
Expand All @@ -123,34 +195,42 @@ def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self.async_write_ha_state()

@property
def data(self):
"""Return the data of this sensor."""
return self._entity.data

@property
def native_value(self):
"""Return the state of the sensor."""

if (self.entity_description.key == "lastDataUpdateTime"):
return datetime.fromisoformat(self._entity.data[self.entity_description.key])
if self.entity_description.key == "lastDataUpdateTime":
return datetime.fromisoformat(self.data[self.entity_description.key])
else:
key_for_value_with_unit = self.entity_description.key + "Named"

if (key_for_value_with_unit in self._entity.data and self._entity.data[key_for_value_with_unit]):
value_split = self._entity.data[key_for_value_with_unit].split(" ")
if (
key_for_value_with_unit in self.data
and self.data[key_for_value_with_unit]
):
value_split = self.data[key_for_value_with_unit].split(" ")

if (value_split and len(value_split) == 2):
if value_split and len(value_split) == 2:
value = value_split[0]
return value
else:
return self._entity.data[self.entity_description.key]
return self.data[self.entity_description.key]
else:
return self._entity.data[self.entity_description.key]
return self.data[self.entity_description.key]

@property
def native_unit_of_measurement(self) -> str | None:
"""Return the unit of measurement."""
key_for_value_with_unit = self.entity_description.key + "Named"

if (key_for_value_with_unit in self._entity.data and self._entity.data[key_for_value_with_unit]):
value_split = self._entity.data[key_for_value_with_unit].split(" ")
if (value_split and len(value_split) == 2):
if key_for_value_with_unit in self.data and self.data[key_for_value_with_unit]:
value_split = self.data[key_for_value_with_unit].split(" ")
if value_split and len(value_split) == 2:
unit = value_split[1]
return SENSOR_UNIT_MAPPING[unit]
return self.entity_description.native_unit_of_measurement
Expand All @@ -165,14 +245,13 @@ def __init__(
sensorEntityDescription: SensorEntityDescription,
):
"""Initialize a TalentMonitor PowerStation sensor."""
TalentMonitorEntity.__init__(self,
coordinator,
power_station,
sensorEntityDescription.key
TalentMonitorEntity.__init__(
self, coordinator, power_station, sensorEntityDescription.key
)
TalentMonitorSensor.__init__(self, power_station)

self.entity_description = sensorEntityDescription
self.translation_key = 'talentmonitor_powerstation_' + camel_case_to_snake_case.sub('_', sensorEntityDescription.key).lower()


class TalentMonitorInverterSensor(TalentMonitorInverterEntity, TalentMonitorSensor):
Expand All @@ -185,13 +264,72 @@ def __init__(
sensorEntityDescription: SensorEntityDescription,
):
"""Initialize a TalentMonitor Inverter sensor."""
TalentMonitorInverterEntity.__init__(self,
TalentMonitorInverterEntity.__init__(
self, coordinator, inverter, sensorEntityDescription.key
)
TalentMonitorSensor.__init__(self, inverter)

self.entity_description = sensorEntityDescription
self.translation_key = 'talentmonitor_inverter_' + camel_case_to_snake_case.sub('_', sensorEntityDescription.key).lower()

class TalentMonitorInverterPhaseSensor(
TalentMonitorInverterEntity, TalentMonitorSensor
):
"""TalentMonitor Inverter Phase Sensor class."""

def __init__(
self,
coordinator,
inverter: Inverter,
sensorEntityDescription: SensorEntityDescription,
phase_index,
):
"""Initialize a TalentMonitor Inverter sensor."""
TalentMonitorInverterEntity.__init__(
self,
coordinator,
inverter,
sensorEntityDescription.key
"phase" + str(phase_index) + sensorEntityDescription.key,
)
TalentMonitorSensor.__init__(self, inverter)

phase_name = inverter.data["acPhaseExpress"].split(",")[phase_index] if "acPhaseExpress" in inverter.data else phase_index
self._attr_translation_placeholders = {"phase_id": phase_name }
self.entity_description = sensorEntityDescription
self.translation_key = 'talentmonitor_inverter_phase_' + camel_case_to_snake_case.sub('_', sensorEntityDescription.key).lower()
self._phase_index = phase_index

@property
def data(self):
"""Return the data of this sensor."""
return self._entity.data["phase"][self._phase_index]

class TalentMonitorInverterPanelSensor(
TalentMonitorInverterEntity, TalentMonitorSensor
):
"""TalentMonitor Inverter Panel Sensor class."""

def __init__(
self,
coordinator,
inverter: Inverter,
sensorEntityDescription: SensorEntityDescription,
panel_index,
):
"""Initialize a TalentMonitor Inverter sensor."""
TalentMonitorInverterEntity.__init__(
self,
coordinator,
inverter,
"panel" + str(panel_index) + sensorEntityDescription.key,
)
TalentMonitorSensor.__init__(self, inverter)

self._attr_translation_placeholders = {"panel_id": panel_index}
self.entity_description = sensorEntityDescription
self.translation_key = 'talentmonitor_inverter_panel_' + sensorEntityDescription.key
self._panel_index = panel_index

@property
def data(self):
"""Return the data of this sensor."""
return self._entity.data["pv"][self._panel_index]
25 changes: 23 additions & 2 deletions custom_components/talent_monitor/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,32 @@
"talentmonitor_powerstation_last_data_update_time": {
"name": "Letzte Datenaktualisierung"
},
"talentmonitor_powerstation_rated_power": {
"talentmonitor_inverter_rated_power": {
"name": "Nennleistung"
},
"talentmonitor_inverter_temp": {
"talentmonitor_inverter_inverter_temp": {
"name": "Temperatur"
},
"talentmonitor_inverter_phase_active_power": {
"name": "Phase {phase_id} Aktuelle Leistung"
},
"talentmonitor_inverter_phase_current": {
"name": "Phase {phase_id} Strom"
},
"talentmonitor_inverter_phase_voltage": {
"name": "Phase {phase_id} Spannung"
},
"talentmonitor_inverter_phase_frequency": {
"name": "Phase {phase_id} Frequenz"
},
"talentmonitor_inverter_panel_power": {
"name": "Panel {panel_id} Leistung"
},
"talentmonitor_inverter_panel_current": {
"name": "Panel {panel_id} Strom"
},
"talentmonitor_inverter_panel_voltage": {
"name": "Panel {panel_id} Spannung"
}
}
}
Expand Down
27 changes: 24 additions & 3 deletions custom_components/talent_monitor/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"entity": {
"sensor": {
"talentmonitor_powerstation_total_active_power": {
"name": "Current Power"
"name": "Active Power"
},
"talentmonitor_powerstation_day_energy": {
"name": "Total Energy Today"
Expand All @@ -37,11 +37,32 @@
"talentmonitor_powerstation_last_data_update_time": {
"name": "Last Data Update"
},
"talentmonitor_powerstation_rated_power": {
"talentmonitor_inverter_rated_power": {
"name": "Rated Power"
},
"talentmonitor_inverter_temp": {
"talentmonitor_inverter_inverter_temp": {
"name": "Temperature"
},
"talentmonitor_inverter_phase_active_power": {
"name": "Phase {phase_id} Active Power"
},
"talentmonitor_inverter_phase_current": {
"name": "Phase {phase_id} Current"
},
"talentmonitor_inverter_phase_voltage": {
"name": "Phase {phase_id} Voltage"
},
"talentmonitor_inverter_phase_frequency": {
"name": "Phase {phase_id} Frequency"
},
"talentmonitor_inverter_panel_power": {
"name": "Panel {panel_id} Power"
},
"talentmonitor_inverter_panel_current": {
"name": "Panel {panel_id} Current"
},
"talentmonitor_inverter_panel_voltage": {
"name": "Panel {panel_id} Voltage"
}
}
}
Expand Down

0 comments on commit a3b91c4

Please sign in to comment.