Fibaro LUA Grundlagen

If-Then-Else Bedingungen

Die ersten eigenen Szenen werden sich darauf beschränken Geräte ein- und auszuschalten. Das ist auch gut so, jedoch gelangt man schnell an den Punkt Aktionen in Abhängigkeit von Bedingungen realisieren zu wollen. Beispielsweise ist es wenig sinnvoll das Licht einzuschalten während die Sonne Dich blendet. Um in einer Szene auf Entscheidungen basierend reagieren gibt das If-then-else (Wenn-Dann-Sonst) Konstrukt.

Neben wir an, das Licht im Badezimmer soll nur eingeschaltet werden, wenn die Helligkeit (Lux) im Raum unter 100 Lux ist. Diese Bedingung wird mit If-Then-Else abgebildet:

luxID = 58
switchID = 96
luxValue = tonumber(fibaro:getValue(luxID, "value"))

if luxValue < 100 then
 fibaro:call(switchID, "turnOn")
 fibaro:debug("Licht eingeschaltet")
else
 fibaro:debug("Es ist hell genug")
end

Zuerst werden die IDs der beteiligten Geräte in Variablen geschrieben. Hier luxID und switchID. In die Variable luxValue wird der aktuelle Helligkeitswert des Fibaro Motion Sensors geschrieben. Wie weiter oben beschrieben stehen uns diese Werte damit an jeder Stelle der Szene zur Verfügung.

In Zeile 5 nun die Bedingung. Intern ist das Ergebnis der Prüfung (Lux Wert kleiner 100) immer ein boolescher Wert, also true oder false. Ist der Lux Wert kleiner 100 ist die Bedingung erfüllt (also true). Das Licht wird eingeschaltet und die Meldung „Licht eingeschaltet“ ausgegeben. Ist zum Zeitpunkt der Prüfung Lux größer als 100, wird die Bedingung nicht erfüllt (also false) und es wird nur die Meldung „Er ist hell genug“ ausgegeben.

If-then-else Bedingungen beinhalten also immer (mindestens) eine Prüfung deren Ergebnis true oder false ist. Das Ergebnis dieser entscheidet dann den weiteren Ablauf der Szene. Für die Bedingungen können alle Vergleichsoperatoren (siehe oben) genutzt werden.

Beispiele:

if  a == b  then fibaro:debug('a ist gleich b')              else fibaro:debug('a ist nicht gleich b') end
if  a ~= b  then fibaro:debug('a ist nicht gleich b')        else fibaro:debug('a ist gleich b') end 
if  a < b   then fibaro:debug('a ist kleiner b')             else fibaro:debug('a ist nicht kleiner b') end 
if  a <= b  then fibaro:debug('a ist kleiner oder gleich b') else fibaro:debug('a ist nicht kleiner oder gleich b') end 
if  a > b   then fibaro:debug('a ist größer b')              else fibaro:debug('a ist nicht größer b') end 
if  a >= b  then fibaro:debug('a ist größer oder gleich b')  else fibaro:debug('a ist nicht größer oder gleich b') end

Weitere Prüfungen

Es gibt noch weitere Möglichkeiten Bedingungen einzusetzen. So lassen sich Bedingungen verknüpfen, verschachteln und auch ein If-Then-Elseif-Konstrukt erstellen.

Verknüpfte Bedingungen

Manchmal reicht eine Bedingung nicht aus. Wenn beispielsweise ein zweiter Lux-Sensor in die Prüfung einbezogen werden soll müssen Bedingungen miteinander verknüpft werden.

luxID1 = 58
luxID2 = 127
luxValue1 = tonumber(fibaro:getValue(luxID1, "value"))
luxValue1 = tonumber(fibaro:getValue(luxID2, "value"))

if luxValue1 < 100 and luxValue2 < 100 then
 fibaro:call(switchID, "turnOn")
 fibaro:debug("Licht eingeschaltet")
