Hallo Leute,
ich bin relativ neu im Bereich Z-Wave und habe mein kleines Smarthome zu meinem neuen Hobby ernannt.
Da ich von Beruf Software- und Systementwickler bin, möchte ich meine Fähigkeiten bei der LUA-Programmierung
mit euch teilen.
Mein erstes kleines Projekt ist das allgeliebte Thema TimeOfDay. Ich habe hier die Informationen aus verschiedenen
Threads des Forums gesammelt und meine Methodik mit einfliessen lassen.
Wer es gerne Testen bzw Nutzen möchte, über Feedback und Ideen freu ich mich immer gerne.
Gerne lass ich noch eure Wünsche mit einfliessen.
Zur Zeit befindet sich das Skript in der Testphase, wird aber schon aktiv von mir genutzt.
Viele Grüsse
Najib
Nun zum Technischen:
Die Tageszeiten liegen als Anordnung vor wobei folgendes möglich ist:
0 Uhr ======> Morgen ======> Tag ======> Abend ======> Nacht =====> 0 Uhr
oder Datumsübergreifend:
0 Uhr ==>Nacht ====> Morgen =====> Tag ======> Abend ===========> 0 Uhr
Alle Tageszeiten können mit dem Sonnenutergang/-aufgang kombiniert werden. Näheres dazu weiter unten
Allgemeine Einstellungen und Funktionen im Skript:
a. Angabe aller Tageszeiten ( Morgen, Tag, Abend, Nacht ) durch:
-
Feste Uhrzeiten
z.B morning = { “08:00”, 0 } Morgen entspricht 08:00 Uhr -
Angabe in durch Sonnenuntergang/-aufgang
z.B morning = { sunrise, 0 } Morgen entspricht Sonnenaufgang
evening = { sunset, 0 } Morgen entspricht Sonnenuntergang -
Angabe durch Offset in Minuten
z.B morning = { sunrise, 30 } Morgen entspricht 30 Minuten nach Sonnenaufgang
evening = { sunset, -70 } Abend entspricht 70 Minuten vor Sonnenaufgang
b. Mapping der Tageszeitenbezeichnungen:
Es können beliebige Bezeichnungen (Tageszeiten) in der globalen Variable TimeOfDay
hinterlegt werden. Die Bezeichnung müssen lediglich in der Mapping-Variable in
Zeile 17 angepasst werden
Der Name der Gloablen Variable TimeOfDay kann in Zeile 13 festgelegt werden.
c. Berechnung der nächsten Ausführung
- Die Szene pausiert bis zum nächsten Tageszeiten-Wechsel. Die Pause wurde in
Abhängigkeit zur Startzeit der nächsten Tageszeit berechnet
** Hier hab ich noch kein Gefühl wie sich die CPU zu einer Szene verhält,
die z.B. im 1 Minuten Intervall gestartet wird **
d. Tests der Einstellung durch 24 Stunden Simulation
- Durch Setzen der Variable debugMode = true (Zeile 10: true => an; false => aus)
wird der Simulationsmodus aktiviert. Im Simulationsmodus wird ein Tag von
0 bis 24:00 Uhr Durchlaufen und die möglichen Ergebnisse angezeigt.
Das Setzen der globale Variable und des Timeouts entfällt.
Hier das Skript setTimeOfDay
--[[
%% autostart
%% properties
%% globals
--]]
-- ------------- Skript setDayTime --------------------------------------------
-- Hier Debugmode auf true setzen und es wird ein Simulationstag (24 Std) durchlaufen,
-- der dir die moeglichen Ergebnisse zeigt jedoch keine Globale Variable ändert
-- und keinen Timeout setzt
local debugMode = false
-- Name der Globalen Variable im Home Center
local timeOfDayGlobalName = "TimeOfDay"
-- Mapping der TimeOfDay Eintraege in beliebiger Sprache
-- der globalen Variable TimeOfDay entsprechend
local timeOfDayLabelMap = {Morning="Morning", Day="Day", Evening="Evening", Night="Night"}
-- Strings Sonnenauf/-untergang im Format Stunde:Minute von fibaro geliefert
local sunrise = fibaro:getValue(1, "sunriseHour") -- Sonnenaufgang
local sunset = fibaro:getValue(1, "sunsetHour") -- Sonnenuntergang
-- Angaben der Bereichsgrenzen:
--
-- Hier koennen die Grenzen angeben werden, ab wann ein neuer Tagesbereich anfaengt.
-- Der Erste Wert ist die Uhrzeit im Format Stunde:Minute, der zweite Wert
-- entspricht einem Offset (Verzoegerung) in Minuten bezogen auf den ersten Wert.
-- Als ersten Wert koennen auch die Variablen sunset/sunrise genommen werden.
--
-- Beispiele:
--
-- morning = { sunrise, 30 } => Morgen beginnt 30 Minuten nach Sonnenaufgang
-- morning = { sunrise, -30 } => Morgen beginnt 30 Minuten vor Sonnenaufgang
-- evening = { "18:00", 0 } => Abend beginnt um genau 18:00 Uhr
-- evening = { sunset, 80 } => Abend beginnt 80 Minuten nach Sonnenaufgang
local morning = { sunrise, 0 }
local day = { "10:00", 0 }
local evening = { sunset, 0 }
local night = { "22:00", 0 }
--
-- =========> Ab hier sind keine Einstellungen noetig
--
local sourceTrigger = fibaro:getSourceTrigger()
-- Berechnet Uhrzeit in Sekunden (Differenz) ab 0:00 Uhr
function getTimeSecsDiff(s)
local hours, minutes = string.match(s, "(%d+):(%d+)")
-- Sekunden = Stunden * 60 (mins) * 60 (secs) + Minuten * 60 (secs)
local calcSecs = (hours-1) * 60 * 60 + minutes * 60
return calcSecs
end
-- Umrechnung der Bereichsgrenze in Sekunden ab 0:00 Uhr (Differenz)
morning = getTimeSecsDiff(morning[1]) + morning[2] * 60
day = getTimeSecsDiff(day[1]) + day[2] * 60
evening = getTimeSecsDiff(evening[1]) + evening[2] * 60
night = getTimeSecsDiff(night[1]) + night[2] * 60
if (debugMode) then
fibaro:debug("---------------- Voreinstellungen -----------------")
fibaro:debug(string.format("%s Uhr Sonnenaufgang",sunrise))
fibaro:debug(string.format("%s Uhr Sonnenuntergang",sunset))
fibaro:debug(string.format("%s Uhr Morgen",os.date("%H:%M", morning)))
fibaro:debug(string.format("%s Uhr Tag",os.date("%H:%M", day)))
fibaro:debug(string.format("%s Uhr Abend",os.date("%H:%M", evening)))
fibaro:debug(string.format("%s Uhr Nacht",os.date("%H:%M", night)))
end
-- Table der Bereichsgrenzen
local dayTimeList = {
{label = timeOfDayLabelMap.Morning, secs = morning},
{label = timeOfDayLabelMap.Day, secs = day},
{label = timeOfDayLabelMap.Evening, secs = evening},
{label = timeOfDayLabelMap.Night, secs = night},
}
-- Sortierung der Bereichsgrenzen nach Zeit (secs)
local sort_func = function( a,b ) return a.secs < b.secs end
table.sort(dayTimeList, sort_func)
-- Hauptfunktion zum setzen der Globalen Variable TimeOfDay
function setTimeOfDay()
local aktTime = 0;
local doLoop = true;
local loopHour = 0;
local timeout = 0
local setDayTime = nil
if (debugMode) then
fibaro:debug("---------------- Beginne Auswertung --------------")
end
repeat
local timeOfDayCur = fibaro:getGlobalValue(timeOfDayGlobalName)
fibaro:debug(string.format("Globale Variable '%s' aktueller Wert: '%s'", timeOfDayGlobalName, timeOfDayCur))
if (debugMode) then
-- Testzeit zur Simulation
aktTime = getTimeSecsDiff(string.format("%02d:00",loopHour))
if (loopHour == 24)then
doLoop = false
end
loopHour = loopHour + 1
else
-- aktuelle Zeit in Sekunden (Differenz)
aktTime = getTimeSecsDiff(os.date("%H:%M"))
doLoop = false
end
for i, record in ipairs( dayTimeList ) do
if (aktTime < record.secs) then
if (i == 1) then
-- falls match beim ersten Element nehme
-- den letzte Zeitbereich in der Liste
setDayTime = dayTimeList[#dayTimeList].label
else
setDayTime = dayTimeList[i-1].label
end
timeout = record.secs - aktTime;
break;
end
lastDayTime = record.label
if (i == 1) then
firstSec = record.secs
end
end
-- Falls Zeitgrenze ueber Datumswechsel muss der Timeout extra berechnet werden
if ( setDayTime == nil ) then
setDayTime = lastDayTime
timeout = 86400 - aktTime + firstSec
end
fibaro:debug(string.format("Es ist '%s' Uhr => setze Globale Variable '%s' auf '%s'", os.date("%H:%M", aktTime), timeOfDayGlobalName, setDayTime))
-- setze globale Variable
if (not debugMode) then
fibaro:debug(string.format("Globale Variable '%s' auf den Wert '%s' gesetzt", timeOfDayGlobalName, setDayTime))
fibaro:setGlobal(timeOfDayGlobalName, setDayTime)
end;
-- Die Szene pausiert bis zum Wechsel in den naechsten Tagesbereich
fibaro:debug(string.format("Timeout für %.2f Minuten", timeout/60))
until not doLoop
if (not debugMode) then
-- Setze Timeout
--fibaro:debug( string.format("vor Timeeout:"));
setTimeout(setTimeOfDay, timeout*1000)
end;
end
--
-- ================ Main ( Aufruf Verarbeitung ) ==============================
--
setTimeOfDay()