Skip to content

Commit

Permalink
stateengine plugin: update, fix, simplify and extend documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
onkelandy committed Sep 8, 2023
1 parent 3860081 commit c8550c1
Show file tree
Hide file tree
Showing 13 changed files with 182 additions and 380 deletions.
10 changes: 2 additions & 8 deletions stateengine/user_doc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,5 @@ Das Webinterface bietet folgende Übersichtsinformationen:
:alt: Web Interface Overview
:align: center

Ein Klick auf das Lupensymbol in der Visu-Spalte öffnet die Detailansicht. Hier ist zu sehen, welcher Zustand eingenommen werden könnte, welcher aktiv ist und welche Aktionen bei welcher Bedingung ausgeführt werden.

.. image:: user_doc/assets/webif_stateengine_detail.png
:height: 1656px
:width: 3312px
:scale: 25%
:alt: Web Interface Detail
:align: center
Ein Klick auf das Lupensymbol in der Visu-Spalte öffnet die Detailansicht. Hier ist zu sehen, welcher Zustand eingenommen werden könnte, welcher aktiv ist und welche Aktionen bei welcher Bedingung ausgeführt werden. Ein Beispiel ist in der
Sektion zu finden.
10 changes: 9 additions & 1 deletion stateengine/user_doc/01_allgemein.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,23 @@ Webinterface
Über das Webinterface lässt sich auf einen Blick erkennen, welche State Engine sich
in welchem Zustand befindet. Zusätzlich ist es möglich, durch Klick auf einen Eintrag
die komplette State Engine visuell zu betrachten. Dabei ist folgende Farbkodierung zu beachten:

- grau: wurde nicht evaluiert (weil bereits ein höherrangiger Zustand eingenommen wurde)
- grün: aktueller Zustand / ausgeführte Aktion
- rot: Bedingungen nicht erfüllt

Innerhalb einer Bedingungsgruppe wird bei evaluierten Zuständen ein rotes X angezeigt,
wenn die Bedingung nicht wahr ist oder ein grünes Häkchen, falls die Bedingung erfüllt ist.

Bei den Aktionen sind die einzelnen Zeilen unter Umständen ebenfalls farbkodiert:

- schwarz: Aktion normal ausgeführt
- weiß: Aktion nicht ausgeführt, da Bedingungen nicht erfüllt
- grau: Aktion wird erst mit Verzögerung ausgeführt
- rot: Fehler in der Konfiguration

.. image:: assets/webinterface.png
Zudem wird hinter ausgeführten Aktionen ein grünes Häkchen angezeigt, hinter nicht ausgeführten
(weil beispielsweise Bedingungen nicht erfüllt sind) ein rotes X und hinter Problemen ein Warnsignal.

.. image:: assets/webif_stateengine_detail.png
:class: screenshot
3 changes: 2 additions & 1 deletion stateengine/user_doc/02_konfiguration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ Logging

Es gibt zwei Möglichkeiten, den Output des Plugins zu loggen:
**intern**
Hierbei werden, sofern das Loglevel 1 oder 2 beträgt, sämtliche Logeinträge in
Hierbei werden, sofern das Loglevel 1 oder mehr beträgt, sämtliche Logeinträge in
eigene Dateien in einem selbst definierten Verzeichnis geschrieben. Das Loglevel
kann sowohl global in der etc/plugin.yaml Datei deklariert, als auch individuell
pro Item mittels ``se_log_level`` (dort wo auch se_plugin: active steht) überschrieben werden.
Wird im Item nichts angegeben oder das Attribut mit dem Wert -1 angegeben, wird der Standardwert herangezogen.

