diff --git a/CHANGELOG.md b/CHANGELOG.md index 9808033..ee3d2c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/docs/module/Manager/README.md b/docs/module/Manager/README.md index 7123ead..19321dd 100644 --- a/docs/module/Manager/README.md +++ b/docs/module/Manager/README.md @@ -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. diff --git a/libs/ManagerEnergieTrait.php b/libs/ManagerEnergieTrait.php index 78a7ae4..0335f9c 100644 --- a/libs/ManagerEnergieTrait.php +++ b/libs/ManagerEnergieTrait.php @@ -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) { diff --git a/tests/ManagerSDLTest.php b/tests/ManagerSDLTest.php index 9f096ae..a93f1db 100644 --- a/tests/ManagerSDLTest.php +++ b/tests/ManagerSDLTest.php @@ -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'];