15211 Zeichen
Score aktualisiert
100%
Code: 34d24d9f2502473daa7b7dd8ccc519f4
Token in Entwicklung nicht aktualisiert
img-Tag in Entwicklung deaktiviert
Ich gebe es zu: Ich übertreibe es manchmal etwas mit der Beleuchtung. In meinem
Wohnzimmer gibt es knapp ein Dutzend Leuchten und fast alle sind einzeln zu schalten. Das
ist toll, wenn man zum Fernsehen, zum Essen, zum Lesen usw. jeweils eigene Szenen
entwerfen kann – aber die Programmierung jeder einzelnen Leuchte ist eine Qual.
Eine Zeit lang hatte ich eine 12-Tasten-Fernbedienung
dafür belegt – jede Taste eine Leuchte. Mittlerweile reicht auch die nicht mehr, um alles
einzeln zu schalten. Vor die Wahl gestellt, viel Geld für die große 19-Tasten-Fernbedienung
auszugeben und ein Dutzend neuer direkter Verknüpfungen anzulegen oder ein Script zu
schreiben, mit dem ich einfach verschiedenste Lichtszenen ansteuern kann, nehme ich
natürlich das Script.
Variablen in HomeMatic-Scripten
Die CCU hatte früher ein Limit von maximal 200 Variablen, das mit
Firmware-Version 2.29.18 aufgehoben wurde. Dieses Limit bezog sich auf alle
Variablen, die in allen Scripten verwendet werden. Gemeint sind Variablen,
die direkt im Script definiert werden: object x; object y;
var z;
Wenn Scripte nicht mehr funktionieren und bei der Prüfung unerklärliche
Syntax-Fehler auftreten, sollte versuchsweise dieses Programm wieder gelöscht
oder deaktiviert werden – oder, noch besser, auf die aktuelle
Firmware-Version aktualisiert werden.
Strings in HomeMatic-Scripten
Durch String-Verwendung in HomeMatic-Scripten kann die CCU fehlerhaft arbeiten,
instabil werden oder sogar abstürzen. Grundsätzlich gilt: Je öfter mit Strings
hantiert wird, desto eher führt dies zu Problemen.
Ich empfehle daher, nach Umsetzung dieser Anleitung die CCU unter Beobachtung
zu halten.
Benennung von Systemvariablen
Prinzipiell kann man Systemvariablen – so wie allen Objekten in der CCU – beliebige
Namen geben, also z. B. auch Umlaute und Sonderzeichen verwenden. Ich empfehle jedoch,
sich auf reguläre Buchstaben (a-z, A-Z) zu beschränken: Bei Umlauten und Sonderzeichen
besteht die Gefahr, dass Systemvariablen in Scripten nicht überall gefunden werden.
Das WebUI-Programm
In der WebUI brauche ich nur ein relativ einfaches Programm. Es reagiert auf alle
Tastendrücke meiner Fernbedienung und startet dann ein Script.
Wie man im Screenshot sieht, gibt es hier für jeden Kanal der Tasterschnittstelle
einen Eintrag, alle mit „oder“ verknüpft. Auch „Tastendruck lang“
werte ich aus. So kann ich mit acht Tasten an der Wand acht verschiedene Lichtszenen
steuern.
Bei der 12-fach-Fernbedienung, die nun keine direkten Verknüpfungen für die einzelnen
Aktoren mehr enthält, sieht der „Wenn … “-Teil etwas umfangreicher aus, ist
aber ebenfalls simpel gestrickt.
Bei genauem Hinsehen fällt auf, dass Taste 9 fehlt. Hier habe ich eine andere Funktion
auf die Fernbedienung gelegt – man muss also den Sender nicht komplett für die
Lichtszenen reservieren.
Der „Dann … “-Teil ist entsprechend kompakt: Hier wird nur das Script
gestartet, in dem die Magie passiert.
Einfaches Script
In der ersten Version schaltet das Script lediglich die Leuchten in meinem Wohnzimmer.
gesamtes Script markieren / kopieren
! HomeMatic-Script
! LICHTSZENEN PER SCRIPT SCHALTEN
! http://www.christian-luetgens.de/homematic/programmierung/beleuchtung/lichtszenen/Lichtszenen.htm
! Fernbedienungstaste bestimmen
! Tasten sind paarweise angeordnet, aber wir brauchen es linear
string s_src = dom.GetObject($src$).Name();
integer i_chn = s_src.StrValueByIndex(".", 1).StrValueByIndex(":", 1).ToInteger();
if (s_src.StrValueByIndex(".", 2) == "PRESS_LONG") {
i_chn = i_chn + 12; ! für langen Tastendruck bei 12-Tasten-FB
}
integer i_btn = 0;
while (i_chn > 1) {
i_chn = i_chn - 1;
i_btn = i_btn + 1;
}
! Kanäle
string tab = "\t";
string prefix = "Wohnzimmer.Licht.";
string s_channels =
prefix # "Fluter Fernseher" # tab #
prefix # "Fluter Sofa" # tab #
prefix # "Esstisch" # tab #
prefix # "Geist" # tab #
prefix # "Plattenregal" # tab #
prefix # "Lavalampen" # tab #
prefix # "Lumibaer" # tab #
prefix # "Sofabeleuchtung" # tab #
prefix # "Sonne" # tab #
prefix # "Vitrine 1" # tab #
prefix # "Vitrine 2";
! Lichtszenen
string s_scenes =
"Wohnzimmer :1:1:0:1:1:1:1:1:0:1:1;" #
"Esszimmer :0:0:1:1:0:0:1:0:0:1:1;" #
"Couchtisch :0:0:0:0:1:1:1:1:1:1:1;" #
"alles aus :0:0:0:0:0:0:0:0:0:0:0;" #
"Ambiente dunkel:0:0:0:1:0:1:0:1:0:0:0;" #
"Ambiente hell :0:0:0:1:1:1:1:1:0:1:1;" #
"Effekte :0:0:0:1:0:1:1:0:0:0:0;" #
"Plattenregal :0:0:0:1:1:1:1:0:0:0:0;" #
"alles ein :1:1:1:1:1:1:1:1:1:1:1;" #
"alles aus :0:0:0:0:0:0:0:0:0:0:0;";
! Lichtszene auswählen
string s_scene = s_scenes.StrValueByIndex(";", i_btn);
! durch Aktoren iterieren
string s_channels_idx;
object o_item;
object o_dp;
integer i_active;
integer i_channel;
integer i_count = 2;
while (i_count > 0) {
i_channel = 0;
i_count = i_count - 1;
foreach (s_channels_idx, s_channels) {
i_channel = i_channel + 1;
o_item = dom.GetObject(s_channels_idx);
i_active = s_scene.StrValueByIndex(":", i_channel).ToInteger();
if (i_active == i_count) {
if (o_item.HssType() == "DIMMER") {
o_item.DPByHssDP("RAMP_TIME").State(2.0); ! schnell einschalten
o_dp = o_item.DPByHssDP("LEVEL");
} else {
o_dp = o_item.DPByHssDP("STATE");
}
if (o_dp.Value() != i_active) {
o_dp.State(i_active);
}
}
}
}
! Ende des Scripts
Eigentlich ziemlich selbsterklärend, oder? Na gut – ein, zwei Sätze vielleicht doch.
Fernbedienungstaste bestimmen
$src$ liefert in Scripten die ID des Objekts, von dem das Programm ausgelöst wurde.
Bei einer Fernbedienungstaste ist das genau der Kanal, der betätigt wurde, mit dem
Zustand „langer“ oder „kurzer“ Tastendruck.
Die Fernbedienungstasten sind paarweise angeordnet. Es gibt also nicht Taste 1, Taste
2, Taste 3 usw., sondern Paar 1 – Taste 1, Paar 1 – Taste 2, Paar 2 – Taste 1 usw. Für
den weiteren Programmablauf ist es einfacher, wenn die Tasten durchnummeriert sind. Die
Zählung beginnt dabei mit 0.
Bei der Gelegenheit wird auch der lange vom kurzen Tastendruck getrennt: 0-11 für
kurzen Tastendruck, 12-23 für langen.
Ein kurzer Tastendruck auf die linke Taste des zweiten Tastenpaares liefert also
„2“, ein langer Tastendruck „14“.
Als nächstes folgt eine Liste der Kanalnamen, unter denen die einzelnen Aktoren für
die Beleuchtung angesprochen werden können.
Den Lumibär gibt es bei Flötotto, der Geist kommt von IKEA und die Lavalampen
natürlich von Mathmos. Nur, falls sich jemand wundert.
Die Lichtszenen sind ebenfalls eine Zeichenkette: Für jede Taste der Fernbedienung
(0-11) gibt es eine Lichtszene. In jeder Lichtszene wiederum ist der Zustand des
jeweiligen Kanals definiert, wobei die Reihenfolge der Kanaldefiniton entspricht.
Beispiel: Bei „Couchtisch“ werden die sechste bis elfte Leuchte
eingeschaltet, also alles von „Lavalampen“ bis „Vitrine 2“.
Die einzelnen Lichtszenen sind mit Semikolons abgetrennt, die einzelnen Kanäle durch
Doppelpunkte. Der Name am Anfang der Zeile dient nur der Übersicht – im Programm hat er
keine Funktion.
An dieser Stelle wird die Fernbedienungstaste einer Lichtszene zugeordnet.
Beispiel: Die linke Taste des zweiten Tastenpaares liefert Szene Nummer 2, wobei die
Zählung bei 0 beginnt. Mit anderen Worten: „Couchtisch“.
Schließlich der Programmablauf: Das Script geht jeden Kanal zweimal durch. Beim ersten
Durchlauf wird geprüft, ob der Kanal in der ausgewählten Szene aktiv sein soll und ggf.
eingeschaltet. Beim zweiten Durchlauf werden entsprechend die nicht benötigten Kanäle
ausgeschaltet.
Für Dimmer wird zusätzlich eine Rampenzeit von 2 Sekunden eingestellt, um das Licht
etwas sanfter ein- und auszuschalten.
Anschließend werden alle Kanäle geschaltet, die noch nicht den richtigen Zustand
haben.
Automatischer Dimmer
Beim einfachen Script werden die Dimmer wie Schaltaktoren behandelt. Lediglich für das
sanfte Ein- und Ausschalten wird die Dimmerfunktion genutzt. Das ist natürlich
langweilig.
Es wäre doch cool, wenn bei einigen Lichtszenen die gedimmten Leuchten eine sanfte
Hintergrundbeleuchtung geben, und zwar automatisch an die Gesamthelligkeit angepasst. Bei
anderen sollen sie ausgeschaltet bleiben – ich mag es nicht, wenn mein Deckenfluter sich
im Fernseher spiegelt – oder mit voller Helligkeit leuchten.
Zeit für ein verbessertes Script.
gesamtes Script markieren / kopieren
! HomeMatic-Script
! LICHTSZENEN PER SCRIPT SCHALTEN
! http://www.christian-luetgens.de/homematic/programmierung/beleuchtung/lichtszenen/Lichtszenen.htm
! Fernbedienungstaste bestimmen
! Tasten sind paarweise angeordnet, aber wir brauchen es linear
string s_src = dom.GetObject($src$).Name();
integer i_chn = s_src.StrValueByIndex(".", 1).StrValueByIndex(":", 1).ToInteger();
if (s_src.StrValueByIndex(".", 2) == "PRESS_LONG") {
i_chn = i_chn + 12; ! für langen Tastendruck bei 12-Tasten-FB
}
integer i_btn = 0;
while (i_chn > 1) {
i_chn = i_chn - 1;
i_btn = i_btn + 1;
}
! Kanäle
string tab = "\t";
string prefix = "Wohnzimmer.Licht.";
string s_channels =
prefix # "Fluter Fernseher" # tab #
prefix # "Fluter Sofa" # tab #
prefix # "Esstisch" # tab #
prefix # "Geist" # tab #
prefix # "Plattenregal" # tab #
prefix # "Lavalampen" # tab #
prefix # "Lumibaer" # tab #
prefix # "Sofabeleuchtung" # tab #
prefix # "Sonne" # tab #
prefix # "Vitrine 1" # tab #
prefix # "Vitrine 2";
! Lichtszenen
string s_scenes =
"Wohnzimmer :1:1:0:1:1:1:1:1:0:1:1;" #
"Esszimmer :0:0:1:1:0:0:1:0:0:1:1;" #
"Couchtisch :2:2:0:0:1:1:1:1:1:1:1;" #
"alles aus :0:0:0:0:0:0:0:0:0:0:0;" #
"Ambiente dunkel:0:2:0:1:0:1:0:1:0:0:0;" #
"Ambiente hell :2:2:0:1:1:1:1:1:0:1:1;" #
"Effekte :0:0:0:1:0:1:1:0:0:0:0;" #
"Plattenregal :2:2:0:1:1:1:1:0:0:0:0;" #
"alles ein :1:1:1:1:1:1:1:1:1:1:1;" #
"alles aus :0:0:0:0:0:0:0:0:0:0:0;";
! Lichtszene auswählen
string s_scene = s_scenes.StrValueByIndex(";", i_btn);
! durch Aktoren iterieren
string s_channels_idx;
object o_item;
object o_dp;
integer i_active;
integer i_channel;
integer i_count = 2;
real r_dimmer;
while (i_count > -1) {
i_channel = 0;
i_count = i_count - 1;
foreach (s_channels_idx, s_channels) {
i_channel = i_channel + 1;
o_item = dom.GetObject(s_channels_idx);
i_active = s_scene.StrValueByIndex(":", i_channel).ToInteger();
if (i_active == i_count) {
if (o_item.HssType() == "DIMMER") {
o_dp = o_item.DPByHssDP("LEVEL");
if (o_dp.Value() != i_active) {
! schnell einschalten, langsam ausschalten
o_item.DPByHssDP("RAMP_TIME").State(2.0 + (3.0 * (1 - i_active)));
o_dp.State(i_active);
}
} else {
o_dp = o_item.DPByHssDP("STATE");
if (o_dp.Value() != i_active) {
o_dp.State(i_active);
}
r_dimmer = r_dimmer + (0.05 * i_active);
}
}
if ((i_active == 2) && (i_count == -1) && (o_item.HssType() == "DIMMER")) {
o_item.DPByHssDP("RAMP_TIME").State(10.0); ! langsam Helligkeit ändern
o_item.DPByHssDP("LEVEL").State(r_dimmer);
}
}
}
! Ende des Scripts
Der größte Teil ist unverändert. Hier die Änderungen.
In der Definition der Lichtszenen gibt es jetzt nicht mehr nur „1“ für
„ein“ und „0“ für „aus“, sondern auch „2“ für
„gedimmt“.
Die Deckenfluter (ja, schon wieder IKEA) sind in der „Wohnzimmer“-Szene
eingeschaltet, in der „Esszimmer“-Szene aus und beim „Couchtisch“
gedimmt.
Das Programm hat jetzt die Variable r_dimmer hinzubekommen. Außerdem gibt es nun drei
Durchläufe.
Beim ersten Durchlauf werden wie bisher die gewünschten Aktoren eingeschaltet.
r_dimmer wird für jeden eingeschalteten Aktor um 5 % erhöht. Beim zweiten Durchlauf
werden ebenfalls wie bisher die nicht benötigten Aktoren ausgeschaltet. Wer genau
hinschaut, kann hier auch eine Neuerung bei den Rampenzeiten der Dimmer sehen: Sie
schalten sich schneller ein als aus.
Der dritte Durchlauf schließlich setzt die Dimmer auf den mit r_dimmer bestimmten
Wert, wenn „2“ in der Lichtszene ausgewählt ist. Die Rampenzeit sind hier
gemächliche 10 Sekunden.
Systemvariable schalten
Meine Vitrinen haben Tür-/Fensterkontakte,
mit denen das Licht automatisch beim Öffnen ein- und ausgeschaltet wird. Wenn sie in
Lichtszenen vorkommen, sollen sie aber nicht ihre Beleuchtung selbsttätig ausschalten.
Darum habe ich für sie die Sperrung
eingerichtet und schalte sie indirekt über Systemvariable.
Die letzte Änderung des Scripts berücksichtigt daher auch Objekte, die Systemvariable
sind und keine Schaltaktoren oder Dimmer.
gesamtes Script markieren / kopieren
! HomeMatic-Script
! LICHTSZENEN PER SCRIPT SCHALTEN
! http://www.christian-luetgens.de/homematic/programmierung/beleuchtung/lichtszenen/Lichtszenen.htm
! Fernbedienungstaste bestimmen
! Tasten sind paarweise angeordnet, aber wir brauchen es linear
string s_src = dom.GetObject($src$).Name();
integer i_chn = s_src.StrValueByIndex(".", 1).StrValueByIndex(":", 1).ToInteger();
if (s_src.StrValueByIndex(".", 2) == "PRESS_LONG") {
i_chn = i_chn + 12; ! für langen Tastendruck bei 12-Tasten-FB
}
integer i_btn = 0;
while (i_chn > 1) {
i_chn = i_chn - 1;
i_btn = i_btn + 1;
}
! Kanäle
string tab = "\t";
string prefix = "Wohnzimmer.Licht.";
string s_channels =
prefix # "Fluter Fernseher" # tab #
prefix # "Fluter Sofa" # tab #
prefix # "Esstisch" # tab #
prefix # "Geist" # tab #
prefix # "Plattenregal" # tab #
prefix # "Lavalampen" # tab #
prefix # "Lumibaer" # tab #
prefix # "Sofabeleuchtung" # tab #
prefix # "Couchtisch" # tab #
prefix # "Vitrinen";
! Lichtszenen
string s_scenes =
"Wohnzimmer :1:1:0:1:1:1:1:1:0:1;" #
"alles aus :0:0:0:0:0:0:0:0:0:0;" #
"Couchtisch :2:2:0:0:1:1:1:1:1:1;" #
"Esszimmer :0:0:1:1:0:0:1:0:0:1;" #
"Ambiente dunkel:2:0:0:1:0:1:0:1:0:0;" #
"Ambiente hell :2:2:0:1:1:1:1:1:0:1;" #
"Effekte :0:0:0:1:0:1:1:0:0:0;" #
"Plattenregal :2:2:0:1:1:1:1:0:0:0;" #
"alles ein :1:1:1:1:1:1:1:1:1:1;" #
"alles aus :0:0:0:0:0:0:0:0:0:0;";
! Lichtszene auswählen
string s_scene = s_scenes.StrValueByIndex(";", i_btn);
! durch Aktoren iterieren
string s_channels_idx;
object o_item;
object o_dp;
integer i_active;
integer i_channel;
integer i_count = 2;
real r_dimmer;
while (i_count > -1) {
i_channel = 0;
i_count = i_count - 1;
foreach (s_channels_idx, s_channels) {
i_channel = i_channel + 1;
o_item = dom.GetObject(s_channels_idx);
i_active = s_scene.StrValueByIndex(":", i_channel).ToInteger();
if (i_active == i_count) {
if (o_item.IsTypeOf(OT_VARDP)) {
if (o_item.Value() != i_active) {
o_item.State(i_active);
}
} else {
if (o_item.HssType() == "DIMMER") {
o_dp = o_item.DPByHssDP("LEVEL");
if (o_dp.Value() != i_active) {
! schnell einschalten, langsam ausschalten
o_item.DPByHssDP("RAMP_TIME").State(2.0 + (3.0 * (1 - i_active)));
o_dp.State(i_active);
}
} else {
o_dp = o_item.DPByHssDP("STATE");
if (o_dp.Value() != i_active) {
o_dp.State(i_active);
}
r_dimmer = r_dimmer + (0.05 * i_active);
}
}
}
if ((i_active == 2) && (i_count == -1) && (o_item.HssType() == "DIMMER")) {
o_item.DPByHssDP("RAMP_TIME").State(10.0); ! langsam Helligkeit ändern
o_item.DPByHssDP("LEVEL").State(r_dimmer);
}
}
}
! Ende des Scripts
Auch hier nur kleine Änderungen.
Kanaldefinition und Lichtszenen
Die Kanaldefiniton verweist nicht mehr auf die einzelnen Aktoren („Vitrine 1“
und „Vitrine 2“), sondern auf die Systemvariable („Vitrine“ –
einfallslos, ich weiß).
Auch die Lichtszenen wurden entsprechend angepasst: Es gibt überall eine Leuchte
weniger.
Beim Schalten der Aktoren wird nicht nur auf Schaltaktoren und Dimmer geprüft, sondern
auch auf Systemvariable. Für Schaltaktoren und Dimmer werden die entsprechenden
Datenpunkte geschaltet – für Systemvariable halt die Systemvariable.
Zusätzliche Sender
Um Lichtszenen aus anderen Programmen auszulösen, kann man nun einfach die
entsprechende Fernbedienungstaste per Programm betätigen und das Script als Unterprogramm starten.
Wenn ich lange auf den Taster für meine Treppenhausbeleuchtung drücke, geht im
Wohnzimmer das Licht aus. Auf ähnliche Art kann ich auch z. B. bei Abwesenheit das Licht
ausschalten oder die Lichtszenen mit anderen Ereignissen verknüpfen.