**logging.yaml**
Sowohl der Output des Plugins generell, als auch der Einträge für bestimmte Items
Expand Down
67 changes: 47 additions & 20 deletions stateengine/user_doc/03_regelwerk.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,27 +49,31 @@ Diese Items müssen auf Ebene des Regelwerk-Items über das Attribut
``se_item_<Bedingungsname/Aktionsname>`` bekannt gemacht werden. Um einfacher zwischen Items,
die für Bedingungen und solchen, die für Aktionen genutzt werden, unterscheiden zu können,
können Items, die nur für Bedingungen gebraucht werden, mittels ``se_status_<Bedingungsname>``
deklariert werden. Diese Variante ist auch besonders dann relevant, wenn es zwei separate Items
für "Senden" und "Empfangen" gibt, also z.B. Senden der Jalousiehöhe und Empfangen des aktuellen
Werts vom KNX-Aktor.
deklariert werden.

Anstatt direkt das Item in Form des absoluten oder relativen Pfades zu setzen, kann auch ein
eval-Ausdruck mittels ``eval:<Ausdruck>`` angegeben werden.

Anstatt direkt das Item in Form des absoluten oder relativen Pfades mittels ``se_item_`` zu
setzen, kann auch die Angabe ``se_eval_`` genutzt werden. In diesem Fall wird eine beliebige
Funktion anstelle des Itemnamen angegeben. Dies ist primär für das Setzen von "dynamischen" Items
gedacht, allerdings ist es auch möglich, hier einen beliebigen Eval-Ausdruck als Bedingung festzulegen.
.. hint::

Aus Kompatibilitätsgründen kann für das Setzen "dynamischer" Items auch die Angabe ``se_eval_``
oder ``se_status_eval_`` genutzt werden. In diesem Fall wird eine beliebige
Funktion anstelle des Itemnamen angegeben, also beispielsweise
se_eval_height: se_eval.get_relative_item('..test'). Hierzu in den Kapiteln :ref:`Bedingungen`
und :ref:`Aktionen` mehr.


Beispiel se_item
================

Im Beispiel wird durch ``se_item_height`` das Item ``beispiel.raffstore1.hoehe``
dem Plugin unter dem Namen "height" bekannt gemacht. Das Item ``beispiel.wetterstation.helligkeit``
wird durch ``se_item_brightness`` (alternativ via ``se_status_brightness``) als "brightness" referenziert.
wird durch ``se_item_brightness`` als "brightness" referenziert.

Auf diese Namen beziehen sich nun in weiterer Folge Bedingungen und Aktionen. Im Beispiel
wird im Zustand Nacht das Item ``beispiel.raffstore1.hoehe`` auf den Wert 100 gesetzt, sobald
``beispiel.wetterstation.helligkeit`` den Wert 25 übersteigt. Erklärungen zu Bedingungen
und Aktionen folgen auf den nächsten Seiten.
``beispiel.wetterstation.helligkeit`` den Wert 25 übersteigt. Erklärungen zu Bedingungen und
Aktionen folgen auf den nächsten Seiten.

.. code-block:: yaml
Expand All @@ -91,18 +95,41 @@ und Aktionen folgen auf den nächsten Seiten.
enter_toodark:
se_max_brightness: 25
Beispiel se_status
==================

Wie erwähnt, können Items, die nur für Bedingungen genutzt werden, auch mittels se_status deklariert
werden. Diese Variante ist aber auch besonders dann relevant, wenn es zwei separate Items
für "Senden" und "Empfangen" gibt, also z.B. Senden der Jalousiehöhe und Empfangen des aktuellen
Werts vom KNX-Aktor.

