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

Schreibe einen Kommentar

Avatar-Platzhalter

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert