Skip to content

Commit ac10957

Browse files
committed
Added some sensors.
1 parent fa386da commit ac10957

File tree

12 files changed

+131
-45
lines changed

12 files changed

+131
-45
lines changed

custom_components/talent_monitor/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
3939

4040
await coordinator.async_config_entry_first_refresh()
4141

42-
_LOGGER.debug("received data %s", json.dumps(coordinator.data))
43-
4442
hass.data[DOMAIN][entry.entry_id] = coordinator
4543

4644
for platform in PLATFORMS:
4745
coordinator.platforms.append(platform)
48-
hass.async_add_job(
46+
hass.async_create_task(
4947
hass.config_entries.async_forward_entry_setup(entry, platform)
5048
)
5149

custom_components/talent_monitor/config_flow.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
import logging
44

5-
from custom_components.talent_monitor.pyTalentMonitor import AuthenticationError, TalentSolarMonitor
5+
from custom_components.talent_monitor.pyTalentMonitor import TalentSolarMonitor
6+
from custom_components.talent_monitor.pyTalentMonitor.data_provider import AuthenticationError
67
import homeassistant.helpers.config_validation as cv
78
import voluptuous as vol
89
from aiohttp import ClientConnectorError

custom_components/talent_monitor/coordinator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ async def _async_update_data(self):
5252
"""Update data via library."""
5353
_LOGGER.debug("_async_update_data ")
5454
try:
55-
return await self.api.fetch_data()
55+
await self.api.fetch_data()
5656
except Exception as exception:
5757
_LOGGER.exception("_async_update_data failed")
5858
raise UpdateFailed() from exception

custom_components/talent_monitor/entity.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ class TalentMonitorEntity(CoordinatorEntity):
1717
_attr_has_entity_name = True
1818

1919
def __init__(
20-
self, coordinator, entity: Entity
20+
self, coordinator, entity: Entity, entity_suffix: str = ""
2121
):
2222
"""Initialize a TalentMonitor entity."""
2323
super().__init__(coordinator)
2424

2525
device_id = f"{entity.entity_id}"
2626
device_name = entity.name
2727

28-
self._attr_unique_id = f"{device_id}"
28+
self._attr_unique_id = f"{device_id}{entity_suffix}"
2929

3030
self._attr_device_info = DeviceInfo(
3131
identifiers={(DOMAIN, device_id)},

custom_components/talent_monitor/pyTalentMonitor/__init__.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import argparse
44
import asyncio
5-
import json
65
import logging
76

87
from aiohttp import ClientSession
@@ -13,13 +12,6 @@
1312
# Configure logging
1413
_LOGGER: logging.Logger = logging.getLogger(__name__)
1514

16-
BASE_URL = "https://www.talent-monitoring.com/prod-api"
17-
TIMEZONE = "+02:00"
18-
19-
class AuthenticationError(Exception):
20-
"""AuthenticationError when connecting to the Talent API."""
21-
pass
22-
2315
class TalentSolarMonitor:
2416
"""TalentSolarMonitor API client."""
2517

@@ -38,13 +30,16 @@ def __init__(
3830
def get_power_stations(self) -> list[PowerStation]:
3931
return self._power_station_data_provider.power_stations
4032

41-
def fetch_data(self):
42-
self._inverter_data_provider.fetch_data()
43-
self._power_station_data_provider.fetch_data()
33+
async def fetch_data(self):
34+
await self._inverter_data_provider.fetch_data()
35+
await self._power_station_data_provider.fetch_data()
4436

4537
async def fetch_solar_data(self):
4638
await self.fetch_data()
4739

40+
async def login(self):
41+
await self._data_provider.login()
42+
4843
async def main(username: str, password: str):
4944
"""Connect to the TalentSolarMonitor API and fetch the solar data."""
5045
async with ClientSession() as session:

custom_components/talent_monitor/pyTalentMonitor/data_provider.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import os
33

44
from aiohttp import ClientSession
5-
from custom_components.talent_monitor.pyTalentMonitor import AuthenticationError
65

76
# Configure logging
87
_LOGGER: logging.Logger = logging.getLogger(__name__)
@@ -31,7 +30,7 @@ def get_credentials(self):
3130
async def login(self):
3231
"""Log in using the given credentials."""
3332
login_data = {"username": self._username, "password": self._password}
34-
response = await self.session.post(f"{self._url}/login", json=login_data)
33+
response = await self._session.post(f"{self._url}/login", json=login_data)
3534
response_data = await response.json()
3635
if "token" in response_data:
3736
self._token = response_data["token"]
@@ -48,13 +47,13 @@ async def refresh_token(self):
4847
async def get_data(self, endpoint):
4948
"""Get data from the given endpoint."""
5049
if not self._token:
51-
self.login()
50+
await self.login()
5251
headers = {"Authorization": f"Bearer {self._token}"}
53-
response = await self.session.get(f"{self._url}/{endpoint}", headers=headers)
52+
response = await self._session.get(f"{self._url}/{endpoint}", headers=headers)
5453
if response.status == 401: # Unauthorized, token might be expired
5554
self.refresh_token()
5655
headers["Authorization"] = f"Bearer {self._token}"
57-
response = await self.session.get(f"{self._url}/{endpoint}", headers=headers)
56+
response = await self._session.get(f"{self._url}/{endpoint}", headers=headers)
5857

5958
if response.status == 200:
6059
return await response.json()
@@ -67,4 +66,8 @@ class Entity:
6766

6867
def __init__(self, entity_id: str, name: str) -> None:
6968
self.entity_id = entity_id
70-
self.name = name
69+
self.name = name
70+
71+
class AuthenticationError(Exception):
72+
"""AuthenticationError when connecting to the Talent API."""
73+
pass

custom_components/talent_monitor/pyTalentMonitor/inverter.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ def __init__(
1313
self, entity_id: str, name: str
1414
) -> None:
1515
super().__init__(entity_id, name)
16-
self._data
17-
18-
@property
19-
def data(self, data):
20-
self._data = data
16+
self._data = {}
2117

2218
@property
2319
def data(self):
2420
return self._data
2521

22+
@data.setter
23+
def data(self, data):
24+
self._data = data
25+
2626

2727
class InverterDataProvider():
2828
def __init__(
@@ -47,6 +47,8 @@ async def fetch_data(self):
4747
if "deviceGuid" in inverter_data:
4848
deviceGuid = inverter_data["deviceGuid"]
4949

50+
_LOGGER.debug("Data for inverter GUID %s: %s", deviceGuid, json.dumps(inverter_data))
51+
5052
if not deviceGuid in self._inverters:
5153
self._inverters["deviceGuid"] = Inverter()
5254

@@ -56,6 +58,6 @@ async def fetch_data(self):
5658
endpoint=f"tools/device/selectDeviceInverterInfo?deviceGuid={deviceGuid}"
5759
)
5860

59-
_LOGGER.debug("Data for inverter GUID %s: %s", deviceGuid, json.dumps(inverter_info))
60-
if inverter_info:
61-
inverter.data = inverter_info
61+
_LOGGER.debug("Details for inverter GUID %s: %s", deviceGuid, json.dumps(inverter_info))
62+
if inverter_info and "data" in inverter_info:
63+
inverter.data = inverter_info["data"]

custom_components/talent_monitor/pyTalentMonitor/power_station.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ def __init__(
1515
self, entity_id: str, name: str
1616
) -> None:
1717
super().__init__(entity_id, name)
18-
self._data
19-
20-
@property
21-
def data(self, data):
22-
self._data = data
18+
self._data = {}
2319

2420
@property
2521
def data(self):
2622
return self._data
2723

24+
@data.setter
25+
def data(self, data):
26+
self._data = data
27+
2828

2929
class PowerStationDataProvider():
3030
def __init__(
@@ -50,15 +50,17 @@ async def fetch_data(self):
5050
powerStationGuid = power_station_data["powerStationGuid"]
5151
powerStationName = power_station_data["stationName"]
5252

53+
_LOGGER.debug("Data for powerstation GUID %s: %s", powerStationGuid, json.dumps(power_station_data))
54+
5355
if not powerStationGuid in self._power_stations:
5456
self._power_stations["powerStationGuid"] = PowerStation(powerStationGuid, powerStationName)
5557

56-
power_station = self._power_stations["deviceGuid"]
58+
power_station = self._power_stations["powerStationGuid"]
5759

5860
power_station_info = await self._data_provider.get_data(
5961
endpoint=f"system/station/getPowerStationByGuid?powerStationGuid={powerStationGuid}&timezone={TIMEZONE}"
6062
)
6163

62-
_LOGGER.debug("Data for powerstation GUID %s: %s", powerStationGuid, json.dumps(data))
63-
if power_station_info:
64-
power_station.data = power_station_info
64+
_LOGGER.debug("Details for powerstation GUID %s: %s", powerStationGuid, json.dumps(power_station_info))
65+
if power_station_info and "data" in power_station_info:
66+
power_station.data = power_station_info["data"]

custom_components/talent_monitor/sensor.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
"""Sensor platform for TalentMonitor."""
2+
from datetime import datetime
3+
import logging
24
from custom_components.talent_monitor.entity import TalentMonitorEntity
35
from custom_components.talent_monitor.pyTalentMonitor.power_station import PowerStation
46
from homeassistant.components.sensor import SensorDeviceClass
@@ -10,13 +12,40 @@
1012

1113
from .const import DOMAIN
1214

15+
16+
_LOGGER: logging.Logger = logging.getLogger(__name__)
17+
1318
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
1419
SensorEntityDescription(
1520
key="totalActivePower",
1621
translation_key="talentmonitor_powerstation_totalActivePower",
1722
state_class=SensorStateClass.MEASUREMENT,
1823
device_class=SensorDeviceClass.POWER,
19-
)
24+
),
25+
SensorEntityDescription(
26+
key="dayEnergy",
27+
translation_key="talentmonitor_powerstation_dayEnergy",
28+
state_class=SensorStateClass.TOTAL_INCREASING,
29+
device_class=SensorDeviceClass.ENERGY,
30+
),
31+
SensorEntityDescription(
32+
key="monthEnergy",
33+
translation_key="talentmonitor_powerstation_monthEnergy",
34+
state_class=SensorStateClass.TOTAL_INCREASING,
35+
device_class=SensorDeviceClass.ENERGY,
36+
),
37+
SensorEntityDescription(
38+
key="yearEnergy",
39+
translation_key="talentmonitor_powerstation_yearEnergy",
40+
state_class=SensorStateClass.TOTAL_INCREASING,
41+
device_class=SensorDeviceClass.ENERGY,
42+
),
43+
SensorEntityDescription(
44+
key="lastDataUpdateTime",
45+
translation_key="talentmonitor_powerstation_lastDataUpdateTime",
46+
state_class=SensorStateClass.MEASUREMENT,
47+
device_class=SensorDeviceClass.DATE,
48+
),
2049
)
2150

2251
SENSORS = {desc.key: desc for desc in SENSOR_TYPES}
@@ -35,6 +64,7 @@ async def async_setup_entry(hass, entry, async_add_devices):
3564
power_stations: list[PowerStation] = coordinator.api.get_power_stations()
3665
for power_station in power_stations:
3766
for index, value in enumerate(power_station.data):
67+
_LOGGER.debug("Iterate data for powerstation %s", value)
3868
if value and value in SENSORS:
3969
async_add_devices(
4070
[
@@ -59,6 +89,7 @@ def __init__(
5989
super().__init__(
6090
coordinator,
6191
power_station,
92+
sensorEntityDescription.key
6293
)
6394

6495
self._power_station = power_station
@@ -67,5 +98,21 @@ def __init__(
6798
@property
6899
def native_value(self):
69100
"""Return the state of the sensor."""
70-
return self._power_station.data[self.entity_description.key]
101+
if (self.entity_description.key == "lastDataUpdateTime"):
102+
return datetime.fromisoformat(self._power_station.data[self.entity_description.key])
103+
else:
104+
return self._power_station.data[self.entity_description.key]
105+
106+
@property
107+
def native_unit_of_measurement(self) -> str | None:
108+
"""Return the unit of measurement."""
109+
key_for_value_with_unit = self.entity_description.key + "Named"
110+
111+
if (key_for_value_with_unit in self._power_station.data and self._power_station.data[key_for_value_with_unit]):
112+
value_split = self._power_station.data[key_for_value_with_unit].split(" ")
113+
if (value_split and len(value_split) == 2):
114+
unit = value_split[1]
115+
return SENSOR_UNIT_MAPPING[unit]
116+
117+
return None
71118

custom_components/talent_monitor/translations/de.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,24 @@
1919
"abort": {
2020
"single_instance_allowed": "Es ist nur eine einzige Instanz zulässig."
2121
}
22+
},
23+
"entity": {
24+
"sensor": {
25+
"talentmonitor_powerstation_totalActivePower": {
26+
"name": "Aktuelle Leistung"
27+
},
28+
"talentmonitor_powerstation_dayEnergy": {
29+
"name": "Energie insgesamt (heute)"
30+
},
31+
"talentmonitor_powerstation_monthEnergy": {
32+
"name": "Energie insgesamt (dieser Monat)"
33+
},
34+
"talentmonitor_powerstation_yearEnergy": {
35+
"name": "Energie insgesamt (dieses Jahr)"
36+
},
37+
"talentmonitor_powerstation_lastDataUpdateTime": {
38+
"name": "Letzte Datenaktualisierung"
39+
}
40+
}
2241
}
2342
}

0 commit comments

Comments
 (0)