else
 fibaro:debug("Es ist hell genug")
end

Beide Lux Wert werden mit der Verknüpfung and verknüpft und geprüft. Die Bedingung ist also nur wahr, wenn beide Lux Werte kleiner 100 sind. Neben der and können Bedingungen auch mit or verknüpft werden und das Licht eingeschaltet werden, wenn einer der beiden Sensoren einen Wert kleiner 100 liefert.

luxID1 = 58
luxID2 = 127
luxValue1 = tonumber(fibaro:getValue(luxID1, "value"))
luxValue1 = tonumber(fibaro:getValue(luxID2, "value"))

if luxValue1 < 100 or luxValue2 < 100 then
 fibaro:call(switchID, "turnOn")
 fibaro:debug("Licht eingeschaltet")
else
 fibaro:debug("Es ist hell genug")
end

Verschachtelungen

Nicht immer reicht eine Bedingung aus um das gewünschte Ergebnis zu erreichen. In unserem Badezimmer könnte es ja sein, dass das Licht nicht eingeschaltet werden muss, da es bereits eingeschaltet ist. Für derartige Fälle kann man If-Bedingungen verschachteln.

luxID1 = 58
luxID2 = 127
switchID = 96
luxValue1 = tonumber(fibaro:getValue(luxID1, "value"))
luxValue1 = tonumber(fibaro:getValue(luxID2, "value"))
switchState = tonumber(fibaro:getValue(switchID, "value"))

if switchState == 0 then
	if luxValue1 < 100 or luxValue2 < 100 then
		fibaro:call(switchID, "turnOn")
		fibaro:debug("Licht eingeschaltet")
	else
		fibaro:debug("Es ist hell genug")
	end
else
	fibaro:debug('Das Licht ist bereits eingeschaltet')
end

If-Then-Elseif-Else

Die Prüfung mehrerer Bedingungen lässt sich weiterhin mit If-Then-Elseif Bedingungen abfragen. Angenommen das Badezimmer verfügt über eine zweite Lampe. Diese soll eingeschaltet werden, wenn es trotz eingeschalteter erster Lampe nicht hell genug im Bad ist.

luxID1 = 58
luxID2 = 127
switchID1 = 96
switchID1 = 178
luxValue1 = tonumber(fibaro:getValue(luxID1, "value"))
luxValue1 = tonumber(fibaro:getValue(luxID2, "value"))
switchState1 = tonumber(fibaro:getValue(switchID1, "value"))
switchState2 = tonumber(fibaro:getValue(switchID2, "value"))

if switchState1 == 0 then
	if luxValue1 < 100 or luxValue2 < 100 then
		fibaro:call(switchID1, "turnOn")
		fibaro:debug("Licht 1 eingeschaltet")
	else
		fibaro:debug("Es ist hell genug")
	end
elseif switchState1 == 1 then
	if luxValue1 < 200 or luxValue2 < 200 then
		fibaro:call(switchID2, "turnOn")
		fibaro:debug("Nicht hell genug, zweite Lampe zusätzlich eingeschaltet")
	else
		fibaro:debug("Es ist hell genug, die zweite Lampe bleibt aus")
	end
end

Boolesche Variable

Zu guter Letzt lassen sich auch boolesche Variablen als Bedingung verwenden. Hier ist jedoch Vorsicht geboten.

if (a) then fibaro:debug('a ist true') else fibaro:debug('a ist nicht true') end

Wenn die Variable a den Wert true hat, ist diese einfache Bedingung wahr und es wir „a ist true“ ausgegeben. Wobei dies nur die halbe Wahrheit ist. Die oben erwähnte Einfachheit der Definition von Variablen zwingt uns hier aufmerksam zu sein. Die Variable a kann per Definition jeden Wert enthalten. Also Text, eine Zahl oder eben true/false. Die hier dargestellte Prüfung ist immer wahr, solange a definiert ist, also irgendeinen Wert enthält.

Schleifen

