This commit is contained in:
+236
-137
@@ -1,159 +1,258 @@
|
|||||||
{
|
{
|
||||||
"elements": [
|
"elements": [
|
||||||
{
|
{
|
||||||
"type": "Select",
|
"type": "ExpansionPanel",
|
||||||
"name": "Rolle",
|
"caption": "Grundeinstellungen",
|
||||||
"caption": "Rolle",
|
"expanded": true,
|
||||||
"options": [
|
"items": [
|
||||||
{"caption": "Alleine", "value": 0},
|
|
||||||
{"caption": "Hauptmanager", "value": 1},
|
|
||||||
{"caption": "Untermanager", "value": 2}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "SelectVariable",
|
|
||||||
"name": "NetzleistungVariableID",
|
|
||||||
"caption": "Netzleistung"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "NumberSpinner",
|
|
||||||
"name": "Netzleistungsfaktor",
|
|
||||||
"caption": "Netzleistungsfaktor",
|
|
||||||
"digits": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "NumberSpinner",
|
|
||||||
"name": "MesswertMaxAlter",
|
|
||||||
"caption": "Maximales Messwertalter",
|
|
||||||
"suffix": " s",
|
|
||||||
"minimum": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "List",
|
|
||||||
"name": "VerbraucherZuordnung",
|
|
||||||
"caption": "Verbraucher",
|
|
||||||
"add": true,
|
|
||||||
"delete": true,
|
|
||||||
"sortable": true,
|
|
||||||
"columns": [
|
|
||||||
{
|
{
|
||||||
"caption": "Instanz",
|
"type": "Select",
|
||||||
"name": "InstanzID",
|
"name": "Rolle",
|
||||||
"width": "auto",
|
"caption": "Rolle",
|
||||||
"add": 0,
|
"options": [
|
||||||
"edit": {"type": "SelectInstance"}
|
{"caption": "Alleine", "value": 0},
|
||||||
|
{"caption": "Hauptmanager", "value": 1},
|
||||||
|
{"caption": "Untermanager", "value": 2}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"caption": "Aktiv",
|
"type": "SelectVariable",
|
||||||
"name": "Aktiv",
|
"name": "NetzleistungVariableID",
|
||||||
"width": "100px",
|
"caption": "Netzleistung"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "NumberSpinner",
|
||||||
|
"name": "SollwertSolarladen",
|
||||||
|
"caption": "Sollwert Solarladen",
|
||||||
|
"suffix": " W",
|
||||||
|
"digits": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Select",
|
||||||
|
"name": "Lastspitzenmodus",
|
||||||
|
"caption": "Lastspitzenmodus",
|
||||||
|
"onChange": "IPS_RequestAction($id, 'FormLastspitzenmodus', $Lastspitzenmodus);",
|
||||||
|
"options": [
|
||||||
|
{"caption": "Aus", "value": 0},
|
||||||
|
{"caption": "Konstant", "value": 1},
|
||||||
|
{"caption": "Monatlich", "value": 2}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "NumberSpinner",
|
||||||
|
"name": "Lastspitzengrenze",
|
||||||
|
"caption": "Lastspitzengrenze",
|
||||||
|
"suffix": " W",
|
||||||
|
"digits": 1,
|
||||||
|
"visible": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Button",
|
||||||
|
"name": "MonatsgrenzenUmschalten",
|
||||||
|
"caption": "Monatsgrenzen anzeigen",
|
||||||
|
"visible": false,
|
||||||
|
"onClick": "IPS_RequestAction($id, 'FormMonatsgrenzenUmschalten', true);"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "List",
|
||||||
|
"name": "Monatsgrenzen",
|
||||||
|
"caption": "Monatliche Lastspitzengrenzen",
|
||||||
|
"rowCount": 12,
|
||||||
"add": false,
|
"add": false,
|
||||||
"edit": {"type": "CheckBox"}
|
"delete": false,
|
||||||
|
"sortable": false,
|
||||||
|
"loadValuesFromConfiguration": false,
|
||||||
|
"visible": false,
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"caption": "Monat",
|
||||||
|
"name": "Monat",
|
||||||
|
"width": "auto",
|
||||||
|
"save": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Grenze",
|
||||||
|
"name": "Grenze_W",
|
||||||
|
"width": "180px",
|
||||||
|
"save": true,
|
||||||
|
"edit": {
|
||||||
|
"type": "NumberSpinner",
|
||||||
|
"suffix": " W",
|
||||||
|
"digits": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Monatsnummer",
|
||||||
|
"name": "MonatIndex",
|
||||||
|
"width": "0px",
|
||||||
|
"visible": false,
|
||||||
|
"save": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CheckBox",
|
||||||
|
"name": "AutomatischeSuche",
|
||||||
|
"caption": "Verbraucher automatisch suchen",
|
||||||
|
"onChange": "IPS_RequestAction($id, 'FormAutomatischeSuche', $AutomatischeSuche);"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SelectObject",
|
||||||
|
"name": "SuchbereichID",
|
||||||
|
"caption": "Suchbereich",
|
||||||
|
"visible": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "List",
|
||||||
|
"name": "VerbraucherZuordnung",
|
||||||
|
"caption": "Verbraucher manuell auswaehlen",
|
||||||
|
"rowCount": 6,
|
||||||
|
"add": true,
|
||||||
|
"delete": true,
|
||||||
|
"sortable": true,
|
||||||
|
"visible": false,
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"caption": "Instanz",
|
||||||
|
"name": "InstanzID",
|
||||||
|
"width": "auto",
|
||||||
|
"add": 0,
|
||||||
|
"edit": {"type": "SelectInstance"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Aktiv",
|
||||||
|
"name": "Aktiv",
|
||||||
|
"width": "100px",
|
||||||
|
"add": false,
|
||||||
|
"edit": {"type": "CheckBox"}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "List",
|
||||||
|
"name": "AutomatischeVerbraucherZuordnung",
|
||||||
|
"caption": "Gefundene Verbraucher",
|
||||||
|
"rowCount": 8,
|
||||||
|
"add": false,
|
||||||
|
"delete": false,
|
||||||
|
"loadValuesFromConfiguration": false,
|
||||||
|
"visible": true,
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"caption": "Verbraucher",
|
||||||
|
"name": "Name",
|
||||||
|
"width": "auto",
|
||||||
|
"save": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Instanz-ID",
|
||||||
|
"name": "InstanzID",
|
||||||
|
"width": "100px",
|
||||||
|
"save": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Verwenden",
|
||||||
|
"name": "Aktiv",
|
||||||
|
"width": "100px",
|
||||||
|
"save": true,
|
||||||
|
"edit": {"type": "CheckBox"}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"values": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "CheckBox",
|
"type": "ExpansionPanel",
|
||||||
"name": "AutomatischeSuche",
|
"caption": "Erweiterte Einstellungen",
|
||||||
"caption": "Verbraucher automatisch suchen"
|
"items": [
|
||||||
},
|
{
|
||||||
{
|
"type": "NumberSpinner",
|
||||||
"type": "SelectObject",
|
"name": "KeepAlive",
|
||||||
"name": "SuchbereichID",
|
"caption": "Keep alive",
|
||||||
"caption": "Suchbereich"
|
"suffix": " s",
|
||||||
},
|
"minimum": 1
|
||||||
{
|
},
|
||||||
"type": "NumberSpinner",
|
{
|
||||||
"name": "Regelintervall",
|
"type": "NumberSpinner",
|
||||||
"caption": "Regelintervall",
|
"name": "VerbraucherTimeout",
|
||||||
"suffix": " s",
|
"caption": "Verbraucher-Timeout",
|
||||||
"minimum": 1
|
"suffix": " s",
|
||||||
},
|
"minimum": 1
|
||||||
{
|
},
|
||||||
"type": "NumberSpinner",
|
{
|
||||||
"name": "Vorgabeintervall",
|
"type": "NumberSpinner",
|
||||||
"caption": "Vorgabeintervall",
|
"name": "MesswertMaxAlter",
|
||||||
"suffix": " s",
|
"caption": "Maximales Messwertalter",
|
||||||
"minimum": 1
|
"suffix": " s",
|
||||||
},
|
"minimum": 1
|
||||||
{
|
},
|
||||||
"type": "NumberSpinner",
|
{
|
||||||
"name": "VerbraucherTimeout",
|
"type": "NumberSpinner",
|
||||||
"caption": "Verbraucher-Timeout",
|
"name": "Umschaltdifferenz",
|
||||||
"suffix": " s",
|
"caption": "Mindestdifferenz vor Umschaltung",
|
||||||
"minimum": 1
|
"suffix": " %",
|
||||||
},
|
"minimum": 0,
|
||||||
{
|
"maximum": 100,
|
||||||
"type": "Select",
|
"digits": 1
|
||||||
"name": "Lastspitzenmodus",
|
},
|
||||||
"caption": "Lastspitzenmodus",
|
{
|
||||||
"options": [
|
"type": "NumberSpinner",
|
||||||
{"caption": "Aus", "value": 0},
|
"name": "Netzleistungsfaktor",
|
||||||
{"caption": "Konstant", "value": 1},
|
"caption": "Netzleistungsfaktor",
|
||||||
{"caption": "Monatlich", "value": 2}
|
"digits": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CheckBox",
|
||||||
|
"name": "LoggingEin",
|
||||||
|
"caption": "Logging ein"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "NumberSpinner",
|
|
||||||
"name": "Lastspitzengrenze",
|
|
||||||
"caption": "Lastspitzengrenze",
|
|
||||||
"suffix": " W",
|
|
||||||
"digits": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "ValidationTextBox",
|
|
||||||
"name": "Monatsgrenzen",
|
|
||||||
"caption": "Monatsgrenzen als JSON"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "CheckBox",
|
|
||||||
"name": "MonatsgrenzenVisuBedienbar",
|
|
||||||
"caption": "Monatsgrenzen in der Visualisierung bedienen"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "NumberSpinner",
|
|
||||||
"name": "SollwertSolarladen",
|
|
||||||
"caption": "Sollwert Solarladen",
|
|
||||||
"suffix": " W",
|
|
||||||
"digits": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "NumberSpinner",
|
|
||||||
"name": "UmschaltschwelleUeberschuss",
|
|
||||||
"caption": "Umschaltschwelle Ueberschuss",
|
|
||||||
"suffix": " W",
|
|
||||||
"digits": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "NumberSpinner",
|
|
||||||
"name": "UmschaltschwelleLastspitze",
|
|
||||||
"caption": "Umschaltschwelle Lastspitze",
|
|
||||||
"suffix": " W",
|
|
||||||
"digits": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "NumberSpinner",
|
|
||||||
"name": "Umschaltdifferenz",
|
|
||||||
"caption": "Mindestdifferenz vor Umschaltung",
|
|
||||||
"suffix": " %",
|
|
||||||
"minimum": 0,
|
|
||||||
"maximum": 100,
|
|
||||||
"digits": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "ExpansionPanel",
|
"type": "ExpansionPanel",
|
||||||
"caption": "Optionale obere Anschluesse",
|
"caption": "Prognose / Forecast",
|
||||||
"items": [
|
"items": [
|
||||||
{"type": "ValidationTextBox", "name": "PrognoseAnschluss", "caption": "Prognose / Forecast als JSON"},
|
{
|
||||||
{"type": "ValidationTextBox", "name": "SDLAnschluss", "caption": "SDL / VGT als JSON"},
|
"type": "ValidationTextBox",
|
||||||
{"type": "ValidationTextBox", "name": "LizenzAnschluss", "caption": "Lizenzierung als JSON"},
|
"name": "PrognoseAnschluss",
|
||||||
{"type": "ValidationTextBox", "name": "StoermeldeAnschluss", "caption": "Stoerueberwachung als JSON"}
|
"caption": "Konfiguration als JSON"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "CheckBox",
|
"type": "ExpansionPanel",
|
||||||
"name": "LoggingEin",
|
"caption": "SDL / VGT",
|
||||||
"caption": "Logging ein"
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "ValidationTextBox",
|
||||||
|
"name": "SDLAnschluss",
|
||||||
|
"caption": "Konfiguration als JSON"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ExpansionPanel",
|
||||||
|
"caption": "Lizenzierung",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "ValidationTextBox",
|
||||||
|
"name": "LizenzAnschluss",
|
||||||
|
"caption": "Konfiguration als JSON"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ExpansionPanel",
|
||||||
|
"caption": "Stoerueberwachung",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "ValidationTextBox",
|
||||||
|
"name": "StoermeldeAnschluss",
|
||||||
|
"caption": "Konfiguration als JSON"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"actions": [
|
"actions": [
|
||||||
|
|||||||
+275
-43
@@ -16,6 +16,13 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
private const STATUS_MESSWERT_UNGUELTIG = 201;
|
private const STATUS_MESSWERT_UNGUELTIG = 201;
|
||||||
private const STATUS_KONFIGURATION_UNGUELTIG = 202;
|
private const STATUS_KONFIGURATION_UNGUELTIG = 202;
|
||||||
private const VM_UPDATE = 10603;
|
private const VM_UPDATE = 10603;
|
||||||
|
private const VERBRAUCHER_MODUL_IDS = [
|
||||||
|
'{B7C54AF4-AD7D-4FE4-B75D-203693906251}',
|
||||||
|
];
|
||||||
|
private const MONATSNAMEN = [
|
||||||
|
1 => 'Januar', 'Februar', 'Maerz', 'April', 'Mai', 'Juni',
|
||||||
|
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember',
|
||||||
|
];
|
||||||
|
|
||||||
public function Create(): void
|
public function Create(): void
|
||||||
{
|
{
|
||||||
@@ -24,21 +31,18 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->RegisterPropertyInteger('Rolle', 0);
|
$this->RegisterPropertyInteger('Rolle', 0);
|
||||||
$this->RegisterPropertyInteger('NetzleistungVariableID', 0);
|
$this->RegisterPropertyInteger('NetzleistungVariableID', 0);
|
||||||
$this->RegisterPropertyFloat('Netzleistungsfaktor', 1.0);
|
$this->RegisterPropertyFloat('Netzleistungsfaktor', 1.0);
|
||||||
$this->RegisterPropertyInteger('MesswertMaxAlter', 30);
|
$this->RegisterPropertyInteger('MesswertMaxAlter', 60);
|
||||||
$this->RegisterPropertyString('VerbraucherZuordnung', '[]');
|
$this->RegisterPropertyString('VerbraucherZuordnung', '[]');
|
||||||
|
$this->RegisterPropertyString('AutomatischeVerbraucherZuordnung', '[]');
|
||||||
$this->RegisterPropertyBoolean('AutomatischeSuche', true);
|
$this->RegisterPropertyBoolean('AutomatischeSuche', true);
|
||||||
$this->RegisterPropertyInteger('SuchbereichID', 0);
|
$this->RegisterPropertyInteger('SuchbereichID', 0);
|
||||||
$this->RegisterPropertyInteger('Regelintervall', 2);
|
$this->RegisterPropertyInteger('KeepAlive', 60);
|
||||||
$this->RegisterPropertyInteger('Vorgabeintervall', 10);
|
$this->RegisterPropertyInteger('VerbraucherTimeout', 60);
|
||||||
$this->RegisterPropertyInteger('VerbraucherTimeout', 30);
|
|
||||||
$this->RegisterPropertyInteger('Lastspitzenmodus', 0);
|
$this->RegisterPropertyInteger('Lastspitzenmodus', 0);
|
||||||
$this->RegisterPropertyFloat('Lastspitzengrenze', 0.0);
|
$this->RegisterPropertyFloat('Lastspitzengrenze', 0.0);
|
||||||
$this->RegisterPropertyString('Monatsgrenzen', $this->standardMonatsgrenzen());
|
$this->RegisterPropertyString('Monatsgrenzen', $this->standardMonatsgrenzen());
|
||||||
$this->RegisterPropertyBoolean('MonatsgrenzenVisuBedienbar', false);
|
|
||||||
$this->RegisterPropertyFloat('SollwertSolarladen', 0.0);
|
$this->RegisterPropertyFloat('SollwertSolarladen', 0.0);
|
||||||
$this->RegisterPropertyFloat('UmschaltschwelleUeberschuss', 0.0);
|
$this->RegisterPropertyFloat('Umschaltdifferenz', 5.0);
|
||||||
$this->RegisterPropertyFloat('UmschaltschwelleLastspitze', 0.0);
|
|
||||||
$this->RegisterPropertyFloat('Umschaltdifferenz', 0.0);
|
|
||||||
$this->RegisterPropertyString('PrognoseAnschluss', '{}');
|
$this->RegisterPropertyString('PrognoseAnschluss', '{}');
|
||||||
$this->RegisterPropertyString('SDLAnschluss', '{}');
|
$this->RegisterPropertyString('SDLAnschluss', '{}');
|
||||||
$this->RegisterPropertyString('LizenzAnschluss', '{}');
|
$this->RegisterPropertyString('LizenzAnschluss', '{}');
|
||||||
@@ -67,13 +71,11 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->RegisterAttributeString('LetzteSollwerte', '{}');
|
$this->RegisterAttributeString('LetzteSollwerte', '{}');
|
||||||
$this->RegisterAttributeInteger('RegistrierteNetzleistungVariableID', 0);
|
$this->RegisterAttributeInteger('RegistrierteNetzleistungVariableID', 0);
|
||||||
|
|
||||||
|
// Die alten Timer bleiben deaktiviert registriert, damit bestehende Instanzen sauber migrieren.
|
||||||
|
$this->RegisterTimer('Regelzyklus', 0, '');
|
||||||
|
$this->RegisterTimer('VorgabenErneuern', 0, '');
|
||||||
$this->RegisterTimer(
|
$this->RegisterTimer(
|
||||||
'Regelzyklus',
|
'KeepAlive',
|
||||||
0,
|
|
||||||
"IPS_RequestAction(\$_IPS['TARGET'], 'Regeln', false);"
|
|
||||||
);
|
|
||||||
$this->RegisterTimer(
|
|
||||||
'VorgabenErneuern',
|
|
||||||
0,
|
0,
|
||||||
"IPS_RequestAction(\$_IPS['TARGET'], 'Regeln', true);"
|
"IPS_RequestAction(\$_IPS['TARGET'], 'Regeln', true);"
|
||||||
);
|
);
|
||||||
@@ -89,19 +91,82 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->SetStatus(self::STATUS_KONFIGURATION_UNGUELTIG);
|
$this->SetStatus(self::STATUS_KONFIGURATION_UNGUELTIG);
|
||||||
$this->SetTimerInterval('Regelzyklus', 0);
|
$this->SetTimerInterval('Regelzyklus', 0);
|
||||||
$this->SetTimerInterval('VorgabenErneuern', 0);
|
$this->SetTimerInterval('VorgabenErneuern', 0);
|
||||||
|
$this->SetTimerInterval('KeepAlive', 0);
|
||||||
$this->protokolliere('Konfiguration', $fehler->getMessage());
|
$this->protokolliere('Konfiguration', $fehler->getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->registriereNetzleistungsmeldung();
|
$this->registriereNetzleistungsmeldung();
|
||||||
$this->SetTimerInterval('Regelzyklus', $this->ReadPropertyInteger('Regelintervall') * 1000);
|
$this->SetTimerInterval('Regelzyklus', 0);
|
||||||
$this->SetTimerInterval('VorgabenErneuern', $this->ReadPropertyInteger('Vorgabeintervall') * 1000);
|
$this->SetTimerInterval('VorgabenErneuern', 0);
|
||||||
|
$this->SetTimerInterval('KeepAlive', $this->ReadPropertyInteger('KeepAlive') * 1000);
|
||||||
$this->SetValue('Monatsgrenzen', $this->ReadPropertyString('Monatsgrenzen'));
|
$this->SetValue('Monatsgrenzen', $this->ReadPropertyString('Monatsgrenzen'));
|
||||||
$this->aktualisiereSichtbarkeit();
|
$this->aktualisiereSichtbarkeit();
|
||||||
$this->aktualisiereAnschlussstatus();
|
$this->aktualisiereAnschlussstatus();
|
||||||
$this->SetStatus(self::STATUS_AKTIV);
|
$this->SetStatus(self::STATUS_AKTIV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function GetConfigurationForm(): string
|
||||||
|
{
|
||||||
|
$formular = json_decode(
|
||||||
|
(string) file_get_contents(__DIR__ . '/form.json'),
|
||||||
|
true,
|
||||||
|
512,
|
||||||
|
JSON_THROW_ON_ERROR
|
||||||
|
);
|
||||||
|
$automatisch = $this->ReadPropertyBoolean('AutomatischeSuche');
|
||||||
|
$lastspitzenmodus = $this->ReadPropertyInteger('Lastspitzenmodus');
|
||||||
|
$monatsgrenzenSichtbar = $lastspitzenmodus === 2
|
||||||
|
&& $this->GetBuffer('MonatsgrenzenSichtbar') === '1';
|
||||||
|
|
||||||
|
$this->setzeFormularParameter($formular['elements'], 'VerbraucherZuordnung', 'visible', !$automatisch);
|
||||||
|
$this->setzeFormularParameter(
|
||||||
|
$formular['elements'],
|
||||||
|
'AutomatischeVerbraucherZuordnung',
|
||||||
|
'visible',
|
||||||
|
$automatisch
|
||||||
|
);
|
||||||
|
$this->setzeFormularParameter($formular['elements'], 'SuchbereichID', 'visible', $automatisch);
|
||||||
|
$this->setzeFormularParameter(
|
||||||
|
$formular['elements'],
|
||||||
|
'AutomatischeVerbraucherZuordnung',
|
||||||
|
'values',
|
||||||
|
$this->automatischeVerbraucherFuerFormular()
|
||||||
|
);
|
||||||
|
$this->setzeFormularParameter(
|
||||||
|
$formular['elements'],
|
||||||
|
'Lastspitzengrenze',
|
||||||
|
'visible',
|
||||||
|
$lastspitzenmodus === 1
|
||||||
|
);
|
||||||
|
$this->setzeFormularParameter(
|
||||||
|
$formular['elements'],
|
||||||
|
'MonatsgrenzenUmschalten',
|
||||||
|
'visible',
|
||||||
|
$lastspitzenmodus === 2
|
||||||
|
);
|
||||||
|
$this->setzeFormularParameter(
|
||||||
|
$formular['elements'],
|
||||||
|
'MonatsgrenzenUmschalten',
|
||||||
|
'caption',
|
||||||
|
$monatsgrenzenSichtbar ? 'Monatsgrenzen ausblenden' : 'Monatsgrenzen anzeigen'
|
||||||
|
);
|
||||||
|
$this->setzeFormularParameter(
|
||||||
|
$formular['elements'],
|
||||||
|
'Monatsgrenzen',
|
||||||
|
'visible',
|
||||||
|
$monatsgrenzenSichtbar
|
||||||
|
);
|
||||||
|
$this->setzeFormularParameter(
|
||||||
|
$formular['elements'],
|
||||||
|
'Monatsgrenzen',
|
||||||
|
'values',
|
||||||
|
$this->monatsgrenzenFuerFormular()
|
||||||
|
);
|
||||||
|
|
||||||
|
return json_encode($formular, JSON_THROW_ON_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
public function MessageSink($zeitstempel, $senderID, $nachricht, $daten): void
|
public function MessageSink($zeitstempel, $senderID, $nachricht, $daten): void
|
||||||
{
|
{
|
||||||
if ((int) $senderID === $this->ReadPropertyInteger('NetzleistungVariableID')
|
if ((int) $senderID === $this->ReadPropertyInteger('NetzleistungVariableID')
|
||||||
@@ -123,6 +188,39 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->regeln((bool) $wert);
|
$this->regeln((bool) $wert);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 'FormAutomatischeSuche':
|
||||||
|
$automatisch = (bool) $wert;
|
||||||
|
$this->UpdateFormField('VerbraucherZuordnung', 'visible', !$automatisch);
|
||||||
|
$this->UpdateFormField('AutomatischeVerbraucherZuordnung', 'visible', $automatisch);
|
||||||
|
$this->UpdateFormField('SuchbereichID', 'visible', $automatisch);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 'FormLastspitzenmodus':
|
||||||
|
$modus = (int) $wert;
|
||||||
|
$this->UpdateFormField('Lastspitzengrenze', 'visible', $modus === 1);
|
||||||
|
$this->UpdateFormField('MonatsgrenzenUmschalten', 'visible', $modus === 2);
|
||||||
|
if ($modus !== 2) {
|
||||||
|
$this->SetBuffer('MonatsgrenzenSichtbar', '0');
|
||||||
|
$this->UpdateFormField('Monatsgrenzen', 'visible', false);
|
||||||
|
$this->UpdateFormField(
|
||||||
|
'MonatsgrenzenUmschalten',
|
||||||
|
'caption',
|
||||||
|
'Monatsgrenzen anzeigen'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 'FormMonatsgrenzenUmschalten':
|
||||||
|
$sichtbar = $this->GetBuffer('MonatsgrenzenSichtbar') !== '1';
|
||||||
|
$this->SetBuffer('MonatsgrenzenSichtbar', $sichtbar ? '1' : '0');
|
||||||
|
$this->UpdateFormField('Monatsgrenzen', 'visible', $sichtbar);
|
||||||
|
$this->UpdateFormField(
|
||||||
|
'MonatsgrenzenUmschalten',
|
||||||
|
'caption',
|
||||||
|
$sichtbar ? 'Monatsgrenzen ausblenden' : 'Monatsgrenzen anzeigen'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
|
||||||
case 'VerbraucherdatenEmpfangen':
|
case 'VerbraucherdatenEmpfangen':
|
||||||
if (!is_string($wert)) {
|
if (!is_string($wert)) {
|
||||||
throw new InvalidArgumentException('Verbraucherdaten muessen als JSON uebergeben werden.');
|
throw new InvalidArgumentException('Verbraucherdaten muessen als JSON uebergeben werden.');
|
||||||
@@ -134,14 +232,6 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->VerbraucherdatenEmpfangen($daten);
|
$this->VerbraucherdatenEmpfangen($daten);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'Monatsgrenzen':
|
|
||||||
if (!$this->ReadPropertyBoolean('MonatsgrenzenVisuBedienbar')) {
|
|
||||||
throw new RuntimeException('Monatsgrenzen sind in der Visualisierung nicht bedienbar.');
|
|
||||||
}
|
|
||||||
$this->dekodiereMonatsgrenzen((string) $wert);
|
|
||||||
IPS_SetProperty($this->InstanceID, 'Monatsgrenzen', (string) $wert);
|
|
||||||
IPS_ApplyChanges($this->InstanceID);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new InvalidArgumentException('Unbekannte Aktion: ' . $ident);
|
throw new InvalidArgumentException('Unbekannte Aktion: ' . $ident);
|
||||||
@@ -200,8 +290,6 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$netzleistung,
|
$netzleistung,
|
||||||
(string) $this->GetValue('Betriebsart'),
|
(string) $this->GetValue('Betriebsart'),
|
||||||
$lastspitzengrenze !== null,
|
$lastspitzengrenze !== null,
|
||||||
$this->ReadPropertyFloat('UmschaltschwelleUeberschuss'),
|
|
||||||
$this->ReadPropertyFloat('UmschaltschwelleLastspitze'),
|
|
||||||
$this->ReadPropertyFloat('SollwertSolarladen'),
|
$this->ReadPropertyFloat('SollwertSolarladen'),
|
||||||
$lastspitzengrenze ?? 0.0,
|
$lastspitzengrenze ?? 0.0,
|
||||||
$this->ReadPropertyFloat('Umschaltdifferenz')
|
$this->ReadPropertyFloat('Umschaltdifferenz')
|
||||||
@@ -297,9 +385,30 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
/** @return list<int> */
|
/** @return list<int> */
|
||||||
private function aktiveVerbraucherIDs(): array
|
private function aktiveVerbraucherIDs(): array
|
||||||
{
|
{
|
||||||
$zuordnung = json_decode($this->ReadPropertyString('VerbraucherZuordnung'), true, 512, JSON_THROW_ON_ERROR);
|
if (!$this->ReadPropertyBoolean('AutomatischeSuche')) {
|
||||||
|
return $this->leseAktiveVerbraucherIDs('VerbraucherZuordnung');
|
||||||
|
}
|
||||||
|
|
||||||
|
$gespeichert = json_decode(
|
||||||
|
$this->ReadPropertyString('AutomatischeVerbraucherZuordnung'),
|
||||||
|
true,
|
||||||
|
512,
|
||||||
|
JSON_THROW_ON_ERROR
|
||||||
|
);
|
||||||
|
if ($gespeichert === []) {
|
||||||
|
// Bestehende Installationen behalten ihre Auswahl, bis die neue Liste gespeichert wurde.
|
||||||
|
return $this->leseAktiveVerbraucherIDs('VerbraucherZuordnung');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->leseAktiveVerbraucherIDs('AutomatischeVerbraucherZuordnung');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return list<int> */
|
||||||
|
private function leseAktiveVerbraucherIDs(string $property): array
|
||||||
|
{
|
||||||
|
$zuordnung = json_decode($this->ReadPropertyString($property), true, 512, JSON_THROW_ON_ERROR);
|
||||||
if (!is_array($zuordnung)) {
|
if (!is_array($zuordnung)) {
|
||||||
throw new InvalidArgumentException('VerbraucherZuordnung muss eine JSON-Liste sein.');
|
throw new InvalidArgumentException($property . ' muss eine JSON-Liste sein.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$ids = [];
|
$ids = [];
|
||||||
@@ -319,6 +428,102 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
return array_values(array_unique($ids));
|
return array_values(array_unique($ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return list<array{Name: string, InstanzID: int, Aktiv: bool}> */
|
||||||
|
private function automatischeVerbraucherFuerFormular(): array
|
||||||
|
{
|
||||||
|
$gespeichert = json_decode(
|
||||||
|
$this->ReadPropertyString('AutomatischeVerbraucherZuordnung'),
|
||||||
|
true,
|
||||||
|
512,
|
||||||
|
JSON_THROW_ON_ERROR
|
||||||
|
);
|
||||||
|
$ausgewaehlt = $gespeichert === []
|
||||||
|
? $this->leseAktiveVerbraucherIDs('VerbraucherZuordnung')
|
||||||
|
: $this->leseAktiveVerbraucherIDs('AutomatischeVerbraucherZuordnung');
|
||||||
|
|
||||||
|
$suchbereichID = $this->ReadPropertyInteger('SuchbereichID');
|
||||||
|
$werte = [];
|
||||||
|
foreach (self::VERBRAUCHER_MODUL_IDS as $modulID) {
|
||||||
|
foreach (IPS_GetInstanceListByModuleID($modulID) as $instanzID) {
|
||||||
|
if (!$this->istImSuchbereich($instanzID, $suchbereichID)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$werte[] = [
|
||||||
|
'Name' => IPS_GetName($instanzID),
|
||||||
|
'InstanzID' => $instanzID,
|
||||||
|
'Aktiv' => in_array($instanzID, $ausgewaehlt, true),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usort($werte, static function (array $links, array $rechts): int {
|
||||||
|
$nameVergleich = strcasecmp($links['Name'], $rechts['Name']);
|
||||||
|
|
||||||
|
return $nameVergleich !== 0
|
||||||
|
? $nameVergleich
|
||||||
|
: $links['InstanzID'] <=> $rechts['InstanzID'];
|
||||||
|
});
|
||||||
|
|
||||||
|
return $werte;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function istImSuchbereich(int $objektID, int $suchbereichID): bool
|
||||||
|
{
|
||||||
|
if ($suchbereichID <= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($objektID > 0) {
|
||||||
|
if ($objektID === $suchbereichID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$objektID = IPS_GetParent($objektID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return list<array{Monat: string, Grenze_W: float, MonatIndex: int}> */
|
||||||
|
private function monatsgrenzenFuerFormular(): array
|
||||||
|
{
|
||||||
|
$grenzen = $this->dekodiereMonatsgrenzen($this->ReadPropertyString('Monatsgrenzen'));
|
||||||
|
$werte = [];
|
||||||
|
foreach (self::MONATSNAMEN as $monat => $name) {
|
||||||
|
$werte[] = [
|
||||||
|
'Monat' => $name,
|
||||||
|
'Grenze_W' => $grenzen[$monat],
|
||||||
|
'MonatIndex' => $monat,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $werte;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param list<array<string, mixed>> $elemente */
|
||||||
|
private function setzeFormularParameter(
|
||||||
|
array &$elemente,
|
||||||
|
string $name,
|
||||||
|
string $parameter,
|
||||||
|
$wert
|
||||||
|
): bool {
|
||||||
|
foreach ($elemente as &$element) {
|
||||||
|
if (($element['name'] ?? null) === $name) {
|
||||||
|
$element[$parameter] = $wert;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isset($element['items'])
|
||||||
|
&& is_array($element['items'])
|
||||||
|
&& $this->setzeFormularParameter($element['items'], $name, $parameter, $wert)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($element);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private function sendeSollwert(int $instanzID, int $sollleistung): void
|
private function sendeSollwert(int $instanzID, int $sollleistung): void
|
||||||
{
|
{
|
||||||
if (!IPS_InstanceExists($instanzID)) {
|
if (!IPS_InstanceExists($instanzID)) {
|
||||||
@@ -381,13 +586,8 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
] as $ident) {
|
] as $ident) {
|
||||||
IPS_SetHidden($this->GetIDForIdent($ident), !$logging);
|
IPS_SetHidden($this->GetIDForIdent($ident), !$logging);
|
||||||
}
|
}
|
||||||
$monatsgrenzenBedienbar = $logging && $this->ReadPropertyBoolean('MonatsgrenzenVisuBedienbar');
|
IPS_SetHidden($this->GetIDForIdent('Monatsgrenzen'), true);
|
||||||
IPS_SetHidden($this->GetIDForIdent('Monatsgrenzen'), !$monatsgrenzenBedienbar);
|
$this->DisableAction('Monatsgrenzen');
|
||||||
if ($monatsgrenzenBedienbar) {
|
|
||||||
$this->EnableAction('Monatsgrenzen');
|
|
||||||
} else {
|
|
||||||
$this->DisableAction('Monatsgrenzen');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function aktualisiereAnschlussstatus(): void
|
private function aktualisiereAnschlussstatus(): void
|
||||||
@@ -406,7 +606,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
|
|
||||||
private function pruefeKonfiguration(): void
|
private function pruefeKonfiguration(): void
|
||||||
{
|
{
|
||||||
foreach (['MesswertMaxAlter', 'Regelintervall', 'Vorgabeintervall', 'VerbraucherTimeout'] as $property) {
|
foreach (['MesswertMaxAlter', 'KeepAlive', 'VerbraucherTimeout'] as $property) {
|
||||||
if ($this->ReadPropertyInteger($property) <= 0) {
|
if ($this->ReadPropertyInteger($property) <= 0) {
|
||||||
throw new InvalidArgumentException($property . ' muss groesser als 0 sein.');
|
throw new InvalidArgumentException($property . ' muss groesser als 0 sein.');
|
||||||
}
|
}
|
||||||
@@ -416,7 +616,8 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
) {
|
) {
|
||||||
throw new InvalidArgumentException('Umschaltdifferenz muss zwischen 0 und 100 liegen.');
|
throw new InvalidArgumentException('Umschaltdifferenz muss zwischen 0 und 100 liegen.');
|
||||||
}
|
}
|
||||||
$this->aktiveVerbraucherIDs();
|
$this->leseAktiveVerbraucherIDs('VerbraucherZuordnung');
|
||||||
|
$this->leseAktiveVerbraucherIDs('AutomatischeVerbraucherZuordnung');
|
||||||
$this->dekodiereMonatsgrenzen($this->ReadPropertyString('Monatsgrenzen'));
|
$this->dekodiereMonatsgrenzen($this->ReadPropertyString('Monatsgrenzen'));
|
||||||
foreach (['PrognoseAnschluss', 'SDLAnschluss', 'LizenzAnschluss', 'StoermeldeAnschluss'] as $property) {
|
foreach (['PrognoseAnschluss', 'SDLAnschluss', 'LizenzAnschluss', 'StoermeldeAnschluss'] as $property) {
|
||||||
$wert = json_decode($this->ReadPropertyString($property), true, 512, JSON_THROW_ON_ERROR);
|
$wert = json_decode($this->ReadPropertyString($property), true, 512, JSON_THROW_ON_ERROR);
|
||||||
@@ -434,13 +635,35 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
throw new InvalidArgumentException('Monatsgrenzen muss ein JSON-Objekt sein.');
|
throw new InvalidArgumentException('Monatsgrenzen muss ein JSON-Objekt sein.');
|
||||||
}
|
}
|
||||||
$ergebnis = [];
|
$ergebnis = [];
|
||||||
for ($monat = 1; $monat <= 12; ++$monat) {
|
if (isset($werte[0]) && is_array($werte[0])) {
|
||||||
$wert = $werte[(string) $monat] ?? $werte[$monat] ?? null;
|
foreach ($werte as $eintrag) {
|
||||||
if (!is_int($wert) && !is_float($wert)) {
|
if (!is_array($eintrag)) {
|
||||||
throw new InvalidArgumentException('Monatsgrenzen muss fuer jeden Monat einen Zahlenwert enthalten.');
|
throw new InvalidArgumentException('Monatsgrenzen muss eine Liste von Monatswerten sein.');
|
||||||
|
}
|
||||||
|
$monat = $eintrag['MonatIndex'] ?? null;
|
||||||
|
$wert = $eintrag['Grenze_W'] ?? null;
|
||||||
|
if (!is_int($monat) || $monat < 1 || $monat > 12
|
||||||
|
|| (!is_int($wert) && !is_float($wert))
|
||||||
|
) {
|
||||||
|
throw new InvalidArgumentException('Jeder Monatswert benoetigt Monatsnummer und Grenze.');
|
||||||
|
}
|
||||||
|
$ergebnis[$monat] = (float) $wert;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for ($monat = 1; $monat <= 12; ++$monat) {
|
||||||
|
$wert = $werte[(string) $monat] ?? $werte[$monat] ?? null;
|
||||||
|
if (!is_int($wert) && !is_float($wert)) {
|
||||||
|
throw new InvalidArgumentException(
|
||||||
|
'Monatsgrenzen muss fuer jeden Monat einen Zahlenwert enthalten.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$ergebnis[$monat] = (float) $wert;
|
||||||
}
|
}
|
||||||
$ergebnis[$monat] = (float) $wert;
|
|
||||||
}
|
}
|
||||||
|
if (count($ergebnis) !== 12) {
|
||||||
|
throw new InvalidArgumentException('Monatsgrenzen muss genau zwoelf Monatswerte enthalten.');
|
||||||
|
}
|
||||||
|
ksort($ergebnis);
|
||||||
|
|
||||||
return $ergebnis;
|
return $ergebnis;
|
||||||
}
|
}
|
||||||
@@ -455,7 +678,16 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
|
|
||||||
private function standardMonatsgrenzen(): string
|
private function standardMonatsgrenzen(): string
|
||||||
{
|
{
|
||||||
return json_encode(array_fill_keys(range(1, 12), 0), JSON_THROW_ON_ERROR);
|
$werte = [];
|
||||||
|
foreach (self::MONATSNAMEN as $monat => $name) {
|
||||||
|
$werte[] = [
|
||||||
|
'Monat' => $name,
|
||||||
|
'Grenze_W' => 0.0,
|
||||||
|
'MonatIndex' => $monat,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_encode($werte, JSON_THROW_ON_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param mixed $daten */
|
/** @param mixed $daten */
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ Symcon-Datenpunkte werden durch `VerbraucherBasisTrait` registriert.
|
|||||||
| `PrioritaetPV` | Integer | `0` | Priorität ab 0; kleinere Zahl bedeutet höhere Priorität. |
|
| `PrioritaetPV` | Integer | `0` | Priorität ab 0; kleinere Zahl bedeutet höhere Priorität. |
|
||||||
| `PrioritaetPeak` | Integer | `0` | Wie PV-Priorität, ohne fachliche Obergrenze. |
|
| `PrioritaetPeak` | Integer | `0` | Wie PV-Priorität, ohne fachliche Obergrenze. |
|
||||||
| `Meldeintervall` | Integer | `10` | Vollständige Rückmeldung in Sekunden; muss grösser als 0 sein. |
|
| `Meldeintervall` | Integer | `10` | Vollständige Rückmeldung in Sekunden; muss grösser als 0 sein. |
|
||||||
| `VorgabeTimeout` | Integer | `30` | Sollwert wird nach dieser Zeit ohne Erneuerung ungültig. |
|
| `VorgabeTimeout` | Integer | `120` | Sollwert wird nach dieser Zeit ohne Erneuerung ungültig. |
|
||||||
| `EinstellungenInVisu` | Boolean | `false` | Blendet lokale Einstellvariablen ein und macht sie geprüft bedienbar. |
|
| `EinstellungenInVisu` | Boolean | `false` | Blendet lokale Einstellvariablen ein und macht sie geprüft bedienbar. |
|
||||||
| `LoggingEin` | Boolean | `false` | Aktiviert das laufende Diagnoseprotokoll. Module können zusätzliche Diagnosevariablen getrennt einblenden. |
|
| `LoggingEin` | Boolean | `false` | Aktiviert das laufende Diagnoseprotokoll. Module können zusätzliche Diagnosevariablen getrennt einblenden. |
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ ergänzt.
|
|||||||
|
|
||||||
- Rückmeldung nach dem Start, bei relevanten Änderungen und zusätzlich alle
|
- Rückmeldung nach dem Start, bei relevanten Änderungen und zusätzlich alle
|
||||||
`Meldeintervall` Sekunden.
|
`Meldeintervall` Sekunden.
|
||||||
- Laufende Vorgaben werden vom Manager standardmässig alle 10 Sekunden erneuert.
|
- Laufende Vorgaben werden vom Manager standardmässig alle 60 Sekunden erneuert.
|
||||||
- Nach `VorgabeTimeout` Sekunden ist eine nicht erneuerte Vorgabe ungültig.
|
- Nach `VorgabeTimeout` Sekunden ist eine nicht erneuerte Vorgabe ungültig.
|
||||||
- Nach einem Neustart wird zuerst der Gerätezustand erfasst; eine alte Vorgabe
|
- Nach einem Neustart wird zuerst der Gerätezustand erfasst; eine alte Vorgabe
|
||||||
wird nicht ungeprüft wieder aufgenommen.
|
wird nicht ungeprüft wieder aufgenommen.
|
||||||
|
|||||||
@@ -35,21 +35,18 @@ Ohne Logging sind nur `Aktiv`, `Betriebsart` und `Netzleistung` sichtbar.
|
|||||||
| `Rolle` | Auswahl | `Alleine`; alternativ `Hauptmanager` oder `Untermanager`. |
|
| `Rolle` | Auswahl | `Alleine`; alternativ `Hauptmanager` oder `Untermanager`. |
|
||||||
| `NetzleistungVariableID` | Integer | `0*`; gültige Messquelle vor Regelstart. |
|
| `NetzleistungVariableID` | Integer | `0*`; gültige Messquelle vor Regelstart. |
|
||||||
| `Netzleistungsfaktor` | Float | `1`; auf W und die vereinbarte Vorzeichenrichtung normieren. |
|
| `Netzleistungsfaktor` | Float | `1`; auf W und die vereinbarte Vorzeichenrichtung normieren. |
|
||||||
| `MesswertMaxAlter` | Integer | `30` s; auf echte Messaktualisierung bezogen. |
|
| `MesswertMaxAlter` | Integer | `60` s; auf echte Messaktualisierung bezogen. |
|
||||||
| `VerbraucherZuordnung` | String/JSON | `[]`; Instanz-ID und Aktiv je Verbraucher. Einzige gespeicherte Zuordnung. |
|
| `VerbraucherZuordnung` | String/JSON | `[]`; manuelle Auswahl aus Instanz-ID und Aktiv-Status. |
|
||||||
| `AutomatischeSuche` | Boolean | `true`; findet Kandidaten, aktiviert sie aber nicht automatisch. |
|
| `AutomatischeVerbraucherZuordnung` | String/JSON | `[]`; Auswahl aus automatisch gefundenen Verbrauchern. |
|
||||||
| `SuchbereichID` | Integer | `0`; optionaler Suchbereich. |
|
| `AutomatischeSuche` | Boolean | `true`; zeigt gefundene Verbraucher zur gezielten Auswahl. |
|
||||||
| `Regelintervall` | Integer | `2` s; zusätzlich auf relevante Änderungen reagieren. |
|
| `SuchbereichID` | Integer | `0`; optionaler Suchbereich für die automatische Suche. |
|
||||||
| `Vorgabeintervall` | Integer | `10` s; laufende Vorgaben erneuern. |
|
| `KeepAlive` | Integer | `60` s; erneuert laufende Vorgaben zyklisch. |
|
||||||
| `VerbraucherTimeout` | Integer | `30` s; ausgebliebene Meldung erkennen. |
|
| `VerbraucherTimeout` | Integer | `60` s; erkennt ausgebliebene Verbrauchermeldungen. |
|
||||||
| `Lastspitzenmodus` | Auswahl | `Aus`; alternativ `Konstant` oder `Monatlich`. |
|
| `Lastspitzenmodus` | Auswahl | `Aus`; alternativ `Konstant` oder `Monatlich`. |
|
||||||
| `Lastspitzengrenze` | Float | Feste Grenze in W für Modus `Konstant`. |
|
| `Lastspitzengrenze` | Float | Feste Grenze in W für Modus `Konstant`. |
|
||||||
| `Monatsgrenzen` | String/JSON | Zwölf Monatswerte in W. |
|
| `Monatsgrenzen` | String/JSON | Editierbare Liste mit zwölf Monatswerten in W. |
|
||||||
| `MonatsgrenzenVisuBedienbar` | Boolean | `false`; Monatstabelle in der Visualisierung bedienen. |
|
|
||||||
| `SollwertSolarladen` | Float | `0` W; gewünschte Netzleistung im Solarladebetrieb. |
|
| `SollwertSolarladen` | Float | `0` W; gewünschte Netzleistung im Solarladebetrieb. |
|
||||||
| `UmschaltschwelleUeberschuss` | Float | Feste W-Schwelle für PV-Betrieb. |
|
| `Umschaltdifferenz` | Float | `5` %; Mindestdifferenz der berechneten Sollleistungen vor Umschaltung. |
|
||||||
| `UmschaltschwelleLastspitze` | Float | Feste W-Schwelle für Peak-Betrieb. |
|
|
||||||
| `Umschaltdifferenz` | Float | `0` %; Mindestdifferenz der berechneten Sollleistungen vor Umschaltung. |
|
|
||||||
| `PrognoseAnschluss` | String/JSON | Optionaler Forecast-Anschluss. |
|
| `PrognoseAnschluss` | String/JSON | Optionaler Forecast-Anschluss. |
|
||||||
| `SDLAnschluss` | String/JSON | Optionaler SDL/VGT-Anschluss. |
|
| `SDLAnschluss` | String/JSON | Optionaler SDL/VGT-Anschluss. |
|
||||||
| `LizenzAnschluss` | String/JSON | Optionaler Lizenzanschluss. |
|
| `LizenzAnschluss` | String/JSON | Optionaler Lizenzanschluss. |
|
||||||
@@ -58,6 +55,9 @@ Ohne Logging sind nur `Aktiv`, `Betriebsart` und `Netzleistung` sichtbar.
|
|||||||
|
|
||||||
Es gibt keine Sollwertquellenauswahl und keine zweite Prioritätseinstellung im
|
Es gibt keine Sollwertquellenauswahl und keine zweite Prioritätseinstellung im
|
||||||
Manager. Im Modus `Aus` bleibt Solarladen aktiv, nur die Peak-Begrenzung entfällt.
|
Manager. Im Modus `Aus` bleibt Solarladen aktiv, nur die Peak-Begrenzung entfällt.
|
||||||
|
Die Monatsgrenzen werden in den Grundeinstellungen über eine Schaltfläche
|
||||||
|
ein- und ausgeblendet. Die vier optionalen oberen Anschlüsse besitzen jeweils
|
||||||
|
einen eigenen Bereich.
|
||||||
|
|
||||||
## Verteilalgorithmus
|
## Verteilalgorithmus
|
||||||
|
|
||||||
@@ -75,15 +75,15 @@ Bereiche werden direkt verarbeitet; Lücken werden nie durch unzulässige Werte
|
|||||||
geschlossen. Eine verbleibende Abweichung wird im `Verbraucherstatus`
|
geschlossen. Eine verbleibende Abweichung wird im `Verbraucherstatus`
|
||||||
dokumentiert.
|
dokumentiert.
|
||||||
|
|
||||||
Die Betriebsart wechselt unterhalb der Überschussschwelle zu `PV` und oberhalb
|
Die Betriebsart wechselt unterhalb des Solar-Sollwerts zu `PV` und oberhalb
|
||||||
der Lastspitzenschwelle zu `Peak`. Zwischen den Schwellen bleibt sie erhalten.
|
der wirksamen Lastspitzengrenze zu `Peak`. Zwischen den beiden Zielwerten
|
||||||
`Umschaltdifferenz` verhindert zusätzlich einen Wechsel, wenn sich die beiden
|
bleibt sie erhalten. `Umschaltdifferenz` verhindert zusätzlich einen Wechsel,
|
||||||
berechneten Korrekturen nicht ausreichend unterscheiden.
|
wenn sich die beiden berechneten Korrekturen nicht ausreichend unterscheiden.
|
||||||
|
|
||||||
## Laufzeit und Fehlerverhalten
|
## Laufzeit und Fehlerverhalten
|
||||||
|
|
||||||
- Netzleistungsänderungen und der Regel-Timer lösen die Berechnung aus.
|
- Netzleistungsänderungen und Verbrauchermeldungen lösen die Berechnung aus.
|
||||||
- Identische Sollwerte werden nur beim Vorgabeintervall erneut gesendet.
|
- Identische Sollwerte werden nur beim Keep-alive erneut gesendet.
|
||||||
- Verbraucherpakete werden zentral geprüft und nur von aktiv zugeordneten
|
- Verbraucherpakete werden zentral geprüft und nur von aktiv zugeordneten
|
||||||
Absendern angenommen.
|
Absendern angenommen.
|
||||||
- Veraltete oder noch fehlende Verbrauchermeldungen werden nicht verteilt und
|
- Veraltete oder noch fehlende Verbrauchermeldungen werden nicht verteilt und
|
||||||
|
|||||||
@@ -50,8 +50,6 @@ final class ManagerRegler
|
|||||||
float $netzleistung,
|
float $netzleistung,
|
||||||
string $bisherigeBetriebsart,
|
string $bisherigeBetriebsart,
|
||||||
bool $peakAktiv,
|
bool $peakAktiv,
|
||||||
float $umschaltschwelleUeberschuss,
|
|
||||||
float $umschaltschwelleLastspitze,
|
|
||||||
float $sollwertSolarladen,
|
float $sollwertSolarladen,
|
||||||
float $wirksameLastspitzengrenze,
|
float $wirksameLastspitzengrenze,
|
||||||
float $umschaltdifferenzProzent
|
float $umschaltdifferenzProzent
|
||||||
@@ -67,9 +65,9 @@ final class ManagerRegler
|
|||||||
}
|
}
|
||||||
|
|
||||||
$kandidat = $bisherigeBetriebsart;
|
$kandidat = $bisherigeBetriebsart;
|
||||||
if ($netzleistung < $umschaltschwelleUeberschuss) {
|
if ($netzleistung < $sollwertSolarladen) {
|
||||||
$kandidat = self::BETRIEBSART_PV;
|
$kandidat = self::BETRIEBSART_PV;
|
||||||
} elseif ($netzleistung > $umschaltschwelleLastspitze) {
|
} elseif ($netzleistung > $wirksameLastspitzengrenze) {
|
||||||
$kandidat = self::BETRIEBSART_PEAK;
|
$kandidat = self::BETRIEBSART_PEAK;
|
||||||
} elseif (!in_array($kandidat, [self::BETRIEBSART_PV, self::BETRIEBSART_PEAK], true)) {
|
} elseif (!in_array($kandidat, [self::BETRIEBSART_PV, self::BETRIEBSART_PEAK], true)) {
|
||||||
$kandidat = self::BETRIEBSART_PV;
|
$kandidat = self::BETRIEBSART_PV;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ trait VerbraucherBasisTrait
|
|||||||
$this->RegisterPropertyInteger('PrioritaetPV', 0);
|
$this->RegisterPropertyInteger('PrioritaetPV', 0);
|
||||||
$this->RegisterPropertyInteger('PrioritaetPeak', 0);
|
$this->RegisterPropertyInteger('PrioritaetPeak', 0);
|
||||||
$this->RegisterPropertyInteger('Meldeintervall', 10);
|
$this->RegisterPropertyInteger('Meldeintervall', 10);
|
||||||
$this->RegisterPropertyInteger('VorgabeTimeout', 30);
|
$this->RegisterPropertyInteger('VorgabeTimeout', 120);
|
||||||
$this->RegisterPropertyBoolean('EinstellungenInVisu', false);
|
$this->RegisterPropertyBoolean('EinstellungenInVisu', false);
|
||||||
$this->RegisterPropertyBoolean('LoggingEin', false);
|
$this->RegisterPropertyBoolean('LoggingEin', false);
|
||||||
|
|
||||||
|
|||||||
@@ -40,14 +40,46 @@ final class ManagerModulstrukturTest extends TestCase
|
|||||||
foreach ([
|
foreach ([
|
||||||
'NetzleistungVariableID',
|
'NetzleistungVariableID',
|
||||||
'VerbraucherZuordnung',
|
'VerbraucherZuordnung',
|
||||||
|
'AutomatischeVerbraucherZuordnung',
|
||||||
'Lastspitzenmodus',
|
'Lastspitzenmodus',
|
||||||
'Monatsgrenzen',
|
'Monatsgrenzen',
|
||||||
'SollwertSolarladen',
|
'SollwertSolarladen',
|
||||||
|
'KeepAlive',
|
||||||
|
'VerbraucherTimeout',
|
||||||
|
'MesswertMaxAlter',
|
||||||
'Umschaltdifferenz',
|
'Umschaltdifferenz',
|
||||||
'LoggingEin',
|
'LoggingEin',
|
||||||
] as $property) {
|
] as $property) {
|
||||||
self::assertStringContainsString($property, $json);
|
self::assertStringContainsString($property, $json);
|
||||||
}
|
}
|
||||||
|
foreach (['Regelintervall', 'Vorgabeintervall', 'UmschaltschwelleUeberschuss',
|
||||||
|
'UmschaltschwelleLastspitze', 'Optionale obere Anschluesse'] as $entfernt
|
||||||
|
) {
|
||||||
|
self::assertStringNotContainsString($entfernt, $json);
|
||||||
|
}
|
||||||
|
foreach (['Grundeinstellungen', 'Erweiterte Einstellungen', 'Prognose / Forecast',
|
||||||
|
'SDL / VGT', 'Lizenzierung', 'Stoerueberwachung'] as $bereich
|
||||||
|
) {
|
||||||
|
self::assertStringContainsString($bereich, $json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManagerVerwendetDieNeuenZeitdefaults(): void
|
||||||
|
{
|
||||||
|
$inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
|
||||||
|
|
||||||
|
self::assertStringContainsString("RegisterPropertyInteger('KeepAlive', 60)", $inhalt);
|
||||||
|
self::assertStringContainsString("RegisterPropertyInteger('VerbraucherTimeout', 60)", $inhalt);
|
||||||
|
self::assertStringContainsString("RegisterPropertyInteger('MesswertMaxAlter', 60)", $inhalt);
|
||||||
|
self::assertStringContainsString("RegisterPropertyFloat('Umschaltdifferenz', 5.0)", $inhalt);
|
||||||
|
self::assertStringNotContainsString("RegisterPropertyInteger('Regelintervall'", $inhalt);
|
||||||
|
self::assertStringNotContainsString("RegisterPropertyInteger('Vorgabeintervall'", $inhalt);
|
||||||
|
|
||||||
|
$verbraucherBasis = (string) file_get_contents(__DIR__ . '/../libs/VerbraucherBasisTrait.php');
|
||||||
|
self::assertStringContainsString(
|
||||||
|
"RegisterPropertyInteger('VorgabeTimeout', 120)",
|
||||||
|
$verbraucherBasis
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testManagerImplementiertDenGemeinsamenEmpfangsvertrag(): void
|
public function testManagerImplementiertDenGemeinsamenEmpfangsvertrag(): void
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ final class ManagerReglerTest extends TestCase
|
|||||||
25000.0,
|
25000.0,
|
||||||
ManagerRegler::BETRIEBSART_INAKTIV,
|
ManagerRegler::BETRIEBSART_INAKTIV,
|
||||||
false,
|
false,
|
||||||
-100.0,
|
|
||||||
10000.0,
|
|
||||||
0.0,
|
0.0,
|
||||||
15000.0,
|
15000.0,
|
||||||
0.0
|
0.0
|
||||||
@@ -30,7 +28,7 @@ final class ManagerReglerTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testBetriebsartBleibtZwischenDenSchwellenErhalten(): void
|
public function testBetriebsartBleibtZwischenDenZielwertenErhalten(): void
|
||||||
{
|
{
|
||||||
self::assertSame(
|
self::assertSame(
|
||||||
ManagerRegler::BETRIEBSART_PEAK,
|
ManagerRegler::BETRIEBSART_PEAK,
|
||||||
@@ -41,8 +39,6 @@ final class ManagerReglerTest extends TestCase
|
|||||||
ManagerRegler::BETRIEBSART_PEAK,
|
ManagerRegler::BETRIEBSART_PEAK,
|
||||||
true,
|
true,
|
||||||
0.0,
|
0.0,
|
||||||
10000.0,
|
|
||||||
0.0,
|
|
||||||
12000.0,
|
12000.0,
|
||||||
0.0
|
0.0
|
||||||
)
|
)
|
||||||
@@ -59,8 +55,6 @@ final class ManagerReglerTest extends TestCase
|
|||||||
11000.0,
|
11000.0,
|
||||||
ManagerRegler::BETRIEBSART_PV,
|
ManagerRegler::BETRIEBSART_PV,
|
||||||
true,
|
true,
|
||||||
0.0,
|
|
||||||
10000.0,
|
|
||||||
10000.0,
|
10000.0,
|
||||||
10500.0,
|
10500.0,
|
||||||
60.0
|
60.0
|
||||||
@@ -68,6 +62,40 @@ final class ManagerReglerTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testWechseltOberhalbDerPeakgrenzeInDenPeakbetrieb(): void
|
||||||
|
{
|
||||||
|
self::assertSame(
|
||||||
|
ManagerRegler::BETRIEBSART_PEAK,
|
||||||
|
ManagerRegler::bestimmeBetriebsart(
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
12500.0,
|
||||||
|
ManagerRegler::BETRIEBSART_PV,
|
||||||
|
true,
|
||||||
|
0.0,
|
||||||
|
12000.0,
|
||||||
|
5.0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWechseltUnterhalbDesSolarsollwertsInDenPvBetrieb(): void
|
||||||
|
{
|
||||||
|
self::assertSame(
|
||||||
|
ManagerRegler::BETRIEBSART_PV,
|
||||||
|
ManagerRegler::bestimmeBetriebsart(
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
-500.0,
|
||||||
|
ManagerRegler::BETRIEBSART_PEAK,
|
||||||
|
true,
|
||||||
|
0.0,
|
||||||
|
12000.0,
|
||||||
|
5.0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testVerteilungBeruecksichtigtPrioritaetEinzelwerteUndBereiche(): void
|
public function testVerteilungBeruecksichtigtPrioritaetEinzelwerteUndBereiche(): void
|
||||||
{
|
{
|
||||||
$ergebnis = ManagerRegler::verteile(
|
$ergebnis = ManagerRegler::verteile(
|
||||||
|
|||||||
Reference in New Issue
Block a user