Hallo an alle, ich habe schon in einem anderem Thread: Externe Motion Steuerung ingorieren, wenn Shelly 1PM manuell einschalten wurde mein Script vorgestellt. Da es allerdings noch einen kleinen Bug hatte, habe ich es jetzt ausgebessert und möchte es euch hiermit in diesem Thread präsentieren. Der Grund, warum ich es in einem Extra Thread poste ist einfach der, daß mein Script zum Teil nicht das macht, was der TE sowie ein weiterer Zukömmling benötigte und Eiche den beiden bereits geholfen hat.
Wozu dient das Script:
Also ich nutze einen Bewegungsmelder, der in meinem Flur (beim durchlaufen) das Licht einschalten soll und nach einer gewissen Zeit, nachdem keine Bewegung mehr erkannt wurde wird das Licht wieder ausgeschaltet.
Dann habe ich noch einen Taster der bei einem Single_Push das Licht etwas länger laufen lassen soll und bei einem weiteren Single_Push das Licht ausschalten soll.
Soweit so gut bis hier hin braucht man keinen Shelly, wenn man den Taster gegen einen Schalter austauschen würde. Aber vielleicht möchte man es, wie ich, etwas Komfortabler haben, dann könnt ihr weiterlesen
Ich habe in meiner Lampe ein 10 Watt (Dimm-fähiges) LED Leuchtmittel eingeschraubt. Dieses ist manchmal Praktisch, wenn die Frau sich anzieht und am Spiegel schauen möchte ob es passt . Nachts allerdings ist es wirklich nervig, wenn man halb verschlafen durch den Flur läuft und man von einem Flutlicht angestrahlt wird. Deshalb habe ich mir den Shelly Dimmer2 angeschafft. Dieser regelt ja ganz Praktisch die Helligkeit eines dimm-fähigen Leuchtmittels . Aber da dieser ja nicht Scriptfähig ist braucht man wiederum ein Shelly gerät, das Scriptfähig ist. Hier nutze ich den Shelly I4. Aber Theoretisch sollte das Script mit jedem Shelly der Gen2 und vielleicht auch der Gen3 funktionieren.
Irgendwie Schweife ich ab, also nochmal von vorn und diesmal in Stichpunkten: Wozu dient dieses Script:
Bewegungsmelder registriert Bewegung -> Licht geht gedimmt an
Bewegungsmelder hat abgeschaltet, da keine Bewegung mehr registriert wurde -> Das Script erhält eine Meldung, und ein Timer für das ausschalten des Lichtes wird gestartet
(Kurze Anmerkung: ich habe den Blind-Timer des Bewegungsmelders auf die niedrigste Stufe gedreht, da ich die Ausschaltzeit über das Script regeln möchte)
Der Timer des Bewegungsmelders im Script ist abgelaufen -> Das Licht geht aus.
Der Taster wurde 1 mal gedrückt ->, das Licht geht für eine Gewisse Zeit (Einstellung im Script vorhanden als TimerDauerlicht) an. Der Bewegungsmelder hat keinen Einfluss mehr auf das Licht ( Ähnlich wie beim Dauerlicht)
Der Taster wurde noch einmal gedrückt (bevor der Timer (TimerDauerlicht) abgelaufen ist) -> das Licht geht aus und der Bewegungsmelder darf wieder arbeiten.
Der Taster wurde 2x gedrückt -> das Licht geht für eine Gewisse Zeit (TimerDauerlicht) an allerdings mit einer 100 % Helligket. Auch hier hat der Bewegungsmelder keinen Einfluss mehr auf das Licht.
Der Taster wurde noch einmal gedrückt (bevor der Timer (TimerDauerlicht) abgelaufen ist) -> das Licht geht aus und der Bewegungsmelder darf wieder arbeiten.
Der Timer (TimerDauerlicht) läuft ab -> das Licht geht aus und der Bewegungsmelder darf wieder arbeiten.
Dazu gibt es noch einen Tag- und einen Nachtmodus, Die Zeiten kann man im Script ebenfalls einstellen. Und für jeden Modus kann man dementsprechend die Helligkeit des Lichtes einstellen.
Wie wird was angeschlossen:
Den Bewegungsmelder habe ich direkt am Dimmer angeschlossen. Das hat den Vorteil, dass man das Licht sofort einschalten lassen kann. Wenn man den Bewegungsmelder an einem anderen gerät anschließt oder den Motion nutzt, gibt eine leichte Verzögerung wegen der Latenzzeiten im Netzwerk. Aber auch das funktioniert mit diesem Script.
Da ich den Dimmer2 habe, könnte ich auch den Taster am Dimmer anschließen. Allerdings ist der Taster bei mir am I4, auf dem das Script installiert ist, angeschlossen. Auch hier sind beide Varianten möglich. Auch der Shelly Button sollte für dieses Script kein Problem sein.
Was wird bei dem Gerät wo der Bewegungsmelder angeschlossen ist eingestellt:
(Ich gehe hier Hauptsächlich vom Dimmer2 aus! Andere Geräte können andere Bezeichnungen haben!)
Der Button Type des Shellys wird auf Detached - switch doesn't control dimmer output eingestellt.
BUTTON 1 SWITCHED ON URL: | 1: http://localhost/light/0?turn=on | <-- Dieser Eintrag ist nur nötig wenn der Bewegungsmelder direkt am Dimmer angeschlossen wird, |
2: http://<IP of Shelly I4>/script/<Skript-ID>/myTrigger?button=BM&push=on | ||
BUTTON 1 SWITCHED OFF URL: | 1: http://<IP of Shelly I4>/script/<Skript-ID>/myTrigger?button=BM&push=off |
Falls der Bewegungsmelder ein Shelly Motion ist, könnte folgendes zutreffen:
(Bitte beachtet, dass ich diese Information nicht mit absoluter Sicherheit bestätigen kann, da ich keinen Shelly Motion besitze. Die folgende Aussage basiert lediglich auf meiner Vermutung:)
MOTION DETECTED: | 2: http://<IP of Shelly I4>/script/<Skript-ID>/myTrigger?button=BM&push=on |
END OF MOTION DETECTED: | 1: http://<IP of Shelly I4>/script/<Skript-ID>/myTrigger?button=BM&push=off |
Was wird beim Gerät eingestellt an dem der Taster angeschlossen ist:
Ist der Taster am Gerät angeschlossen, auf dem das Script ausgeführt wird, dann muss nur bei den Input/Output settings der Type auf "Button" bzw. "Momentary - Set Shelly device to be "Momentary" switch..." eingestellt werden.
Ist der Taster an einem anderen Gerät angeschlossen oder beim Shelly Button dann muss noch zusätzlich bei:
BUTTON SHORT PRESSED URL oder BUTTON PUSH URL: | 2: http://<IP of Shelly I4>/script/<Skript-ID>/myTrigger?button=extbutton&push=single_push |
BUTTON LONG PRESSED URL oder BUTTON DOUBLE PUSH URL: | 1: http://<IP of Shelly I4>/script/<Skript-ID>/myTrigger?button=extbutton&push=double_push |
Insbesondere bei den GEN1-Geräten scheint es keine Option zu geben, eine Double Push URL einzurichten. In solchen Fällen muss man auf die Long Pressed URL und Methode zurückgreifen, um das Licht mit voller Leistung (100%) einzuschalten.
Darüber hinaus habe ich nicht Zugang zu allen Shelly-Geräten, um die spezifischen Bezeichnungen der einzelnen URL-Aktionen zu überprüfen. Die oben genannten Bezeichnungen stammen vom Shelly1 und Shelly 2PM. Es ist jedoch zu beachten, dass diese Bezeichnungen bei den verschiedenen Shelly-Modellen variieren können.
Das Script:
let ShellyIP = '192.168.1.2'; //IP-Adresse des Shellys, an dem das Licht angeschlossen ist
let TimerDauerlicht = 10; // Zeit die das Dauerlicht maximal an sein darf
let TimerDauerwert = "m"; // Wert für TimerDauerlicht (s=Sekunden, m=Minuten)
let dimState = 35; // Prozent Dimmerhelligkeit
let SWINT = true; /* Wert für die funktion des internen Tasters
(Wichtig, falls ein Taster oder Schalter an diesem Gerät angeschlossen ist,
der nicht den Dimmer schalten soll, muss der Wert auf "false" stehen!)*/
let SWID = 0; //TasterID (Muss nur angepasst werden, wenn der Taster an diesem Gerät und nicht am SW1 angeschlossen ist)
let ZeitNacht = "21:30"; // Uhrzeit für den Nachtmodus
let ZeitTag = "06:00"; // Uhrzeit für den Tagmodus
let DimNacht = 40; // Helligkeit bei Nachtmodus
let DimTag = 45; // Helligkeit bei Tagmodus
let BMTimer = 50; // Zeitdauer für den Bewegungsmelder
let BMTimerWert = 's'; // Einheit für BMTimer (s=Sekunden, m=Minuten)
let debug = false; // wenn true dann sende Ausgaben für Debug-Infos
/***************************************************************
* *
* Ab dieser Position Bitte nichts mehr ändern! *
* *
****************************************************************/
// Funktion zum Umrechnen der Uhrzeit in Minuten seit Mitternacht
function timeToMinutes(time)
{
let parts = time.split(':');
let stunden = Number(parts[0]);
let minuten = Number(parts[1]);
return stunden * 60 + minuten;
}
let nachtZeit = timeToMinutes(ZeitNacht);
let tagZeit = timeToMinutes(ZeitTag);
//Funktion zur Einstellung der Helligkeit im Tag- bzw. Nachtmodus
function adjustBrightness() {
let jetzt = new Date();
let stunden = jetzt.getHours();
let minuten = jetzt.getMinutes();
// Konvertiere die aktuelle Uhrzeit in Minuten seit Mitternacht
let aktuelleZeit = stunden * 60 + minuten;
if (aktuelleZeit >= nachtZeit || aktuelleZeit < tagZeit) {
// Wenn es nach der Nachtzeit oder vor der Tagzeit ist, setze die Helligkeit auf DimNacht
//setLightBrightness(ip, DimNacht);
dimState = DimNacht;
dPrint("Nachtmodus ist aktiv, Helligkeit ist bei " + DimNacht + "%");
} else {
// Ansonsten setze die Helligkeit auf DimTag
//setLightBrightness(ip, DimTag);
dimState = DimTag;
dPrint("Tagmodus ist aktiv, Helligkeit ist bei " + DimTag + "%");
}
}
// Funktion zum Umrechnen der Zeit in Millisekunden
function calcTime(timer, value){
let msec;
if(value === "s") {
msec = timer*1000;
} else {
msec = timer*60*1000;
}
return msec;
}
let SWTimer; // Variable für den Taster-Timer
let BMTimer; // Variable für den Bewegungsmelder-Timer
let SWtimerAktiv = false; // Variable, um den Status des Taster-Timers zu speichern
let BMtimerAktiv = false; // Variable, um den Status des Bewegungsmelder-Timers zu speichern
let bmZeit = calcTime(BMTimer, BMTimerWert); // Zeitdauer Bewegungsmelder in Millisekunden
let TDL = calcTime(TimerDauerlicht, TimerDauerwert); // Zeitdauer Taster in Millisekunden
//Funktion zur Überprüfung des Lichtes, wenn der Taster gedrückt wurde (Wenn Aus, dann an und umgekehrt nur aus wenn über Taster angeschaltet wurde)
function handleButtonPress(ip,DoublePress) {
adjustBrightness(); //reguliert den Tag- und Nachtmodus
isLightOn(ip, function(isOn) {
if (SWtimerAktiv && DoublePress === false) {
// Wenn das Licht durch den Taster eingeschaltet wurde, schalte es aus und setze SWtimerAktiv auf false
Timer.clear(SWTimer); //löscht den Timer
setLightBrightness(ip, dimState); //ändert die Helligkeit auf dimState (Wichtig: vor allem wenn das licht bei 100% ist, damit der BM wieder im gedimmten Modus einschaltet)
setLightBrightness(ip, 0); //(schaltet das Licht aus)
SWtimerAktiv = false; //Damit wird der BM wieder freigegeben
// Verwende die print Funktion, um eventuelle Fehler zu behandeln (debug muss auf true sein)
dPrint('Taster wurde 1x gedrückt: Licht wurde zuvor über den Taster eingeschaltet und wird daher jetzt Ausgeschaltet');
} else {
// Wenn das Licht aus ist oder durch den Bewegungsmelder eingeschaltet wurde, schalte es ein, starte den Timer und setze SWtimerAktiv auf true
if (DoublePress===false)
{
setLightBrightness(ip, dimState); //schaltet das Licht im gedimmten Modus ein
// Verwende die print Funktion, um eventuelle Fehler zu behandeln (debug muss auf true sein)
dPrint('Taster wurde 1x gedrückt: Licht wurde zuvor über nicht den Taster eingeschaltet und wird daher jetzt eingeschaltet');
}
else
{
setLightBrightness(ip, 100); //schaltet das Licht auf voller Last ein
// Verwende die print Funktion, um eventuelle Fehler zu behandeln (debug muss auf true sein)
dPrint('Taster wurde 2x gedrückt: wird daher mit 100% Helligkeit eingeschaltet');
}
//Timer wird gestartet damit das Licht nicht ewig brennt, wenn vergessen wird, das Licht über den Taster auszuschalten
SWTimer = Timer.set(TDL, false, function()
{
setLightBrightness(ip, dimState); //ändert die Helligkeit auf dimState (Wichtig: vor allem wenn das licht bei 100% ist, damit der BM wieder im gedimmten Modus einschaltet)
setLightBrightness(ip, 0); //(schaltet das Licht aus)
SWtimerAktiv = false; //Damit wird der BM wieder freigegeben
// Verwende die print Funktion, um eventuelle Fehler zu behandeln (debug muss auf true sein)
dPrint('Dauerlicht hat das Zeitlimit von '+ TDL + 'ms erreicht und wird jetzt ausgeschaltet');
}, null);
SWtimerAktiv = true; // Setze die Variable auf true, wenn das Licht eingeschaltet wird. Damit wird der BM gesperrt.
}
});
}
// Funktion zum Drucken von Debugging-Nachrichten
function dPrint(text){
if(debug===true){
print(text)
}
}
//Funktion zum einschalten des Lichtes mit der gesetzten Helligkeit
function setLightBrightness(ip, brightness) {
// Überprüfe, ob die Helligkeit größer als 0 ist
if (brightness > 0) {
// Wenn ja, schalte das Licht mit der angegebenen Helligkeit ein
let url = 'http://' + ip + '/light/0?turn=on&brightness=' + brightness;
Shelly.call("http.get", {url: url}, function (rs, ec, em) { }, null);
} else {
// Wenn nicht, schalte das Licht aus
let url = 'http://' + ip + '/light/0?turn=off';
Shelly.call("http.get", {url: url}, function (rs, ec, em) { }, null);
}
}
//Funktion zur Überprufung, ob das Licht an- oder ausgeschaltet ist.
function isLightOn(ip, callback) {
let url = 'http://' + ip + '/settings/light/0';
Shelly.call("http.get", {url: url}, function (response, error_code, error_message, ud) {
let resBody = JSON.parse(response.body);
if (resBody && typeof resBody.ison !== 'undefined') {
callback(resBody.ison);
} else {
// Verwende die print Funktion, um eventuelle Fehler zu behandeln (debug muss auf true sein)
dPrint('Fehler beim Abrufen des Lichtstatus: ', error_code, error_message);
callback(false);
}
}, null);
}
//Funktion zur Abfrage der HTTP-Get Parameter des Bewegungsmelders
function myCallback(optionalArg)
{
if (optionalArg && optionalArg.query)
{
//dPrint(optionalArg);
let optArg= optionalArg.query;
let ArgArray= getQueryParams(optArg);
if (ArgArray.button === "BM" && ArgArray.push === "off")
{
// Verwende die print Funktion, um eventuelle Fehler zu behandeln (debug muss auf true sein)
dPrint("Blindtime des Bewegungsmelders ist abgelaufen. Prüfe den Tasterstatus, ob weitere Aktionen notwendig sind...");
isLightOn(ShellyIP, function(isOn)
{
//dPrint("Licht ist an!");
if (!SWtimerAktiv)
{
BMtimerAktiv = true;
// Wenn der Timer nicht aktiv ist, schalte das Licht ein und starte einen neuen Timer
BMTimer = Timer.set(bmZeit, false, function()
{ // Setze den Timer auf bmZeit
adjustBrightness(); //reguliert den Tag- und Nachtmodus
setLightBrightness(ShellyIP, dimState); //ändert die Helligkeit auf dimState
setLightBrightness(ShellyIP, 0); // schaltet das Licht aus
// Verwende die print Funktion, um eventuelle Fehler zu behandeln (debug muss auf true sein)
dPrint("Es wurde keine weitere Bewegung registriert, und die Blindtime des Scriptes ist abgelaufen.");
dPrint("Das Licht wurde ausgeschaltet.");
BMtimerAktiv = false;
}, null);
// Verwende die print Funktion, um eventuelle Fehler zu behandeln (debug muss auf true sein)
dPrint("Timer von "+ bmZeit +"ms wurde gestartet da Bewegungsmelder aus ist und keine Taste vorher gedrückt wurde");
}
else
{
// Verwende die print Funktion, um eventuelle Fehler zu behandeln (debug muss auf true sein)
dPrint("Licht wurde mit Taster aktiviert, der Bewegungsmelder darf nicht ausschalten!");
}
});
}
if (ArgArray.button === "BM" && ArgArray.push === "on")
{
dPrint("Bewegungsmelder wurde angeschaltet und Überprüfung, ob BMTimer aktiv ist, wird durchgeführt");
if (BMtimerAktiv)
{
Timer.clear(BMTimer);
BMtimerAktiv = false;
// Verwende die print Funktion, um eventuelle Fehler zu behandeln (debug muss auf true sein)
dPrint("BMTimer war aktiv und wurde gelöscht");
}
}
// Ausführung eines externen Tasters (wie z.B.: der Shelly Button1 oder ein Taster an einem anderen Shelly )
if (ArgArray.button === "extbutton" && ArgArray.push === "single_push")
{
handleButtonPress(ShellyIP, false);
}
if (ArgArray.button === "extbutton" && ArgArray.push === "double_push")
{
handleButtonPress(ShellyIP, true);
}
}
}
// Registrierung des Endpunkts (myTrigger) für HTTP-Anfragen und Aufruf der Funktion myCallback
// Das heißt sobald das Script über die URL http://localhost/script/1/myTrigger?param1=value1¶m2=value2¶m3=value3
// aufgerufen wird, werden die Parameter (param1=value1¶m2=value2¶m3=value3) als String an die Funktion myCallback übergeben und bearbeitet
HTTPServer.registerEndpoint(
"myTrigger",
myCallback,
"callback_arg"
);
// Funktion zum Parsen von Query-Parametern aus einer URL
// Beispiel: Aus "http://localhost/script/1/myTrigger?param1=value1¶m2=value2¶m3=value3"
// wird ein Objekt erstellt: {"param1": "value1","param2": "value2","param3": "value3"}
function getQueryParams(str)
{
let result = {}; // Ein leeres Objekt wird erstellt, um die Parameter und ihre Werte zu speichern
let params = str.split('&'); // Die Eingabezeichenkette wird an jedem '&' aufgeteilt, um ein Array von Parametern zu erstellen
// Beispiel: Aus "param1=value1¶m2=value2¶m3=value3" wird
// ["param1=value1", "param2=value2", "param3=value3"]
// in der folgenden Schleife werden die Paramerter mit Namen und deren Wert in das Objekt eingetragen
params.forEach(function(param)
{
let paramParts = param.split('='); // Der Parameter wird an '=' aufgeteilt, um den Namen und den Wert des Parameters zu extrahieren
result[paramParts[0]] = paramParts[1]; // Der Parametername wird als Schlüssel und der Parameterwert als Wert zum Ergebnisobjekt hinzugefügt
});
return result; // Das Ergebnisobjekt, das die Parameter und ihre Werte enthält, wird zurückgegeben
}
//Funktion zur Überprüfung diverser Aktionen des Shelly I4 (in diesem Falle die Überprüfung, wie der Taster gedrückt wurde und was in dem Falle getan werden soll)
Shelly.addEventHandler(
function (event, user_data)
{
if (typeof event.info.event !== 'undefined' && SWINT === true)
{
if (event.info.id === SWID && event.info.event === 'single_push')
{
handleButtonPress(ShellyIP,false);
}
else if (event.info.id === SWID && event.info.event === 'double_push')
{
handleButtonPress(ShellyIP,true);
}
}
}
);
Alles anzeigen
Ich kann mir vorstellen, dass es einige abschrecken wird, diesen langen Text zu lesen. Aber wenn jemand ein ähnliches Projekt haben möchte, kann er hoffentlich dadurch eine gute Unterstützung finden.
Ich denke, damit sollte alles nötige gesagt sein. Ich wünsche euch viel Spaß damit
LG Maik