Es gibt zwei unterschiedliche Arten von Schleifen in LUA. Die while- und die for-Schleife.

while-Schleifen

Eine while-Schleife wiederholt eine Anweisung solange bis eine definierte Bedingung erfüllt ist. Im folgenden Beispiel wird für jeden Durchlauf der Schleife ein Wert ausgegeben und anschließend eine 1 addiert.

a = 1

while a < 10 do
	fibaro:debug(a)
	a = a + 1
end

Ausgabe der Schleife

[DEBUG] 11:49:00: 1
[DEBUG] 11:49:00: 2
[DEBUG] 11:49:00: 3
[DEBUG] 11:49:00: 4
[DEBUG] 11:49:00: 5
[DEBUG] 11:49:00: 6
[DEBUG] 11:49:00: 7
[DEBUG] 11:49:00: 8
[DEBUG] 11:49:00: 9

a wird also hochgezählt und ausgegeben solange a kleiner als 10 ist.

Der Einsatz derartiger Schleifen ist sinnvoll, wenn Aktionen (hier a) solange ausgeführt werden sollen bis eine Bedingung erfüllt ist. Ein kleines Beispiel:

switchID1 = 96

while tonumber(fibaro:getValue(switchID1, "value")) == 1 do
	fibaro:debug('Die Lampe 1 im Badezimmer ist eingeschaltet')
	fibaro:sleep(60*1000)
end

Diese Schleife gibt einmal die Sekunde den Text „Die Lampe 1 im Badezimmer ist eingeschaltet“ aus, bis die Bedingung nicht mehr wahr ist. Also die Lampe ausgeschaltet wurde.

for-Schleife

In Fibaro Szenen weitaus häufiger verwendet wird die for-Schleife. Im Gegensatz zur while-Schleife ist hier vorher bekannt, wie viele Durchläufe stattfinden.

for a = 1, 10 do
	fibaro:debug(a)
end

Ausgabe der Schleife

[DEBUG] 11:59:39: 1
[DEBUG] 11:59:39: 2
[DEBUG] 11:59:39: 3
[DEBUG] 11:59:39: 4
[DEBUG] 11:59:39: 5
[DEBUG] 11:59:39: 6
[DEBUG] 11:59:39: 7
[DEBUG] 11:59:39: 8
[DEBUG] 11:59:39: 9
[DEBUG] 11:59:39: 10

for-Schleifen benötigen 2 (+ 1 optionalen) Parameter bzw. Variablen um zu funktionieren.

  • Startwert: a = 1
  • Zielwert: 10
  • (Optional: Inkrement)

Beim ersten Durchlauf der Schleife ist a = 1, beim zweiten ist a = 2, usw. Diese Variable – auch Index genannt – steht innerhalb der for-Schleife zur Verfügung und dient unter Anderem dem Zugriff auf dem Inhalt von Tables.
Der dritte Parameter bestimmt den zur Startvariable zu addierenden Wert. Wird er nicht angegeben ist er stets 1 was in Szenen meist der Fall ist.

Zum Einsatz kommen for-Schleifen wenn wiederkehrende Aktionen für eine definierte Anzahl Objekte bzw. Aktoren durchgeführt werden sollen. Ein kleines Beispiel:

switchIDs = {96, 178}

for i = 1, #switchIDs do
	fibaro:call(switchIDs[i], "turnOff")
end

#switchIDs beinhaltet die Anzahl der Objekte im Array #switchIDs. In diesem Fall also 2, da das Array die IDs 96 und 178 umfasst. Die for-Schleife schaltet beide Aktoren nacheinander aus.

Verwendung von Schleifen

Bisher sind in unserem Badezimmer nur einzelne Aktionen durchgeführt worden. Es sewurden Lichter eingeschaltet, wenn entsprechende Bedingungen erfüllt waren. Alle Operationen der Szenen wurden – wie in der Einleitung beschrieben von „oben nach unten“ – genau einmal ausgeführt.

Nun soll das Licht im Badezimmer nach 60 Sekunden wieder ausgeschaltet werden. Die erste Idee dies zu tun ist vermutlich die Szene nach dem Einschalten des Lichtes 60 Sekunden pausieren zu lassen und dann die Aktionen zum Ausschalten auszuführen.

luxID1 = 58
luxID2 = 127
switchID1 = 96
switchID1 = 178
luxValue1 = tonumber(fibaro:getValue(luxID1, "value"))
luxValue1 = tonumber(fibaro:getValue(luxID2, "value"))
switchState1 = tonumber(fibaro:getValue(switchID1, "value"))
switchState2 = tonumber(fibaro:getValue(switchID2, "value"))

if switchState1 == 0 then
	if luxValue1 < 100 or luxValue2 < 100 then
		fibaro:call(switchID1, "turnOn")
		fibaro:debug("Licht 1 eingeschaltet")
	else
		fibaro:debug("Es ist hell genug")
	end
elseif switchState1 == 1 then
	if luxValue1 < 200 or luxValue2 < 200 then
		fibaro:call(switchID2, "turnOn")
		fibaro:debug("Nicht hell genug, zweite Lampe zusätzlich eingeschaltet")
	else
		fibaro:debug("Es ist hell genug, die zweite Lampe bleibt aus")
	end
end

-- 60 * 1000 Millisekunden warten
fibaro:sleep(60*1000)

-- Lampen ausschalten
fibaro:call(switchID1, "turnOff")
fibaro:call(switchID2, "turnOff")

Da während des andauernden „Schlafes“ der Szene (Sleep) keine weiteren Aktionen durchgeführt werden können und somit der Status der Szene auf den ersten Blick nicht zu erkennen ist, liefert diese Lösung zwar den gewünschten Effekt, ist aber nicht sonderlich smart. Deutlich smarter ist hier die Verwendung von Schleifen. Denn, wie oben beschrieben, ist der Einsatz von Schleifen immer dann sinnvoll, wenn es wiederkehrende Dinge zu tun gib. In diesem konkreten Fall soll sechzig mal eine Sekunde gewartet werden bevor die Lampen im Badezimmer wieder ausgeschaltet werden. Um dies zu realisieren wird eine while-Schleife für die Bestimmung der 60 Sekunden sowie eine for-Schleife zum Ausschalten der Lampen benötigt.

while-Schleife mit Timer

Um das Licht 60 Sekunden eingeschaltet zu lassen wird eine while-Schleife benutzt.

laufzeit = 60 -- Sekunden
a = 1 -- Vergleichswert

while a <= laufzeit do
	fibaro:debug('Timer läuft '..a..' Sekunden')
	a = a + 1
	fibaro:sleep(1000)
end

Die Schleife erzeugt bei jedem Durchlauf eine Debug-Meldung, addiert 1 zur Variable a und wartet anschließend 1000 Millisekunden. Sobald a den Wert 60 erreicht, ist die Bedingung erfüllt und die Schleife wird beendet. Hier die Ausgabe der while-Schleife:

[DEBUG] 12:49:07: Timer läuft 1 Sekunden
[DEBUG] 12:49:08: Timer läuft 2 Sekunden
[DEBUG] 12:49:09: Timer läuft 3 Sekunden
.
.
[DEBUG] 12:49:10: Timer läuft 59 Sekunden
[DEBUG] 12:49:11: Timer läuft 60 Sekunden

Im Gegensatz zur 60 sekündigen Pause haben wir bei dieser Variante des Timers stets einen Überblick über den Verlauf der Szene.

for-Schleife zum Ausschalten des Lichtes

Die benötigte for-Schleife wird zum ausschalten des Lichtes verwendet und soll nach Ablauf der definierten 60 Sekunden ausgeführt werden.

for i = 1, #switchIDs do
	fibaro:call(switchIDs[i], "turnOff")
        fibaro:debug('Lampe '..switchIDs[i]..' ausgeschaltet.')