Im Beispiel wird durch ``se_item_height`` das Item ``beispiel.raffstore1.hoehe`` (das den Befehl an den
KNX Aktor übermittelt) dem Plugin unter dem Namen "height" bekannt gemacht. ``se_status_height`` referenziert auf das
separate Status-Item (das vom KNX Aktor den Rückmeldestatus erhält) ``beispiel.raffstore1.hoehe.status``.
Dies ist aktuell insbesondere dann wichtig, wenn `se_mindelta_height`` genutzt wird (siehe :ref:`Aktionen`).

.. code-block:: yaml
raffstore1:
automatik:
struct: stateengine.general
rules:
se_item_height: beispiel.raffstore1.hoehe
se_status_height: beispiel.raffstore1.hoehe.status
se_mindelta_height: 10
Standard:
on_enter_or_stay:
se_action_height:
- 'function: set'
- 'to: 100'
Beispiel se_eval
================

se_eval ist für Sonderfälle und etwas komplexere Konfigurationen sinnvoll, kann aber
im ersten Durchlauf ignoriert werden. Es wird daher empfohlen, als Beginner
dieses Beispiel einfach zu überspringen ;)

Im Beispiel wird durch ``se_eval_brightness`` das Item für den Check von
Bedingungen bekannt gemacht. Aufgrund der angegebenen Funktion wird das Item
abhängig vom aktuellen Zustandsnamen eruiert. Da Zustand_Eins den Namen "sueden"
hat, wird somit auch der Wert von wetterstation.helligkeit_sueden abgefragt.
Würde der Zustand "osten" heißen, würde der Helligkeitswert vom Osten getestet werden.
Im Beispiel werden zwei Helligkeitswerte addiert und das Resultat durch 2 geteilt
(also der Mittelwert gebildet). Das Resultat wird dann mit dem Wert 5000 verglichen.

.. code-block:: yaml
Expand All @@ -122,7 +149,7 @@ Würde der Zustand "osten" heißen, würde der Helligkeitswert vom Osten geteste
automatik:
struct: stateengine.general
rules:
se_eval_brightness: se_eval.get_relative_itemvalue('wetterstation.helligkeit_{}'.format(se_eval.get_variable('current.state_name')))
se_eval_brightness: (se_eval.get_relative_itemvalue('wetterstation.helligkeit_sueden') + se_eval.get_relative_itemvalue('wetterstation.helligkeit_osten'))/2
Zustand_Eins:
name: sueden
Expand Down
64 changes: 49 additions & 15 deletions stateengine/user_doc/05_bedingungen.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,52 @@ die Helligkeit (über se_item_brightness oder se_status_brightness definiert) ü
enter:
se_min_brightness: 500
Name der Bedingung
------------------

Der Name einer Bedingung setzt sich aus folgenden drei Teilen zusammen,
die jeweils mit einem Unterstrich "_" getrennt werden:

- ``se_``: eindeutiger Prefix, um dem Plugin zugeordnet zu werden
- ``<Vergleichsfunktion>``: siehe unten. Beispiel: min = der Wert des <Bedingungsitems> muss mindestens dem beim Attribut angegebenen Wert entsprechen.
- ``<Vergleichsitem/Bedingungsname>``: Hier wird entweder das im Regelwerk-Item mittels ``se_item_<Name>`` oder ``se_status_<Name>`` deklarierte Item oder eine besondere Bedingung (siehe unten) referenziert.


Referenzieren von Items
-----------------------

Für jede "standardmäßige" Bedingung muss ein Item hinterlegt werden, das geprüft werden soll.
Dies geschieht in der Regel durch ``se_status_<Name>``, kann aber auch durch ``se_item_<Name>``
erfolgen, falls z.B. das gleiche Item für Bedingungen und Aktionen gebraucht wird.

Im Beispiel wird durch ``se_status_brightness`` das Item für den Check von
Bedingungen bekannt gemacht. Aufgrund der angegebenen eval-Funktion wird das Item
abhängig vom aktuellen Zustandsnamen eruiert. Da Zustand_Eins den Namen "sueden"
hat, wird somit der Wert von wetterstation.helligkeit_sueden abgefragt. Ist dieser
mehr als 499, ist die Bedingung erfüllt. Würde der Zustand "osten" heißen (Name von Zustand_Zwei),
würde der Helligkeitswert vom Osten getestet werden. Bedingung wäre dann erfüllt,
wenn die Helligkeit 1500 oder mehr beträge.

.. code-block:: yaml
#items/item.yaml
raffstore1:
automatik:
struct: stateengine.general
rules:
se_status_brightness: eval:se_eval.get_relative_itemvalue('wetterstation.helligkeit_{}'.format(se_eval.get_variable('current.state_name')))
Zustand_Eins:
name: sueden
enter:
se_min_brightness: 500
Zustand_Zwei:
name: osten
enter:
se_min_brightness: 1500
Bedingungsgruppen
-----------------

Expand Down Expand Up @@ -67,18 +113,6 @@ Der zu vergleichende Wert einer Bedingung kann auf folgende Arten definiert werd
des StateEngine Items eingesetzt werden kann. Angegeben durch ``template:<Name des Templates>``


Name der Bedingung
------------------

Der Name einer Bedingung setzt sich aus folgenden drei Teilen zusammen,
die jeweils mit einem Unterstrich "_" getrennt werden:

- ``se_``: eindeutiger Prefix, um dem Plugin zugeordnet zu werden
- ``<Vergleichsfunktion>``: siehe unten. Beispiel: min = der Wert des <Bedingungsitems> muss mindestens dem beim Attribut angegebenen Wert entsprechen.
- ``<Vergleichsitem/Bedingungsname>``: Hier wird entweder das im Regelwerk-Item mittels ``se_item_<Name>``
oder ``se_status_<Name>`` deklarierte Item oder eine besondere Bedingung (siehe unten) referenziert.


Templates für Bedingungsabfragen
--------------------------------

Expand Down Expand Up @@ -352,7 +386,7 @@ Freitag, 5 = Samstag, 6 = Sonntag
Der Azimut (Horizontalwinkel) ist die Kompassrichtung, in der die
Sonne steht. Der Azimut wird von smarthomeNg auf Basis der
aktuellen Zeit sowie der konfigurierten geographischen Position
berechnet. Siehe auch `Dokumentation <https://www.smarthomeng.de/user/logiken/objekteundmethoden_sonne_mond.html>`_
berechnet. Siehe auch `Dokumentation <https://www.smarthomeng.de/user/referenz/smarthomeng/methoden_sonne_mond.html>`_
für Voraussetzungen zur Berechnung der Sonnenposition.
Beispielwerte: 0 → Sonne exakt im Norden, 90 → Sonne exakt im
Osten, 180 → Sonne exakt im Süden, 270 → Sonne exakt im Westen
Expand All @@ -363,8 +397,8 @@ Osten, 180 → Sonne exakt im Süden, 270 → Sonne exakt im Westen
Die Altitude (Vertikalwikel) ist der Winkel, in dem die Sonne über
dem Horizont steht. Die Altitude wird von smarthomeNG auf Basis
der aktuellen Zeit sowie der konfigurierten geographischen
Position berechnet. Siehe auch `SmarthomeNG
Dokumentation <https://www.smarthomeng.de/user/logiken/objekteundmethoden_sonne_mond.html>`_
Position berechnet. Siehe ebenfalls `SmarthomeNG
Dokumentation <https://www.smarthomeng.de/user/referenz/smarthomeng/methoden_sonne_mond.html>`_
für Voraussetzungen zur Berechnung der Sonnenposition. Werte:
negativ → Sonne unterhalb des Horizonts, 0 →
Sonnenaufgang/Sonnenuntergang, 90 → Sonne exakt im Zenith
Expand Down
21 changes: 10 additions & 11 deletions stateengine/user_doc/06_aktionen.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ Aktionen
Es gibt zwei Möglichkeiten, Aktionen zu definieren. Die :ref:`Aktionen - einzeln`
Variante wird am Ende der Dokumentation der Vollständigkeit halber beschrieben.
Für einfache Aktionen ohne Angabe zusätzlicher Attribute wie delay, order, repeat, etc.
kann diese andere Möglichkeit der Aktionsangabe durchaus Sinn machen. Sie wurde
allerdings in der weiteren Pluginentwicklung nicht mehr getestet.
kann diese andere Möglichkeit der Aktionsangabe durchaus Sinn machen.

Bei der hier beschriebenen kombinierten Variante zur Definition von Aktionen werden
alle Parameter einer Aktion in einem Attribut definiert. Der Aktionsname ``se_action_<Bedingungsname/Aktionsname>``
Expand All @@ -29,7 +28,7 @@ das den Wert vom KNX-Aktor empfängt.

Außerdem ist es möglich, über ``se_repeat_actions`` generell zu definieren,
ob Aktionen für die Stateengine wiederholt ausgeführt werden sollen oder nicht. Diese Konfiguration
kann für einzelne Aktionen individuell über die Angabe ``repeat`` überschrieben werden. Siehe auch :ref:`Aktionen`.
kann für einzelne Aktionen individuell über die Angabe ``repeat`` überschrieben werden.

Beispiel zu Aktionen
--------------------
Expand Down Expand Up @@ -346,20 +345,20 @@ Die einzelnen Angaben einer Liste werden als ``OR`` evaluiert.

.. code-block:: yaml
screens:
conditionset_to_check:
type: str
value: "screens.osten_s1.automatik.rules.abend.enter_abend"
screens:
conditionset_to_check:
type: str
value: "screens.osten_s1.automatik.rules.abend.enter_abend"
conditionset:
- regex:enter_(.*)_test
- eval:sh.screens.conditionset_to_check.property.name
conditionset:
- regex:enter_(.*)_test
- eval:sh.screens.conditionset_to_check.property.name
Der gesamte Pfad könnte wie folgt evaluiert werden:

