Diagnosevariablen bedarfsgesteuert anlegen
Tests / test (push) Successful in 43s

This commit is contained in:
dh
2026-09-17 08:54:17 +00:00
parent 4514ccb557
commit 9e6a675b25
5 changed files with 183 additions and 73 deletions
+138 -47
View File
@@ -25,10 +25,16 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
/** @var list<string> */
private const DIAGNOSE_VARIABLEN = [
'Istleistung',
'Leistungsquelle',
'Sollleistung',
'SollwertGueltig',
'Verfuegbar',
'AenderungMoeglich',
'Stoerung',
'Stoertext',
'AktiveStufe',
'BezogeneEnergie',
'TemperaturGueltig',
'NachladenAktiv',
'LegionellenbetriebAktiv',
@@ -60,15 +66,10 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->RegisterPropertyBoolean('DiagnosevariablenAnzeigen', false);
$this->RegisterVariableFloat('Boilertemperatur', 'Boilertemperatur', '~Temperature', 100);
$this->RegisterVariableInteger('AktiveStufe', 'Aktive Stufe', '', 110);
$this->RegisterVariableFloat('BezogeneEnergie', 'Bezogene Energie', '~Electricity', 120);
$this->RegisterVariableFloat('Mindesttemperatur', 'Mindesttemperatur', '~Temperature', 130);
$this->RegisterVariableFloat('Maximaltemperatur', 'Maximaltemperatur', '~Temperature', 140);
$this->RegisterVariableFloat('Legionellentemperatur', 'Legionellentemperatur', '~Temperature', 150);
$this->EnableAction('Mindesttemperatur');
$this->EnableAction('Maximaltemperatur');
$this->EnableAction('Legionellentemperatur');
$this->RegisterAttributeBoolean('InitialwerteGesetzt', false);
$this->RegisterAttributeInteger('RegistrierteFuehlerID', 0);
@@ -80,6 +81,13 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->RegisterAttributeBoolean('GlaettungInitialisiert', false);
$this->RegisterAttributeString('Leistungsangebot', '[]');
$this->RegisterAttributeString('Schaltfehler', '');
$this->RegisterAttributeFloat('ZustandIstleistung', 0.0);
$this->RegisterAttributeInteger('ZustandSollleistung', 0);
$this->RegisterAttributeBoolean('ZustandStoerung', false);
$this->RegisterAttributeString('ZustandStoertext', '');
$this->RegisterAttributeInteger('ZustandAktiveStufe', 0);
$this->RegisterAttributeFloat('ZustandBezogeneEnergie', 0.0);
$this->RegisterAttributeFloat('ZustandLegionellentemperatur', 65.0);
$this->RegisterAttributeBoolean('ZustandSollwertGueltig', false);
$this->RegisterAttributeBoolean('ZustandVerfuegbar', false);
$this->RegisterAttributeBoolean('ZustandAenderungMoeglich', false);
@@ -209,7 +217,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->WriteAttributeInteger('LetzteManagerID', $managerID);
$this->WriteAttributeInteger('LetzteVorgabeZeit', time());
$this->SetValue('Sollleistung', $sollleistung);
$this->setzeZustand('Sollleistung', $sollleistung);
$this->setzeZustand('SollwertGueltig', true);
$this->regelzyklus(false);
@@ -243,7 +251,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
if ($zwangsleistung !== null) {
$ziel = $zwangsleistung;
} elseif ((bool) $this->leseZustand('SollwertGueltig')) {
$ziel = (int) $this->GetValue('Sollleistung');
$ziel = (int) $this->leseZustand('Sollleistung');
if (!in_array($ziel, $angebot, true)) {
$this->setzeZustand('SollwertGueltig', false);
$ziel = 0;
@@ -252,7 +260,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
$this->schalteLeistung($ziel);
$this->SetValue('Sollleistung', $ziel);
$this->setzeZustand('Sollleistung', $ziel);
$this->aktualisiereStoerungen($temperaturGueltig);
if ($meldungPlanen) {
$this->SetTimerInterval('RueckmeldungVerzoegert', 100);
@@ -261,8 +269,8 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->WriteAttributeString('Schaltfehler', $fehler->getMessage());
$this->setzeZustand('Verfuegbar', false);
$this->setzeZustand('AenderungMoeglich', false);
$this->SetValue('Stoerung', true);
$this->SetValue('Stoertext', $fehler->getMessage());
$this->setzeZustand('Stoerung', true);
$this->setzeZustand('Stoertext', $fehler->getMessage());
$this->SetStatus(self::STATUS_SCHALTFEHLER);
$this->protokolliere('Regelzyklus', $fehler->getMessage());
}
@@ -334,10 +342,10 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->ReadPropertyInteger('LegionellenMaximalintervallTage'),
$minimum,
$maximum,
(float) $this->GetValue('Legionellentemperatur')
(float) $this->ReadAttributeFloat('ZustandLegionellentemperatur')
);
$hysterese = $this->ReadPropertyFloat('Hysterese');
$aktuelleLeistung = (int) round((float) $this->GetValue('Istleistung'));
$aktuelleLeistung = (int) round((float) $this->leseZustand('Istleistung'));
$nachladen = (bool) $this->leseZustand('NachladenAktiv');
if ($temperatur < $minimum) {
@@ -382,7 +390,8 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$sekundenSeitAbschluss = max(0, $jetzt - $letzterAbschluss);
if ($aktiviert && $temperaturGueltig
&& (float) $this->GetValue('Boilertemperatur') >= (float) $this->GetValue('Legionellentemperatur')
&& (float) $this->GetValue('Boilertemperatur')
>= $this->ReadAttributeFloat('ZustandLegionellentemperatur')
) {
$this->WriteAttributeInteger('LetzterLegionellenabschluss', $jetzt);
$sekundenSeitAbschluss = 0;
@@ -398,7 +407,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
{
$stufen = WarmwasserRegler::dekodiereLeistungsstufen($this->ReadPropertyString('LeistungsStufen'));
$zielStufe = WarmwasserRegler::stufeFuerLeistung($stufen, $zielLeistung);
$bisherigeLeistung = (int) round((float) $this->GetValue('Istleistung'));
$bisherigeLeistung = (int) round((float) $this->leseZustand('Istleistung'));
if ($zielLeistung === $bisherigeLeistung && $this->kontakteEntsprechenZiel($stufen, $zielLeistung)) {
$this->WriteAttributeString('Schaltfehler', '');
$this->verarbeiteIdle(false);
@@ -425,15 +434,15 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
} catch (Throwable $ignoriert) {
}
}
$this->SetValue('Istleistung', 0.0);
$this->SetValue('AktiveStufe', 0);
$this->setzeZustand('Istleistung', 0.0);
$this->setzeZustand('AktiveStufe', 0);
throw new RuntimeException('Leistungsstufe konnte nicht sicher geschaltet werden: ' . $fehler->getMessage());
}
$this->WriteAttributeString('Schaltfehler', '');
$this->SetValue('Istleistung', (float) $zielLeistung);
$this->setzeZustand('Istleistung', (float) $zielLeistung);
$this->setzeZustand('Leistungsquelle', Nachrichtenvertrag::LEISTUNGSQUELLE_BERECHNET);
$this->SetValue('AktiveStufe', $zielStufe);
$this->setzeZustand('AktiveStufe', $zielStufe);
$this->verarbeiteIdle(true);
$this->protokolliere('Leistungsstufe', ['Leistung_W' => $zielLeistung, 'Stufe' => $zielStufe]);
}
@@ -477,10 +486,10 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
$zuwachs = WarmwasserRegler::energieKWh(
(float) $this->GetValue('Istleistung'),
(float) $this->leseZustand('Istleistung'),
$jetzt - $letzteBerechnung
);
$this->SetValue('BezogeneEnergie', (float) $this->GetValue('BezogeneEnergie') + $zuwachs);
$this->setzeZustand('BezogeneEnergie', (float) $this->leseZustand('BezogeneEnergie') + $zuwachs);
}
private function aktualisiereStoerungen(bool $temperaturGueltig): void
@@ -489,20 +498,15 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
if (!$temperaturGueltig) {
$stoerungen[] = 'Boilertemperatur fehlt oder ist veraltet.';
}
$uebertemperatur = $temperaturGueltig
&& (float) $this->GetValue('Boilertemperatur')
> max(
(float) $this->GetValue('Maximaltemperatur'),
(float) $this->GetValue('Legionellentemperatur')
) + $this->ReadPropertyFloat('Hysterese');
$uebertemperatur = $this->istUebertemperatur($temperaturGueltig);
if ($uebertemperatur) {
$stoerungen[] = 'Uebertemperatur erkannt.';
}
if ($this->ReadAttributeString('Schaltfehler') !== '') {
$stoerungen[] = $this->ReadAttributeString('Schaltfehler');
}
$this->SetValue('Stoerung', $stoerungen !== []);
$this->SetValue('Stoertext', implode("\n", array_values(array_unique($stoerungen))));
$this->setzeZustand('Stoerung', $stoerungen !== []);
$this->setzeZustand('Stoertext', implode("\n", array_values(array_unique($stoerungen))));
if ($this->ReadAttributeString('Schaltfehler') !== '') {
$this->SetStatus(self::STATUS_SCHALTFEHLER);
} elseif (!$temperaturGueltig) {
@@ -512,6 +516,21 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
}
private function istUebertemperatur(bool $temperaturGueltig): bool
{
if (!$temperaturGueltig) {
return false;
}
$grenze = (float) $this->GetValue('Maximaltemperatur');
if ($this->ReadPropertyBoolean('LegionellenfunktionAktiv')) {
$grenze = max($grenze, $this->ReadAttributeFloat('ZustandLegionellentemperatur'));
}
return (float) $this->GetValue('Boilertemperatur')
> $grenze + $this->ReadPropertyFloat('Hysterese');
}
private function sendeVerbraucherdaten(): void
{
foreach ($this->zugeordneteManagerIDs() as $managerID) {
@@ -534,12 +553,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
{
$temperaturGueltig = (bool) $this->leseZustand('TemperaturGueltig');
$schaltfehler = $this->ReadAttributeString('Schaltfehler');
$uebertemperatur = $temperaturGueltig
&& (float) $this->GetValue('Boilertemperatur')
> max(
(float) $this->GetValue('Maximaltemperatur'),
(float) $this->GetValue('Legionellentemperatur')
) + $this->ReadPropertyFloat('Hysterese');
$uebertemperatur = $this->istUebertemperatur($temperaturGueltig);
return [
'Kopf' => [
@@ -553,14 +567,14 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
'Leistungswerte_W' => $this->leseLeistungsangebot(),
'AenderungMoeglich' => (bool) $this->leseZustand('AenderungMoeglich'),
'Verfuegbar' => (bool) $this->leseZustand('Verfuegbar'),
'Istleistung_W' => (float) $this->GetValue('Istleistung'),
'Istleistung_W' => (float) $this->leseZustand('Istleistung'),
'Leistungsquelle' => Nachrichtenvertrag::LEISTUNGSQUELLE_BERECHNET,
'Zustand' => [
[
'Kennung' => 'Sollleistung_W',
'Art' => 'Sollwert',
'Wert' => (bool) $this->leseZustand('SollwertGueltig')
? (int) $this->GetValue('Sollleistung')
? (int) $this->leseZustand('Sollleistung')
: null,
'Einheit' => 'W',
],
@@ -579,7 +593,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
[
'Kennung' => 'AktiveStufe',
'Art' => 'Status',
'Wert' => (int) $this->GetValue('AktiveStufe'),
'Wert' => (int) $this->leseZustand('AktiveStufe'),
'Einheit' => '',
],
[
@@ -680,7 +694,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
$minimum = (float) $this->GetValue('Mindesttemperatur');
$maximum = (float) $this->GetValue('Maximaltemperatur');
$legionellen = (float) $this->GetValue('Legionellentemperatur');
$legionellen = (float) $this->ReadAttributeFloat('ZustandLegionellentemperatur');
if ($minimum < 0 || $minimum >= $maximum || $legionellen < $maximum) {
throw new InvalidArgumentException(
'Temperaturen muessen Mindesttemperatur < Maximaltemperatur <= Legionellentemperatur erfuellen.'
@@ -735,7 +749,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
$this->SetValue('Mindesttemperatur', 45.0);
$this->SetValue('Maximaltemperatur', 60.0);
$this->SetValue('Legionellentemperatur', 65.0);
$this->WriteAttributeFloat('ZustandLegionellentemperatur', 65.0);
$this->setzeZustand('Leistungsquelle', Nachrichtenvertrag::LEISTUNGSQUELLE_BERECHNET);
$this->setzeZustand('Idle', true);
$this->WriteAttributeBoolean('InitialwerteGesetzt', true);
@@ -747,6 +761,11 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
if (!$this->ReadPropertyBoolean('EinstellungenInVisu')) {
throw new RuntimeException('Temperatureinstellungen sind in der Visualisierung nicht freigegeben.');
}
if ($ident === 'Legionellentemperatur'
&& !$this->ReadPropertyBoolean('LegionellenfunktionAktiv')
) {
throw new RuntimeException('Die Legionellenfunktion ist nicht aktiviert.');
}
if (!is_int($wert) && !is_float($wert)) {
throw new InvalidArgumentException('Temperatursollwert muss numerisch sein.');
}
@@ -758,7 +777,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$werte = [
'Mindesttemperatur' => (float) $this->GetValue('Mindesttemperatur'),
'Maximaltemperatur' => (float) $this->GetValue('Maximaltemperatur'),
'Legionellentemperatur' => (float) $this->GetValue('Legionellentemperatur'),
'Legionellentemperatur' => $this->ReadAttributeFloat('ZustandLegionellentemperatur'),
];
$werte[$ident] = $temperatur;
if ($werte['Mindesttemperatur'] >= $werte['Maximaltemperatur']
@@ -769,14 +788,34 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
);
}
$this->SetValue($ident, $temperatur);
if ($ident === 'Legionellentemperatur') {
$this->WriteAttributeFloat('ZustandLegionellentemperatur', $temperatur);
$variablenID = @IPS_GetObjectIDByIdent($ident, $this->InstanceID);
if (is_int($variablenID) && $variablenID > 0 && IPS_VariableExists($variablenID)) {
SetValue($variablenID, $temperatur);
}
} else {
$this->SetValue($ident, $temperatur);
}
$this->regelzyklus(true);
}
private function aktualisiereVariablen(): void
{
foreach (self::DIAGNOSE_VARIABLEN as $ident) {
if ($ident === 'Leistungsquelle') {
continue;
}
$variablenID = @IPS_GetObjectIDByIdent($ident, $this->InstanceID);
if (is_int($variablenID) && $variablenID > 0 && IPS_VariableExists($variablenID)) {
$this->setzeZustand($ident, GetValue($variablenID));
}
}
if ($this->ReadPropertyBoolean('DiagnosevariablenAnzeigen')) {
$this->registriereVerbraucherDiagnose();
$this->RegisterVariableInteger('AktiveStufe', 'Aktive Stufe', '', 110);
$this->RegisterVariableFloat('BezogeneEnergie', 'Bezogene Energie', '~Electricity', 120);
$this->RegisterVariableBoolean('TemperaturGueltig', 'Temperatur gueltig', '~Switch', 200);
$this->RegisterVariableBoolean('NachladenAktiv', 'Nachladen aktiv', '~Switch', 210);
$this->RegisterVariableBoolean(
@@ -789,9 +828,11 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->RegisterVariableBoolean('Idle', 'Idle', '~Switch', 240);
$this->RegisterVariableInteger('IdleCounter', 'Idle Counter', '', 250);
$this->setzeZustand('Leistungsquelle', Nachrichtenvertrag::LEISTUNGSQUELLE_BERECHNET);
foreach (array_slice(self::DIAGNOSE_VARIABLEN, 1) as $ident) {
$this->setzeZustand($ident, $this->leseZustand($ident));
foreach (self::DIAGNOSE_VARIABLEN as $ident) {
$wert = $ident === 'Leistungsquelle'
? Nachrichtenvertrag::LEISTUNGSQUELLE_BERECHNET
: $this->leseZustand($ident);
$this->setzeZustand($ident, $wert);
}
} else {
foreach (self::DIAGNOSE_VARIABLEN as $ident) {
@@ -803,7 +844,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
$einstellungen = $this->ReadPropertyBoolean('EinstellungenInVisu');
foreach (['Mindesttemperatur', 'Maximaltemperatur', 'Legionellentemperatur'] as $ident) {
foreach (['Mindesttemperatur', 'Maximaltemperatur'] as $ident) {
IPS_SetHidden($this->GetIDForIdent($ident), !$einstellungen);
if ($einstellungen) {
$this->EnableAction($ident);
@@ -811,24 +852,52 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
$this->DisableAction($ident);
}
}
$legionellenID = @IPS_GetObjectIDByIdent('Legionellentemperatur', $this->InstanceID);
if (is_int($legionellenID) && $legionellenID > 0 && IPS_VariableExists($legionellenID)) {
$this->WriteAttributeFloat('ZustandLegionellentemperatur', (float) GetValue($legionellenID));
}
if ($this->ReadPropertyBoolean('LegionellenfunktionAktiv')) {
$this->RegisterVariableFloat('Legionellentemperatur', 'Legionellentemperatur', '~Temperature', 150);
$legionellenID = $this->GetIDForIdent('Legionellentemperatur');
SetValue($legionellenID, $this->ReadAttributeFloat('ZustandLegionellentemperatur'));
IPS_SetHidden($legionellenID, !$einstellungen);
if ($einstellungen) {
$this->EnableAction('Legionellentemperatur');
} else {
$this->DisableAction('Legionellentemperatur');
}
} elseif (is_int($legionellenID) && $legionellenID > 0 && IPS_VariableExists($legionellenID)) {
$this->UnregisterVariable('Legionellentemperatur');
}
}
/** @param bool|int $wert */
/** @param bool|int|float|string $wert */
private function setzeZustand(string $ident, $wert): void
{
$booleanAttribute = [
'SollwertGueltig' => 'ZustandSollwertGueltig',
'Verfuegbar' => 'ZustandVerfuegbar',
'AenderungMoeglich' => 'ZustandAenderungMoeglich',
'Stoerung' => 'ZustandStoerung',
'TemperaturGueltig' => 'ZustandTemperaturGueltig',
'NachladenAktiv' => 'ZustandNachladenAktiv',
'LegionellenbetriebAktiv' => 'ZustandLegionellenbetriebAktiv',
'Idle' => 'ZustandIdle',
];
$integerAttribute = [
'Sollleistung' => 'ZustandSollleistung',
'AktiveStufe' => 'ZustandAktiveStufe',
'LegioCounter' => 'ZustandLegioCounter',
'IdleCounter' => 'ZustandIdleCounter',
];
$floatAttribute = [
'Istleistung' => 'ZustandIstleistung',
'BezogeneEnergie' => 'ZustandBezogeneEnergie',
];
$stringAttribute = [
'Stoertext' => 'ZustandStoertext',
];
if (isset($booleanAttribute[$ident])) {
$wert = (bool) $wert;
@@ -836,6 +905,12 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
} elseif (isset($integerAttribute[$ident])) {
$wert = (int) $wert;
$this->WriteAttributeInteger($integerAttribute[$ident], $wert);
} elseif (isset($floatAttribute[$ident])) {
$wert = (float) $wert;
$this->WriteAttributeFloat($floatAttribute[$ident], $wert);
} elseif (isset($stringAttribute[$ident])) {
$wert = (string) $wert;
$this->WriteAttributeString($stringAttribute[$ident], $wert);
} elseif ($ident !== 'Leistungsquelle') {
throw new LogicException('Unbekannter interner Zustand: ' . $ident);
}
@@ -846,22 +921,32 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
}
}
/** @return bool|int */
/** @return bool|int|float|string */
private function leseZustand(string $ident)
{
$booleanAttribute = [
'SollwertGueltig' => 'ZustandSollwertGueltig',
'Verfuegbar' => 'ZustandVerfuegbar',
'AenderungMoeglich' => 'ZustandAenderungMoeglich',
'Stoerung' => 'ZustandStoerung',
'TemperaturGueltig' => 'ZustandTemperaturGueltig',
'NachladenAktiv' => 'ZustandNachladenAktiv',
'LegionellenbetriebAktiv' => 'ZustandLegionellenbetriebAktiv',
'Idle' => 'ZustandIdle',
];
$integerAttribute = [
'Sollleistung' => 'ZustandSollleistung',
'AktiveStufe' => 'ZustandAktiveStufe',
'LegioCounter' => 'ZustandLegioCounter',
'IdleCounter' => 'ZustandIdleCounter',
];
$floatAttribute = [
'Istleistung' => 'ZustandIstleistung',
'BezogeneEnergie' => 'ZustandBezogeneEnergie',
];
$stringAttribute = [
'Stoertext' => 'ZustandStoertext',
];
if (isset($booleanAttribute[$ident])) {
return $this->ReadAttributeBoolean($booleanAttribute[$ident]);
@@ -869,6 +954,12 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
if (isset($integerAttribute[$ident])) {
return $this->ReadAttributeInteger($integerAttribute[$ident]);
}
if (isset($floatAttribute[$ident])) {
return $this->ReadAttributeFloat($floatAttribute[$ident]);
}
if (isset($stringAttribute[$ident])) {
return $this->ReadAttributeString($stringAttribute[$ident]);
}
throw new LogicException('Unbekannter interner Zustand: ' . $ident);
}