end

Badezimmer-Licht-Steuerung mit Schleifen und Timer

In unsere Badezimmer-Licht-Steuerung integriert sieht es dann so aus:

luxID = 58
switchIDs = {96, 178}
luxValue = tonumber(fibaro:getValue(luxID, "value"))
laufzeit = 60 -- Sekunden

a = 1 -- Vergleichswert

if luxValue < 100 then
	--for Schleife zum Einschalten der Lampen
	for i=1, #switchIDs do
		fibaro:call(switchIDs[i],"turnOn")
		fibaro:debug('Lampe mit der ID '..switchIDs[i]..' eingeschaltet')
	end
	--while Schleife für den Countdown
	while a <= laufzeit do
		fibaro:debug('Timer läuft '..a..' Sekunden')
		a = a + 1
		fibaro:sleep(1000)
	end
	--for Schleife zum Ausschalten der Lampen
	for i=1, #switchIDs do
		fibaro:call(switchIDs[i],"turnOff")
		fibaro:debug('Lampe mit der ID '..switchIDs[i]..' ausgeschaltet')
	end
else
	fibaro:debug("Es ist hell genug")
end

Wird die Szene gestartet und der Lux-Wert liegt unterhalb von 100 werden die Lampen (IDs 96 und 178) mit der ersten for-Schleife eingeschaltet. Mit der while-Schleife wird der 60 Sekunden-Timer gestartet nach dessen Ablauf die zweite for-Schleife beide Lampen wieder ausschaltet.

Funktionen

Um Code innerhalb einer Szene wiederverwendbar zu machen lassen sich in LUA Szenen Funktionen erstellen. Funktionen sind sozusagen kleine Programmteile die – ähnlich der Variablen – vor ihrer Verwendung definiert werden und dadurch an (fast) jeder Stelle der Szene wiederverwendet werden können. Weiterhin können Variablen an Funktionen übergeben werden um diese innerhalb der Szene verwenden zu können. Neben der Wiederverwendung von Code fördern Funktionen die Übersichtlichkeit und Wartbarkeit von Szenen.

Funktion definieren

Um zu verdeutlichen wie sinnvoll der Einsatz von Funktionen ist, ein kleines Beispiel mit Bezug zur Badezimmer Szene. Mit der folgenden Funktion werden alle Lampen im Badezimmer geschaltet. Und zwar abhängig vom Inhalt der Variable turn ein oder aus:

function switchLights(IDs, turn)
	for i=1, #IDs do
		fibaro:call(IDs[i],turn)
		fibaro:debug('Lampe mit der ID '..IDs[i]..' geschaltet')
	end
end

Mit dem Schlüsselwort function wird eine Funktion mit dem Namen switchLights definiert. Die Funktion nimmt die Variablen IDs und turn entgegen um diese innerhalb der Funktion verwenden zu können. In unserem Beispiel die Table mit den IDs der Lampen (96 und 178) sowie die durchzuführende Aktion („turnOn“ oder „turnOff“). An Funktionen übergebene Variablen behalten ihre Gattung (Text, Nummer, Bool oder Table).

Wichtig ist die Positionierung der Funktionen innerhalb der Szene. Sie müssen vor (also oberhalb) ihrem Aufruf definiert sein, damit sie verwendet werden können.

Funktionsaufruf

Der Aufruf einer Funktion erfolgt über den definierten Namen unter Berücksichtigung der von der Funktion erwarteten Variablen Im Beispiel also IDs und turn.

switchLights(lightIDs, "turnOn")

Der Code zum Schalten der Aktoren ist deutlich kürzer geworden und sollten sich einmal Änderungen ergeben ist diese nur innerhalb der Funktion durchzuführen.

Integration in Szenen

Richtig deutlich wird die Vereinfachung des Quellcodes innerhalb der kompletten Szene.

