Hinweis: Die hier beschriebene Funktion ist erst ab SmartHomeNG 1.6 verfügbar.
Structs aus Plugins
Die „struct“ Vorlagen ermöglichen es zum einen, vorgegebene Item-Strukturen aus Plugins zu integrieren, zum anderen aber auch, eigene Vorlagen für immer wiederkehrende Item-Bäume bereitzustellen.
Bei gleichen Gerätetypen ist die Struktur oft sehr ähnlich, was zu sehr vielen gleich aufgebauten Item-Definitionen führt. Leuchten, Jalousien, Bewegungsmelder können dabei ähnlich leicht vereinfacht werden wie Sollwerte, Vorgaben für Zustände des stateengine Plugins und vieles mehr. Zuerst ein Beispiel, wie mit nur einer Zeile ein Zeitschalt-Unteritem aus dem UZSU Plugin eingefügt werden kann. Da diese Vorlage bereits mit dem Plugin mitgeliefert wird, ist nichts weiter zu tun, also mittels struct Attribug darauf zuzugreifen. Welche Vorlagen von welchen Plugins bereitgestellt werden, ist zum einen in den jeweiligen plugin.yaml Dateien, zum anderen im Admin Tool einzusehen.
# item.yaml
item:
struct: uzsu.child
Durch diese Angabe entsteht beim Start von SmartHomeNG folgende Struktur, die zuvor noch bei jedem Item, das die Zeitschaltuhr nutzt, manuell angegeben werden musste:
# item.yaml
item:
uzsu:
type: dict
uzsu_item: ..
cache: True
visu_acl: rw
active:
type: bool
eval: sh...activate(value)
visu_acl: rw
Eigene Vorlagen
Folgendes Beispiel zeigt, wie Vorlagen selbst in der Datei etc/struct.yaml hinterlegt werden können. Generell bedarf es keinerlei besonderer Syntax. Strukturen werden dort genauso angelegt wie normale Item-Bäume. Die jeweils oberste Hierarchieebene definiert den Namen der Vorlage. Und genau auf dieses Item wird dann in der eigentlichen item.yaml Datei durch das Attribut struct verwiesen. Zuerst der Inhalt der struct.yaml für ein dimmbares Licht mit einigen Zusatzfunktionen:
# struct.yaml
dimmervorlage:
name: Vorlage für dimmbare Leuchten
knx_dpt: 1
visu_acl: rw
type: bool
knx_send: 0/0/0
knx_cache: 0/0/0
bwm:
knx_dpt: 1
visu_acl: rw
type: bool
zwangvalue:
knx_dpt: 5001
visu_acl: rw
type: num
cache: True
zwangsstellung:
knx_dpt: 2
visu_acl: rw
type: list
enforce_updates: yes
dimmen:
knx_dpt: 5001
visu_acl: rw
type: num
database: yes
influxdb: yes
sim: track
sollwert:
knx_dpt: 5001
visu_acl: rw
type: num
enforce_updates: yes
cache: True
Und hier die Einbindung in die yaml Datei im items Verzeichnis für ein Licht mit separaten warm- und kaltweißen Leuchtmitteln:
# item.yaml
licht1:
warm:
struct: dimmervorlage
knx_send: 3/0/21
knx_cache: 3/0/27
bwm:
knx_send: 3/3/67
knx_cache: 3/3/67
zwangvalue:
zwangsstellung:
knx_send: 3/0/50
knx_cache: 3/0/50
dimmen:
knx_send: 3/0/23
knx_cache: 3/0/28
sollwert:
knx_send: 3/3/53
kalt:
struct: dimmervorlage
knx_send: 3/0/24
knx_cache: 3/0/29
bwm:
knx_send: 3/3/68
knx_cache: 3/3/68
zwangvalue:
zwangsstellung:
knx_send: 3/0/51
knx_cache: 3/0/51
dimmen:
knx_send: 3/0/26
knx_cache: 3/0/30
sollwert:
knx_send: 3/3/54
Was passiert hier? Es wird jeweils zuerst die Vorlage geladen, in der die Grundinformationen zu den Items verankert ist. Also Infos zu Typ, Cache, KNX DPT, Visu, Datenbank, etc. Diese Vorlage wird nun im tatsächlichen Item nur noch durch die KNX Adressen ergänzt. Etwaige gleich benannte Attribute werden dabei überschrieben (im Beispiel knx_send: 0/0/0).
In der Version 1.6.0 ist zu beachten, dass auch tatsächlich alle bereits definierten Attribute überschrieben werden, also beispielsweise auch Listeneinträge für eval_trigger. Möchte man also verschiedene Vorlagen mit verschiedenen eval_trigger Einträgen miteinander kombinieren, muss das Attribut nach den struct Einträgen manuell mit allen gewünschten Listeneinträgen überschrieben werden.
Zum Abschluss noch ein weiteres Beispiel, das neben einer klassischen Schaltfunktion für das entsprechende Item auch die Einschaltdauer über die Datenbankeinträge evaluiert. Dank relativer Item-Angaben können somit komplexere Konfigurationsblöcke problemlos wiederverwendet werden. Zum einen erleichtert dieser Ansatz ein Aktualisieren und Erweitern von Itemconfigs ungemein, zum anderen bleibt in den yaml Files die Übersicht bewahrt (auch wenn Letzteres Dank Admin Tool zukünftig weniger Relevanz haben wird). Folgend zwei separate Vorlagen:
#struct.yaml
schaltervorlage:
name: einfache Vorlage für Schalter
sa:
knx_dpt: 1
visu_acl: rw
type: bool
database: yes
cache: yes
sperren:
knx_dpt: 1
visu_acl: rw
type: bool
laufzeitvorlage:
name: Vorlage für Laufzeitmessung
laufzeit_1w:
type: num
visu_acl: ro
crontab: init
eval: (sh...sa.db('on', '1w') or 0) * 10080
eval_trigger:
- ..sa
laufzeit_24h:
type: num
visu_acl: ro
crontab: init
eval: (sh...sa.db('on', '24h') or 0) * 1440
eval_trigger:
- ..sa
Die tatsächlichen Items benötigen schließlich wieder nur eine Angabe der KNX Adressen, alle anderen Funktionalitäten und Definition werden über die Vorlage eingebunden:
#item.yaml
schalter1:
struct: schaltervorlage
sa:
knx_send: 1/1/1
sperren:
knx_send: 1/1/2
schalter2:
struct:
- schaltervorlage
- laufzeitvorlage
sa:
knx_send: 1/1/3
sperren:
knx_send: 1/1/4
laufzeit_1w:
eval_trigger:
- ..sa
- ..sperren
schalter3:
struct: schaltervorlage
laufzeit:
struct: laufzeitvorlage
Schalter1 greift ledigilich auf eine Vorlage (schaltervorlage) zurück, während Schalter2 mehrere Vorlagen als Liste miteinander kombiniert. Für Schalter2 existieren also auch die Einträge laufzeit_1w und laufzeit_24h, die eben die Einschaltdauer während der letzten Woche bzw. 24 Stunden von der Datenbank auslesen. Die Triggerung der laufzeit_1w soll in diesem Fall auch vom Sperritem erfolgen, während dies bei Schalter3 lediglich durch das in der Vorlage angegebene Schaltitem geschieht. Da Schalter3 keine Angaben zu den KNX Gruppenadressen macht, handelt es sich hier auch nicht um einen KNX Schalter, sondern z.B. ein Item, das nur über eine Logik oder die Visu geschalten werden kann/soll. Das schalter3 Beispiel zeigt auch, dass die Structs auf jeder beliebigen Hierarchieebene eingebunden werden können.
Limitierungen
Aktuell (inkl. Version 1.9) ist es nicht möglich, structs beliebig zu verschachteln. Das Einbeziehen von anderen structs in einem selbst kreierten struct ist nur auf Rootebene möglich, also beispielsweise so:
# struct.yaml
beispielstruct1:
test1:
type: bool
initial_value: True
beispielstruct2:
test2:
type: bool
initial_value: False
combinedstruct:
struct:
- beispielstruct1
- beispielstruct2
Debugging
Im Admin Interface sind alle structs, sowohl die von den aktiven Plugins als auch die selbst erstellten einsehbar. Hier lässt sich somit auch prüfen, wie die Structs miteinander kombiniert wurden. Ob und wie der Merge mit Attributen aus den Items geklappt hat, lässt sich am besten im Item Baum nachvollziehen.
8 Kommentare
gama · 29. Juli 2019 um 19:07
Im ersten Beispiel ist ein Fehler: „-struct: uzsu.child“ sollte ohne „-“ nur „struct: uzsu.child“ lauten.
Martin Sinn · 18. Juni 2019 um 5:24
Wie im Log steht, ist die Ausgabe in etc/structs_joined.yaml temporär (zum testen). Die Datei wir mit dem nächsten Release verschwinden. Das Ergebnis ist am besten im admin Interface zu besichtigen.
Haiphong · 18. Juni 2019 um 1:46
Hallo Andy,
schreib doch noch dazu, daß das Ergebis in der Datei „etc/structs_joined.yaml“ zu finden ist
Hendrik (henfri) · 15. Juni 2019 um 13:18
Danke für die Implementierung und danke für den Beitrag!
onkelandy · 31. Mai 2019 um 11:59
Hab das Schalter Beispiel so aktualisiert, damit klar ist, dass die structs in jeder Hierarchieebene eingesetzt werden können. Verschachtelte structs gibt es wie Martin schrieb aktuell noch nicht – sollte dann aber ermöglichen, Vorlagen innerhalb von Vorlagen zu nutzen.
Martin Sinn · 31. Mai 2019 um 11:51
Das sollte in den item Definitionen bereits gehen. – Oder möchtest Du rollladen in der struct fenstervorlage definieren? Solche „nested structs“ gehen noch nicht. Dazu gibt es aber auf github in den issues bereits eine Diskussion.
gama · 31. Mai 2019 um 11:12
Irgendwie hat er die Formatierung nicht übernommen – also rolladen ist ein item unterhalb von fenster.
gama · 31. Mai 2019 um 11:11
Toller Beitrag. Vielleicht wäre eine Ergänzung auf mehrstufige structs hilfreich, z.B.
fenster:
struct: fenstervorlage
rolladen:
struct: rolladenvorlage