NEWS
[Skript] Verständnisfrage Trigger
-
Hi allerseits, ganz kurze Frage:
on(id1[1][5], function (dp) { //Bei Änderung AstroChoice
MyTimer[1][5] = getState(id1[1][5]).val; //Nach Änderung neuen Wert einlesen
KillTimer(1);
SetTimer(1);
if (logging) log("AstroChoice geändert");
});funktioniert einwandfrei. Ersetz ich jetzt aber die 1er mit ner Variable wie geplant, krieg ich beim getState nen Fehler. Warum?
Also SO gehts nicht:
var x=1;
on(id1[x][5], function (dp) { //Bei Änderung AstroChoice
MyTimer[x][5] = getState(id1[x][5]).val; //Nach Änderung neuen Wert einlesen
KillTimer(x);
SetTimer(x);
if (logging) log("AstroChoice geändert");
});Wo is mein (Denk-)Fehler?
-
@Pittini Hallo erstmal. Setz deinen Code doch bitte in den entsprechenden Code Tag, damit man ihn besser lesen kann. (Links vom Link, der Kette).
//Sieht dann so aus. on(id1[x][5], function (dp) { [...] });
Was ist denn der Fehler?
Log mal id1[x][5] vor dem getState.Ändert sich x im Laufe des scripts?
-
Ich vermute, du bist gerade auf folgendes Problem (analog) gestoßen:
https://wsvincent.com/javascript-closure-settimeout-for-loop/In vielen Fällen lässt sich das durch
let
anstattvar
und/oder Arrow-Funktionen() => { ... }
anstattfunction() { ... }
lösen. Dazu müssten wir aber vollständigen Code sehen -
Ok, zum ganzen Code, erstmal kurz ne Erklärung was der eigentlich soll bzw. was mein Plan ist.
Ich hab keinen flexiblen Timer gefunden den ich beliebig Anpassen und einsetzen kann, also dacht ich selbermachen und wenns was taugt freut sich sicher auch die Community dann. Zum Code gibts auch ein passendes visFür einen An,Aus Timer braucht man 2 dieser Blöcke, es gehen aber auch mehr. Im Dropdown gibts auch die Option "Zeit", daurch ändert sich das vis zu:
Im script leg ich die Datenpunkte einmalig an und Kommentier den Teil des scripts dann aus. Das isn Workaround weil mir sonst die Datenpunkt immer mit den defaults überschrieben werden. Egal, dasn anderes Problem, der Workaround funktioniert ja.
Die ganze Struktur ist als mehrdimensionales Array angelegt, die erste Ebene zählt einfach die Timer durch, auf der 2ten liegen dann quasi die Eigenschaften meines spezifischen Timers.
So kann ich beliebig viele Timer anlegen und Verwalten da alles durch Loops erzeugt wird.
Tja und nu wollte ich ja eigentlich auch die Trigger loopen weil sich da ja nix ändert. Genau da hustet mir js aber was.
Hier der ganze Code://Wichtige Einstellungen const AnzahlTimer = 2; //Wieviele Timer anlegen? Der erste ist 1, nicht 0! const id0 = "broadlink2.0.States.Outlet_2"; //Zu schaltendes Device const logging = true; //Logmeldungen an/aus const praefix = "javascript.1.Meine_Geraete.Outlet_2.Zeitschaltung."; //Produktiv auf 0, zum testen auf 1 var Wochentage = ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"]; //Array für createStateschleife zum anlegen der Wochentage var Astrotrigger = ["dawn", "sunrise", "dusk", "goldenHour", "dusk", "sunset"]; //Array für Astro var TimerState = ["Ein", "Aus"]; //if (logging) { log(Astrotrigger.length.toString()) }; var x; //Anzahl der Timer var y; //Zähler für Wochentage var z; //Zähler /* for (x = 1; x < AnzahlTimer + 1; x++) { //Datenpunkte anlegen createState(praefix + x + ".Aktiv", false, { read: true, write: true, name: "Timer aktiv", type: "boolean", role: "switch", def: false }); //Legt fest ob der Timer aktiv ist createState(praefix + x + ".Rolle", true, { read: true, write: true, name: "Rolle", type: "boolean", role: "switch", def: true }); //Legt fest ob der Timer für An oder Aus zuständig ist createState(praefix + x + ".TimerTimestamp", "00:00:00", { read: true, write: true, name: "Zeitstempel für schaltzeit", type: "string" }); createState(praefix + x + ".TimerAstroTimestamp", "00:00:00", { read: true, write: true, name: "Zeitstempel für Astroschaltzeit", type: "string" }); createState(praefix + x + ".TimerAstroShift", 0, { read: true, write: true, name: "Zeitverschiebung für Astroschaltzeit", type: "number" }); for (y = 0; y < 7; y++) { //Einträge für jeden Wochentag anlegen createState(praefix + x + ".Timer" + Wochentage[y], true, { read: true, write: true, name: Wochentage[y], type: "boolean", role: "switch", def: true }); } createState(praefix + x + ".TimerChoice", "Zeit",{ read: true, write: true, name: "Funktionswahl für Timer/Astro", type: "string", def: "Zeit" }); //Gewählte Funktion, Timer oder Astro }; //**************************** */ //Datenpunkte Id"s zuweisen //x = 0; //Anzahl der Timer //z = 0; //Schleifenvariable für Wochentage var id1 = []; for (x = 1; x < AnzahlTimer + 1; x++) { y = 0; id1[x] = []; id1[x][y] = (praefix + x + ".Aktiv"); y = y + 1; id1[x][y] = (praefix + x + ".Rolle"); y = y + 1; id1[x][y] = praefix + x + ".TimerTimestamp"; y = y + 1; id1[x][y] = praefix + x + ".TimerAstroTimestamp"; y = y + 1; id1[x][y] = praefix + x + ".TimerAstroShift"; y = y + 1; id1[x][y] = praefix + x + ".TimerChoice"; y = y + 1; for (z = 0; z < Wochentage.length; z++) { id1[x][y] = praefix + x + ".Timer" + Wochentage[z]; y = y + 1; }; }; if (logging) { for (x = 1; x < AnzahlTimer + 1; x++) { for (z = 0; z < id1[x].length; z++) { if (logging) log(id1[x][z] + " z=" + z + " x=" + x); }; }; }; // TimerVariablenArray anlegen für schedules var TimerAction = []; for (x = 1; x < AnzahlTimer + 1; x++) { TimerAction[x] = null; }; //Alle Daten in MyTimer Array einlesen var MyTimer = []; for (x = 1; x < AnzahlTimer + 1; x++) { MyTimer[x] = []; for (y = 0; y < id1[x].length; y++) { //log("x=" + x + " y=" + y); MyTimer[x][y] = getState(id1[x][y]).val; //log(MyTimer[x][y]); }; }; function MakeCronString(whichone) { //String nach Cronsyntax zusammenbauen für Schedule var DaysSubString = ""; for (x = 0; x < 7; x++) { if (MyTimer[whichone][x + 6] == true) { //Beginnend mit dem 6ten Eintrag (TimerSonntag) die 7 Wochentage durchzählen und Werte anhängen DaysSubString = DaysSubString + x + ","; }; }; DaysSubString = DaysSubString.substr(0, DaysSubString.length - 1);//Komma am Ende entfernen log(DaysSubString); var tempString = ""; if (MyTimer[whichone][5] == "Zeit") { //Wenn Zeit gewählt tempString = SplitTime(MyTimer[whichone][2])[1] + " " + SplitTime(MyTimer[whichone][2])[0] + " * * " + DaysSubString; log("CronString für Timer ausgelöst " + tempString); } else if (MyTimer[whichone][5] != "Zeit") { //Wenn Astro gewählt var tempTime = calcTime(whichone); tempString = SplitTime(tempTime)[1] + " " + SplitTime(tempTime)[0] + " * * " + DaysSubString; // tempString = SplitTime(MyTimer[whichone][3])[1] + " " + SplitTime(MyTimer[whichone][3])[0] + " * * " + DaysSubString; log("Cronstring für Astro ausgelöst " + tempString); }; return tempString; }; //spezifischen Timer setzen function SetTimer(whichone) { if (MyTimer[whichone][0] == true) { //Ist der Timer aktiv? log("Timer " + whichone + " Set") TimerAction[whichone] = schedule(MakeCronString(whichone), function () { DoAction(whichone); }); }; }; //Alle Timer setzen function SetAllTimer() { for (x = 1; x < AnzahlTimer + 1; x++) { SetTimer(x); } }; //spezifischen Timer löschen function KillTimer(whichone) { clearSchedule(TimerAction[whichone]); log("Timer " + whichone + " killed"); } //Shift mit Astrotime verrechnen function calcTime(whichone) { var Shift = parseInt(MyTimer[whichone][4]); //Wert für Shift var AstroTime = getDateObject(MyTimer[whichone][3]); //Astrotime einlesen //log(AstroTime); AstroTime.setMinutes(AstroTime.getMinutes() + Shift);//zammrechna log("Astrozeit mit Shift verrechnet. Neue Zeit=" + AstroTime.toLocaleTimeString()); return AstroTime.toLocaleTimeString(); }; /*/Astro oder Zeit Gateway function AstroOrTime(whichone) { if (MyTimer[whichone][5] == "Zeit") { log("Zeit gewählt " + MyTimer[whichone][2]); } else if (MyTimer[whichone][5] != "Zeit") { GetChoosenAstroTime(whichone); log("Astro gewählt, Variante " + MyTimer[whichone][5]); }; };*/ function GetChoosenAstroTime(whichone) { //Zeit für gewählte Astrozeit eintragen var Shift = MyTimer[whichone][4]; //Wert für Shift var AstroTime = MyTimer[whichone][3]; //Wert für Astrotime var AstroChoice = MyTimer[whichone][5].trim(); //Wert für Astroereignis AstroTime = getAstroDate(AstroChoice).toLocaleTimeString(); log(Shift + AstroTime + AstroChoice); setState(id1[whichone][3], AstroTime); }; function DoAction(whichone) { if (MyTimer[whichone][0] == true) { //Wenn Timer aktiv if (MyTimer[whichone][1] == true) { // Wenns ein Anschalter ist setState(id0, true); log("Timer " + whichone + " hat angeschaltet"); } else if (MyTimer[whichone][1] == false) { //Wenns ein Ausschalter ist setState(id0, false); log("Timer " + whichone + " hat ausgeschaltet"); }; }; }; function main(){ SetAllTimer(); }; main(); //Trigger für Timer1 on(id1[1][5], function (dp) { //Bei Änderung AstroChoice MyTimer[1][5] = getState(id1[1][5]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("AstroChoice geändert"); }); on(id1[1][1], function (dp) { //Bei Änderung AstroChoice MyTimer[1][1] = getState(id1[1][1]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("Rolle geändert"); }); on(id1[1][4], function (dp) { //Bei Änderung Shift MyTimer[1][4] = getState(id1[1][4]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("Shift geändert"); }); on(id1[1][2], function (dp) { //Bei Änderung Zeit (TimerTimestamp) setTimeout(function () { //1sek Timeout um prellen zu vermeiden MyTimer[1][2] = getState(id1[1][2]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("TimerTimestamp Zeit geändert auf " + MyTimer[1][2]); }, 1000); }); on(id1[1][0], function (dp) { //Bei Änderung Timer Aktiv MyTimer[1][0] = getState(id1[1][0]).val; //Nach Änderung neuen Wert einlesen if (logging) log("TimerActive geändert auf " + MyTimer[1][0]); KillTimer(1); //SetTimer(1); }); on(id1[1][6], function (dp) { //Bei Änderung Wochentage MyTimer[1][6] = getState(id1[1][6]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("TimerTag " + Wochentage[0] + " geändert auf " + MyTimer[1][6]); }); on(id1[1][7], function (dp) { //Bei Änderung Wochentage MyTimer[1][7] = getState(id1[1][7]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("TimerTag " + Wochentage[1] + " geändert auf " + MyTimer[1][7]); }); on(id1[1][8], function (dp) { //Bei Änderung Wochentage MyTimer[1][8] = getState(id1[1][8]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("TimerTag " + Wochentage[2] + " geändert auf " + MyTimer[1][8]); }); on(id1[1][9], function (dp) { //Bei Änderung Wochentage MyTimer[1][9] = getState(id1[1][9]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("TimerTag " + Wochentage[3] + " geändert auf " + MyTimer[1][9]); }); on(id1[1][10], function (dp) { //Bei Änderung Wochentage MyTimer[1][10] = getState(id1[1][10]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("TimerTag " + Wochentage[4] + " geändert auf " + MyTimer[1][10]); }); on(id1[1][11], function (dp) { //Bei Änderung Wochentage MyTimer[1][11] = getState(id1[1][6]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("TimerTag " + Wochentage[5] + " geändert auf " + MyTimer[1][11]); }); on(id1[1][12], function (dp) { //Bei Änderung Wochentage MyTimer[1][12] = getState(id1[1][12]).val; //Nach Änderung neuen Wert einlesen KillTimer(1); SetTimer(1); if (logging) log("TimerTag " + Wochentage[6] + " geändert auf " + MyTimer[1][12]); }); //***************Zeit in Stunden und Minuten teilen für späteren Cronstring function SplitTime(Time) { var timesplit = Time.split(":", 2); //h = timesplit[0] / m = timesplit[1]; return timesplit; }; // Ab hier Tests, einfach ignorieren //if (logging) { log(SplitTime("12:05") + h + m) }; //***************
Das ist mein Zwischenstand der soweit funktioniert, is aber noch nicht ganz fertig und nur minimal getestet.
Ich verwende btw. kein astro schedule, sondern mache alles mitm normalen schedule.So das ganze ist jetzt für einen Timer, meist brauch ich aber mind. zwei davon (Ein/Aus) also war der Plan unten im Teil der mitt Trigger Timer1 kommentiert ist, die ganzen on auch zu loopen was dann so aussähe:
//Trigger für Timer1 for (x = 1; x < AnzahlTimer+1; x++) { on(id1[x][5], function (dp) { //Bei Änderung AstroChoice MyTimer[x][5] = getState(id1[x][5]).val; //Nach Änderung neuen Wert einlesen KillTimer(x); SetTimer(x); if (logging) log("AstroChoice geändert"); }); };
Starten kann ich das Script jetzt, aber sobald der Trigger auslöst, also das getState ausgeführt wird kommt:
18:16:36.719 error javascript.0 at Object.<anonymous> (script.js.Meine_Geräte.Steckdose2.Timer:175:40)
Tja und nu steh ich da und verstehs nicht. Was nix heißen muss, ich bin n Dinosaurier und ganz sicher nicht uptodate.
Wäre nett wenn noch mal wer drüberschaut. -
@Pittini sagte in [Skript] Verständnisfrage Trigger:
Tja und nu steh ich da und verstehs nicht. Was nix heißen muss, ich bin n Dinosaurier und ganz sicher nicht uptodat
Ändere
for (x = 1; x < AnzahlTimer+1; x++)
zu
for (let x = 1; x < AnzahlTimer+1; x++)
Ohne
let
(also mitvar
) ist der Wert vonx
nicht an den Schleifendurchlauf gebunden. D.h. zu dem Zeitpunkt, zu dem der Trigger aufgerufen wird, hatx
den WertAnzahlTimer+1
, welcher für alle Trigger-Callbacks genutzt wird.
Mitlet
hatx
den Wert, der dem jeweiligen Schleifendurchlauf entspricht. -
@AlCalzone Super, vielen Dank, zumindest kommt so schon mal kein Fehler mehr, wenngleich ichs nicht wirklich versteh, weil ja in Zeile 11 immer noch das Var x steht. Aber ich kann jetzt auf jeden Fall mal weitermachen.
Weist Du evtl auch noch warum meine createStates immer die Werte mit den defaults überschreiben? Geplant war ein anlegen nur wenn nicht vorhanden. Was ich jetzt mit auskommentieren mach, aber elegant ist das nicht mal für meine Verhältnisse.
Ach ja und weist kennst Du evtl das Phänomen das sich die Logeinträge vervielfachen immer so nach ca. 15 Stunden wirds einer mehr. Sieht dann z.B. so ausDas is übrigens vom Script unabhängig, is bei jedem. Nach nem Neustart des PCs is alles wieder normal, nach ca. 15 Stunden isses dann doppelt, dann dreifach usw.. Ich hab das mal als Bug abgehakt, aber vieleicht weißt Du ja näheres.