feat(manager): use overall Energy Pie balance with SDL
Tests / test (push) Successful in 1m3s

This commit is contained in:
dh
2026-10-08 09:40:14 +00:00
parent 86834bb8aa
commit af69151165
4 changed files with 82 additions and 2 deletions
+6
View File
@@ -4,6 +4,12 @@ Alle wesentlichen Aenderungen an Enelix EMS werden in dieser Datei dokumentiert.
## Unreleased
- Manager: Energy Pie verwendet die bilanzielle Gesamtanlage inklusive SDL
unabhaengig von SDLAktiv. Kein Mischen des SDL-bereinigten Hauszaehlers mit
physischen Netzzaehlern, keine doppelte Addition von SDL-Energie. Benoetigt
zuerst Enelix Utils mit Gesamtbilanz-Unterstuetzung; Quellen, Farben, Archive,
Hauslast fuer Regelung/Prognose und Stellpfade bleiben unveraendert.
- Ladestation Stand-Alone: Ladepausen und einzelne Nullwerte verriegeln das
Fahrzeug nicht mehr als geladen. Ladeende nur mit aktuellem eindeutigen
Geraetesignal; Pico hat kein solches Voll-Signal. go-e-Fehler, Pico-Status
+24
View File
@@ -405,6 +405,30 @@ der wirksamen Lastspitzengrenze zu `Peak`. Zwischen den beiden Zielwerten
bleibt sie erhalten. `Umschaltdifferenz` verhindert zusätzlich einen Wechsel,
wenn sich die beiden berechneten Korrekturen nicht ausreichend unterscheiden.
## Energy Pie: Gesamtbilanz inklusive SDL
Der Manager aktiviert am eigenen Energy Pie `Gesamtbilanz=true`, unabhaengig
von `SDLAktiv`. Der bilanzielle Gesamtverbrauch ist Produktion plus physischer
Netzbezug minus Einspeisung (mindestens 0). SDL-Ladung bzw. -Abgabe wirkt damit
ueber die bereits vorhandenen Netzzaehler; separate SDL-Zaehler werden nicht
nochmals addiert. Eine Versorgung des Hauses durch SDL ist keine Netzeinspeisung.
Die Hausquelle bleibt gespeichert, fliesst jedoch nicht in diese Gesamtbilanz ein.
Die weiterhin SDL-bereinigte Hauslast fuer Regelung und Prognose bleibt unveraendert.
Die Quoten sind ausdruecklich **bilanziell**, keine reine PV-Herkunftszuordnung
oder physische Hausautarkie. Speicherentladung kann den Netto-Bilanzverbrauch
senken; bei negativem Saldo zeigt der Pie einen Hinweis und begrenzt Verbrauch
und Quoten auf 0. Fehlende Daten werden weiterhin als unbekannt behandelt.
Migration: zuerst Enelix Utils mit Gesamtbilanz-Unterstuetzung aktualisieren,
dann den EMS-Manager anwenden. Zaehlervariablen, Archivdaten und individuelle
Farben bleiben erhalten. Historische Zeitraeume werden neu aus den vorhandenen
drei Zaehlern berechnet. Die alte Property `EnergieanteileBerechenbar` bleibt
fuer einen Rueckwechsel erhalten und blockiert die Gesamtbilanz nicht.
Mit einem alten Utils bleibt die bisherige SDL-Schutzlogik bestehen, bis Utils
aktualisiert wird; es wird keine falsche Hausbilanz erzwungen. Kein Anlagenrollout
oder Stellbefehl ist Teil dieser Quellcode-Aenderung.
## Laufzeit und Fehlerverhalten
- Netzleistungsänderungen und Verbrauchermeldungen lösen die Berechnung aus.
+14 -2
View File
@@ -297,9 +297,21 @@ trait ManagerEnergieTrait
private function synchronisiereEnergyPieAnteile(int $instanzID, bool $anwenden = true): void
{
// Physischer Netzbezug enthaelt SDL, die Hausenergie dagegen nicht.
$berechenbar = !$this->ReadPropertyBoolean('SDLAktiv');
$konfiguration = json_decode(IPS_GetConfiguration($instanzID), true, 512, JSON_THROW_ON_ERROR);
if (is_array($konfiguration) && array_key_exists('Gesamtbilanz', $konfiguration)) {
// Physical grid counters already include SDL; Utils derives the complete site balance.
IPS_SetHidden($instanzID, false);
if (IPS_GetProperty($instanzID, 'Gesamtbilanz') !== true) {
IPS_SetProperty($instanzID, 'Gesamtbilanz', true);
if ($anwenden) {
IPS_ApplyChanges($instanzID);
}
}
return;
}
// Compatibility until Utils is updated: do not enable the old mixed-boundary calculation.
$berechenbar = !$this->ReadPropertyBoolean('SDLAktiv');
if (!is_array($konfiguration) || !array_key_exists('EnergieanteileBerechenbar', $konfiguration)) {
IPS_SetHidden($instanzID, !$berechenbar);
if (!$berechenbar) {
+38
View File
@@ -413,6 +413,44 @@ final class ManagerSDLTest extends TestCase
self::assertSame($custom, ManagerSDLRuntime::$properties[303]);
}
public function testModernEnergyPieUsesOverallBalanceWithAndWithoutSDL(): void
{
$custom = [
'ProduktionZaehlerID' => 801, 'NetzbezugZaehlerID' => 802,
'EinspeisungZaehlerID' => 803, 'VerbrauchZaehlerID' => 804,
'FarbeEigenverbrauch' => '#123456', 'FarbeAutarkie' => '#ABCDEF',
'Standardzeitraum' => 'month', 'EnergieanteileBerechenbar' => false,
'Gesamtbilanz' => false,
];
foreach ([true, false] as $sdl) {
ManagerSDLRuntime::$properties[303] = $custom;
ManagerSDLRuntime::$hidden[303] = true;
$this->properties(['SDLAktiv' => $sdl]);
$this->invoke('synchronisiereEnergyPieAnteile', [303]);
self::assertSame(array_replace($custom, ['Gesamtbilanz' => true]),
ManagerSDLRuntime::$properties[303]);
self::assertFalse(ManagerSDLRuntime::$hidden[303]);
$writes = ManagerSDLRuntime::$writes;
$this->invoke('synchronisiereEnergyPieAnteile', [303]);
self::assertSame($writes, ManagerSDLRuntime::$writes);
}
self::assertSame([], ManagerSDLRuntime::$logs);
}
public function testUtilsUpgradeRestoresBalanceWithoutResettingCustomSources(): void
{
ManagerSDLRuntime::$properties[303] = ['ProduktionZaehlerID' => 801];
$this->properties(['SDLAktiv' => true]);
$this->invoke('synchronisiereEnergyPieAnteile', [303]);
self::assertTrue(ManagerSDLRuntime::$hidden[303]);
ManagerSDLRuntime::$properties[303]['Gesamtbilanz'] = false;
ManagerSDLRuntime::$properties[303]['EnergieanteileBerechenbar'] = false;
$this->invoke('synchronisiereEnergyPieAnteile', [303]);
self::assertFalse(ManagerSDLRuntime::$hidden[303]);
self::assertTrue(ManagerSDLRuntime::$properties[303]['Gesamtbilanz']);
self::assertSame(801, ManagerSDLRuntime::$properties[303]['ProduktionZaehlerID']);
}
public function testOlderEnergyPieStaysVisibleWithoutSDLAndKeepsConfiguration(): void
{
$custom = ['ProduktionZaehlerID' => 801, 'FarbeEigenverbrauch' => '#123456'];