2 Commits
Author SHA1 Message Date
dh d804ba4bc1 Manager-Lizenzierung dokumentieren
Tests / test (push) Successful in 45s
2026-09-22 07:07:29 +00:00
dh e7c546ff2d docs: README fuer Verbraucher 1-Stufig ergaenzen 2026-09-22 07:04:41 +00:00
4 changed files with 274 additions and 13 deletions
+1 -1
View File
@@ -62,7 +62,7 @@ der Uebernahme in einen Freigabebranch erfolgreich sein.
- [Zentrale Liste offener Teamentscheidungen](docs/Offene-Punkte.md)
- [Manager-Verbraucher-Schnittstelle](docs/Schnittstelle.md)
- [Manager-Modul](docs/module/Manager/README.md)
- [Manager-Modul inklusive Lizenzierung](docs/module/Manager/README.md)
- [Warmwassererwaermer-Modul](docs/module/Wassererwaermer/README.md)
- [Verbraucher-1-Stufig-Modul](docs/module/Verbraucher-1-Stufig/README.md)
- [Ladestation-Stand-Alone-Modul](docs/module/Ladestation-Stand-Alone/README.md)
+172
View File
@@ -0,0 +1,172 @@
# Verbraucher 1-Stufig
IP-Symcon-Modul fuer einen elektrischen Verbraucher, der genau zwei
Leistungszustaende kennt: aus (`0 W`) und ein (`Nennleistung`).
Das Modul ist fuer IP-Symcon ab Version 8.0 und den Enelix-Nachrichtenvertrag
`4.0` ausgelegt. Es arbeitet ereignisbasiert und besitzt weder einen
Regelzyklus noch eine konfigurierbare Zyklusanzahl oder Zykluszeit.
## Funktionen
- Schalten eines Boolean-Aktors auf `0 W` oder die konfigurierte Nennleistung
- optionale separate Schaltzustands-Rueckmeldung
- Mindest-Einschalt- und Mindest-Ausschaltdauer
- taegliche Mindestlaufzeit
- getrennte Prioritaeten fuer PV- und Peakbetrieb
- ereignisbasierte Zustandsmeldung an den Enelix Manager
- Diagnosevariablen und optionales Debug-Logging
- sichere lokale Deaktivierung ueber die Variable `Aktiv`
## Installation
1. Im IP-Symcon Module Control die Bibliothek
`https://git.belevo.ch/ENELIX/Enelix-EMS.git` installieren.
2. Fuer Entwicklung und Tests den Kanal beziehungsweise Branch `develop`
verwenden.
3. Unter **Instanz hinzufuegen** nach **Verbraucher 1-Stufig** suchen.
4. Eine Instanz anlegen und mindestens Nennleistung und Schaltkontakt
konfigurieren.
## Konfiguration
| Einstellung | Standard | Beschreibung |
| --- | ---: | --- |
| `PrioritaetPV` | `0` | Reihenfolge bei der PV-Leistungsverteilung. |
| `PrioritaetPeak` | `0` | Reihenfolge bei der Lastspitzenregelung. |
| `Meldeintervall` | `10 s` | Periodische Vollmeldung an zugeordnete Manager. |
| `VorgabeTimeout` | `120 s` | Gueltigkeitsdauer einer Manager-Vorgabe. |
| `Mindesteinschaltdauer` | `5 s` | Mindestdauer eines bestaetigten Ein-Zustands. |
| `Mindestausschaltdauer` | `5 s` | Mindestdauer eines bestaetigten Aus-Zustands. |
| `Nennleistung` | `0 W` | Leistungsaufnahme im eingeschalteten Zustand. |
| `SchaltkontaktVariableID` | `0` | Booleanvariable des zu schaltenden Aktors. |
| `SchaltkontaktInvertiert` | `false` | Invertiert die Aktorlogik. |
| `RueckmeldungVariableID` | `0` | Optionale Booleanvariable fuer den physischen Zustand. |
| `Mindestlaufzeit` | `0 s` | Geforderte Laufzeit pro lokalem Kalendertag. |
| `PeakSperreBeiMindestlaufzeitAnbieten` | `true` | Erlaubt im Peakbetrieb eine Sperre trotz faelliger Tagesmindestlaufzeit. |
| `DiagnosevariablenAnzeigen` | `false` | Blendet technische Diagnosevariablen ein. |
| `LoggingEin` | `false` | Aktiviert zusaetzliche Debug-Ausgaben. |
`Nennleistung` muss groesser als `0` sein. Der Schaltkontakt muss eine
Booleanvariable mit funktionsfaehiger Standard- oder benutzerdefinierter
Aktion sein. Beide Mindestzeiten duerfen auf `0` gesetzt werden.
Der fruehere allgemeine `Umschaltabstand` sowie Properties fuer Zyklusanzahl
und Zykluszeit existieren nicht.
## Verhalten ohne separate Rueckmeldung
Ist keine `RueckmeldungVariableID` konfiguriert, wird die Aktorvariable als
unmittelbare Schaltbestaetigung verwendet.
Nach einem erfolgreichen Schaltbefehl beginnt ab dem uebernommenen
Aktorzustand:
- beim Einschalten die `Mindesteinschaltdauer`,
- beim Ausschalten die `Mindestausschaltdauer`.
Uebernimmt die Aktorvariable den angeforderten Wert nicht, meldet das Modul
einen Schaltfehler und stellt sich dem Manager nicht als schaltbereit dar.
## Verhalten mit separater Rueckmeldung
Ist eine `RueckmeldungVariableID` konfiguriert, bestimmt ausschliesslich deren
Booleanwert den bestaetigten Schaltzustand. `true` muss dabei physisch
eingeschaltet bedeuten.
Zwischen Aktorbefehl und passender Rueckmeldung meldet das Modul:
- den bisherigen bestaetigten Schaltzustand und die bisherige Istleistung,
- `SchaltbefehlAusstehend=true`,
- `Schaltbereit=false`,
- `AenderungMoeglich=false`.
Die jeweilige Mindestzeit beginnt erst, sobald die Rueckmeldung den neuen
Zustand bestaetigt. Bleibt die Rueckmeldung aus, bleibt der Schaltbefehl
sichtbar ausstehend. Eine abweichende Rueckmeldung ohne laufenden
Schaltvorgang wird als Rueckmeldefehler gemeldet.
## Mindestzeiten und Leistungsangebot
Waerend einer Mindest-Ein- oder Mindest-Aus-Zeit bietet das Modul nur die
bestaetigte aktuelle Leistung an. Ein regulaerer Lastwechsel ist erst nach
Ablauf der Mindestzeit wieder moeglich.
Der Manager erhaelt dazu unter anderem:
| Zustand | Bedeutung |
| --- | --- |
| `Schaltzustand` | Bestaetigter Ein-/Aus-Zustand. |
| `SchaltbefehlAusstehend` | Aktorbefehl wartet auf physische Bestaetigung. |
| `Schaltbereit` | Ein weiterer regulaerer Lastwechsel ist moeglich. |
| `RestMindestzeit_s` | Verbleibende Mindestzeit in Sekunden. |
| `Tageslaufzeit_s` | Bestaetigte Laufzeit des aktuellen Tages. |
| `Rueckmeldefehler` | Aktor und Rueckmeldung widersprechen sich unerwartet. |
Die lokale Aktion `Aktiv=false` ist ein bewusster Sicherheits-Override. Sie
schaltet den Verbraucher auch waehrend einer laufenden
Mindesteinschaltdauer aus.
## Sichtbare Variablen
Immer vorhanden sind:
- `Aktiv`: lokale Freigabe fuer das Energiemanagement
- `Schaltzustand`: bestaetigter oder aus dem Aktor abgeleiteter Zustand
- `Tageslaufzeit`: bestaetigte Laufzeit des aktuellen Tages in Sekunden
Bei aktivierter Diagnose werden zusaetzlich Soll- und Istleistung,
Verfuegbarkeit, Schaltbereitschaft, Stoerung, Rueckmeldefehler,
ausstehender Schaltbefehl und verbleibende Mindestzeit angezeigt.
## Inbetriebnahme
1. Nennleistung und Schaltkontakt konfigurieren.
2. Falls vorhanden, die separate Rueckmeldung auswaehlen und ihre
`true`-Semantik pruefen.
3. Mindest-Ein- und Mindest-Ausschaltdauer passend zum angeschlossenen
Geraet festlegen.
4. Den Verbraucher im Enelix Manager manuell oder automatisch aktiv
zuordnen.
5. Fuer die Erstpruefung Diagnosevariablen und bei Bedarf Logging aktivieren.
6. Die Variable `Aktiv` einschalten.
7. Unter Aufsicht je eine Ein- und Aus-Vorgabe durch den Manager ausfuehren.
8. Kontrollieren, dass Rueckmeldung, Mindestzeiten und `Schaltbereit`
erwartungsgemaess wechseln.
## Fehlersuche
- **Konfiguration ungueltig:** Nennleistung, Variablentyp und Aktoraktion
pruefen.
- **Schaltbefehl bleibt ausstehend:** Separate Rueckmeldung und deren
`true`-Semantik pruefen.
- **Rueckmeldefehler:** Aktor- und Rueckmeldewert stimmen ausserhalb eines
laufenden Schaltvorgangs nicht ueberein.
- **Kein Lastwechsel moeglich:** `RestMindestzeit`, `Aktiv`,
`SollwertGueltig` und die Managerzuordnung kontrollieren.
- **Keine Manager-Vorgabe akzeptiert:** Der Verbraucher muss beim sendenden
Manager aktiv zugeordnet sein.
## Tests
Nur dieses Modul:
~~~bash
composer check:verbraucher-einstufig
~~~
Gesamtes Repository inklusive dieser Testsuite:
~~~bash
composer check
~~~
Die Modulsuite kann damit unabhaengig weiterentwickelt werden und bleibt
gleichzeitig Bestandteil des allgemeinen Tests.
## Weiterfuehrende Dokumentation
- [Ausfuehrliche Modulbeschreibung](../docs/module/Verbraucher-1-Stufig/README.md)
- [Manager-Verbraucher-Schnittstelle](../docs/Schnittstelle.md)
- [Migration von Enelix 1](../docs/migration/Verbraucher-1-Stufig.md)
- [Aufbau der separaten Testsuite](../tests/VerbraucherEinStufig/README.md)
+84 -6
View File
@@ -59,12 +59,90 @@ Manager. Im Modus `Aus` bleibt Solarladen aktiv, nur die Peak-Begrenzung entfäl
Die Monatsgrenzen werden in den Grundeinstellungen über eine Schaltfläche
ein- und ausgeblendet. Die automatische Verbrauchersuche kann dort erneut
ausgeführt werden, ohne andere ungespeicherte Formulareingaben zu verlieren.
Die Lizenzierung steht an erster Stelle des Formulars. Der Manager erzeugt dabei
einmalig eine UUIDv4 als stabile Installations-ID. Mit "Lizenz pruefen und binden"
wird der eingegebene Code ueber
`POST https://license.enelix.ch/api/v1/licenses/activate` an diese Installation
gebunden. Es werden weder Portal-Cookies noch ein CSRF-Token oder ein noch nicht
implementierter Lizenzendpunkt verwendet.
## Lizenzierung
Der Manager arbeitet nur mit einer gueltigen Manager-Lizenz. Das Lizenzfeld steht
zuoberst im Konfigurationsformular. Ohne Freigabe bleibt die Instanz mit Status
`203` inaktiv und sendet keine Leistungsvorgaben.
### Voraussetzungen
- Der Auftrag im Enelix-Lizenzportal ist bezahlt und enthaelt eine aktive
Manager-Berechtigung.
- IP-Symcon erreicht `https://license.enelix.ch` ueber HTTPS (Port 443).
- Der Lizenzcode liegt im Format `ENX-XXXX-XXXX-XXXX-XXXX` vor.
### Lizenz aktivieren
1. Manager-Konfiguration in IP-Symcon oeffnen.
2. Lizenzcode im Bereich `Lizenzierung` eintragen.
3. `Lizenz pruefen und binden` ausloesen.
4. Die erfolgreiche Freigabe am angezeigten Lizenzstatus kontrollieren.
5. Die Manager-Konfiguration mit `Uebernehmen` beziehungsweise `OK` speichern,
damit der eingegebene Lizenzcode als Property erhalten bleibt.
Beim ersten Anlegen erzeugt die Manager-Instanz eine UUIDv4 als stabile
Installations-ID. Die Aktivierung sendet ausschliesslich `code` und
`installationId` per
`POST https://license.enelix.ch/api/v1/licenses/activate`. Sie benoetigt weder
Portal-Cookies noch einen CSRF-Token. Derselbe Code kann von derselben
Installation erneut abgerufen werden; die Bindung an eine andere Installation
wird vom Lizenzserver abgelehnt.
### Berechtigungen
| Berechtigung | Freigegebene Funktion |
| --- | --- |
| `manager_standard` | Manager-Grundregelung ohne Lastspitzenmodus. |
| `manager_peak` | Manager-Grundregelung einschliesslich konstantem oder monatlichem Lastspitzenmodus. |
Wird mit `manager_standard` ein Lastspitzenmodus aktiviert, bleibt der Manager
mit dem Hinweis `Peak Shaving ist nicht lizenziert` gesperrt. `manager_peak`
gilt zugleich als Berechtigung fuer die Grundregelung.
### Erneuerung und Offline-Betrieb
Die erfolgreiche Serverantwort wird als Lease in der Manager-Instanz gespeichert.
Der Manager erneuert sie ab `refreshAfter` automatisch ueber denselben
Aktivierungsendpunkt. Schlaegt eine Erneuerung fehl, wird fruehestens nach einer
Stunde erneut angefragt. Eine bereits bestaetigte Entwicklungsfreigabe bleibt
bis `offlineUntil` verwendbar. Der aktuelle Entwicklungsvertrag setzt diesen
Zeitpunkt ungefaehr 14 Tage nach Ausstellung. Danach sperrt der Manager die
Regelung, bis der Lizenzserver wieder eine gueltige Antwort liefert.
Die Installations-ID und die Lease liegen in internen Instanzattributen. Bei
einer Migration muss deshalb die vollstaendige Manager-Instanz mitsamt ihren
Attributen uebernommen werden. Eine neu erzeugte Instanz erhaelt eine andere
Installations-ID und kann einen bereits gebundenen Code nicht selbststaendig
uebertragen.
### Status und Fehlerbehebung
| Anzeige / Serverstatus | Bedeutung und Massnahme |
| --- | --- |
| `Lizenzcode fehlt.` | Code eintragen, pruefen und die Konfiguration speichern. |
| `Lizenzcode ist ungueltig.` | Format und Zeichen des Codes kontrollieren. |
| HTTP `404` | Code unbekannt oder zugehoeriger Auftrag noch nicht bezahlt. |
| HTTP `409` | Code ist bereits an eine andere Installation gebunden. |
| HTTP `429` | Zu viele Aktivierungsversuche; vor dem naechsten Versuch warten. |
| `Lizenzserver nicht erreichbar` | DNS, Internetzugang, HTTPS und Systemzeit des Symcon-Systems pruefen. Eine bestehende Lease gilt nur bis `offlineUntil`. |
| `Offline-Freigabe ist abgelaufen.` | Verbindung zum Lizenzserver wiederherstellen und Lizenz erneut pruefen. |
Fuer eine genauere Diagnose koennen die Diagnosevariablen eingeblendet werden.
`Lizenzstatus` zeigt dann den aktuellen Zustand. Mit aktiviertem Debug-Logging
werden Fehlermeldungen der Lizenzpruefung ausgegeben, niemals jedoch der
Lizenzcode selbst.
### Datenschutz und Entwicklungsstand
Der Lizenzcode wird als Manager-Property in der IP-Symcon-Konfiguration
gespeichert. Fuer den internen Abgleich mit der Lease verwendet der Manager
zusaetzlich nur einen SHA-256-Hash und schreibt den Code nicht ins Debug-Log.
Die aktuelle Serverantwort ist ein Entwicklungsvertrag mit
`development: true` und noch nicht kryptografisch signiert. Ein optionaler
Geraete-Public-Key sowie Challenge-, Heartbeat- oder separate
Entitlement-Endpunkte werden vom Manager derzeit bewusst nicht verwendet.
## Verteilalgorithmus
+17 -6
View File
@@ -43,7 +43,7 @@ final class DokumentationsstrukturTest extends TestCase
{
$inhalt = file_get_contents(__DIR__ . '/../docs/module/Ladestation-Stand-Alone/README.md');
self::assertNotFalse($inhalt);
self::assertStringContainsString('Status: Implementiert', $inhalt);
self::assertStringContainsStringIgnoringCase('Status: implementiert', $inhalt);
self::assertStringContainsString('Properties', $inhalt);
self::assertStringContainsString('Fake-HTTP-Transport', $inhalt);
}
@@ -65,11 +65,22 @@ final class DokumentationsstrukturTest extends TestCase
public function testVerbraucherEinStufigDokumentiertDenImplementiertenStand(): void
{
$inhalt = file_get_contents(__DIR__ . '/../docs/module/Verbraucher-1-Stufig/README.md');
self::assertNotFalse($inhalt);
self::assertStringContainsString('Status: implementiert', $inhalt);
self::assertStringContainsString('Umschaltabstand', $inhalt);
self::assertStringContainsString('Installation und Inbetriebnahme', $inhalt);
$detailInhalt = file_get_contents(
__DIR__ . '/../docs/module/Verbraucher-1-Stufig/README.md'
);
self::assertNotFalse($detailInhalt);
self::assertStringContainsString('Status: implementiert', $detailInhalt);
self::assertStringContainsString('Umschaltabstand', $detailInhalt);
self::assertStringContainsString('Installation und Inbetriebnahme', $detailInhalt);
$modulInhalt = file_get_contents(__DIR__ . '/../VerbraucherEinStufig/README.md');
self::assertNotFalse($modulInhalt);
self::assertStringContainsString('Verhalten ohne separate Rueckmeldung', $modulInhalt);
self::assertStringContainsString('Mindesteinschaltdauer', $modulInhalt);
self::assertStringContainsString(
'composer check:verbraucher-einstufig',
$modulInhalt
);
}
public function testWarmwassererwaermerDokumentiertDenImplementiertenStand(): void