Hier mein Skriptentwurf. Ich konnte es nicht komplett testen, vermute aber, dass es so funktioniert, wie du es haben willst.
// von eiche für deebeo, 2024-03-26
// begin of configuration
let MeasureComponent = "switch:0", // Messkomponente
SwitchOut = 1, // Welcher Ausgang soll geschaltet werden?
Level1 = 50, // unterer Wert zum ausschalten
Level2 = 100, // oberer Wert zum einschalten
Duration1 = 30, // Mindestdauer Unterschreitung des Level1 zum ausschalten
Duration2 = 30, // Mindestdauer Überschreitung des Level2 zum einschalten
// end of configuration
Time = null, LastPower = null, CurrentPower = null;
function startTime(result) {
//print(JSON.stringify(result));
if(result.uptime!==undefined) {
Time = result.uptime;
print("Time Startwert:", Time);
}
}
function checkTime(result) {
//print(JSON.stringify(result));
if(result.uptime !== undefined && Time !== null) {
let dt = result.uptime - Time;
print("Dauer:", dt);
if(CurrentPower > Level2 && dt >= Duration2) {
print("Ausgang " + SwitchOut + " einschalten");
Shelly.call("switch.set", {id:SwitchOut, on:true}); // Schaltausgang einschalten
}
else if(CurrentPower < Level1 && dt >= Duration1) {
print("Ausgang " + SwitchOut + " ausschalten");
Shelly.call("switch.set", {id:SwitchOut, on:false}); // Schaltausgang ausschalten
}
}
}
function processStatus(status) {
if(status.component === MeasureComponent
&& status.delta !== undefined
&& status.delta.apower !== undefined) {
print(JSON.stringify(status));
LastPower = CurrentPower;
CurrentPower = status.delta.apower;
if(CurrentPower < Level1) {
if(LastPower === null || LastPower >= Level1) Shelly.call("sys.getstatus", {}, startTime);
else Shelly.call("sys.getstatus", {}, checkTime);
}
else if(CurrentPower > Level2) {
if(LastPower === null || LastPower <= Level2) Shelly.call("sys.getstatus", {}, startTime);
else Shelly.call("sys.getstatus", {}, checkTime);
}
else Time = null; // Time ungültig machen
}
}
Shelly.addStatusHandler(processStatus);
Alles anzeigen
Das Problem besteht darin, dass der Status keine erforderliche Zeitinformation mitbringt.
Deshalb habe ich in der StatusHandler Funktion per Methode "Sys.GetStatus" diese Zeit abgefragt.
Weil aber eine solche Abfrage asynchron ist, muss die Verarbeitung von Zeit, Dauer und Leistung in der callback Funktion des Methodenaufrufs erfolgen.
Wenn die aktuelle Leistung erstmals oberhalb Level2 liegt, wird die Zeit gespeichert, ebenso wenn die aktuelle Leistung erstmals unter Level1 liegt.
Liegt die aktuelle Leistung zwischen Level1 und Level2 einschließlich, wird die gespeicherte Zeit ungültig gemacht.
Solange die Leistung unter Level1 liegt, wird deren Dauer per Zeitdifferenz ermittelt und bei Überschreitung der konfigurierten Dauer der Schaltausgang ausgeschaltet.
Entsprechendes gilt, solange die Leistung über Level2 liegt.
Ich habe das Skript möglichst schlank gehalten, damit es leichter verständlich ist. Außerdem ist es bereits so imho sehr robust gestaltet.
Als Zeitwert nutze ich die uptime, weil diese immer existiert, was mit unixtime nicht zwingend der Fall ist.
Ich bin gespannt, wie es laufen wird und überarbeite das Skript gerne, wenn die gewünschte Funktionalität nicht erfüllt sein sollte.
Dann brauche ich möglichst detaillierte Informationen über das Fehlverhalten.
Edit:
Es kann sein, dass der Status nicht hinreichend oft gesendet wird. In diesem Fall muss ich noch einen Timer einbauen, der gestartet wird, wenn erstmalig Level1 unterschritten oder Level2 überschritten wird. Das ist kein Problem. Aber teste erst einmal ...!
Ich überarbeite das Skript, weil mit Sicherheit ein Timer erforderlich ist. Dann kann statt der uptime-Differenz vielleicht besser ein Periodenzähler genutzt werden. Ich denke über Vor- und Nachteile nach ...