.. code-block:: yaml
"eval:se_eval.get_relative_itemid('{}.<bedingungsset>'.format(se_eval.get_relative_itemvalue('..state_id')))"
"eval:se_eval.get_relative_itemid('{}.<bedingungsset>'.format(se_eval.get_relative_itemvalue('..state_id')))"
Eine sinnvolle Anwendung hierfür wäre, anstelle von verschiedenen Zuständen mit
leicht anderen Bedingungen, alles in einen Zustand zu packen und anhand des Conditionsets
Expand Down
2 changes: 1 addition & 1 deletion stateengine/user_doc/07_zeitpunkt.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Die Konfiguration von instant_leaveaction bestimmt, ob on_leave Aktionen sofort
eines Zustands ausgeführt werden oder erst am Ende der Statusevaluierung.
Die Option kann sowohl in der globalen Pluginkonfiguration
mittels ``instant_leaveaction`` (boolscher Wert True oder False), als auch pro Item
mittels ``se_instant_leaveaction``festgelegt werden. Letzteres Attribut kann auch
mittels ``se_instant_leaveaction`` festgelegt werden. Letzteres Attribut kann auch
auf ein Item verweisen, dem der Wert -1 = Nutzen des Default Wertes, 0 = False,
1 = True zugewiesen werden kann. Im ``general struct`` sind bereits entsprechende
Einträge und Items angelegt (mit einem Wert von -1).
14 changes: 6 additions & 8 deletions stateengine/user_doc/08_beispiel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -390,14 +390,14 @@ Beim zweiten Durchlauf wird somit der Zustand Sonnenschutz aktiviert. Der Raffst

Let's play god. Ändern wir das Wetter ;) Entweder über das CLI, Visu oder Backend-Plugin oder Admin-Interface:

c) up beispiel.wetterstation.helligkeit=35000
c) beispiel.wetterstation.helligkeit=35000

- Die erste Bedingungsgruppe des Sonnenstandzustands ist nicht mehr "wahr", da die Helligkeit zu niedrig ist.
- Es wird ``enter_hysterese`` evaluiert. Da die Helligkeit noch über 25000 und die Sonnenposition gleich wie zuvor ist, ist diese Gruppe wahr.

Der Sonnenschutz bleibt somit aktiv, weil trotz der Helligkeitsverringerung der untere Schwellwert noch überschritten wurde. Der Raffstore bleibt unten.

d) up beispiel.wetterstation.helligkeit=15000
d) beispiel.wetterstation.helligkeit=15000

