Open GetUpdate opened 4 months ago
I got the same problem here with my new fox ESS. I'm trying to integrate your changes but I'm not sure where. Do I understand you right, that you modified the original sensor.py file from the extension by simply editing the file from the custom_components\enpal\ folder?
@GetUpdate Maybe you can attach your sensor.py file here?
@gickowtf Of course it would also be fantactic if it could be added to the official extension
@GetUpdate I managed to integrate it succesfully. But I believe that the value with the String 1 and Sring 2 is wrong in your script above: They do not represent the phases but the Watt amount of the 2 PV strings connected to the Enpal system
i have published a prerelease v0.2.1 https://github.com/gickowtf/enpal-homeassistant/releases/tag/0.2.1
hey ich glaube wir können, da es um enpal geht, auch deutsch schreiben ;D ich habe gerade eben mal ein pre release rein gestellt... habe ihr Zugang zu influxdb?? könnt ihr mir die genauen fields
nennen. dann kann ich nochmal ein vernünftiges update machen.
hey ich glaube wir können, da es um enpal geht, auch deutsch schreiben ;D ich habe gerade eben mal ein pre release rein gestellt...
Klasse, vielen Dank. :-)
habe ihr Zugang zu influxdb?? könnt ihr mir die genauen
fields
nennen. dann kann ich nochmal ein vernünftiges update machen.
Leider habe ich keinen Zugang zur Influxdb. Ich hab die Konfigurationsbeispiele oben etwas abgeändert, indem ich nicht die Phasen A/B/C, sondern die Strings abgefragt habe und mir ausgeben lasse. Das klappt super:
#Power Sensor -> Inverter if measurement == "inverter" and field == "Voltage.String.1": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Voltage String 1', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'voltage', 'V')) if measurement == "inverter" and field == "Current.String.1": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Ampere String 1', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'current', 'A')) if measurement == "inverter" and field == "Power.DC.String.1": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Power String 1', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W')) if measurement == "inverter" and field == "Voltage.String.2": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Voltage String 2', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'voltage', 'V')) if measurement == "inverter" and field == "Current.String.2": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Ampere String 2', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'current', 'A')) if measurement == "inverter" and field == "Power.DC.String.2": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Power String 2', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
Ich bekomme aber bei meiner FoxESS Anlage leider keinen Wert für 'Enpal Energy External In Day' (bzw. immer 0 kwh), obwohl für 'Enpal Energy External Out Day' alles timmt. Ich vermute aber, dass das kein Problem deines Skriptes ist, denn in dem Enpal Solar Rel wird der Wert ebenfalls mit 0 aufgeführt (anders als in der App).
Was ich noch nicht verstehe ist die Bedeutung von "Enpal Energy Consumption". Was verbirgt sich dahinter?
Viele Grüße und ein frohes Osterfest :-),
Sven
Hi,
ein kurzer Nachtrag: Ich habe die if measurement == "..."
statements nun mit der Ausnahme vom Power-Abschnitt ganz bei mir rausgenommen, da die Werte andernfalls ab und zu nicht übertragen wurden. Nun läuft alles stabil mit der FoxESS - bzw. zumindest mit den Werten, die ich auch im Solar Rel sehe.
hey ich glaube wir können, da es um enpal geht, auch deutsch schreiben ;D ich habe gerade eben mal ein pre release rein gestellt...
Klasse, vielen Dank. :-)
habe ihr Zugang zu influxdb?? könnt ihr mir die genauen
fields
nennen. dann kann ich nochmal ein vernünftiges update machen.Leider habe ich keinen Zugang zur Influxdb. Ich hab die Konfigurationsbeispiele oben etwas abgeändert, indem ich nicht die Phasen A/B/C, sondern die Strings abgefragt habe und mir ausgeben lasse. Das klappt super:
#Power Sensor -> Inverter if measurement == "inverter" and field == "Voltage.String.1": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Voltage String 1', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'voltage', 'V')) if measurement == "inverter" and field == "Current.String.1": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Ampere String 1', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'current', 'A')) if measurement == "inverter" and field == "Power.DC.String.1": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Power String 1', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W')) if measurement == "inverter" and field == "Voltage.String.2": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Voltage String 2', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'voltage', 'V')) if measurement == "inverter" and field == "Current.String.2": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Ampere String 2', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'current', 'A')) if measurement == "inverter" and field == "Power.DC.String.2": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Power String 2', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
Ich bekomme aber bei meiner FoxESS Anlage leider keinen Wert für 'Enpal Energy External In Day' (bzw. immer 0 kwh), obwohl für 'Enpal Energy External Out Day' alles timmt. Ich vermute aber, dass das kein Problem deines Skriptes ist, denn in dem Enpal Solar Rel wird der Wert ebenfalls mit 0 aufgeführt (anders als in der App).
Was ich noch nicht verstehe ist die Bedeutung von "Enpal Energy Consumption". Was verbirgt sich dahinter?
Viele Grüße und ein frohes Osterfest :-),
Sven
Hi Sven,
Ich habe in meiner Übersicht auch meistens für die "Enpal Energy Consumption" 0kWh stehen. Aktuell steht der Wert auf 0,5kWh. So wie ich das verstehe ist das der Gesamtbezug deines Hauses aus dem Netz. Wenn Du also ein System mit Speicher hast der über die Nacht reicht und Du momentan mehr produzierst als Du verbrauchst macht es Sinn, dass da eine 0 steht. Das ist bei mir der Fall, es schient aber so als ob über den Tag verteilt eine gewisse Minimalmenge immer aus dem Netz bezogen wird. Ich habe seit der Installation der Anlage vor ca 2 Wochen im Schnitt einen täglichen Bezug aus dem Netz con ca 0,5kWh gehabt.
Gruß, Stephan
Hi Stephan,
ich habe noch einen zweiten Smart Meter von der Wallbox und auch den Zähler etwas beobachtet. Es scheint so als wenn der Gesamtverbrauch aus dem Netz immer "Enpal Energy Consumption" + " Energy External In Day" entspricht. Bei mir sind beispielsweise heute beide Werte gefüllt - einmal mit 1,1kwh und einmal mit 0,2kwh. Der korrekte Wert lauf meinem SmartMeter der Wallbox liegt bei 1.3...
hey ich glaube wir können, da es um enpal geht, auch deutsch schreiben ;D ich habe gerade eben mal ein pre release rein gestellt... habe ihr Zugang zu influxdb?? könnt ihr mir die genauen
fields
nennen. dann kann ich nochmal ein vernünftiges update machen.
Hi Gicko,
Ich habe seit knapp 2 Wochen ebenfalls ein System von Enpal mit Inverter und 20 kWh Speicher vonFox ESS. Heute habe ich auch den "viewer"-Zugang von Enpal erhalten und mir Deine Integration gleich mal installiert und angeschaut. Vielen Dank für die Arbeit die Du da investiert hast.
Bei mir funktionieren ebenfalls momentan einige der Sensoren nicht. Ich sehe mit der aktuellen Version der Integration folgendes:
Was mir nicht angezeigt wird sind sämtliche Batterie bezogenen Werte sowie die Enpal Voltage Phase A-C, Enpal Power Phase A-C, Enpal Ampere Phase A-C und die Werte zur Wallbox (habe ich keine).
Auf die Schnelle musste ich feststellen, dass bei mir die relevanten measurements teilweise anders heißen als in Deiner Integration. Ich habe zum Beispiel kein measurement namens "battery". Bei mir stehen die entsprechenden Felder zum Großteil im measurement "inverter" und (teilweise gedoppelt und mit anderem Feldbezeichner) im measurement "system".
Ein schneller Test bei dem ich das measurement für die Batteriegruppe durch "inverter" ersetzt habe hat dafür gesorgt, dass ich jetzt die entsprechenden Batteriesensoren angezeigt bekomme. Ich werde mir das in den nächsten Tagen mal genauer anschauen und Dir dann meinen Fix zukommen lassen. Ich kann Dir auch gerne das genaue Schema der influxDB die auf meinem System läuft (Solar Rel 8.35) zukommen lassen wenn Du mir sagst, auf welchem Weg ich das am besten machen soll.
Als weitere kurze Information habe ich vom Enpal Service-Team noch folgende Aussage bekommen: "Wir arbeiten in diesem Jahr an einer größeren Umstrukturierung unserer Lösung die dann auch auf Ihrem System ausgerollt wird. Dies wird dann auf jeden Fall auch die Influx DB betreffen. Sie müssten dann noch einmal Anpassungen an Ihrem System vornehmen."
Nur als kleine Warnung vorab, dass zumindest bei den neuen Enpal-Boxen wohl in absehbarer Zukunft noch das eine oder andere an Anpassungen fällig werden wird.
Gruß, Stephan
hey ich glaube wir können, da es um enpal geht, auch deutsch schreiben ;D ich habe gerade eben mal ein pre release rein gestellt... habe ihr Zugang zu influxdb?? könnt ihr mir die genauen
fields
nennen. dann kann ich nochmal ein vernünftiges update machen.Hi Gicko,
Ich habe seit knapp 2 Wochen ebenfalls ein System von Enpal mit Inverter und 20 kWh Speicher vonFox ESS. Heute habe ich auch den "viewer"-Zugang von Enpal erhalten und mir Deine Integration gleich mal installiert und angeschaut. Vielen Dank für die Arbeit die Du da investiert hast.
Bei mir funktionieren ebenfalls momentan einige der Sensoren nicht. Ich sehe mit der aktuellen Version der Integration folgendes:
- Enpal Energy Consumption
- Enpal Energy External In Day
- Enpal Energy External Out Day
- Enpal Power External Total
- Enpal Power House Total
- Enpal Production Day
- Enpal Solar Production Power
Was mir nicht angezeigt wird sind sämtliche Batterie bezogenen Werte sowie die Enpal Voltage Phase A-C, Enpal Power Phase A-C, Enpal Ampere Phase A-C und die Werte zur Wallbox (habe ich keine).
Auf die Schnelle musste ich feststellen, dass bei mir die relevanten measurements teilweise anders heißen als in Deiner Integration. Ich habe zum Beispiel kein measurement namens "battery". Bei mir stehen die entsprechenden Felder zum Großteil im measurement "inverter" und (teilweise gedoppelt und mit anderem Feldbezeichner) im measurement "system".
Ein schneller Test bei dem ich das measurement für die Batteriegruppe durch "inverter" ersetzt habe hat dafür gesorgt, dass ich jetzt die entsprechenden Batteriesensoren angezeigt bekomme. Ich werde mir das in den nächsten Tagen mal genauer anschauen und Dir dann meinen Fix zukommen lassen. Ich kann Dir auch gerne das genaue Schema der influxDB die auf meinem System läuft (Solar Rel 8.35) zukommen lassen wenn Du mir sagst, auf welchem Weg ich das am besten machen soll.
Als weitere kurze Information habe ich vom Enpal Service-Team noch folgende Aussage bekommen: "Wir arbeiten in diesem Jahr an einer größeren Umstrukturierung unserer Lösung die dann auch auf Ihrem System ausgerollt wird. Dies wird dann auf jeden Fall auch die Influx DB betreffen. Sie müssten dann noch einmal Anpassungen an Ihrem System vornehmen."
Nur als kleine Warnung vorab, dass zumindest bei den neuen Enpal-Boxen wohl in absehbarer Zukunft noch das eine oder andere an Anpassungen fällig werden wird.
Gruß, Stephan
Hallo, Sorry für die späte Rückmeldung, war 2 Wochen am Roten Meer und leider ist dort kein VPN möglich... Sehe mit der V02.2 auch wie @skehrer nur die Enitäten wie oben beschrieben.
Mir fehlt mit V0.2.2 noch immer die Werte wie ich oben angegeben habe (Battery und Phases). Mit meiner "abgeleiteten" Sensor.py klappt das jedoch auch mit der V02.2. wieder.
@skehrer Du kannst ja mal versuchen ob das dann bei Dir auch klappt. Die zu editierende Datei findest Du unter /homeassistant/custom_components/enpal/sensor.py -> Umbenennen und als Kopie behalten -> Inhalt von sensor.py mit werten unten überschreiben. -> HA neu starten...
Gruß Michael
Sensor.py:
"""Platform for sensor integration.""" from future import annotations
import asyncio import uuid from datetime import timedelta, datetime from homeassistant.components.sensor import (SensorEntity) from homeassistant.core import HomeAssistant from homeassistant import config_entries from homeassistant.helpers.device_registry import DeviceEntryType from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_registry import async_get, async_entries_for_config_entry from custom_components.enpal.const import DOMAIN import aiohttp import logging from influxdb_client import InfluxDBClient
_LOGGER = logging.getLogger(name) SCAN_INTERVAL = timedelta(seconds=20)
VERSION= '0.1.0'
def get_tables(ip: str, port: int, token: str): client = InfluxDBClient(url=f'http://{ip}:{port}', token=token, org='enpal') query_api = client.query_api()
query = 'from(bucket: "solar") \
|> range(start: -5m) \
|> last()'
tables = query_api.query(query)
return tables
async def async_setup_entry( hass: HomeAssistant, config_entry: config_entries.ConfigEntry, async_add_entities, ):
config = hass.data[DOMAIN][config_entry.entry_id]
if config_entry.options:
config.update(config_entry.options)
to_add = []
if not 'enpal_host_ip' in config:
_LOGGER.error("No enpal_host_ip in config entry")
return
if not 'enpal_host_port' in config:
_LOGGER.error("No enpal_host_port in config entry")
return
if not 'enpal_token' in config:
_LOGGER.error("No enpal_token in config entry")
return
global_config = hass.data[DOMAIN]
tables = await hass.async_add_executor_job(get_tables, config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'])
for table in tables:
field = table.records[0].values['_field']
measurement = table.records[0].values['_measurement']
if measurement == "inverter" and field == "Power.DC.Total":
to_add.append(EnpalSensor(field, measurement, 'mdi:solar-power', 'Enpal Solar Production Power', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
if measurement == "inverter" and field == "Power.House.Total":
to_add.append(EnpalSensor(field, measurement, 'mdi:home-lightning-bolt', 'Enpal Power House Total', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
if measurement == "system" and field == "Power.External.Total":
to_add.append(EnpalSensor(field, measurement, 'mdi:home-lightning-bolt', 'Enpal Power External Total', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
# Consum Total per Day
if measurement == "system" and field == "Energy.Consumption.Total.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:home-lightning-bolt', 'Enpal Energy Consumption', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
# to the Grid and from the Grid
if measurement == "system" and field == "Energy.External.Total.Out.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:transmission-tower-export', 'Enpal Energy External Out Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
if measurement == "system" and field == "Energy.External.Total.In.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:transmission-tower-import', 'Enpal Energy External In Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
# Solar Energy.Production.Total.Day
if measurement == "system" and field == "Energy.Production.Total.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:solar-power-variant', 'Enpal Production Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
#Battery
if field == "Power.Battery.Charge.Discharge":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery-charging', 'Enpal Battery Power', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
if field == "Energy.Battery.Charge.Level":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery', 'Enpal Battery Percent', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'battery', '%'))
if field == "Energy.Battery.Charge.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery-arrow-up', 'Enpal Battery Charge Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
if field == "Energy.Battery.Discharge.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery-arrow-down', 'Enpal Battery Discharge Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
if field == "Energy.Battery.Charge.Load":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery-arrow-up', 'Enpal Battery Charge Total', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
#Power Sensor -> Inverter
if measurement == "inverter" and field == "Voltage.String.1":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Voltage Phase A', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'voltage', 'V'))
if measurement == "inverter" and field == "Current.String.1":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Ampere Phase A', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'current', 'A'))
if measurement == "inverter" and field == "Power.DC.String.1":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Power Phase A', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
if measurement == "inverter" and field == "Voltage.String.2":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Voltage Phase B', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'voltage', 'V'))
if measurement == "inverter" and field == "Current.String.2":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Ampere Phase B', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'current', 'A'))
if measurement == "inverter" and field == "Power.DC.String.2":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Power Phase B', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
entity_registry = async_get(hass)
entries = async_entries_for_config_entry(
entity_registry, config_entry.entry_id
)
for entry in entries:
entity_registry.async_remove(entry.entity_id)
async_add_entities(to_add, update_before_add=True)
class EnpalSensor(SensorEntity):
def __init__(self, field: str, measurement: str, icon:str, name: str, ip: str, port: int, token: str, device_class: str, unit: str):
self.field = field
self.measurement = measurement
self.ip = ip
self.port = port
self.token = token
self.enpal_device_class = device_class
self.unit = unit
self._attr_icon = icon
self._attr_name = name
self._attr_unique_id = f'enpal_{measurement}_{field}'
self._attr_extra_state_attributes = {}
async def async_update(self) -> None:
# Get the IP address from the API
try:
client = InfluxDBClient(url=f'http://{self.ip}:{self.port}', token=self.token, org="enpal")
query_api = client.query_api()
query = f'from(bucket: "solar") \
|> range(start: -5m) \
|> filter(fn: (r) => r["_measurement"] == "{self.measurement}") \
|> filter(fn: (r) => r["_field"] == "{self.field}") \
|> last()'
tables = await self.hass.async_add_executor_job(query_api.query, query)
value = 0
if tables:
value = tables[0].records[0].values['_value']
self._attr_native_value = round(float(value), 2)
self._attr_device_class = self.enpal_device_class
self._attr_native_unit_of_measurement = self.unit
self._attr_state_class = 'measurement'
self._attr_extra_state_attributes['last_check'] = datetime.now()
self._attr_extra_state_attributes['field'] = self.field
self._attr_extra_state_attributes['measurement'] = self.measurement
#if self.field == 'Energy.Consumption.Total.Day' or 'Energy.Storage.Total.Out.Day' or 'Energy.Storage.Total.In.Day' or 'Energy.Production.Total.Day' or 'Energy.External.Total.Out.Day' or 'Energy.External.Total.In.Day':
if self._attr_native_unit_of_measurement == "kWh":
self._attr_extra_state_attributes['last_reset'] = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
self._attr_state_class = 'total'
if self._attr_native_unit_of_measurement == "Wh":
self._attr_extra_state_attributes['last_reset'] = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
self._attr_state_class = 'total'
if self.field == 'Percent.Storage.Level':
if self._attr_native_value >= 10:
self._attr_icon = "mdi:battery-outline"
if self._attr_native_value <= 19 and self._attr_native_value >= 10:
self._attr_icon = "mdi:battery-10"
if self._attr_native_value <= 29 and self._attr_native_value >= 20:
self._attr_icon = "mdi:battery-20"
if self._attr_native_value <= 39 and self._attr_native_value >= 30:
self._attr_icon = "mdi:battery-30"
if self._attr_native_value <= 49 and self._attr_native_value >= 40:
self._attr_icon = "mdi:battery-40"
if self._attr_native_value <= 59 and self._attr_native_value >= 50:
self._attr_icon = "mdi:battery-50"
if self._attr_native_value <= 69 and self._attr_native_value >= 60:
self._attr_icon = "mdi:battery-60"
if self._attr_native_value <= 79 and self._attr_native_value >= 70:
self._attr_icon = "mdi:battery-70"
if self._attr_native_value <= 89 and self._attr_native_value >= 80:
self._attr_icon = "mdi:battery-80"
if self._attr_native_value <= 99 and self._attr_native_value >= 90:
self._attr_icon = "mdi:battery-90"
if self._attr_native_value == 100:
self._attr_icon = "mdi:battery"
except Exception as e:
_LOGGER.error(f'{e}')
self._state = 'Error'
self._attr_native_value = None
self._attr_extra_state_attributes['last_check'] = datetime.now()
Führt dann zu 18 Entitäten:
Hi Gicko,
Danke für die angepasste Sensor.py. Ich teste morgen (sofern ich dazu komme) mal aus ob das bei mir funktioniert. Ich habe mir aber die statements gerade mal angeschaut und denke das müsste passen. Gibt es einen Grund warum Du bei den Sensoren für die Batterie das measurement aus der if-Abfrage rausgenommen hast? Ich hätte eher mit sowas gerechnet:
if measurement == "inverter" and field == "Power.Battery.Charge.Discharge":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery-charging', 'Enpal Battery Power', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
Was ich heute abend mal gemacht habe ist mir den aktuellen Aufbau des solar-Buckets anzuschauen. In der aktuellen Version (immer noch Solar Rel 8.35 vom 25.03.2024) habe ich im measurement "inverter" etliche zusätzliche Felder gegenüber dem letzten Mal als ich mir das angeschaut habe. Das Schema sieht bei mir aktuell so aus:
Measurement "System":
Energy.Consumption.Total.Day
Energy.External.Total.In.Day
Energy.External.Total.Out.Day
Energy.Production.Total.Day
Energy.Storage.Level
Energy.Storage.Total.In.Day
Energy.Storage.Total.Out.Day
Percent.Storage.Level
Power.Consumption.Total
Power.External.Total
Power.Production.Total
Power.Storage.Total
measureId
Measurement "inverter":
Battery.ChargeLevel.Max
Battery.ChargeLevel.Min
Battery.ChargeLevel.MinOnGrid
Battery.SOH
Command.Start.Stop
Current.Battery
Current.String.1
Current.String.2
Dongle.BackendConnection
Energy.Battery.Ah
Energy.Battery.Charge.Day
Energy.Battery.Charge.Level
Energy.Battery.Charge.Load
Energy.Battery.Discharge.Day
Energy.Consumption.Total.Day
Energy.Grid.Export.Day
Energy.Grid.Import.Day
Energy.Production.Total.Day
Frequency.Grid
Inverter.System.State
Meter.Connect.State
Meter.Enable.Disable
Meter2.AC.Phase.A
Meter2.AC.Phase.B
Meter2.AC.Phase.C
Meter2.AC.Total
Meter2.Connect.State
Meter2.Enable.Disable
Mode.Forcible.Charge.Discharge
Mode.Forcible.Timeout
Power.AC.Phase.A
Power.AC.Phase.B
Power.AC.Phase.C
Power.Battery.Charge.Discharge
Power.Battery.Charge.Discharge.Set
Power.DC.String.1
Power.DC.String.2
Power.DC.Total
Power.Factor
Power.Grid.Export
Power.House.Total
Power.Limit
Power.Reactive
Voltage.Battery
Voltage.Phase.A
Voltage.Phase.B
Voltage.Phase.C
Voltage.String.1
Voltage.String.2
Measurement "iot":
Cpu.Load
LTE.Predictor.Result.Passed
LTE.Quality
LTE.RSRP
LTE.RSRQ
LTE.RSSI
LTE.SNR
Memory.Usage
Measurement "wallbox":
Power.Wallbox.Connector.0.Charging.Requested
Power.Wallbox.Connector.1.Charging.Requested
Status.Wallbox.Connected
Einige Felder scheinen dabei Dopplungen zu sein, z.B. "system-Energy.Storage.Total.In.Day" und "inverter-Energy.Battery.Charge.Day", die beide "Enpal Battery Charge Day" anzuzeigen scheinen.
Ich nehme mir in den nächsten Tagen mal Deine originale Sensor.py und passe sie so an, dass sie für mein System passt. Wenn ich das gemacht habe stelle ich sie Dir hier in einen Post.
Gruß, Stephan
Da ich noch ein Paar Probleme mit dem Energy Dashboard hatte, habe ich mir die Config und die Daten aus dem "Solar" nachmal genauer angeschaut. Wie es aussieht, gibt es noch bei dem Output der Daten gewisse Diskrepanzen, wie zum Beispiel bei Energy.Consumption.Total.Day und Energy.Production.Total.Day
Unter System werden die Daten des Vortags angezeigt und unter Inverter die aktuellen Live Daten. Ich habe meine Konfiguration auf Inverter umgestellt und damit scheint es nun die richtigen Daten auszuspucken.
Hat eigentlich einer von euch die Enpal PIN für die Inverter Config? Leider hat sich bei mir die Sommerzeit noch nicht umgestellt :(
Interessant, dass das bei Dir voneinander abweicht. Ich habe gerade eben mal geschaut und zumindest stand heute abend 22 Uhr sind die Werte unter System und Inverter bei mir identisch. Ich schaue mir das morgen früh nochmal an. Mal schauen ob es da bei mir dann trotzdem identische Werte sind oder ob das einfach erst im Lauf des Tages nachgezogen wird.
Bezüglich der Uhrzeit: nein, ich habe keine PIN für die Inverter Config. Welche Uhrzeit meinst Du, die bei Dir nicht korrekt ist? Bei mir ist die Uhrzeit der Werte im Menüpunkt "Messages" ebenfalls um zwei Stunden daneben. Allerdings gehe ich davon aus, dass diese Uhrzeit in UTC ausgeliefert wird. Das würde passen da es vor der Zeitumstellung bei mir eine Stunde war. Die Zeitstempel in der InfluxDB sind bei mir korrekt in CEST. Das scheint mir also (auf meinem System) soweit alles zu passen.
Kleine Randbemerkung noch: ich habe gerade gesehen dass ich seit heute eine neue Version der Solar habe, nämlich Rel 8.35.1 vom 10.04.2024. Das Schema der InfluxDB ist aber unverändert!
Hat eigentlich einer von euch die Enpal PIN für die Inverter Config? Leider hat sich bei mir die Sommerzeit noch nicht umgestellt :(
Das habe ich hier auch und das Zeitproblem führte bei mit dazu, dass die Werte von Energy.Production.Total.Day z.b. verspätet auf 0 gesetzt wurden und daurch bei HomeAssistant das Energiedashboard nicht mehr stimmte. Ich habe das dadurch gelöst, dass ich einen Verbrauchszähler erstellt habe, der die Werte immer aufsummiert und dass ich den dann als Quelle im Energiedashboard genommen habe...
Bezüglich der Uhrzeit: nein, ich habe keine PIN für die Inverter Config. Welche Uhrzeit meinst Du, die bei Dir nicht korrekt ist? Bei mir ist die Uhrzeit der Werte im Menüpunkt "Messages" ebenfalls um zwei Stunden daneben. Allerdings gehe ich davon aus, dass diese Uhrzeit in UTC ausgeliefert wird. Das würde passen da es vor der Zeitumstellung bei mir eine Stunde war. Die Zeitstempel in der InfluxDB sind bei mir korrekt in CEST. Das scheint mir also (auf meinem System) soweit alles zu passen.
Bei mir passt die Uhrzeit auf dem Inverter selbst nicht. Die Daten in der Datenbank sind mit dem korrekten UTC-Zeitstempel versehen. Es ist mehr ein "Es triggert mich" als ein technisches Problem.
Kleine Randbemerkung noch: ich habe gerade gesehen dass ich seit heute eine neue Version der Solar habe, nämlich Rel 8.35.1 vom 10.04.2024. Das Schema der InfluxDB ist aber unverändert!
Ja, das kann ich bestätigen.
Was mir auch noch aufgefallen ist: Der Wert "Energy.External.Total.In.Day" (aktuell 6,6kWh) und "Energy.Grid.Import.Day" (aktuell 1,1kWh) sind beide unterschiedlich bei mir. Und beide sind falsch! In der ENPAL App allerdings wird der richtige Wert angezeigt (aktuell 3,4kWh). Ich verstehe zum verrecken nicht, wo die App sich den Wert herzieht. Soweit ich es rekonstruieren kann, ist der Wert Energy.External.Total.In.Day der gestrige Verbrauch. Bei den anderen Werte, stehe ich auf dem Schlauch...
Was mir auch noch aufgefallen ist: Der Wert "Energy.External.Total.In.Day" (aktuell 6,6kWh) und "Energy.Grid.Import.Day" (aktuell 1,1kWh) sind beide unterschiedlich bei mir. Und beide sind falsch! In der ENPAL App allerdings wird der richtige Wert angezeigt (aktuell 3,4kWh). Ich verstehe zum verrecken nicht, wo die App sich den Wert herzieht.
Schau mal, ob Energy.Grid.Import.Day + Energy.Consumption.Total.Day in Summe bei dir die 3,4 kWh ergeben. Bei mir ist das so, dass beide Werte zusammen dem Netzimport entsprechen
Schau mal, ob Energy.Grid.Import.Day + Energy.Consumption.Total.Day in Summe bei dir die 3,4 kWh ergeben. Bei mir ist das so, dass beide Werte zusammen dem Netzimport entsprechen
Leider nein. Der Energy.Consumption.Total.Day Wert, ist bei mir der Gesamtverbrauch des Hauses. Ich müsste also, um mir den Wert zu errechnen folgendes tun: Gesamtverbrauch -Batterieladen -Batterieentladen -solarerzeugungTag -netzeinspeisung rechnen. Das setzt aber voraus, das ich den Akku nicht über das Netz geladen habe, wenn der Strom günstig ist. Alternativ baue ich mir einen ESP der mir den Verbrauch am Zähler direkt ermittelt. Das System von ENPAL scheint noch nicht richtig ausgereift zu sein...
Denke vom Zähler, die Werte bekommt ENPAL direkt über die Antenne am Zähler, Der Zähler gibt diese m.E. nach nicht an die Hausinterne influx DB weiter.
Hallo Zusammen,
habe dieses issue gestartet um die Fox Ess Harware ebenfalls auslesen zu können. Leider geht das mit der standard integration nach wie vor nicht. Nutze daher noch immer eine angepasste sensor.py. Ist es möglich diese zu integrieren oder braucht man für Fox Ess eine eigene Integration?
Gruß und Dank im Voraus M
hey ich glaube wir können, da es um enpal geht, auch deutsch schreiben ;D ich habe gerade eben mal ein pre release rein gestellt... habe ihr Zugang zu influxdb?? könnt ihr mir die genauen
fields
nennen. dann kann ich nochmal ein vernünftiges update machen.Hi Gicko, Ich habe seit knapp 2 Wochen ebenfalls ein System von Enpal mit Inverter und 20 kWh Speicher vonFox ESS. Heute habe ich auch den "viewer"-Zugang von Enpal erhalten und mir Deine Integration gleich mal installiert und angeschaut. Vielen Dank für die Arbeit die Du da investiert hast. Bei mir funktionieren ebenfalls momentan einige der Sensoren nicht. Ich sehe mit der aktuellen Version der Integration folgendes:
- Enpal Energy Consumption
- Enpal Energy External In Day
- Enpal Energy External Out Day
- Enpal Power External Total
- Enpal Power House Total
- Enpal Production Day
- Enpal Solar Production Power
Was mir nicht angezeigt wird sind sämtliche Batterie bezogenen Werte sowie die Enpal Voltage Phase A-C, Enpal Power Phase A-C, Enpal Ampere Phase A-C und die Werte zur Wallbox (habe ich keine). Auf die Schnelle musste ich feststellen, dass bei mir die relevanten measurements teilweise anders heißen als in Deiner Integration. Ich habe zum Beispiel kein measurement namens "battery". Bei mir stehen die entsprechenden Felder zum Großteil im measurement "inverter" und (teilweise gedoppelt und mit anderem Feldbezeichner) im measurement "system". Ein schneller Test bei dem ich das measurement für die Batteriegruppe durch "inverter" ersetzt habe hat dafür gesorgt, dass ich jetzt die entsprechenden Batteriesensoren angezeigt bekomme. Ich werde mir das in den nächsten Tagen mal genauer anschauen und Dir dann meinen Fix zukommen lassen. Ich kann Dir auch gerne das genaue Schema der influxDB die auf meinem System läuft (Solar Rel 8.35) zukommen lassen wenn Du mir sagst, auf welchem Weg ich das am besten machen soll. Als weitere kurze Information habe ich vom Enpal Service-Team noch folgende Aussage bekommen: "Wir arbeiten in diesem Jahr an einer größeren Umstrukturierung unserer Lösung die dann auch auf Ihrem System ausgerollt wird. Dies wird dann auf jeden Fall auch die Influx DB betreffen. Sie müssten dann noch einmal Anpassungen an Ihrem System vornehmen." Nur als kleine Warnung vorab, dass zumindest bei den neuen Enpal-Boxen wohl in absehbarer Zukunft noch das eine oder andere an Anpassungen fällig werden wird. Gruß, Stephan
Hallo, Sorry für die späte Rückmeldung, war 2 Wochen am Roten Meer und leider ist dort kein VPN möglich... Sehe mit der V02.2 auch wie @skehrer nur die Enitäten wie oben beschrieben.
Mir fehlt mit V0.2.2 noch immer die Werte wie ich oben angegeben habe (Battery und Phases). Mit meiner "abgeleiteten" Sensor.py klappt das jedoch auch mit der V02.2. wieder.
@skehrer Du kannst ja mal versuchen ob das dann bei Dir auch klappt. Die zu editierende Datei findest Du unter /homeassistant/custom_components/enpal/sensor.py -> Umbenennen und als Kopie behalten -> Inhalt von sensor.py mit werten unten überschreiben. -> HA neu starten...
Gruß Michael
Sensor.py:
"""Platform for sensor integration.""" from future import annotations
import asyncio import uuid from datetime import timedelta, datetime from homeassistant.components.sensor import (SensorEntity) from homeassistant.core import HomeAssistant from homeassistant import config_entries from homeassistant.helpers.device_registry import DeviceEntryType from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_registry import async_get, async_entries_for_config_entry from custom_components.enpal.const import DOMAIN import aiohttp import logging from influxdb_client import InfluxDBClient
_LOGGER = logging.getLogger(name) SCAN_INTERVAL = timedelta(seconds=20)
VERSION= '0.1.0'
def get_tables(ip: str, port: int, token: str): client = InfluxDBClient(url=f'http://{ip}:{port}', token=token, org='enpal') query_api = client.query_api()
query = 'from(bucket: "solar") \ |> range(start: -5m) \ |> last()' tables = query_api.query(query) return tables
async def async_setup_entry( hass: HomeAssistant, config_entry: config_entries.ConfigEntry, async_add_entities, ): # Get the config entry for the integration config = hass.data[DOMAIN][config_entry.entry_id] if config_entry.options: config.update(config_entry.options) to_add = [] if not 'enpal_host_ip' in config: _LOGGER.error("No enpal_host_ip in config entry") return if not 'enpal_host_port' in config: _LOGGER.error("No enpal_host_port in config entry") return if not 'enpal_token' in config: _LOGGER.error("No enpal_token in config entry") return
global_config = hass.data[DOMAIN] tables = await hass.async_add_executor_job(get_tables, config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token']) for table in tables: field = table.records[0].values['_field'] measurement = table.records[0].values['_measurement'] if measurement == "inverter" and field == "Power.DC.Total": to_add.append(EnpalSensor(field, measurement, 'mdi:solar-power', 'Enpal Solar Production Power', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W')) if measurement == "inverter" and field == "Power.House.Total": to_add.append(EnpalSensor(field, measurement, 'mdi:home-lightning-bolt', 'Enpal Power House Total', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W')) if measurement == "system" and field == "Power.External.Total": to_add.append(EnpalSensor(field, measurement, 'mdi:home-lightning-bolt', 'Enpal Power External Total', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W')) # Consum Total per Day if measurement == "system" and field == "Energy.Consumption.Total.Day": to_add.append(EnpalSensor(field, measurement, 'mdi:home-lightning-bolt', 'Enpal Energy Consumption', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh')) # to the Grid and from the Grid if measurement == "system" and field == "Energy.External.Total.Out.Day": to_add.append(EnpalSensor(field, measurement, 'mdi:transmission-tower-export', 'Enpal Energy External Out Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh')) if measurement == "system" and field == "Energy.External.Total.In.Day": to_add.append(EnpalSensor(field, measurement, 'mdi:transmission-tower-import', 'Enpal Energy External In Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh')) # Solar Energy.Production.Total.Day if measurement == "system" and field == "Energy.Production.Total.Day": to_add.append(EnpalSensor(field, measurement, 'mdi:solar-power-variant', 'Enpal Production Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh')) #Battery if field == "Power.Battery.Charge.Discharge": to_add.append(EnpalSensor(field, measurement, 'mdi:battery-charging', 'Enpal Battery Power', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W')) if field == "Energy.Battery.Charge.Level": to_add.append(EnpalSensor(field, measurement, 'mdi:battery', 'Enpal Battery Percent', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'battery', '%')) if field == "Energy.Battery.Charge.Day": to_add.append(EnpalSensor(field, measurement, 'mdi:battery-arrow-up', 'Enpal Battery Charge Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh')) if field == "Energy.Battery.Discharge.Day": to_add.append(EnpalSensor(field, measurement, 'mdi:battery-arrow-down', 'Enpal Battery Discharge Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh')) if field == "Energy.Battery.Charge.Load": to_add.append(EnpalSensor(field, measurement, 'mdi:battery-arrow-up', 'Enpal Battery Charge Total', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh')) #Power Sensor -> Inverter if measurement == "inverter" and field == "Voltage.String.1": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Voltage Phase A', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'voltage', 'V')) if measurement == "inverter" and field == "Current.String.1": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Ampere Phase A', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'current', 'A')) if measurement == "inverter" and field == "Power.DC.String.1": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Power Phase A', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W')) if measurement == "inverter" and field == "Voltage.String.2": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Voltage Phase B', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'voltage', 'V')) if measurement == "inverter" and field == "Current.String.2": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Ampere Phase B', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'current', 'A')) if measurement == "inverter" and field == "Power.DC.String.2": to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Power Phase B', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W')) entity_registry = async_get(hass) entries = async_entries_for_config_entry( entity_registry, config_entry.entry_id ) for entry in entries: entity_registry.async_remove(entry.entity_id) async_add_entities(to_add, update_before_add=True)
class EnpalSensor(SensorEntity):
def __init__(self, field: str, measurement: str, icon:str, name: str, ip: str, port: int, token: str, device_class: str, unit: str): self.field = field self.measurement = measurement self.ip = ip self.port = port self.token = token self.enpal_device_class = device_class self.unit = unit self._attr_icon = icon self._attr_name = name self._attr_unique_id = f'enpal_{measurement}_{field}' self._attr_extra_state_attributes = {} async def async_update(self) -> None: # Get the IP address from the API try: client = InfluxDBClient(url=f'http://{self.ip}:{self.port}', token=self.token, org="enpal") query_api = client.query_api() query = f'from(bucket: "solar") \ |> range(start: -5m) \ |> filter(fn: (r) => r["_measurement"] == "{self.measurement}") \ |> filter(fn: (r) => r["_field"] == "{self.field}") \ |> last()' tables = await self.hass.async_add_executor_job(query_api.query, query) value = 0 if tables: value = tables[0].records[0].values['_value'] self._attr_native_value = round(float(value), 2) self._attr_device_class = self.enpal_device_class self._attr_native_unit_of_measurement = self.unit self._attr_state_class = 'measurement' self._attr_extra_state_attributes['last_check'] = datetime.now() self._attr_extra_state_attributes['field'] = self.field self._attr_extra_state_attributes['measurement'] = self.measurement #if self.field == 'Energy.Consumption.Total.Day' or 'Energy.Storage.Total.Out.Day' or 'Energy.Storage.Total.In.Day' or 'Energy.Production.Total.Day' or 'Energy.External.Total.Out.Day' or 'Energy.External.Total.In.Day': if self._attr_native_unit_of_measurement == "kWh": self._attr_extra_state_attributes['last_reset'] = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0) self._attr_state_class = 'total' if self._attr_native_unit_of_measurement == "Wh": self._attr_extra_state_attributes['last_reset'] = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0) self._attr_state_class = 'total' if self.field == 'Percent.Storage.Level': if self._attr_native_value >= 10: self._attr_icon = "mdi:battery-outline" if self._attr_native_value <= 19 and self._attr_native_value >= 10: self._attr_icon = "mdi:battery-10" if self._attr_native_value <= 29 and self._attr_native_value >= 20: self._attr_icon = "mdi:battery-20" if self._attr_native_value <= 39 and self._attr_native_value >= 30: self._attr_icon = "mdi:battery-30" if self._attr_native_value <= 49 and self._attr_native_value >= 40: self._attr_icon = "mdi:battery-40" if self._attr_native_value <= 59 and self._attr_native_value >= 50: self._attr_icon = "mdi:battery-50" if self._attr_native_value <= 69 and self._attr_native_value >= 60: self._attr_icon = "mdi:battery-60" if self._attr_native_value <= 79 and self._attr_native_value >= 70: self._attr_icon = "mdi:battery-70" if self._attr_native_value <= 89 and self._attr_native_value >= 80: self._attr_icon = "mdi:battery-80" if self._attr_native_value <= 99 and self._attr_native_value >= 90: self._attr_icon = "mdi:battery-90" if self._attr_native_value == 100: self._attr_icon = "mdi:battery" except Exception as e: _LOGGER.error(f'{e}') self._state = 'Error' self._attr_native_value = None self._attr_extra_state_attributes['last_check'] = datetime.now()
Führt dann zu 18 Entitäten:
Hi zusammen, ich habe vor 2 Wochen auf das von dir aktualisierte Skript umgestellt und ein paar Tage später dann noch etwas weiter entwickelt und jetzt mal eine Woche beobachtet. Hatte es einen Grund, die state_class
wieder zurück auf total
zu ändern? Das wurde ja ursprünglich mit dem letzten Release v0.2.2 gemacht und habe ich in meiner Anpassung auch wieder vorgenommen. Damit scheint es bei mir mit den Daten vom Stromzähler und Solar Rel. 8.36.1 (24.04.2024)
übereinzustimmen.
Abgesehen habe ich bei mir erstmal die Wallbox Daten entfernt da wir zurzeit noch keine haben.
"""Platform for sensor integration."""
from __future__ import annotations
import asyncio
import uuid
from datetime import timedelta, datetime
from homeassistant.components.sensor import (SensorEntity)
from homeassistant.core import HomeAssistant
from homeassistant import config_entries
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_registry import async_get, async_entries_for_config_entry
from custom_components.enpal.const import DOMAIN
import aiohttp
import logging
from influxdb_client import InfluxDBClient
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=20)
VERSION= '0.1.0'
def get_tables(ip: str, port: int, token: str):
client = InfluxDBClient(url=f'http://{ip}:{port}', token=token, org='enpal')
query_api = client.query_api()
query = 'from(bucket: "solar") \
|> range(start: -5m) \
|> last()'
tables = query_api.query(query)
return tables
async def async_setup_entry(
hass: HomeAssistant,
config_entry: config_entries.ConfigEntry,
async_add_entities,
):
# Get the config entry for the integration
config = hass.data[DOMAIN][config_entry.entry_id]
if config_entry.options:
config.update(config_entry.options)
to_add = []
if not 'enpal_host_ip' in config:
_LOGGER.error("No enpal_host_ip in config entry")
return
if not 'enpal_host_port' in config:
_LOGGER.error("No enpal_host_port in config entry")
return
if not 'enpal_token' in config:
_LOGGER.error("No enpal_token in config entry")
return
global_config = hass.data[DOMAIN]
tables = await hass.async_add_executor_job(get_tables, config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'])
for table in tables:
field = table.records[0].values['_field']
measurement = table.records[0].values['_measurement']
if measurement == "inverter" and field == "Power.DC.Total":
to_add.append(EnpalSensor(field, measurement, 'mdi:solar-power', 'Enpal Solar Production Power', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
if measurement == "inverter" and field == "Power.House.Total":
to_add.append(EnpalSensor(field, measurement, 'mdi:home-lightning-bolt', 'Enpal Power House Total', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
if measurement == "system" and field == "Power.External.Total":
to_add.append(EnpalSensor(field, measurement, 'mdi:home-lightning-bolt', 'Enpal Power External Total', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
# Consum Total per Day
if measurement == "system" and field == "Energy.Consumption.Total.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:home-lightning-bolt', 'Enpal Energy Consumption', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
# to the Grid and from the Grid
if measurement == "system" and field == "Energy.External.Total.Out.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:transmission-tower-export', 'Enpal Energy External Out Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
if measurement == "system" and field == "Energy.External.Total.In.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:transmission-tower-import', 'Enpal Energy External In Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
# Solar Energy.Production.Total.Day
if measurement == "system" and field == "Energy.Production.Total.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:solar-power-variant', 'Enpal Production Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
#Battery
if measurement == "inverter" and field == "Power.Battery.Charge.Discharge":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery-charging', 'Enpal Battery Power', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
if measurement == "inverter" and field == "Energy.Battery.Charge.Level":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery', 'Enpal Battery Percent', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'battery', '%'))
if measurement == "inverter" and field == "Energy.Battery.Charge.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery-arrow-up', 'Enpal Battery Charge Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
if measurement == "inverter" and field == "Energy.Battery.Discharge.Day":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery-arrow-down', 'Enpal Battery Discharge Day', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
if measurement == "inverter" and field == "Energy.Battery.Charge.Load":
to_add.append(EnpalSensor(field, measurement, 'mdi:battery-arrow-up', 'Enpal Battery Charge Total', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'energy', 'kWh'))
#Power Sensor -> Inverter
if measurement == "inverter" and field == "Voltage.String.1":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Voltage String 1', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'voltage', 'V'))
if measurement == "inverter" and field == "Current.String.1":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Ampere String 1', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'current', 'A'))
if measurement == "inverter" and field == "Power.DC.String.1":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Power String 1', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
if measurement == "inverter" and field == "Voltage.String.2":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Voltage String 2', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'voltage', 'V'))
if measurement == "inverter" and field == "Current.String.2":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Ampere String 2', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'current', 'A'))
if measurement == "inverter" and field == "Power.DC.String.2":
to_add.append(EnpalSensor(field, measurement, 'mdi:lightning-bolt', 'Enpal Power String 2', config['enpal_host_ip'], config['enpal_host_port'], config['enpal_token'], 'power', 'W'))
entity_registry = async_get(hass)
entries = async_entries_for_config_entry(
entity_registry, config_entry.entry_id
)
for entry in entries:
entity_registry.async_remove(entry.entity_id)
async_add_entities(to_add, update_before_add=True)
class EnpalSensor(SensorEntity):
def __init__(self, field: str, measurement: str, icon:str, name: str, ip: str, port: int, token: str, device_class: str, unit: str):
self.field = field
self.measurement = measurement
self.ip = ip
self.port = port
self.token = token
self.enpal_device_class = device_class
self.unit = unit
self._attr_icon = icon
self._attr_name = name
self._attr_unique_id = f'enpal_{measurement}_{field}'
self._attr_extra_state_attributes = {}
async def async_update(self) -> None:
# Get the IP address from the API
try:
client = InfluxDBClient(url=f'http://{self.ip}:{self.port}', token=self.token, org="enpal")
query_api = client.query_api()
query = f'from(bucket: "solar") \
|> range(start: -5m) \
|> filter(fn: (r) => r["_measurement"] == "{self.measurement}") \
|> filter(fn: (r) => r["_field"] == "{self.field}") \
|> last()'
tables = await self.hass.async_add_executor_job(query_api.query, query)
value = 0
if tables:
value = tables[0].records[0].values['_value']
self._attr_native_value = round(float(value), 2)
self._attr_device_class = self.enpal_device_class
self._attr_native_unit_of_measurement = self.unit
self._attr_state_class = 'measurement'
self._attr_extra_state_attributes['last_check'] = datetime.now()
self._attr_extra_state_attributes['field'] = self.field
self._attr_extra_state_attributes['measurement'] = self.measurement
#if self.field == 'Energy.Consumption.Total.Day' or 'Energy.Storage.Total.Out.Day' or 'Energy.Storage.Total.In.Day' or 'Energy.Production.Total.Day' or 'Energy.External.Total.Out.Day' or 'Energy.External.Total.In.Day':
if self._attr_native_unit_of_measurement == "kWh":
self._attr_extra_state_attributes['last_reset'] = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
self._attr_state_class = 'total_increasing'
if self._attr_native_unit_of_measurement == "Wh":
self._attr_extra_state_attributes['last_reset'] = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
self._attr_state_class = 'total_increasing'
if self.field == 'Percent.Storage.Level':
if self._attr_native_value >= 10:
self._attr_icon = "mdi:battery-outline"
if self._attr_native_value <= 19 and self._attr_native_value >= 10:
self._attr_icon = "mdi:battery-10"
if self._attr_native_value <= 29 and self._attr_native_value >= 20:
self._attr_icon = "mdi:battery-20"
if self._attr_native_value <= 39 and self._attr_native_value >= 30:
self._attr_icon = "mdi:battery-30"
if self._attr_native_value <= 49 and self._attr_native_value >= 40:
self._attr_icon = "mdi:battery-40"
if self._attr_native_value <= 59 and self._attr_native_value >= 50:
self._attr_icon = "mdi:battery-50"
if self._attr_native_value <= 69 and self._attr_native_value >= 60:
self._attr_icon = "mdi:battery-60"
if self._attr_native_value <= 79 and self._attr_native_value >= 70:
self._attr_icon = "mdi:battery-70"
if self._attr_native_value <= 89 and self._attr_native_value >= 80:
self._attr_icon = "mdi:battery-80"
if self._attr_native_value <= 99 and self._attr_native_value >= 90:
self._attr_icon = "mdi:battery-90"
if self._attr_native_value == 100:
self._attr_icon = "mdi:battery"
except Exception as e:
_LOGGER.error(f'{e}')
self._state = 'Error'
self._attr_native_value = None
self._attr_extra_state_attributes['last_check'] = datetime.now()
habs probiert und funtkioniert einwandfrei. Habe dann jetzt auch 17 Entitäten, Werte selbst habe ich noch nicht gecheckt
Hallo, ich bekomme die Entität Batterie nicht. In der Enpal Konfiguration bzw. im Data-Collektor ist sie mit Storage benannt. Kennt jemand von euch das Problem. Leider bin ich noch ein ziemlicher Neuling und bekomme die Änderung alleine auch nicht hin.
Hallo, ich habe meine Anlage mit den Komponenten von Fox vor 1 Woche bekommen. Es scheint, dass Enpal die Datenstruktur schon wieder ändert hat. Ich habe mit der Mail von Enpal mit den Zugangsdaten auch die Information bekommen, dass:
"Die InfluxDB ist auch Teil unserer zentralen SW-Lösung. Falls notwendig, kann es sein, dass wir hier kurzfristig Anpassungen durchführen müssen. Wir arbeiten in diesem Jahr an einer größeren Umstrukturierung unserer Lösung, die dann auch auf Ihrem System ausgerollt wird. Dies wird dann auf jeden Fall auch die InfluxDB betreffen. Sie müssten dann noch einmal Anpassungen an Ihrem System vornehmen."
Ich kann gerne versuchen die Datenbankstruktur auszulesen. Vielleicht kann mir dann jemand helfen, die Änderungen vorzunehmen.
Enpal hat mir mitgeteilt das weitere Änderungen anstehen. Können wir uns also eh drauf einstellen.
Gruß
Enpal hat mir mitgeteilt das weitere Änderungen anstehen. Können wir uns also eh drauf einstellen.
Sollten sie zu viel umbauen, könnten wir zur Not auch die Webseite der Enpal-Box parsen. Dafür habe ich mir ein kleines Skript geschrieben. Das ist zwar nicht so schön wie das Abfragen der InfluxDB, aber es erfüllt seinen Zweck...
Viele Grüße,
Sven
Enpal hat mir mitgeteilt das weitere Änderungen anstehen. Können wir uns also eh drauf einstellen.
Sollten sie zu viel umbauen, könnten wir zur Not auch die Webseite der Enpal-Box parsen. Dafür habe ich mir ein kleines Skript geschrieben. Das ist zwar nicht so schön wie das Abfragen der InfluxDB, aber es erfüllt seinen Zweck...
Viele Grüße,
Sven
Cool :-) Gut zu Wissen. Hörte sich eher nach Änderungen der Metadaten / Formatierungen an, falls nicht komme ich gerne auf Dich zurück. Gruß und Dank
Ich habe mir gerade mal das aktuelle DB Format (bei mir die 8.39.1 vom 21.06.2024) angeschaut. So viel hat sich zur Version 8.35.1 tatsächlich gar nicht getan. Im Measurement "inverter" sind ein paar Werte dazugekommen, aber die bereits bestehenden Werte wurden nicht verändert. Neu sind:
In den anderen Measurements gab es keine Veränderungen.
Meine für die 8.35.1 lokal angepasste Version der sensor.py liefert mir nach wie vor alle relevanten Werte. Ich habe meine aktuelle Version der sensor.py mal an diesen Post angehängt. @JuergenNe Du kannst ja mal testen ob Du mit der version auch die Werte für die Batterie siehst. Bei mir klappt es und ich habe auch die FoxESS Komponenten. Github hat mich hier leider keine .py Datei anhängen lassen, daher habe ich sie zu .txt umbenannt. Du musst die Datei also wieder von einer .txt. zu einer .py umbenennen.
Gruß, Stephan sensor.txt
@skehrer Hallo, jetzt hab ich auch 22 Entitäten. Super. Vielen Dank.
Darf ich unverschämt ragen, ob du ein ansprechendes Dashboard schon konfiguriert hast, das ich verwenden könnte.
Vielen Dank
Gruß, Jürgen
First at all, THE for the integration :-)
Today my ENPAL Solar system had been connected. FOX Ess Inverter and Battery plus ENPAL Box. The Inverter is connected via LAN cable with the Enpal Box. The Enpal Box is via LAN cable connected to my Switch. The Enpal Box is -up to now- in the same LAN (would like to put it later in to separate vLAN).
I could access the Box as explained in the Read.me, but I only get the one of the three cards (Enpal Energy Consumption , DAY, TOTAL...), I currently don't get the Battery nor the Inverter.
Via Data Collector (see belwo) the battery and inverter data is available, BUT the data fields ara partly with other device names or sensor names (inverter instead of sensor), Rename those within sensor.py
Block 1 Phases: Result:![image](https://github.com/gickowtf/enpal-homeassistant/assets/60690839/0473b225-c7a0-4f74-9496-c6eb4d2eea9b)
Changed:
Power Sensor -> Inverter
Block 2 Battery: Result:![image](https://github.com/gickowtf/enpal-homeassistant/assets/60690839/18a37fc5-bf45-467a-80ce-b837ae50bbac)
Changed (had problems with dev.class therefore deleted and just searched for the data field)
Battery
Kindly ask for your support / hints to get this more professional into your great Integration please
Kindest Regards M
Attached the view via Solar Rel. 8.33.1 Data Collector '{ "collectionId": "aafcafa4-1155-48de-b86c-4f3ccaa6dedb", "ioTDeviceId": "", "collectionType": "LiveValues", "timeStampUtc": "2024-03-06T16:36:21.0046923Z", "numberDataPoints": { "Power.Storage.Total": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9385405Z", "unit": "W", "value": -475.0 }, "Energy.Storage.Total.In.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:04.8880897Z", "unit": "kWh", "value": 2.1 }, "Energy.Storage.Total.Out.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:04.888126Z", "unit": "kWh", "value": 3.6 }, "Energy.Storage.Level": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9391969Z", "unit": "Wh", "value": 1614.6000000000001 }, "Percent.Storage.Level": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:21.0045407Z", "unit": "Percent", "value": 3.3333333333333335 }, "Power.Production.Total": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9388277Z", "unit": "W", "value": 121.0 }, "Energy.Production.Total.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:06.9827422Z", "unit": "kWh", "value": 2.6 }, "Power.External.Total": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9388336Z", "unit": "W", "value": -47.0 }, "Energy.External.Total.Out.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:04.888149Z", "unit": "kWh", "value": 0.1 }, "Energy.External.Total.In.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:04.888227Z", "unit": "kWh", "value": 1.4 }, "Energy.Consumption.Total.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:20.0746153Z", "unit": "kWh", "value": 3.0 }, "Power.Consumption.Total": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9397455Z", "unit": "W", "value": 643.0 } }, "textDataPoints": {}, "errorCodes": [], "DeviceCollections": [ { "deviceId": "15d04345-8d9a-43f7-a7b3-bba51697a811", "deviceClass": "Wallbox", "timeStampUtc": "2024-03-06T16:36:21.0047227Z", "numberDataPoints": { "Power.Wallbox.Connector.0.Charging.Requested": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:20.9996624Z", "unit": "W", "value": 4500.0 }, "Power.Wallbox.Connector.1.Charging.Requested": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:20.9996663Z", "unit": "W", "value": 4500.0 }, "Status.Wallbox.Connected": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:20.9996669Z", "unit": "None", "value": 0.0 } }, "textDataPoints": { "Wallbox.DeviceId": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:20.9996676Z", "unit": "None", "value": "" } }, "errorCodes": [] }, { "deviceId": "ac2ad07d-2c24-492c-a347-9e1aa4cfa518", "deviceClass": "IoTEdgeDevice", "timeStampUtc": "2024-03-06T16:36:21.0047617Z", "numberDataPoints": { "LTE.RSRP": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15Z", "unit": "None", "value": -102.0 }, "LTE.RSRQ": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15Z", "unit": "None", "value": -10.0 }, "LTE.RSSI": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15Z", "unit": "None", "value": -77.0 }, "LTE.SNR": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15Z", "unit": "None", "value": 11.0 }, "LTE.Quality": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15Z", "unit": "Percent", "value": 59.0 }, "LTE.Predictor.Result.Passed": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:21.0025447Z", "unit": "None", "value": 1.0 }, "Cpu.Load": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:05Z", "unit": "Percent", "value": 24.0 }, "Memory.Usage": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:05Z", "unit": "Percent", "value": 55.0 } }, "textDataPoints": { "IoT.MainState": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:20.9996896Z", "unit": "None", "value": "Installation" }, "LTE.CellularGuard.Result.Timestamp": { "timeStampUtcOfMeasurement": "2024-03-06T16:24:13Z", "unit": "None", "value": "2024-03-06T16:24:13Z" }, "LTE.CellularGuard.Result.Version": { "timeStampUtcOfMeasurement": "2024-03-06T16:24:13Z", "unit": "None", "value": "v6.3" }, "LTE.CellularGuard.Result.Value": { "timeStampUtcOfMeasurement": "2024-03-06T16:24:13Z", "unit": "None", "value": "cg.ok" }, "LTE.Cronny.Result": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15Z", "unit": "None", "value": "cronny.lte_signal.weak" }, "LTE.State": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15Z", "unit": "None", "value": "connected" }, "LTE.Connection.Type": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15Z", "unit": "None", "value": "LTE" }, "LTE.Modem.Type": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15Z", "unit": "None", "value": "quectel_ec21eux" }, "LTE.Modem.Firmware.Version": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15Z", "unit": "None", "value": "EC21EUXGAR08A07M1G_20.200.20.200" }, "HW.Cronny.Result": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:05Z", "unit": "None", "value": "cronny.hw_metrics.ok" }, "LTE.Failover.Result": { "timeStampUtcOfMeasurement": "2024-03-06T16:35:00Z", "unit": "None", "value": "cronny.lte_failover.lan_ok" }, "LTE.Fail-over.Message.0": { "timeStampUtcOfMeasurement": "2024-03-06T16:35:38Z", "unit": "None", "value": "current connection: eth1" }, "LTE.Fail-over.Message.1": { "timeStampUtcOfMeasurement": "2024-03-06T16:35:52Z", "unit": "None", "value": "eth1 is acceptable latency: 0.55425, errors: 0" }, "LTE.Fail-over.Message.2": { "timeStampUtcOfMeasurement": "2024-03-06T16:35:52Z", "unit": "None", "value": "current connection is good, staying on eth1" } }, "errorCodes": [] }, { "deviceId": "9a54c3ea-bf16-40e9-8c51-bd48b6480869", "deviceClass": "Battery", "timeStampUtc": "2024-03-06T16:36:21.0048423Z", "numberDataPoints": { "Mode.Forcible.Timeout": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.4161067Z", "unit": "None", "value": 0.0 }, "Power.Battery.Charge.Discharge": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9385405Z", "unit": "W", "value": -475.0 }, "Energy.Battery.Charge.Load": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9391969Z", "unit": "Wh", "value": 1614.6000000000001 }, "Power.Battery.Charge.Discharge.Set": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:18.5085443Z", "unit": "W", "value": 0.0 }, "Mode.Forcible.Charge.Discharge": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:20.599429Z", "unit": "None", "value": 0.0 }, "Voltage.Battery": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:11.691463Z", "unit": "V", "value": 172.9 }, "Current.Battery": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:11.6914727Z", "unit": "A", "value": 2.7 }, "Energy.Battery.Charge.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:04.8880897Z", "unit": "kWh", "value": 2.1 }, "Energy.Battery.Discharge.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:04.888126Z", "unit": "kWh", "value": 3.6 }, "Battery.SOH": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:06.4597381Z", "unit": "Percent", "value": 100.0 }, "Energy.Battery.Ah": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15.3682438Z", "unit": "None", "value": 69.0 }, "Battery.ChargeLevel.Min": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:13.2600391Z", "unit": "Percent", "value": 10.0 }, "Battery.ChargeLevel.Max": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:13.7791188Z", "unit": "Percent", "value": 100.0 }, "Battery.ChargeLevel.MinOnGrid": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:14.3031146Z", "unit": "Percent", "value": 10.0 }, "Energy.Battery.Charge.Level": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:21.0045407Z", "unit": "Percent", "value": 3.3333333333333335 } }, "textDataPoints": { "Battery.Model.Code": { "timeStampUtcOfMeasurement": "2024-03-06T14:34:34.1105756Z", "unit": "None", "value": "ECS4300" } }, "errorCodes": [] }, { "deviceId": "a75a0173-d2a9-463a-a029-052a4aaaebb1", "deviceClass": "Inverter", "timeStampUtc": "2024-03-06T16:36:21.0048925Z", "numberDataPoints": { "Energy.Grid.Export.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:04.888149Z", "unit": "kWh", "value": 0.1 }, "Energy.Grid.Import.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:04.888227Z", "unit": "kWh", "value": 1.4 }, "Energy.Production.Total.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:06.9827422Z", "unit": "kWh", "value": 2.6 }, "Voltage.String.1": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:07.5071515Z", "unit": "V", "value": 674.1 }, "Current.String.1": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:07.5071816Z", "unit": "A", "value": 0.0 }, "Power.DC.String.1": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:07.5071856Z", "unit": "W", "value": 67.0 }, "Voltage.String.2": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:07.5071891Z", "unit": "V", "value": 416.2 }, "Current.String.2": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:07.507192Z", "unit": "A", "value": 0.1 }, "Power.DC.String.2": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:07.5071976Z", "unit": "W", "value": 52.0 }, "Frequency.Grid": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:09.0749769Z", "unit": "Hz", "value": 50.0 }, "Command.Start.Stop": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:10.647852Z", "unit": "None", "value": 1.0 }, "Dongle.BackendConnection": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15.3684889Z", "unit": "None", "value": 1.0 }, "Inverter.System.State": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9385905Z", "unit": "None", "value": 2.0 }, "Voltage.Phase.A": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9386985Z", "unit": "V", "value": 234.1 }, "Voltage.Phase.B": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9387025Z", "unit": "V", "value": 235.3 }, "Voltage.Phase.C": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9387059Z", "unit": "V", "value": 235.3 }, "Power.DC.Total": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9388277Z", "unit": "W", "value": 121.0 }, "Power.Grid.Export": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9388336Z", "unit": "W", "value": -47.0 }, "Power.House.Total": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9397455Z", "unit": "W", "value": 643.0 }, "Power.Limit": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:17.9832924Z", "unit": "Percent", "value": 100.0 }, "Energy.Consumption.Total.Day": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:20.0746153Z", "unit": "kWh", "value": 3.0 }, "Mode.Forcible.Charge.Discharge": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:20.599429Z", "unit": "None", "value": 0.0 } }, "textDataPoints": {}, "errorCodes": [] }, { "deviceId": "83facf0f-35ff-4d3d-afe8-b86de47d3f22", "deviceClass": "PowerSensor", "timeStampUtc": "2024-03-06T16:36:21.0049552Z", "numberDataPoints": { "Power.AC.Phase.A": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:05.9366111Z", "unit": "W", "value": -45.0 }, "Power.AC.Phase.B": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:05.9366236Z", "unit": "W", "value": 162.0 }, "Power.AC.Phase.C": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:05.9366321Z", "unit": "W", "value": -77.0 }, "Power.Factor": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:06.4595887Z", "unit": "Percent", "value": -0.05 }, "Power.Reactive": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:09.5993263Z", "unit": "kW", "value": 469.0 }, "Meter.Enable.Disable": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:12.7362465Z", "unit": "None", "value": 0.0 }, "Meter2.AC.Phase.A": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15.3684354Z", "unit": "W", "value": 0.0 }, "Meter2.AC.Phase.B": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15.3684487Z", "unit": "W", "value": 0.0 }, "Meter2.AC.Phase.C": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15.3684644Z", "unit": "W", "value": 0.0 }, "Meter2.Enable.Disable": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:15.8921872Z", "unit": "None", "value": 0.0 }, "Meter.Connect.State": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:16.9386066Z", "unit": "None", "value": 1.0 }, "Meter2.Connect.State": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:17.4602924Z", "unit": "None", "value": 0.0 }, "Meter2.AC.Total": { "timeStampUtcOfMeasurement": "2024-03-06T16:36:19.5554592Z", "unit": "W", "value": 0.0 } }, "textDataPoints": {}, "errorCodes": [] } ], "EnergyManagement": [ { "energyManagementId": "17e99b63-439e-43ab-a6ce-7cb2444e93ce", "referenceDeviceId": "15d04345-8d9a-43f7-a7b3-bba51697a811", "timeStampUtc": "2024-03-06T16:36:21.0061354Z", "numberDataPoints": {}, "textDataPoints": {}, "errorCodes": [] } ] }