NEWS
setTimeout Verständnisproblem
-
Hi,
ich überwache meinen Trockner mit einem Shelly und habe dafür ein kleines Skript geschrieben, dass die Leistungsuafnahme des Shelly überwacht.
Ich unterscheide zwischen off/ready/drying und cooldown
Cooldown sit der Knitterschutz, der Trockner macht am alle paar Sekunden ein paar Umdrehungen.
Dafür nutze ich ein settimeout von 10 min. Dieses wird gecleared wenn der Trockner wieder eine Umdrehung amcht und von daher wieder n paar W mehr braucht.
Theoretisch sollte er also erst sagen, dass der Trockner 10 min lang keinen mucks macht und ihn dann in ready schalten und mir eine Nachricht schicken.Wenn ich an der stelle Logbucheinträge mache, dann sind die timer auch gelöscht aber sie schicken mir trotzdem 10min später nachrichten.
Liegt das evtl an dem trigger mit on, das jedesmal eine neue Instanz gebildet wird?
[edit] laut recherche ist jeder aufruf mit "on" ein neuer Handle und somit setzt er halt keinen timer zurück, weil es in dem Handle keinen gibt. Und der Andere läuft fröhlich weiter.createState("javascript.0.Helper.DryerState", "off", {type: 'string',name: 'Zustand Trockner'});//cooldown/idle/drying/off //Function zum Ende function coolDown () { setState("javascript.0.Helper.DryerState", 'ready'); setState("javascript.0.Logbuch.array_LogMsg", ['info','Trockner fertig']); sendTo("telegram", "send", { text: 'ℹ️ - Trockner fertig.' }); } on({id: 'shelly.0.SHPLG-S#DCEB70#1.Relay0.Power', change: "any"}, async function (obj) { var power = getState("shelly.0.SHPLG-S#DCEB70#1.Relay0.Power").val; var dryerState = getState("javascript.0.Helper.DryerState").val; if (power > 0 && dryerState == 'off'){//Wird eingeschaltet dryerState = 'ready'; setState("javascript.0.Logbuch.array_LogMsg", ['info','Trockner eingeschaltet']); sendTo("telegram", "send", { text: 'ℹ️ - Trockner eingeschaltet.' }); }else if(power == 0 && dryerState != 'off'){ //wird Ausgeschaltet dryerState = 'off'; clearTimeout (cooldowntimer); //Coutndown unterbrechen setState("javascript.0.Logbuch.array_LogMsg", ['info','Trockner ausgeschaltet']); sendTo("telegram", "send", { text: 'ℹ️ - Trockner ausgeschaltet.' }); } else if (power > 20 && (dryerState == 'off' || dryerState == 'ready') ) { //beginnt mit Trocknen starttime = new Date().getTime(); dryerState = 'drying'; setState("javascript.0.Logbuch.array_LogMsg", ['info','Trockner gestartet.'+ power]); sendTo("telegram", "send", { text: 'ℹ️ - Trockner gestartet!' }); }else if(power < 20 && dryerState == 'drying' ) { //start Knitterschutz 10 min warten und dann als fertig erkennen dryerState = 'cooldown'; var cooldowntimer = setTimeout (coolDown, 600000); }else if(power > 20 && dryerState == 'cooldown'){ //trommel bewegt sich im Knitterschutz dryerState = 'drying'; clearTimeout (cooldowntimer); //Coutndown unterbrechen } setState("javascript.0.Helper.DryerState", dryerState); // Am Ende die lokale Variable auf den state übertragen });
Da ich das gleiche Prinzip auch eisnetzen möchte um zu sehen ob meine Entwässerungspumpen zu lange laufen, hätte ich das gerne verstanden.
Gruß
Nils -
2 Probleme sehe ich.
1)
der folgende befehl legt jedes mal ein neues timeout anvar cooldowntimer = setTimeout (coolDown, 600000);
damit du wieder darauf zugreifen kanns gibt er die ein handle/referenz zurück, anhand dessen javascript erkennt welchen du meinst.
durch das das du da var davor stehen hast, wird die bei jedem funktionsaufruf immer wieder neu initialisiert. der wert der drin steht ist bei verlassen der funktion verloren. d.h. auf genau diesen timeout kannst du nie wieder zugreifen.
also musst du die variable nach ausserhalb der funktion legen, damit der wert erhalten wird und sie auch nur einmal bei start des skripts initialisiert wirdwenn du das var entfernt hast, würdest du mit dem obigen befehl ja dennoch immer noch einen neuen timeout generieren und den anderen vergessen.
daher musst du zuvor prüfen, ob du schonmal einen timeout gestartet hast also bspw soif (cooldowntimer!=0) { clearTimeout(cooldowntimer); cooldowntimer=0; }
Nicht vergessen cooldowntimer beim initialisieren und auch nach jedem clearTimeout wieder auf 0 setzen.
-
@oliverio Danke Dir.
Ich habe gerade nochmal ganz lange nachgedacht ob ich das mit einem Zeitpunkt regeln kann aber stehe grad auf dem Schlauch.
Ich habe jetzt folgende Idee: Wie von dir gesagt den handle des Timers in ein objekt von ioBroker schreiben, und beim nächsten Aufruf, genau diesen Timer resetten, Jetzt läuft die Waschmaschine und nachher der Trockner, bin gespannt
[Edit: deine idee ist besser, ich setze mal beide Parallel um und schau mal welche geht.]
Nils -
@oliverio Hey kleine Rückmeldung.
Deine Lösung war die richtige.
Ist ja auch total sinnvoll, jedes on startet n neues handle. Alle darin deklarierten Variablen sind futsch.Danke für den Tipp.
Nils
-
@jmeister79
freut mich.
vor allem. das ist ein besipiel für ein speicherleck.
der reservierte bereich für den timeout geht ja solange nicht weg, bis der prozess (also skript oder gar javascript-adapter) neu gestartet wird.
wenn das jetzt sehr oft aufgerufen wird oder das skript längers läuft, dann wird der freie speicher immer weniger -
@oliverio ich hab hier zu nochmal neuigkeiten.
Trotz dieser Umbauten hat das nicht wirklich funktioniert. Der Timer hat manchmal ziemlichen Mist gebaut udn er hat mit der Zeit eine riesige SWAP Datei erzeugt.
Ich habe es ejtzt so umgebaut, dass ich auf den Änderugnszeitpunkt der Zustände schaue. das funktioniert zuverlässiger.
LG
Nils -
@jmeister79 sagte in setTimeout Verständnisproblem:
Ich habe es ejtzt so umgebaut,
Ich bin als Anfänger mit dem SetTimeout() und Cron auch schon schwer gegen die Wand gelaufen. Deshalb habe ich mir für mein Waschhaus eine Routine gebaut ohne diese zwei Timer. Ist allerdings nicht die schönste Technik.
// Pause Timer in Sekunden function Pause(ms=1) { ms=ms*1000; // Millisekunden return new Promise(resolve => setTimeout(resolve, ms)); } async function Waschhaus(){ While (true){ // Endlosschleife code..... await Pause(600); // hier wird dann der Code angehalten für 10 Minuten code.... await Pause(10); // stop 10 Sekunden usw... } } // Start Waschhaus();
tschuess