- Die ersten beiden Bedingungsgruppen sind unwahr, da die Helligkeit zu gering ist.
- Durch den Eintrag ``se_agemax_brightnessGt25k: 60`` in der Gruppe ``enter_delay`` wird 60 Sekunden gewartet.
Expand All @@ -411,13 +411,13 @@ e) Es erfolgt eine weitere Evaluierung des Automaten durch das cycle Attribut:

Der Zustand wird verlassen. Gibt es einen nachfolgenden Zustand, der eingenommen werden kann, ist dies der neue aktive Zustand. Gibt es keine Zustände, die aktiviert werden könnten, verbleibt die State Engine beim letzten aktiven Zustand, also beim Sonnenschutz. Im Beispiel gibt es noch einen Standard "Tag" Eintrag, wodurch der Raffstore hoch fährt.

f) up beispiel.raffstore1.aufab = 1
f) beispiel.raffstore1.aufab = 1

- Durch Triggern des "Manuell" Items wird die Zustandsevaluierung pausiert.

Sämtliche Änderungen der Helligkeit, Temperatur, etc. werden für die suspend_time ignoriert. Die Dauer ist im Template auf 60 Minuten festgelegt, kann aber manuell durch Ändern des entsprechenden Items geändert werden.

g) up beispiel.raffstore1.automatik.settings.suspendduration = 1
g) beispiel.raffstore1.automatik.settings.suspendduration = 1

- Die Suspendzeit wird auf eine Minute verkürzt.
- Beim erneuten Durchlauf ist die Suspendzeit abgelaufen, daher dieser Zustand nicht mehr aktiv.
Expand Down Expand Up @@ -639,7 +639,7 @@ Settings für Itemwerte
----------------------

Das Setup ist besonders flexibel, wenn zu setzende Werte nicht fix in den Zustandsvorgaben
definiert werden, sondern in eigenen Items, die dann jederzeit zur Laufzeit abänderbar
definiert werden, sondern in eigenen Items, die dann jederzeit zur Laufzeit änderbar
sind. Das folgende Beispiel zeigt eine Leuchte, die abhängig vom aktuell definierten
Lichtmodus (z.B. über die Visu) verschiedene Stati einnimmt und immer wieder dieselben
Änderungen vornimmt. Sollte eine Änderung nicht möglich sein, weil das entsprechende
Expand All @@ -649,8 +649,6 @@ Die Struct-Vorlagen sehen dabei folgendermaßen aus. Besonders ist der Eval Ausd
Dieser führt dazu, dass der zu setzende Wert aus dem Item ``automatik.settings.<STATUSNAME>.sollwert``
im aktuellen Item gelesen wird. Somit kann diese Vorlage für sämtliche Zustände 1:1 eingesetzt werden,
wobei natürlich zu beachten ist, dass sowohl "Settings" als auch Zustand richtig benannt sind.
Das Item state_name wird bis zur Pluginversion 1.5.0 erst nach Ausführen der Aktionen aktualisiert,
weshalb diese Vorgehensweise erst ab 1.5.1 empfohlen wird.

.. code-block:: yaml
Expand Down Expand Up @@ -758,7 +756,7 @@ Letzten Endes wird alles in einem item.yaml auf folgende Art und Weise implement
- licht_rules_heimkino
- licht_rules_lichtkurve
remark: Das eval_trigger muss vor SmarthomeNG 1.7 noch manuell mit der kompletten Liste überschrieben werden, auch wenn die Structs bereits Einträge enthalten. Ab 1.7 würde licht.modus* ausreichen!
remark: Das eval_trigger muss vor SmarthomeNG 1.7 noch manuell mit der kompletten Liste überschrieben werden, auch wenn die Structs bereits Einträge enthalten. Ab 1.7 würde merge_unique* und licht.modus* ausreichen!
eval_trigger:
- ..settings_edited
- ..lock
Expand Down
Loading

0 comments on commit c8550c1

Please sign in to comment.