Mini-Bibliothek für neue LUA-Szenen

Hallo werte siio-Gemeinde,

als kleines Dankeschön für so manche erhaltene Hilfestellung hier im Forum möchte ich einige Hilfsfunktionen posten, mit denen ich jede etwas größere LUA-Szene beginne. Seit mehreren Wochen (Stand Mai 2017) tun diese Routinen bei mir ihren Job, ich würde sagen “gutes Beta-Stadium”.

Hintergrund: Nach einiger Zeit der HC2-Programmierung stellt man fest, dass durch Flüchtigkeits- oder Programmierfehler ganze Szenen scheitern, nur weil man nicht jeden (unerwarteten) Sonderfall bedacht hatte. Ich hatte mal eine ganze Woche lang die Nachtbeleuchtung eingeschaltet, nur weil ein völlig überflüssiger fibaro:debug()-Befehl Probleme mit einer Zeichenverkettung bekam.

Daher habe ich einen kleinen Satz Hilfsfunktionen geschrieben, um solche typischen Fehlerquellen abzufangen. Den kopiere ich nun stets an den Beginn einer neuen LUA-Szene, gleich nach den Startkommentaren.

Ich habe auf drei Dinge großen Wert gelegt:

  1. Kürze.
    Die Funktionen sind “minifiziert”, indem überflüssige Zeilenumbrüche und Leerzeichen weggekürzt wurden und die Funktionsargumente keine sprechenden Namen haben. Dafür benötigt die gesamte Bibliothek auch nur 6 Zeilen bzw. knapp 400 Byte im Rohzustand, wenn man die darunter stehenden Kommentare weglässt. Wer mag, kann sogar noch ein paar Byte durch kürzere Funktionsnamen rauskitzeln :slight_smile:
    Außerdem werden Skripte letztendlich übersichtlicher, weil man nun s(a,b) schreiben kann anstatt if(b~=NIL) then fibaro:setGlobal(a,b) end

  2. Arbeitserleichterung.
    Die Funktionen c() und d() benötigt man hauptsächlich für das Debuggen während der Entwicklungsphase; sie sind um ein Vielfaches schneller getippt als ihre “richtigen” Basisfunktionen, während sie sogar mehr Fehler verzeihen.

  3. Fehlertoleranz.
    Wenn man beispielsweise eine Szene mit einer fälschlicherweise undefinierten Nummer aufruft - also im Prinzip fibaro:startScene(NIL) - oder den Wert einer nicht existierenden globalen Variable abfragt (was ebenfalls ein klassischer Programmierfehler ist), dann geht’s halt mit diesen Hilfsfunktionen trotzdem weiter im Programm, ohne Fehlermeldung. “The script will silently fail”, nennt das der Programmierer. Ob das immer im Sinne der Aufgabe ist, muss man selbst entscheiden. In den meisten Fällen (zumindest im Bereich Smart Home!) sollte dieser pragmatische Ansatz eine gute Wahl sein, sprich wenn 99 Prozent Erfolg “besser” sind als ein kompletter Programmabbruch. Eine Datenbank würde man selbstverständlich nicht so tolerant programmieren…

Da man im Fibaro Home Center 2 leider keine Funktionen im globalen Scope definieren kann, sondern in jeder Szene alles wieder neu hinschreiben muss, ist diese Mini-Bibliothek, wie ich finde, ein guter Kompromiss zwischen Ressourcenschonung und Arbeitserleichterung.

Ich freue mich über Eure Anregungen. Gibt es noch Bugs im Code? Habt Ihr auch nützliche Hilfsroutinen geschrieben? Dann immer her damit!

Beste Grüße,
Andreas


function c(...)local s=''for i,v in ipairs({...})do s=s..v..' 'end return s end
function d(s)fibaro:debug(s)end
function g(n)return fibaro:getGlobal(n)or''end
function s(n,v)if(g(n)~=(v or''))then fibaro:setGlobal(n,v or'')end end
function sc(n)if((n or 0)>0)then fibaro:startScene(n)end end
function scene(l)if(type(l)=='table')then for i,v in ipairs(l)do sc(v)end else sc(n)end end

--[[
function c     : Fügt eine beliebige Anzahl von Komma-separierten Argumenten
                 zusammen ("concatenate"), jeweils mit einem Leerzeichen 
                 dazwischen und am Ende zur besseren Lesbarkeit,
                 und gibt den gesamten String zurück.
                 Beim ersten NIL-Argument gibt die Funktion das bisherige 
                 Ergebnis zurück.
                 Beispiel:
                 fibaro:debug(c('Samstag', 'und', 'Sonntag', 'ist', 'frei.'));
function d     : nur eine Abkürzung für fibaro:debug, weil man das so häufig benutzt.
                 Beispiel: d('hallo Welt'); d(_VERSION);
function g     : liest den Wert einer globalen Variablen,
                 liefert dabei niemals NIL zurück.
                 Beispiel: if(g('PresentState') == 'Away') then ...
function s     : setzt den Wert einer globalen Variablen, falls dies nötig ist. 
                 NIL wird wie ein Leerstring behandelt.
                 Der Befehl fibaro:setGlobal wird nur aufgerufen, wenn der
                 aktuelle Wert der globalen Variablen ein anderer ist.
                 Beispiel: s('PresentState', 'Away')
function sc    : Führt eine Szene aus, wenn deren Nummer nicht NIL oder 0 ist.
                 Beispiel: sc(4711); sc();
function scene : Startet eine einzelne Szene oder mehrere Szenen.
                 Der Parameter l (wie "Liste") kann vom Typ 
                 "number" oder "table" sein. 
                 Szenennummern 0 und NIL werden ignoriert.
                 Beispiele:
                 scene(4711); scene( {15, 19, 42} ); scene(); 
--]]

Nette Idee, danke fürs Teilen!

Interessant.
Was machst Du mit “c”?

siehe Beispiel im Kommentar, also etwa


-- vorher:
fibaro:debug(x..' '..y..' '..z);

-- nachher:
d(c(x,y,z));

-- oder:
d(c('Das Licht wird', x==1 and 'eingeschaltet' or 'ausgeschaltet'))

wie gesagt, c() und d() sind hauptsächlich zum schnellen Debuggen.
Man kann die erste Zeile mit der Funktion c() auch weglassen, wenn man sie nicht braucht, da keine andere Funktion abhängig von ihr ist.
c() könnte man auch so umstellen, dass es unmittelbar ein debug mit d() durchführt, aber ich brauche die Funktion auch zum Zusammenstellen von Wertelisten, die ich in vielen meiner Programme verwende (Werteübergabe mittels globalen Variablen von/an externe Systeme). Oder vielleicht statt des Leerzeichens ein Komma als Trenner verwenden.

ja, das Beispiel hatte ich gelesen, aber keine Idee, wie /wobei ich das nutzen kann…

Verstehe.
Version 0.02: Habe die Funktion c entfernt. Ihre Funktionlität ist jetzt in d enthalten, wodurch d noch attraktiver wird :slight_smile:


function d(...)local s=''for i,v in ipairs({...})do s=s..(v or'')..' 'end fibaro:debug(s) end

--[[
function d     : schreibt fibaro:debug für eine beliebige Anzahl an kommaseparierten
                 Parametern, Ausgabe in derselben Zeile, getrennt mit Leerzeichen.
                 Beispiel: d(_VERSION); d('Temperatur:', g('TEMP'), 'Licht:', g('LUX')); -- siehe function g, globale Variablen TEMP und LUX existieren
                 [DEBUG] 07:52:31: Lua 5.2
                 [DEBUG] 07:52:31: Temperatur: 21 Licht: 86
--]]