Lastwechsel ereignisbasiert sperren
Tests / test (push) Failing after 39s

This commit is contained in:
dh
2026-09-17 09:14:15 +00:00
parent 1b4a788f22
commit 355e7163fb
7 changed files with 100 additions and 46 deletions
+47 -26
View File
@@ -56,8 +56,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->RegisterPropertyBoolean('BoilertemperaturGlaetten', false);
$this->RegisterPropertyInteger('Boilervolumen', 300);
$this->RegisterPropertyString('Zeitplan', '[]');
$this->RegisterPropertyInteger('Interval', 5);
$this->RegisterPropertyInteger('IdleCounterMax', 2);
$this->RegisterPropertyInteger('LastwechselSperrzeit', 5);
$this->RegisterPropertyInteger('TemperaturMaxAlter', 30);
$this->RegisterPropertyFloat('Hysterese', 5.0);
$this->RegisterPropertyBoolean('LegionellenfunktionAktiv', true);
@@ -74,7 +73,9 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->RegisterAttributeBoolean('InitialwerteGesetzt', false);
$this->RegisterAttributeInteger('RegistrierteFuehlerID', 0);
$this->RegisterAttributeInteger('LetzteBerechnung', 0);
$this->RegisterAttributeInteger('LetzteTemperaturberechnung', 0);
$this->RegisterAttributeInteger('LetzteVorgabeZeit', 0);
$this->RegisterAttributeInteger('LetzterLastwechsel', 0);
$this->RegisterAttributeInteger('LetzteManagerID', 0);
$this->RegisterAttributeInteger('LetzterLegionellenabschluss', 0);
$this->RegisterAttributeFloat('Glaettungswert', 0.0);
@@ -99,9 +100,9 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->RegisterAttributeInteger('ZustandIdleCounter', 0);
$this->RegisterTimer(
'Regelzyklus',
'LastwechselFreigabe',
0,
"IPS_RequestAction(\$_IPS['TARGET'], 'Regelzyklus', false);"
"IPS_RequestAction(\$_IPS['TARGET'], 'LastwechselFreigabe', false);"
);
$this->RegisterTimer(
'Meldezyklus',
@@ -125,7 +126,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
try {
$this->pruefeKonfiguration();
} catch (Throwable $fehler) {
$this->SetTimerInterval('Regelzyklus', 0);
$this->SetTimerInterval('LastwechselFreigabe', 0);
$this->SetTimerInterval('Meldezyklus', 0);
$this->SetTimerInterval('RueckmeldungVerzoegert', 0);
$this->setzeZustand('Verfuegbar', false);
@@ -136,7 +137,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
$this->registriereFuehlermeldung();
$this->SetTimerInterval('Regelzyklus', $this->ReadPropertyInteger('Interval') * 1000);
$this->SetTimerInterval('LastwechselFreigabe', 0);
$this->SetTimerInterval('Meldezyklus', $this->ReadPropertyInteger('Meldeintervall') * 1000);
if ($this->ReadAttributeInteger('LetzterLegionellenabschluss') <= 0) {
$this->WriteAttributeInteger('LetzterLegionellenabschluss', time());
@@ -168,7 +169,8 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->setzeTemperaturSollwert((string) $ident, $wert);
return;
case 'Regelzyklus':
case 'LastwechselFreigabe':
$this->SetTimerInterval('LastwechselFreigabe', 0);
$this->regelzyklus(true);
return;
@@ -176,6 +178,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
if ((bool) $wert) {
$this->SetTimerInterval('RueckmeldungVerzoegert', 0);
}
$this->regelzyklus(false);
$this->sendeVerbraucherdaten();
return;
@@ -233,8 +236,15 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$temperaturGueltig = $this->aktualisiereTemperatur();
$this->aktualisiereLegionellenstatus($temperaturGueltig, $jetzt);
$restzeit = $this->aktualisiereLastwechselstatus($jetzt);
[$angebot, $aenderungMoeglich, $verfuegbar, $zwangsleistung] =
$this->bestimmeLeistungsangebot($temperaturGueltig, $jetzt);
$aktuelleLeistung = (int) round((float) $this->leseZustand('Istleistung'));
$lastwechselGesperrt = $restzeit > 0 && $verfuegbar && $zwangsleistung !== 0;
if ($lastwechselGesperrt) {
$angebot = [$aktuelleLeistung];
$aenderungMoeglich = false;
}
$this->WriteAttributeString('Leistungsangebot', json_encode($angebot, JSON_THROW_ON_ERROR));
$this->setzeZustand('Verfuegbar', $verfuegbar);
$this->setzeZustand('AenderungMoeglich', $aenderungMoeglich);
@@ -247,7 +257,9 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
$ziel = 0;
if ($verfuegbar) {
if ($lastwechselGesperrt) {
$ziel = $aktuelleLeistung;
} elseif ($verfuegbar) {
if ($zwangsleistung !== null) {
$ziel = $zwangsleistung;
} elseif ((bool) $this->leseZustand('SollwertGueltig')) {
@@ -259,7 +271,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
}
$this->schalteLeistung($ziel);
$this->schalteLeistung($ziel, $jetzt);
$this->setzeZustand('Sollleistung', $ziel);
$this->aktualisiereStoerungen($temperaturGueltig);
if ($meldungPlanen) {
@@ -296,18 +308,23 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
$temperatur = (float) $rohwert;
$jetzt = time();
$letzteTemperaturberechnung = $this->ReadAttributeInteger('LetzteTemperaturberechnung');
$this->WriteAttributeInteger('LetzteTemperaturberechnung', $jetzt);
if ($this->ReadPropertyBoolean('BoilertemperaturGlaetten')) {
if (!$this->ReadAttributeBoolean('GlaettungInitialisiert')) {
$this->WriteAttributeFloat('Glaettungswert', $temperatur);
$this->WriteAttributeBoolean('GlaettungInitialisiert', true);
} else {
} elseif ($letzteTemperaturberechnung > 0 && $jetzt > $letzteTemperaturberechnung) {
$temperatur = WarmwasserRegler::pt1(
$this->ReadAttributeFloat('Glaettungswert'),
$temperatur,
$this->ReadPropertyInteger('Interval'),
$jetzt - $letzteTemperaturberechnung,
$this->ReadPropertyInteger('ZeitKonstante')
);
$this->WriteAttributeFloat('Glaettungswert', $temperatur);
} else {
$temperatur = $this->ReadAttributeFloat('Glaettungswert');
}
} else {
$this->WriteAttributeBoolean('GlaettungInitialisiert', false);
@@ -403,14 +420,13 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->setzeZustand('LegionellenbetriebAktiv', $fruehestensFaellig);
}
private function schalteLeistung(int $zielLeistung): void
private function schalteLeistung(int $zielLeistung, int $jetzt): void
{
$stufen = WarmwasserRegler::dekodiereLeistungsstufen($this->ReadPropertyString('LeistungsStufen'));
$zielStufe = WarmwasserRegler::stufeFuerLeistung($stufen, $zielLeistung);
$bisherigeLeistung = (int) round((float) $this->leseZustand('Istleistung'));
if ($zielLeistung === $bisherigeLeistung && $this->kontakteEntsprechenZiel($stufen, $zielLeistung)) {
$this->WriteAttributeString('Schaltfehler', '');
$this->verarbeiteIdle(false);
return;
}
@@ -436,6 +452,8 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
$this->setzeZustand('Istleistung', 0.0);
$this->setzeZustand('AktiveStufe', 0);
$this->WriteAttributeInteger('LetzterLastwechsel', $jetzt);
$this->aktualisiereLastwechselstatus($jetzt);
throw new RuntimeException('Leistungsstufe konnte nicht sicher geschaltet werden: ' . $fehler->getMessage());
}
@@ -443,7 +461,8 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->setzeZustand('Istleistung', (float) $zielLeistung);
$this->setzeZustand('Leistungsquelle', Nachrichtenvertrag::LEISTUNGSQUELLE_BERECHNET);
$this->setzeZustand('AktiveStufe', $zielStufe);
$this->verarbeiteIdle(true);
$this->WriteAttributeInteger('LetzterLastwechsel', $jetzt);
$this->aktualisiereLastwechselstatus($jetzt);
$this->protokolliere('Leistungsstufe', ['Leistung_W' => $zielLeistung, 'Stufe' => $zielStufe]);
}
@@ -465,16 +484,18 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
return true;
}
private function verarbeiteIdle(bool $geaendert): void
private function aktualisiereLastwechselstatus(int $jetzt): int
{
$counter = (int) $this->leseZustand('IdleCounter');
if ($geaendert) {
$counter = $this->ReadPropertyInteger('IdleCounterMax');
} elseif ($counter > 0) {
--$counter;
}
$this->setzeZustand('IdleCounter', $counter);
$this->setzeZustand('Idle', $counter === 0);
$restzeit = WarmwasserRegler::restzeitBisLastwechsel(
$this->ReadAttributeInteger('LetzterLastwechsel'),
$jetzt,
$this->ReadPropertyInteger('LastwechselSperrzeit')
);
$this->setzeZustand('IdleCounter', $restzeit);
$this->setzeZustand('Idle', $restzeit === 0);
$this->SetTimerInterval('LastwechselFreigabe', $restzeit > 0 ? $restzeit * 1000 : 0);
return $restzeit;
}
private function aktualisiereEnergie(int $jetzt): void
@@ -674,7 +695,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
}
foreach ([
'Meldeintervall', 'VorgabeTimeout', 'Interval', 'IdleCounterMax', 'TemperaturMaxAlter',
'Meldeintervall', 'VorgabeTimeout', 'LastwechselSperrzeit', 'TemperaturMaxAlter',
'ZeitKonstante', 'Boilervolumen', 'LegionellenMinimalintervallTage',
'LegionellenMaximalintervallTage',
] as $property) {
@@ -825,8 +846,8 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
220
);
$this->RegisterVariableInteger('LegioCounter', 'Zeit seit Legionellenabschluss', '', 230);
$this->RegisterVariableBoolean('Idle', 'Idle', '~Switch', 240);
$this->RegisterVariableInteger('IdleCounter', 'Idle Counter', '', 250);
$this->RegisterVariableBoolean('Idle', 'Lastwechsel freigegeben', '~Switch', 240);
$this->RegisterVariableInteger('IdleCounter', 'Restzeit bis Lastwechsel', '', 250);
foreach (self::DIAGNOSE_VARIABLEN as $ident) {
$wert = $ident === 'Leistungsquelle'