luxID = 58
switchIDs = {96, 178}
luxValue = tonumber(fibaro:getValue(luxID, "value"))
laufzeit = 60 -- Sekunden

a = 1 -- Vergleichswert

function switchLights(IDs, turn)
	for i=1, #IDs do
		fibaro:call(IDs[i],turn)
		fibaro:debug('Lampe mit der ID '..IDs[i]..' geschaltet')
	end
end

if luxValue < 100 then
	switchLights(switchIDs, "turnOn")
	while a <= laufzeit do
		fibaro:debug('Timer läuft '..a..' Sekunden')
		a = a + 1
		fibaro:sleep(1000)
	end
	switchLights(switchIDs, "turnOff")
else
	fibaro:debug("Es ist hell genug")
end

11 Comments
  1. Hallo Bastian, bin gerade im Urlaub und hab mir es gestern alles durchgelesen. Echt super geschrieben. Ich glaub das wird mir und Anderen helfen.

  2. Hallo Bastian,

    ein starker Artikel, aus dem ich direkt ein paar Zeilen Code entwenden kann:-)
    Jetzt habe ich das auch endlich mit dem fibaro:sleep verstanden.

    Danke für die Arbeit. Das hat bestimmt eine Weile gedauert.

    VG
    Mr.Coffee

  3. Hallo Bastian,
    vielen Dank für Deine Fleißarbeit! Ich habe sie zum Anlass genommen, einen zweiseitigen, kompakten Überblick zur LUA-Syntax und verschiedenen Fibaro-Befehlen zu erstellen:
    https://www.subreality.de/blog/wp-content/uploads/2017/02/lua_syntax_fibaro_befehle.pdf
    Das kann noch Flüchtigkeitsfehler enthalten und es ist sicherlich auch noch nicht „vollständig“, denn ich bin noch dabei, mich schrittweise einzuarbeiten. Aber zumindest mit leistet dieses Dokument, laminiert auf der Tischplatte, bisher gute Dienste. Ich werde es ggf. nach und nach erweitern.
    Beste Grüße, Rüdiger

    1. Hallo Rüdiger,

      vielen Dank für die netten Worte und Deine Mühe mit dem PDF! Den Link veröffentliche ich natürlich gern und bin mir sicher, dass er dem Ein oder Anderen User helfen wird.

      Gruß
      Bastian

  4. Hallo Bastian,
    ich kann mich auch nur Bedanken. Ich fange gerade an, mich mit Lua zu beschäftigen. Es ist toll, wenn man sich einmal komplett an einem Beispiel orientieren kann. Mir hat es sehr geholfen die krptischen Zeichen zu verstehen.
    An deiner Seite sollten sich mehr Foren orientieren. In den meisten Foren bekommt man immer nur Schnipsel und muss dann wieder nachfragen.

    großes DANKE an dich
    Gruß Manfred

    1. Hi Modell75,

      schau Dir mal das Kapitel „Variablen-Typen“ an. Mit der Funktion tonumber() kannst Du den Typ einer Variable von String zu Number ändern. Dies ist insbesondere wichtig, wenn Du mit Variablen Rechnen oder Vergleichen möchtest. Das geht nämlich mit Texten nicht 😉

      Gruß
      Bastian

  5. Danke Bastian für diese ausführliche und sehr gut verständliche Anleitung!!
    Ich nehme sie immer wieder gerne her, wenn ich mir neue LUA Skripte ausdenke!!

  6. Hallo Bastian
    ich bin auch neu in der LUA Programmierung, da wir gerade einen Neubau planen.
    Dank deinen super Beiträgen habe ich einen wesentlich leichteren Einstieg ins Thema und gute Beispiele zum nachlesen und üben.
    Danke vielmals für deinen Aufwand!

    Liebe Grüsse
    Clemens

Schreibe einen Kommentar

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

Ich akzeptiere

Fibaro LUA Grundlagen

von Bastian Lesezeit: 20 min