This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
{
|
||||
"elements": [
|
||||
{
|
||||
"type": "ExpansionPanel",
|
||||
"caption": "Manager und Zeitverhalten",
|
||||
"expanded": true,
|
||||
"items": [
|
||||
{"type": "NumberSpinner", "name": "PrioritaetPV", "caption": "Prioritaet PV", "minimum": 0},
|
||||
{"type": "NumberSpinner", "name": "PrioritaetPeak", "caption": "Prioritaet Peak", "minimum": 0},
|
||||
{"type": "NumberSpinner", "name": "Meldeintervall", "caption": "Meldeintervall", "suffix": " s", "minimum": 1},
|
||||
{"type": "NumberSpinner", "name": "VorgabeTimeout", "caption": "Vorgabe-Timeout", "suffix": " s", "minimum": 1},
|
||||
{"type": "NumberSpinner", "name": "LastwechselSperrzeit", "caption": "Lastwechsel-Sperrzeit", "suffix": " s", "minimum": 0}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "ExpansionPanel",
|
||||
"caption": "Pufferspeicher",
|
||||
"expanded": true,
|
||||
"items": [
|
||||
{
|
||||
"type": "List",
|
||||
"name": "LeistungsStufen",
|
||||
"caption": "Leistungsstufen",
|
||||
"add": true,
|
||||
"delete": true,
|
||||
"columns": [
|
||||
{
|
||||
"caption": "Stufe",
|
||||
"name": "Stufe",
|
||||
"width": "100px",
|
||||
"add": 1,
|
||||
"edit": {"type": "NumberSpinner", "minimum": 1}
|
||||
},
|
||||
{
|
||||
"caption": "Leistung",
|
||||
"name": "Leistung",
|
||||
"width": "180px",
|
||||
"add": 0,
|
||||
"edit": {"type": "NumberSpinner", "minimum": 1, "suffix": " W"}
|
||||
},
|
||||
{
|
||||
"caption": "Schaltkontakt",
|
||||
"name": "Schaltkontakt_Stufe",
|
||||
"width": "300px",
|
||||
"add": 0,
|
||||
"edit": {"type": "SelectVariable", "validVariableTypes": [0]}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "SelectVariable",
|
||||
"name": "PufferfuehlerVariableID",
|
||||
"caption": "Puffertemperatur",
|
||||
"validVariableTypes": [1, 2]
|
||||
},
|
||||
{
|
||||
"type": "SelectVariable",
|
||||
"name": "AussentemperaturVariableID",
|
||||
"caption": "Aussentemperatur",
|
||||
"validVariableTypes": [1, 2]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "ExpansionPanel",
|
||||
"caption": "Heizkurve",
|
||||
"expanded": true,
|
||||
"items": [
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "FusspunktVorlauftemperatur",
|
||||
"caption": "Vorlauftemperatur bei 20 Grad C aussen",
|
||||
"suffix": " Grad C",
|
||||
"digits": 1
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "HeizkurvenSteigung",
|
||||
"caption": "Heizkurvensteigung",
|
||||
"minimum": 0,
|
||||
"digits": 2
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "HeizkurveMinimaltemperatur",
|
||||
"caption": "Untere Begrenzung der Solltemperatur",
|
||||
"suffix": " Grad C",
|
||||
"digits": 1
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "HeizkurveMaximaltemperatur",
|
||||
"caption": "Obere Begrenzung der Solltemperatur",
|
||||
"suffix": " Grad C",
|
||||
"digits": 1
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "Hysterese",
|
||||
"caption": "Hysterese",
|
||||
"suffix": " K",
|
||||
"minimum": 0.1,
|
||||
"digits": 1
|
||||
},
|
||||
{
|
||||
"type": "Select",
|
||||
"name": "MindesttemperaturModus",
|
||||
"caption": "Optionale Mindesttemperatur",
|
||||
"options": [
|
||||
{"caption": "Aus", "value": 0},
|
||||
{"caption": "Statisch", "value": 1},
|
||||
{"caption": "Differenz zur Solltemperatur", "value": 2}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "Mindesttemperatur",
|
||||
"caption": "Statische Mindesttemperatur",
|
||||
"suffix": " Grad C",
|
||||
"digits": 1
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "MindesttemperaturDifferenz",
|
||||
"caption": "Differenz zur Solltemperatur",
|
||||
"suffix": " K",
|
||||
"minimum": 0,
|
||||
"digits": 1
|
||||
},
|
||||
{
|
||||
"type": "SelectVariable",
|
||||
"name": "WaermepumpenSolltemperaturVariableID",
|
||||
"caption": "Optionale Solltemperatur der Waermepumpe",
|
||||
"validVariableTypes": [1, 2]
|
||||
},
|
||||
{
|
||||
"type": "Button",
|
||||
"name": "HeizkurveVonWaermepumpeUebernehmen",
|
||||
"caption": "Wert von Waermepumpe uebernehmen",
|
||||
"onClick": "IPS_RequestAction($id, 'HeizkurveVonWaermepumpeUebernehmen', 0);"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "ExpansionPanel",
|
||||
"caption": "Erweiterte Einstellungen",
|
||||
"items": [
|
||||
{"type": "NumberSpinner", "name": "TemperaturMaxAlter", "caption": "Maximales Temperaturalter", "suffix": " s", "minimum": 1},
|
||||
{"type": "CheckBox", "name": "PuffertemperaturGlaetten", "caption": "Puffertemperatur glaetten"},
|
||||
{"type": "NumberSpinner", "name": "ZeitKonstante", "caption": "PT1-Zeitkonstante", "suffix": " s", "minimum": 1},
|
||||
{"type": "CheckBox", "name": "EinstellungenInVisu", "caption": "Einstellungen in der Visualisierung anzeigen"},
|
||||
{"type": "CheckBox", "name": "DiagnosevariablenAnzeigen", "caption": "Diagnosevariablen anzeigen"},
|
||||
{"type": "CheckBox", "name": "LoggingEin", "caption": "Diagnoseprotokoll aktivieren"}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": [
|
||||
{"code": 102, "icon": "active", "caption": "Aktiv"},
|
||||
{"code": 201, "icon": "error", "caption": "Temperaturmessung ungueltig"},
|
||||
{"code": 202, "icon": "error", "caption": "Konfiguration ungueltig"},
|
||||
{"code": 203, "icon": "error", "caption": "Schaltfehler"}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"id": "{C92D5EEF-9632-47A5-9659-4B02BF40FBE9}",
|
||||
"name": "VerbraucherPufferspeicher",
|
||||
"type": 3,
|
||||
"vendor": "Enelix",
|
||||
"aliases": [
|
||||
"Pufferspeicher"
|
||||
],
|
||||
"parentRequirements": [],
|
||||
"childRequirements": [],
|
||||
"implemented": [],
|
||||
"prefix": "ENELIX",
|
||||
"url": "https://git.belevo.ch/ENELIX/Enelix-EMS/src/branch/develop/Pufferspeicher"
|
||||
}
|
||||
@@ -0,0 +1,899 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../libs/VerbraucherSchnittstelle.php';
|
||||
require_once __DIR__ . '/../libs/VerbraucherBasisTrait.php';
|
||||
require_once __DIR__ . '/../libs/Nachrichtenvertrag.php';
|
||||
require_once __DIR__ . '/../libs/PufferspeicherRegler.php';
|
||||
|
||||
use Belevo\EnelixEMS\Nachrichtenvertrag;
|
||||
use Belevo\EnelixEMS\PufferspeicherRegler;
|
||||
use Belevo\EnelixEMS\VerbraucherBasisTrait;
|
||||
use Belevo\EnelixEMS\VerbraucherSchnittstelle;
|
||||
|
||||
class VerbraucherPufferspeicher extends IPSModule implements VerbraucherSchnittstelle
|
||||
{
|
||||
use VerbraucherBasisTrait;
|
||||
|
||||
private const MANAGER_MODULE_ID = '{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}';
|
||||
private const STATUS_AKTIV = 102;
|
||||
private const STATUS_TEMPERATUR_UNGUELTIG = 201;
|
||||
private const STATUS_KONFIGURATION_UNGUELTIG = 202;
|
||||
private const STATUS_SCHALTFEHLER = 203;
|
||||
private const VM_UPDATE = 10603;
|
||||
|
||||
/** @var list<string> */
|
||||
private const DIAGNOSE_VARIABLEN = [
|
||||
'Istleistung',
|
||||
'Leistungsquelle',
|
||||
'Sollleistung',
|
||||
'SollwertGueltig',
|
||||
'Verfuegbar',
|
||||
'AenderungMoeglich',
|
||||
'Stoerung',
|
||||
'Stoertext',
|
||||
'AktiveStufe',
|
||||
'BezogeneEnergie',
|
||||
'TemperaturenGueltig',
|
||||
];
|
||||
|
||||
public function Create(): void
|
||||
{
|
||||
parent::Create();
|
||||
|
||||
$this->registriereVerbraucherBasis();
|
||||
$this->RegisterPropertyString('LeistungsStufen', '[]');
|
||||
$this->RegisterPropertyInteger('PufferfuehlerVariableID', 0);
|
||||
$this->RegisterPropertyInteger('AussentemperaturVariableID', 0);
|
||||
$this->RegisterPropertyInteger('WaermepumpenSolltemperaturVariableID', 0);
|
||||
$this->RegisterPropertyFloat('FusspunktVorlauftemperatur', 35.0);
|
||||
$this->RegisterPropertyFloat('HeizkurvenSteigung', 1.0);
|
||||
$this->RegisterPropertyFloat('HeizkurveMinimaltemperatur', 20.0);
|
||||
$this->RegisterPropertyFloat('HeizkurveMaximaltemperatur', 80.0);
|
||||
$this->RegisterPropertyFloat('Hysterese', 5.0);
|
||||
$this->RegisterPropertyInteger('MindesttemperaturModus', PufferspeicherRegler::MINIMUM_AUS);
|
||||
$this->RegisterPropertyFloat('Mindesttemperatur', 20.0);
|
||||
$this->RegisterPropertyFloat('MindesttemperaturDifferenz', 5.0);
|
||||
$this->RegisterPropertyInteger('LastwechselSperrzeit', 5);
|
||||
$this->RegisterPropertyInteger('TemperaturMaxAlter', 120);
|
||||
$this->RegisterPropertyBoolean('PuffertemperaturGlaetten', false);
|
||||
$this->RegisterPropertyInteger('ZeitKonstante', 120);
|
||||
$this->RegisterPropertyBoolean('DiagnosevariablenAnzeigen', false);
|
||||
|
||||
$this->RegisterVariableFloat('Puffertemperatur', 'Puffertemperatur', '~Temperature', 100);
|
||||
$this->RegisterVariableFloat('Aussentemperatur', 'Aussentemperatur', '~Temperature', 110);
|
||||
$this->RegisterVariableFloat('Solltemperatur', 'Solltemperatur', '~Temperature', 120);
|
||||
$this->RegisterVariableBoolean('Heizbedarf', 'Heizbedarf', '~Switch', 130);
|
||||
|
||||
$this->RegisterAttributeInteger('RegistriertePufferID', 0);
|
||||
$this->RegisterAttributeInteger('RegistrierteAussenID', 0);
|
||||
$this->RegisterAttributeInteger('LetzteBerechnung', 0);
|
||||
$this->RegisterAttributeInteger('LetzteTemperaturberechnung', 0);
|
||||
$this->RegisterAttributeInteger('LetzteVorgabeZeit', 0);
|
||||
$this->RegisterAttributeInteger('LetzterLastwechsel', 0);
|
||||
$this->RegisterAttributeInteger('LetzteManagerID', 0);
|
||||
$this->RegisterAttributeFloat('Glaettungswert', 0.0);
|
||||
$this->RegisterAttributeBoolean('GlaettungInitialisiert', false);
|
||||
$this->RegisterAttributeString('Leistungsangebot', '[0]');
|
||||
$this->RegisterAttributeString('Betriebsart', Nachrichtenvertrag::BETRIEBSART_PV);
|
||||
$this->RegisterAttributeString('Schaltfehler', '');
|
||||
|
||||
$this->RegisterAttributeFloat('ZustandIstleistung', 0.0);
|
||||
$this->RegisterAttributeInteger('ZustandSollleistung', 0);
|
||||
$this->RegisterAttributeBoolean('ZustandSollwertGueltig', false);
|
||||
$this->RegisterAttributeBoolean('ZustandVerfuegbar', false);
|
||||
$this->RegisterAttributeBoolean('ZustandAenderungMoeglich', false);
|
||||
$this->RegisterAttributeBoolean('ZustandStoerung', false);
|
||||
$this->RegisterAttributeString('ZustandStoertext', '');
|
||||
$this->RegisterAttributeInteger('ZustandAktiveStufe', 0);
|
||||
$this->RegisterAttributeFloat('ZustandBezogeneEnergie', 0.0);
|
||||
$this->RegisterAttributeBoolean('ZustandTemperaturenGueltig', false);
|
||||
|
||||
$this->RegisterTimer(
|
||||
'LastwechselFreigabe',
|
||||
0,
|
||||
"IPS_RequestAction(\$_IPS['TARGET'], 'LastwechselFreigabe', false);"
|
||||
);
|
||||
$this->RegisterTimer(
|
||||
'Meldezyklus',
|
||||
0,
|
||||
"IPS_RequestAction(\$_IPS['TARGET'], 'Melden', false);"
|
||||
);
|
||||
$this->RegisterTimer(
|
||||
'RueckmeldungVerzoegert',
|
||||
0,
|
||||
"IPS_RequestAction(\$_IPS['TARGET'], 'Melden', true);"
|
||||
);
|
||||
}
|
||||
|
||||
public function ApplyChanges(): void
|
||||
{
|
||||
parent::ApplyChanges();
|
||||
|
||||
$this->aktualisiereVariablen();
|
||||
try {
|
||||
$this->pruefeKonfiguration();
|
||||
} catch (Throwable $fehler) {
|
||||
$this->deaktiviereTimer();
|
||||
$this->setzeZustand('Verfuegbar', false);
|
||||
$this->setzeZustand('AenderungMoeglich', false);
|
||||
$this->setzeZustand('Stoerung', true);
|
||||
$this->setzeZustand('Stoertext', $fehler->getMessage());
|
||||
$this->SetStatus(self::STATUS_KONFIGURATION_UNGUELTIG);
|
||||
$this->protokolliere('Konfiguration', $fehler->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
$this->registriereTemperaturmeldungen();
|
||||
$this->SetTimerInterval('LastwechselFreigabe', 0);
|
||||
$this->SetTimerInterval('Meldezyklus', $this->ReadPropertyInteger('Meldeintervall') * 1000);
|
||||
$this->regelzyklus(true);
|
||||
}
|
||||
|
||||
public function MessageSink($zeitstempel, $senderID, $nachricht, $daten): void
|
||||
{
|
||||
if ((int) $nachricht !== self::VM_UPDATE) {
|
||||
return;
|
||||
}
|
||||
if (in_array((int) $senderID, [
|
||||
$this->ReadPropertyInteger('PufferfuehlerVariableID'),
|
||||
$this->ReadPropertyInteger('AussentemperaturVariableID'),
|
||||
], true)) {
|
||||
$this->regelzyklus(true);
|
||||
}
|
||||
}
|
||||
|
||||
public function RequestAction($ident, $wert): void
|
||||
{
|
||||
switch ($ident) {
|
||||
case 'Aktiv':
|
||||
$this->SetValue('Aktiv', (bool) $wert);
|
||||
if (!(bool) $wert) {
|
||||
$this->setzeZustand('SollwertGueltig', false);
|
||||
}
|
||||
$this->regelzyklus(true);
|
||||
return;
|
||||
|
||||
case 'HeizkurveVonWaermepumpeUebernehmen':
|
||||
$this->uebernehmeWaermepumpenwert();
|
||||
return;
|
||||
|
||||
case 'LastwechselFreigabe':
|
||||
$this->SetTimerInterval('LastwechselFreigabe', 0);
|
||||
$this->regelzyklus(true);
|
||||
return;
|
||||
|
||||
case 'Melden':
|
||||
if ((bool) $wert) {
|
||||
$this->SetTimerInterval('RueckmeldungVerzoegert', 0);
|
||||
}
|
||||
$this->regelzyklus(false);
|
||||
$this->sendeVerbraucherdaten();
|
||||
return;
|
||||
|
||||
case 'ManagerdatenEmpfangen':
|
||||
if (!is_string($wert)) {
|
||||
throw new InvalidArgumentException('Managerdaten muessen als JSON uebergeben werden.');
|
||||
}
|
||||
$daten = json_decode($wert, true, 512, JSON_THROW_ON_ERROR);
|
||||
if (!is_array($daten)) {
|
||||
throw new InvalidArgumentException('Managerdaten muessen ein JSON-Objekt sein.');
|
||||
}
|
||||
$this->ManagerdatenEmpfangen($daten);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('Unbekannte Aktion: ' . $ident);
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $daten */
|
||||
public function ManagerdatenEmpfangen(array $daten): void
|
||||
{
|
||||
Nachrichtenvertrag::pruefeManagerdaten($daten);
|
||||
if ($daten['Kopf']['EmpfaengerID'] !== $this->InstanceID) {
|
||||
throw new InvalidArgumentException('Managerdaten sind an eine andere Instanz adressiert.');
|
||||
}
|
||||
|
||||
$managerID = $daten['Kopf']['AbsenderID'];
|
||||
if (!in_array($managerID, $this->zugeordneteManagerIDs(), true)) {
|
||||
throw new InvalidArgumentException('Der Manager hat diesen Pufferspeicher nicht aktiv zugeordnet.');
|
||||
}
|
||||
|
||||
$this->WriteAttributeString('Betriebsart', $daten['Betriebsart']);
|
||||
$this->regelzyklus(false);
|
||||
$angebot = $this->leseLeistungsangebot();
|
||||
$sollleistung = $daten['Sollleistung_W'];
|
||||
if ($sollleistung === null) {
|
||||
if ((bool) $this->leseZustand('SollwertGueltig')
|
||||
&& !in_array((int) $this->leseZustand('Sollleistung'), $angebot, true)
|
||||
) {
|
||||
$this->setzeZustand('SollwertGueltig', false);
|
||||
$this->regelzyklus(false);
|
||||
}
|
||||
$this->SetTimerInterval('RueckmeldungVerzoegert', 100);
|
||||
return;
|
||||
}
|
||||
if (!in_array($sollleistung, $angebot, true)) {
|
||||
throw new InvalidArgumentException('Sollleistung_W liegt nicht im aktuell gemeldeten Leistungsangebot.');
|
||||
}
|
||||
|
||||
$this->WriteAttributeInteger('LetzteManagerID', $managerID);
|
||||
$this->WriteAttributeInteger('LetzteVorgabeZeit', time());
|
||||
$this->setzeZustand('Sollleistung', $sollleistung);
|
||||
$this->setzeZustand('SollwertGueltig', true);
|
||||
$this->regelzyklus(false);
|
||||
$this->SetTimerInterval('RueckmeldungVerzoegert', 100);
|
||||
}
|
||||
|
||||
|
||||
private function regelzyklus(bool $meldungPlanen): void
|
||||
{
|
||||
try {
|
||||
$jetzt = time();
|
||||
$this->aktualisiereEnergie($jetzt);
|
||||
$temperaturenGueltig = $this->aktualisiereTemperaturen();
|
||||
$stufen = PufferspeicherRegler::dekodiereLeistungsstufen(
|
||||
$this->ReadPropertyString('LeistungsStufen')
|
||||
);
|
||||
|
||||
$solltemperatur = 0.0;
|
||||
$einschaltschwelle = 0.0;
|
||||
if ($temperaturenGueltig) {
|
||||
$solltemperatur = PufferspeicherRegler::solltemperatur(
|
||||
(float) $this->GetValue('Aussentemperatur'),
|
||||
$this->ReadPropertyFloat('FusspunktVorlauftemperatur'),
|
||||
$this->ReadPropertyFloat('HeizkurvenSteigung'),
|
||||
$this->ReadPropertyFloat('HeizkurveMinimaltemperatur'),
|
||||
$this->ReadPropertyFloat('HeizkurveMaximaltemperatur')
|
||||
);
|
||||
$einschaltschwelle = PufferspeicherRegler::einschaltschwelle(
|
||||
$solltemperatur,
|
||||
$this->ReadPropertyFloat('Hysterese'),
|
||||
$this->ReadPropertyInteger('MindesttemperaturModus'),
|
||||
$this->ReadPropertyFloat('Mindesttemperatur'),
|
||||
$this->ReadPropertyFloat('MindesttemperaturDifferenz')
|
||||
);
|
||||
}
|
||||
$this->SetValue('Solltemperatur', $solltemperatur);
|
||||
|
||||
$aktiv = (bool) $this->GetValue('Aktiv');
|
||||
$peak = $this->ReadAttributeString('Betriebsart') === Nachrichtenvertrag::BETRIEBSART_PEAK;
|
||||
$angebot = PufferspeicherRegler::leistungsangebot(
|
||||
$aktiv,
|
||||
$peak,
|
||||
$temperaturenGueltig,
|
||||
(float) $this->GetValue('Puffertemperatur'),
|
||||
$einschaltschwelle,
|
||||
$stufen
|
||||
);
|
||||
$heizbedarf = count($angebot) > 1;
|
||||
$this->SetValue('Heizbedarf', $heizbedarf);
|
||||
|
||||
$verfuegbar = $aktiv && $temperaturenGueltig && $stufen !== [];
|
||||
$aenderungMoeglich = $verfuegbar && count($angebot) > 1;
|
||||
$zwangsleistung = (!$verfuegbar || !$heizbedarf) ? 0 : null;
|
||||
$aktuelleLeistung = (int) round((float) $this->leseZustand('Istleistung'));
|
||||
$restzeit = PufferspeicherRegler::restzeitBisLastwechsel(
|
||||
$this->ReadAttributeInteger('LetzterLastwechsel'),
|
||||
$jetzt,
|
||||
$this->ReadPropertyInteger('LastwechselSperrzeit')
|
||||
);
|
||||
$lastwechselGesperrt = $restzeit > 0 && $verfuegbar && $zwangsleistung !== 0;
|
||||
$this->SetTimerInterval('LastwechselFreigabe', $lastwechselGesperrt ? $restzeit * 1000 : 0);
|
||||
if ($lastwechselGesperrt) {
|
||||
$angebot = [$aktuelleLeistung];
|
||||
$aenderungMoeglich = false;
|
||||
}
|
||||
|
||||
$letzteVorgabe = $this->ReadAttributeInteger('LetzteVorgabeZeit');
|
||||
if ($letzteVorgabe <= 0
|
||||
|| $jetzt - $letzteVorgabe > $this->ReadPropertyInteger('VorgabeTimeout')
|
||||
) {
|
||||
$this->setzeZustand('SollwertGueltig', false);
|
||||
}
|
||||
|
||||
$ziel = 0;
|
||||
if ($lastwechselGesperrt) {
|
||||
$ziel = $aktuelleLeistung;
|
||||
} elseif ($zwangsleistung !== null) {
|
||||
$ziel = $zwangsleistung;
|
||||
} elseif ((bool) $this->leseZustand('SollwertGueltig')) {
|
||||
$ziel = (int) $this->leseZustand('Sollleistung');
|
||||
if (!in_array($ziel, $angebot, true)) {
|
||||
$this->setzeZustand('SollwertGueltig', false);
|
||||
$ziel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$lastwechsel = $this->schalteLeistung($ziel, $jetzt);
|
||||
if ($lastwechsel) {
|
||||
$angebot = [$ziel];
|
||||
$aenderungMoeglich = false;
|
||||
}
|
||||
$this->WriteAttributeString('Leistungsangebot', json_encode($angebot, JSON_THROW_ON_ERROR));
|
||||
$this->setzeZustand('Sollleistung', $ziel);
|
||||
$this->setzeZustand('Verfuegbar', $verfuegbar);
|
||||
$this->setzeZustand('AenderungMoeglich', $aenderungMoeglich);
|
||||
$this->aktualisiereStoerungen($temperaturenGueltig);
|
||||
if ($meldungPlanen) {
|
||||
$this->SetTimerInterval('RueckmeldungVerzoegert', 100);
|
||||
}
|
||||
} catch (Throwable $fehler) {
|
||||
$this->WriteAttributeString('Schaltfehler', $fehler->getMessage());
|
||||
$this->setzeZustand('Verfuegbar', false);
|
||||
$this->setzeZustand('AenderungMoeglich', false);
|
||||
$this->setzeZustand('Stoerung', true);
|
||||
$this->setzeZustand('Stoertext', $fehler->getMessage());
|
||||
$this->SetStatus(self::STATUS_SCHALTFEHLER);
|
||||
$this->protokolliere('Regelzyklus', $fehler->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function aktualisiereTemperaturen(): bool
|
||||
{
|
||||
$pufferID = $this->ReadPropertyInteger('PufferfuehlerVariableID');
|
||||
$aussenID = $this->ReadPropertyInteger('AussentemperaturVariableID');
|
||||
if (!$this->temperaturwertGueltig($pufferID) || !$this->temperaturwertGueltig($aussenID)) {
|
||||
$this->setzeZustand('TemperaturenGueltig', false);
|
||||
return false;
|
||||
}
|
||||
|
||||
$puffertemperatur = (float) GetValue($pufferID);
|
||||
$aussentemperatur = (float) GetValue($aussenID);
|
||||
$jetzt = time();
|
||||
$letzteBerechnung = $this->ReadAttributeInteger('LetzteTemperaturberechnung');
|
||||
$this->WriteAttributeInteger('LetzteTemperaturberechnung', $jetzt);
|
||||
if ($this->ReadPropertyBoolean('PuffertemperaturGlaetten')) {
|
||||
if (!$this->ReadAttributeBoolean('GlaettungInitialisiert')) {
|
||||
$this->WriteAttributeFloat('Glaettungswert', $puffertemperatur);
|
||||
$this->WriteAttributeBoolean('GlaettungInitialisiert', true);
|
||||
} elseif ($letzteBerechnung > 0 && $jetzt > $letzteBerechnung) {
|
||||
$puffertemperatur = PufferspeicherRegler::pt1(
|
||||
$this->ReadAttributeFloat('Glaettungswert'),
|
||||
$puffertemperatur,
|
||||
$jetzt - $letzteBerechnung,
|
||||
$this->ReadPropertyInteger('ZeitKonstante')
|
||||
);
|
||||
$this->WriteAttributeFloat('Glaettungswert', $puffertemperatur);
|
||||
} else {
|
||||
$puffertemperatur = $this->ReadAttributeFloat('Glaettungswert');
|
||||
}
|
||||
} else {
|
||||
$this->WriteAttributeBoolean('GlaettungInitialisiert', false);
|
||||
}
|
||||
|
||||
$this->SetValue('Puffertemperatur', $puffertemperatur);
|
||||
$this->SetValue('Aussentemperatur', $aussentemperatur);
|
||||
$this->setzeZustand('TemperaturenGueltig', true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function temperaturwertGueltig(int $variablenID): bool
|
||||
{
|
||||
if ($variablenID <= 0 || !IPS_VariableExists($variablenID)) {
|
||||
return false;
|
||||
}
|
||||
$variable = IPS_GetVariable($variablenID);
|
||||
if (!in_array((int) $variable['VariableType'], [1, 2], true)) {
|
||||
return false;
|
||||
}
|
||||
if (time() - (int) $variable['VariableUpdated'] > $this->ReadPropertyInteger('TemperaturMaxAlter')) {
|
||||
return false;
|
||||
}
|
||||
$wert = GetValue($variablenID);
|
||||
|
||||
return is_int($wert) || is_float($wert);
|
||||
}
|
||||
|
||||
private function uebernehmeWaermepumpenwert(): void
|
||||
{
|
||||
$wpID = $this->ReadPropertyInteger('WaermepumpenSolltemperaturVariableID');
|
||||
$aussenID = $this->ReadPropertyInteger('AussentemperaturVariableID');
|
||||
if (!$this->temperaturwertGueltig($wpID) || !$this->temperaturwertGueltig($aussenID)) {
|
||||
throw new RuntimeException('Waermepumpen-Solltemperatur oder Aussentemperatur ist ungueltig.');
|
||||
}
|
||||
$fusspunkt = PufferspeicherRegler::fusspunktAusWaermepumpenwert(
|
||||
(float) GetValue($wpID),
|
||||
(float) GetValue($aussenID),
|
||||
$this->ReadPropertyFloat('HeizkurvenSteigung')
|
||||
);
|
||||
IPS_SetProperty($this->InstanceID, 'FusspunktVorlauftemperatur', $fusspunkt);
|
||||
IPS_ApplyChanges($this->InstanceID);
|
||||
$this->protokolliere('Heizkurve', ['FusspunktVorlauftemperatur' => $fusspunkt]);
|
||||
}
|
||||
|
||||
private function schalteLeistung(int $zielLeistung, int $jetzt): bool
|
||||
{
|
||||
$stufen = PufferspeicherRegler::dekodiereLeistungsstufen(
|
||||
$this->ReadPropertyString('LeistungsStufen')
|
||||
);
|
||||
$zielStufe = PufferspeicherRegler::stufeFuerLeistung($stufen, $zielLeistung);
|
||||
$bisher = (int) round((float) $this->leseZustand('Istleistung'));
|
||||
if ($zielLeistung === $bisher && $this->kontakteEntsprechenZiel($stufen, $zielLeistung)) {
|
||||
$this->WriteAttributeString('Schaltfehler', '');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($stufen as $stufe) {
|
||||
RequestAction($stufe['KontaktID'], false);
|
||||
}
|
||||
foreach ($stufen as $stufe) {
|
||||
if ($stufe['Leistung_W'] === $zielLeistung && $zielLeistung > 0) {
|
||||
RequestAction($stufe['KontaktID'], true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable $fehler) {
|
||||
foreach ($stufen as $stufe) {
|
||||
try {
|
||||
RequestAction($stufe['KontaktID'], false);
|
||||
} catch (Throwable $ignoriert) {
|
||||
}
|
||||
}
|
||||
$this->setzeZustand('Istleistung', 0.0);
|
||||
$this->setzeZustand('AktiveStufe', 0);
|
||||
throw new RuntimeException('Leistungsstufe konnte nicht sicher geschaltet werden: ' . $fehler->getMessage());
|
||||
}
|
||||
|
||||
$this->WriteAttributeString('Schaltfehler', '');
|
||||
$this->setzeZustand('Istleistung', (float) $zielLeistung);
|
||||
$this->setzeZustand('Leistungsquelle', Nachrichtenvertrag::LEISTUNGSQUELLE_BERECHNET);
|
||||
$this->setzeZustand('AktiveStufe', $zielStufe);
|
||||
$this->WriteAttributeInteger('LetzterLastwechsel', $jetzt);
|
||||
$this->protokolliere('Leistungsstufe', ['Leistung_W' => $zielLeistung, 'Stufe' => $zielStufe]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @param list<array{Stufe: int, Leistung_W: int, KontaktID: int}> $stufen */
|
||||
private function kontakteEntsprechenZiel(array $stufen, int $zielLeistung): bool
|
||||
{
|
||||
foreach ($stufen as $stufe) {
|
||||
if (!IPS_VariableExists($stufe['KontaktID'])) {
|
||||
return false;
|
||||
}
|
||||
$sollEin = $zielLeistung > 0 && $stufe['Leistung_W'] === $zielLeistung;
|
||||
if ((bool) GetValue($stufe['KontaktID']) !== $sollEin) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function aktualisiereEnergie(int $jetzt): void
|
||||
{
|
||||
$letzteBerechnung = $this->ReadAttributeInteger('LetzteBerechnung');
|
||||
$this->WriteAttributeInteger('LetzteBerechnung', $jetzt);
|
||||
if ($letzteBerechnung <= 0 || $jetzt <= $letzteBerechnung) {
|
||||
return;
|
||||
}
|
||||
$zuwachs = PufferspeicherRegler::energieKWh(
|
||||
(float) $this->leseZustand('Istleistung'),
|
||||
$jetzt - $letzteBerechnung
|
||||
);
|
||||
$this->setzeZustand(
|
||||
'BezogeneEnergie',
|
||||
(float) $this->leseZustand('BezogeneEnergie') + $zuwachs
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private function aktualisiereStoerungen(bool $temperaturenGueltig): void
|
||||
{
|
||||
$stoerungen = [];
|
||||
if (!$temperaturenGueltig) {
|
||||
$stoerungen[] = 'Puffer- oder Aussentemperatur fehlt oder ist veraltet.';
|
||||
}
|
||||
if ($this->ReadAttributeString('Schaltfehler') !== '') {
|
||||
$stoerungen[] = $this->ReadAttributeString('Schaltfehler');
|
||||
}
|
||||
$this->setzeZustand('Stoerung', $stoerungen !== []);
|
||||
$this->setzeZustand('Stoertext', implode("
|
||||
", array_values(array_unique($stoerungen))));
|
||||
if ($this->ReadAttributeString('Schaltfehler') !== '') {
|
||||
$this->SetStatus(self::STATUS_SCHALTFEHLER);
|
||||
} elseif (!$temperaturenGueltig) {
|
||||
$this->SetStatus(self::STATUS_TEMPERATUR_UNGUELTIG);
|
||||
} else {
|
||||
$this->SetStatus(self::STATUS_AKTIV);
|
||||
}
|
||||
}
|
||||
|
||||
private function sendeVerbraucherdaten(): void
|
||||
{
|
||||
foreach ($this->zugeordneteManagerIDs() as $managerID) {
|
||||
$daten = $this->baueVerbraucherdaten($managerID);
|
||||
Nachrichtenvertrag::pruefeVerbraucherdaten($daten);
|
||||
try {
|
||||
IPS_RequestAction(
|
||||
$managerID,
|
||||
'VerbraucherdatenEmpfangen',
|
||||
json_encode($daten, JSON_THROW_ON_ERROR)
|
||||
);
|
||||
} catch (Throwable $fehler) {
|
||||
$this->protokolliere('Managerkommunikation', $fehler->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
private function baueVerbraucherdaten(int $managerID): array
|
||||
{
|
||||
$temperaturenGueltig = (bool) $this->leseZustand('TemperaturenGueltig');
|
||||
$schaltfehler = $this->ReadAttributeString('Schaltfehler');
|
||||
|
||||
return [
|
||||
'Kopf' => [
|
||||
'Version' => Nachrichtenvertrag::VERSION,
|
||||
'AbsenderID' => $this->InstanceID,
|
||||
'EmpfaengerID' => $managerID,
|
||||
'Zeitpunkt' => time(),
|
||||
],
|
||||
'Betriebsart' => $this->ReadAttributeString('Betriebsart'),
|
||||
'PrioritaetPV' => $this->ReadPropertyInteger('PrioritaetPV'),
|
||||
'PrioritaetPeak' => $this->ReadPropertyInteger('PrioritaetPeak'),
|
||||
'Leistungswerte_W' => $this->leseLeistungsangebot(),
|
||||
'AenderungMoeglich' => (bool) $this->leseZustand('AenderungMoeglich'),
|
||||
'Verfuegbar' => (bool) $this->leseZustand('Verfuegbar'),
|
||||
'Istleistung_W' => (float) $this->leseZustand('Istleistung'),
|
||||
'Leistungsquelle' => Nachrichtenvertrag::LEISTUNGSQUELLE_BERECHNET,
|
||||
'Zustand' => [
|
||||
[
|
||||
'Kennung' => 'Sollleistung_W',
|
||||
'Art' => 'Sollwert',
|
||||
'Wert' => (bool) $this->leseZustand('SollwertGueltig')
|
||||
? (int) $this->leseZustand('Sollleistung')
|
||||
: null,
|
||||
'Einheit' => 'W',
|
||||
],
|
||||
[
|
||||
'Kennung' => 'Puffertemperatur_C',
|
||||
'Art' => 'Istwert',
|
||||
'Wert' => $temperaturenGueltig ? (float) $this->GetValue('Puffertemperatur') : null,
|
||||
'Einheit' => 'C',
|
||||
],
|
||||
[
|
||||
'Kennung' => 'Aussentemperatur_C',
|
||||
'Art' => 'Istwert',
|
||||
'Wert' => $temperaturenGueltig ? (float) $this->GetValue('Aussentemperatur') : null,
|
||||
'Einheit' => 'C',
|
||||
],
|
||||
[
|
||||
'Kennung' => 'Solltemperatur_C',
|
||||
'Art' => 'Sollwert',
|
||||
'Wert' => $temperaturenGueltig ? (float) $this->GetValue('Solltemperatur') : null,
|
||||
'Einheit' => 'C',
|
||||
],
|
||||
[
|
||||
'Kennung' => 'Heizbedarf',
|
||||
'Art' => 'Status',
|
||||
'Wert' => (bool) $this->GetValue('Heizbedarf'),
|
||||
'Einheit' => '',
|
||||
],
|
||||
[
|
||||
'Kennung' => 'AktiveStufe',
|
||||
'Art' => 'Status',
|
||||
'Wert' => (int) $this->leseZustand('AktiveStufe'),
|
||||
'Einheit' => '',
|
||||
],
|
||||
[
|
||||
'Kennung' => 'Fuehlerfehler',
|
||||
'Art' => 'Stoerung',
|
||||
'Wert' => !$temperaturenGueltig,
|
||||
'Einheit' => '',
|
||||
'Text' => $temperaturenGueltig
|
||||
? ''
|
||||
: 'Puffer- oder Aussentemperatur fehlt oder ist veraltet.',
|
||||
],
|
||||
[
|
||||
'Kennung' => 'Schaltfehler',
|
||||
'Art' => 'Stoerung',
|
||||
'Wert' => $schaltfehler !== '',
|
||||
'Einheit' => '',
|
||||
'Text' => $schaltfehler,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/** @return list<int> */
|
||||
private function zugeordneteManagerIDs(): array
|
||||
{
|
||||
$ergebnis = [];
|
||||
foreach (IPS_GetInstanceListByModuleID(self::MANAGER_MODULE_ID) as $managerID) {
|
||||
try {
|
||||
$automatisch = (bool) IPS_GetProperty($managerID, 'AutomatischeSuche');
|
||||
$property = $automatisch
|
||||
? 'AutomatischeVerbraucherZuordnung'
|
||||
: 'VerbraucherZuordnung';
|
||||
$zuordnung = $this->leseManagerZuordnung($managerID, $property);
|
||||
if ($automatisch && $zuordnung === []) {
|
||||
$zuordnung = $this->leseManagerZuordnung($managerID, 'VerbraucherZuordnung');
|
||||
}
|
||||
} catch (Throwable $fehler) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($zuordnung as $eintrag) {
|
||||
if (!is_array($eintrag) || ($eintrag['Aktiv'] ?? false) !== true) {
|
||||
continue;
|
||||
}
|
||||
$instanzID = $eintrag['InstanzID'] ?? $eintrag['Verbraucher'] ?? null;
|
||||
if ($instanzID === $this->InstanceID) {
|
||||
$ergebnis[] = (int) $managerID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique($ergebnis));
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
private function leseManagerZuordnung(int $managerID, string $property): array
|
||||
{
|
||||
$zuordnung = json_decode(
|
||||
(string) IPS_GetProperty($managerID, $property),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
return is_array($zuordnung) ? $zuordnung : [];
|
||||
}
|
||||
|
||||
private function pruefeKonfiguration(): void
|
||||
{
|
||||
foreach (['PrioritaetPV', 'PrioritaetPeak'] as $property) {
|
||||
if ($this->ReadPropertyInteger($property) < 0) {
|
||||
throw new InvalidArgumentException($property . ' muss mindestens 0 sein.');
|
||||
}
|
||||
}
|
||||
foreach ([
|
||||
'Meldeintervall',
|
||||
'VorgabeTimeout',
|
||||
'TemperaturMaxAlter',
|
||||
'ZeitKonstante',
|
||||
] as $property) {
|
||||
if ($this->ReadPropertyInteger($property) <= 0) {
|
||||
throw new InvalidArgumentException($property . ' muss groesser als 0 sein.');
|
||||
}
|
||||
}
|
||||
if ($this->ReadPropertyInteger('LastwechselSperrzeit') < 0) {
|
||||
throw new InvalidArgumentException('LastwechselSperrzeit darf nicht negativ sein.');
|
||||
}
|
||||
if ($this->ReadPropertyFloat('Hysterese') <= 0.0) {
|
||||
throw new InvalidArgumentException('Hysterese muss groesser als 0 sein.');
|
||||
}
|
||||
|
||||
PufferspeicherRegler::solltemperatur(
|
||||
20.0,
|
||||
$this->ReadPropertyFloat('FusspunktVorlauftemperatur'),
|
||||
$this->ReadPropertyFloat('HeizkurvenSteigung'),
|
||||
$this->ReadPropertyFloat('HeizkurveMinimaltemperatur'),
|
||||
$this->ReadPropertyFloat('HeizkurveMaximaltemperatur')
|
||||
);
|
||||
PufferspeicherRegler::einschaltschwelle(
|
||||
50.0,
|
||||
$this->ReadPropertyFloat('Hysterese'),
|
||||
$this->ReadPropertyInteger('MindesttemperaturModus'),
|
||||
$this->ReadPropertyFloat('Mindesttemperatur'),
|
||||
$this->ReadPropertyFloat('MindesttemperaturDifferenz')
|
||||
);
|
||||
|
||||
foreach (['PufferfuehlerVariableID', 'AussentemperaturVariableID'] as $property) {
|
||||
$variablenID = $this->ReadPropertyInteger($property);
|
||||
if ($variablenID <= 0 || !IPS_VariableExists($variablenID)) {
|
||||
throw new InvalidArgumentException($property . ' ist nicht eingerichtet.');
|
||||
}
|
||||
$variable = IPS_GetVariable($variablenID);
|
||||
if (!in_array((int) $variable['VariableType'], [1, 2], true)) {
|
||||
throw new InvalidArgumentException($property . ' muss eine Integer- oder Floatvariable sein.');
|
||||
}
|
||||
}
|
||||
|
||||
$wpID = $this->ReadPropertyInteger('WaermepumpenSolltemperaturVariableID');
|
||||
if ($wpID > 0) {
|
||||
if (!IPS_VariableExists($wpID)) {
|
||||
throw new InvalidArgumentException('WaermepumpenSolltemperaturVariableID existiert nicht.');
|
||||
}
|
||||
$wpVariable = IPS_GetVariable($wpID);
|
||||
if (!in_array((int) $wpVariable['VariableType'], [1, 2], true)) {
|
||||
throw new InvalidArgumentException(
|
||||
'WaermepumpenSolltemperaturVariableID muss eine Integer- oder Floatvariable sein.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$stufen = PufferspeicherRegler::dekodiereLeistungsstufen(
|
||||
$this->ReadPropertyString('LeistungsStufen')
|
||||
);
|
||||
if ($stufen === []) {
|
||||
throw new InvalidArgumentException('Mindestens eine Leistungsstufe ist erforderlich.');
|
||||
}
|
||||
foreach ($stufen as $stufe) {
|
||||
if (!IPS_VariableExists($stufe['KontaktID'])) {
|
||||
throw new InvalidArgumentException('Schaltkontakt ' . $stufe['KontaktID'] . ' existiert nicht.');
|
||||
}
|
||||
$kontakt = IPS_GetVariable($stufe['KontaktID']);
|
||||
if ((int) $kontakt['VariableType'] !== 0) {
|
||||
throw new InvalidArgumentException('Alle Schaltkontakte muessen Booleanvariablen sein.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function registriereTemperaturmeldungen(): void
|
||||
{
|
||||
$zuordnungen = [
|
||||
'RegistriertePufferID' => $this->ReadPropertyInteger('PufferfuehlerVariableID'),
|
||||
'RegistrierteAussenID' => $this->ReadPropertyInteger('AussentemperaturVariableID'),
|
||||
];
|
||||
foreach ($zuordnungen as $attribut => $neueID) {
|
||||
$alteID = $this->ReadAttributeInteger($attribut);
|
||||
if ($alteID > 0 && $alteID !== $neueID) {
|
||||
$this->UnregisterMessage($alteID, self::VM_UPDATE);
|
||||
}
|
||||
if ($neueID > 0 && $neueID !== $alteID) {
|
||||
$this->RegisterMessage($neueID, self::VM_UPDATE);
|
||||
}
|
||||
$this->WriteAttributeInteger($attribut, $neueID);
|
||||
}
|
||||
}
|
||||
|
||||
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', '', 200);
|
||||
$this->RegisterVariableFloat('BezogeneEnergie', 'Bezogene Energie', '~Electricity', 210);
|
||||
$this->RegisterVariableBoolean(
|
||||
'TemperaturenGueltig',
|
||||
'Temperaturen gueltig',
|
||||
'~Switch',
|
||||
220
|
||||
);
|
||||
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) {
|
||||
$variablenID = @IPS_GetObjectIDByIdent($ident, $this->InstanceID);
|
||||
if (is_int($variablenID) && $variablenID > 0 && IPS_VariableExists($variablenID)) {
|
||||
$this->UnregisterVariable($ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param bool|int|float|string $wert */
|
||||
private function setzeZustand(string $ident, $wert): void
|
||||
{
|
||||
$booleanAttribute = [
|
||||
'SollwertGueltig' => 'ZustandSollwertGueltig',
|
||||
'Verfuegbar' => 'ZustandVerfuegbar',
|
||||
'AenderungMoeglich' => 'ZustandAenderungMoeglich',
|
||||
'Stoerung' => 'ZustandStoerung',
|
||||
'TemperaturenGueltig' => 'ZustandTemperaturenGueltig',
|
||||
];
|
||||
$integerAttribute = [
|
||||
'Sollleistung' => 'ZustandSollleistung',
|
||||
'AktiveStufe' => 'ZustandAktiveStufe',
|
||||
];
|
||||
$floatAttribute = [
|
||||
'Istleistung' => 'ZustandIstleistung',
|
||||
'BezogeneEnergie' => 'ZustandBezogeneEnergie',
|
||||
];
|
||||
$stringAttribute = ['Stoertext' => 'ZustandStoertext'];
|
||||
|
||||
if (isset($booleanAttribute[$ident])) {
|
||||
$wert = (bool) $wert;
|
||||
$this->WriteAttributeBoolean($booleanAttribute[$ident], $wert);
|
||||
} 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);
|
||||
}
|
||||
|
||||
$variablenID = @IPS_GetObjectIDByIdent($ident, $this->InstanceID);
|
||||
if (is_int($variablenID) && $variablenID > 0 && IPS_VariableExists($variablenID)) {
|
||||
SetValue($variablenID, $wert);
|
||||
}
|
||||
}
|
||||
|
||||
/** @return bool|int|float|string */
|
||||
private function leseZustand(string $ident)
|
||||
{
|
||||
$booleanAttribute = [
|
||||
'SollwertGueltig' => 'ZustandSollwertGueltig',
|
||||
'Verfuegbar' => 'ZustandVerfuegbar',
|
||||
'AenderungMoeglich' => 'ZustandAenderungMoeglich',
|
||||
'Stoerung' => 'ZustandStoerung',
|
||||
'TemperaturenGueltig' => 'ZustandTemperaturenGueltig',
|
||||
];
|
||||
$integerAttribute = [
|
||||
'Sollleistung' => 'ZustandSollleistung',
|
||||
'AktiveStufe' => 'ZustandAktiveStufe',
|
||||
];
|
||||
$floatAttribute = [
|
||||
'Istleistung' => 'ZustandIstleistung',
|
||||
'BezogeneEnergie' => 'ZustandBezogeneEnergie',
|
||||
];
|
||||
$stringAttribute = ['Stoertext' => 'ZustandStoertext'];
|
||||
|
||||
if (isset($booleanAttribute[$ident])) {
|
||||
return $this->ReadAttributeBoolean($booleanAttribute[$ident]);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/** @return list<int> */
|
||||
private function leseLeistungsangebot(): array
|
||||
{
|
||||
$angebot = json_decode(
|
||||
$this->ReadAttributeString('Leistungsangebot'),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
if (!is_array($angebot)) {
|
||||
return [0];
|
||||
}
|
||||
|
||||
return array_values(array_map('intval', $angebot));
|
||||
}
|
||||
|
||||
private function deaktiviereTimer(): void
|
||||
{
|
||||
foreach (['LastwechselFreigabe', 'Meldezyklus', 'RueckmeldungVerzoegert'] as $timer) {
|
||||
$this->SetTimerInterval($timer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** @param mixed $daten */
|
||||
private function protokolliere(string $bezeichnung, $daten): void
|
||||
{
|
||||
if (!$this->ReadPropertyBoolean('LoggingEin')) {
|
||||
return;
|
||||
}
|
||||
$this->SendDebug(
|
||||
$bezeichnung,
|
||||
is_string($daten) ? $daten : json_encode($daten, JSON_THROW_ON_ERROR),
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user