Es ließ mir keine Ruhe. Hier die verbesserte Version des Skripts.
Was habe ich verbessert?
- Das Skript ist besser strukturiert.
- Die Methode Script.Eval habe ich durch einen zweiten HTTP Endpoint ersetzt.
Solange in den remote Geräten solche Endpoints verwendet werden - und kein Script.Eval - wird das Skript nicht abgebrochen, auch wenn der Endpoint Name nicht passen sollte. - Die Protokollausgaben sind verständlicher und lassen den Ablauf leichter verfolgen.
- Der Ausgang, also dessen Id, kann per Variable out festgelegt werden.
Was bleibt wie es war?
Der Action URL in den Bewegungsmeldern, also nicht ändern! Endpoint Name lautet "on".
http://<IP Adresse des Schalt-Shelly>/script/<Skript Id>/on?<Dauer in Sekunden>
Was muss geändert werden?
Der Action URL in den Geräten, die remote umschalten, also ändern! Endpoint Name lautet "toggle".
http://<IP Adresse des Schalt-Shelly>/script/<Skript Id>/toggle
Beide Informationen werden bei Skriptstart im Protokollfenster mit aktuellen Werten ausgegeben.
// Created by Gerhard Eichelsdörfer alias eiche - 2024-03-13
let Retrigger = true, // Set to false if you don't want the motion to retrigger!
MotionName = "motion",
RemoteName = "remote",
out = 0, // output id
on = null, // output status
th = null, // timer handle
src = null; // source of switching
function send_response(response, body) {
response.code = 200;
response.body = body;
response.send();
}
function switchSet(id, state) {
Shelly.call("Switch.set", {id:id, on:state},
function(result, errcode, errmsg, ud) {
if(errcode!==0) print("error in switchSet(" + ud.id + ", " + ud.state + "): ", errcode, ", ", errmsg);
}, {id:id, state:state}
);
}
function startTimer(dur) {
Timer.clear(th);
if(dur>0) {
dur = Math.floor(1000*dur);
th = Timer.set(dur, false, function () {switchSet(out, false);});
print("Timer started for " + (dur/1000) +" seconds");
}
}
// from a remote motion sensor - with a duration value
HTTPServer.registerEndpoint('on',
function (request, response) {
send_response(response, "OK");
let dur = 0;
if(request.query.length > 0) dur = JSON.parse(request.query);
if(!isNaN(dur) && dur>0 && (!on || (Retrigger && src===MotionName))) startTimer(dur);
if(!on) {
src = MotionName;
switchSet(out, true);
}
}
);
// from a remote toggle call, e.g. from an i4.
HTTPServer.registerEndpoint('toggle',
function (request, response) {
send_response(response, "OK");
let tmp = src;
src = RemoteName;
let st = Shelly.getComponentStatus("switch:" + out);
if(st.output && tmp===MotionName) {
Timer.clear(th);
print("source: ", src, ", Timer cleared")
return;
}
Shelly.call("Switch.Toggle", {id:out},
function (result, errcode, errmsg, ud) {
if(errcode!==0) {
src = ud.src;
print(ud.msg, errcode, ", ", errmsg);
}
}, {src:tmp, msg:"error in remote toggle: "}
);
}
);
Shelly.addEventHandler(function(e) {
//print(JSON.stringify(e));
if(e.info.event==="toggle") {
on = e.info.state;
let st = Shelly.getComponentStatus("switch:" + out);
if(st.source!==undefined && st.source!=="loopback") src = st.source;
print("source: ", src, ", status: ", on ? "on" : "off");
}
});
//Do some user friendly printout
function messages() {
let ipAddress = Shelly.getComponentStatus("wifi").sta_ip;
if(ipAddress===null) ipAddress = '<IP address of your switching Shelly>';
let myId = Shelly.getCurrentScriptId();
print('The action URL of your motion is: http://' + ipAddress + '/script/' + myId + '/on?<duration in seconds>');
print('When switching via remote command, e.g. Shelly i4, the URL for the remote action is:');
print('http://' + ipAddress + '/script/' + myId + '/toggle');
}
messages();
let info = Shelly.getComponentStatus("switch:" + out);
//print(JSON.stringify(info));
src = info.source;
on = info.output;
Alles anzeigen