FHEM Tutorial-Reihe - Part 41: Lichtszenen an Anwesenheit koppeln
Wieder einmal geht es um das Thema Licht. Hier habe ich mir viele Gedanken gemacht, wie ich das Licht etwas automatisierter schalten kann. Und zwar gehe ich jetzt soweit, dass ich nichtmal mehr das Licht ausschalten muss, wenn ich die Wohnung verlasse. Das alles passiert automatisch. Weiterhin wird das Licht sogar wieder eingeschaltet wie es war, wenn ich innerhalb von zwei Stunden wider nach Hause komme. Sicherlich erst die Grundlage meiner Wünsche und Gedanken zu dem Thema, aber hier geht es ja primär darum, dass Du etwas neues lernst.
Was wird benötigt?
- Eine FHEM-Installation
- Ein paar eingebundene Lampen
Video
Befehle
Als erstes definiere ich die entsprechenen Szenen. Dabei achte ich darauf, ein einheitliches Namens-Schema einzuhalten. Also für jeden Raum WZ (Wohnzimmer), SZ (Schlafzimmer) usw. lege ich ein Gerät an, dessen Name genau gleich endet. Das ist wichtig, da wir so später alle Räume auf einmal korrekt ansprechen können.
define WZ_LichtSzene LightScene WZ_Fernsehlicht WZ_Fensterlicht WZ_Dekolicht WZ_Vitrinelicht WZ_Vaselicht WZ_Schranklicht
define SZ_LichtSzene LightScene SZ_Deckenlicht SZ_NadineBettLicht SZ_MatthiasBettLicht
Nachdem die Szenen wie im Video gezeigt angelegt wurden, kann ich nun ganz einfach alles im Haus ausschalten. Natürlich muss es dafür in jedem Raum eine Szene mit dem Namen “AllesAus” geben. Hier merkt man nun auch schnell wie wichtig das richtige benennen von Geräten ist. Es sind nicht nur Namen, sondern mit vernünftigen “Patterns” kann man sich viel Schreibarbeit sparen.
Ich probiere dabei immer alles generisch zu halten, dass ich später ganz einfach neue Räume im gleichen Schema dazu nehmen kann, und meine komplette Logik weiterhin genauso funktioniert, ohne dass ich etwas anpassen muss. Lieber also zweimal mehr überlegen als am Ende alles umbauen zu müssen.
set .*LichtSzene scene AllesAus
Jetzt geht es an die eigentliche Logik, welche im Video genau erklärt wird. Kurzfassung:
- Wir gehen alle Szenen in den Räumen durch
- Holen uns von jeder den aktuellen Status (also die aktive Szene)
- Und speichern den Wert in ein Reading
Dadurch können wir später wieder auf das Reading zugreifen und haben auch automatisch den Zeitpunkt, zu welchem wir die Szene umgestellt haben mit gespeichert (da man zu jedem Reading auch auf dessen Datum zugreifen kann).
sub saveLightStates() {
my $n = 0;
my @ls = devspec2array(".*_LichtSzene");
foreach (@ls) {
my $scene = Value($_);
if ($scene ne "") {
fhem("setreading $_ previousScene $scene");
$n++;
}
}
return $n;
}
sub restoreLightStates() {
my $n = 0;
my @ls = devspec2array(".*_LichtSzene");
foreach (@ls) {
my $scene = Value($_);
my $previousScene = ReadingsVal($_, "previousScene", "");
if ($previousScene ne "" && $scene ne $previousScene) {
fhem("set $_ scene $previousScene");
$n++;
}
fhem("deletereading $_ previousScene");
}
return $n;
}
Testen können wir die beiden Funktionen, indem direkt Perl-Code in die Befehlseingabe geschrieben wird:
{saveLightStates()}
{restoreLightStates()}
In der zweiten Ausbaustufe wird noch das Datum beim “restore” einbezogen:
sub restoreLightStates() {
my $n = 0;
my @ls = devspec2array(".*_LichtSzene");
my $pattern = "%Y-%m-%d %H:%M:%S";
my $strp = DateTime::Format::Strptime->new(pattern => $pattern);
my $now = DateTime->now(time_zone => 'Europe/Berlin');
foreach (@ls) {
my $scene = Value($_);
my $previousScene = ReadingsVal($_, "previousScene", "");
my $previousSceneTime = ReadingsTimestamp($_, "previousScene", "1970-01-01 00:00:00");
my $previousDateTime = $strp->parse_datetime($previousSceneTime);
my $diffSeconds = $now->subtract_datetime($previousDateTime)->in_units('seconds');
if ($previousScene ne "" && $scene ne $previousScene && $diffSeconds <= 7200) {
fhem("set $_ scene $previousScene");
$n++;
}
fhem("deletereading $_ previousScene");
}
return $n;
}
Fertig.