NEWS
Schleife um einen Eintrag zurück setzen
-
@paul53 Leider nicht, das wäre ja zu fixen.
Das Problem ist folgendes:
Das Script findet mit i=0 Arbeitszimmer, mit i=1 Lottizimmer und legt Ordner und DPs an.
Mit i=2 trifft es auf Wohnzimmer_1 und macht daraus Wohnzimmer. Soll es ja auch und legt jetzt den Ordner und dann weiter Datenpunkte darunter an.
Mit i=3 kommt jetzt aber Wohnzimmer_2
Sprich Wohnzimmer_1 wird gar nicht bearbeitet. Ich müsste das Script also dazu bekommen zweimal die Schleife mit i=2 zu durchlaufen.
Allerdings führt ein "i--;" innerhalb der if exists Schleife zum beenden des Javascript im iobroker. -
@warhammer73 das hört sich zum einen nach einem Problem welches mit einer
async
function gelöst werden kann.Wenn du deine Funktion als
async
deklarierst kannst du perawait createObject
sicherstellen das dieses vollständig abgelaufen ist - in der Theorie.Was mir nicht klar ist - warum arbeitest du mit klassischem for
i=1-n
anstelle vonfor each (item) of
A.
-
@warhammer73
Ungetestet, aber ich würde hierName=Name.split("_")[0];
nicht den Namen neu zuordnen, sondern stattdessen ein zusätzliches
createDevice (folderName + '.' + Name.Split("_")[0], Name.split("_")[0]);
einbauen.
Dann sollte es dir eigentlich bei i=2 auch beides anlegen.
-
@Asgothian Wie geschrieben ist das Problem aktuell keine Racecondition (Wohnzimmer_2 wird nicht zu Wohnzimmer ersetzt was ja passieren würde wenn die Abfrage noch nicht erkennen würde das der DP da ist). Aber guter Hinweis, falls ich mal auf was schnelleres als den RP4 umsteige.
for each würde mir an der Stelle keine Vorteile bringen, denn rückwärts kann ich damit ja auch nicht gehen soweit ich mich erinnere.@ofri2607
Name.Split("_")[0] als zusätzlichen Eintrag zu Name? Ja, mit zusätzlicher Abfrage ob das an der Stelle schon funktioniert sollte das funktionieren. Blöd ist halt das ich jeden anzulegenden DP doppeln müsste, denn da kommen noch einige die ich nur wegen der Übersichtlichkeit weggelassen habe.Ich habe das ganze jetzt so gelöst:
for (let i=0; i<deviceName.length; i++) { let Room = deviceName[i]; let j=1; if (Room.includes("_")) { if (!(existsObject(folderName + '.' + Room.split("_")[0] + "MAIN"))) { // Pruefen ob uebergeordnete Zimmer vorhanden sind Room=Room.split("_")[0] + "MAIN"; } } if (Room != deviceName[i]) { j=2; } else { j=1; } for (let k=0; k<j; k++) { if (k==1) { Room = deviceName[i]; } console.log ("++++ Name" + Room); createDevice (folderName + '.' + Room, Room);
Damit kann ich jetzt zum einen gleich unterscheiden ob es ein Raum aus der Liste ist oder einer der als "übergeordneter" Raum erzeugt wurde, weil er MAIN am Schluss hat.
Wenn er den Namen wegen dem "_" ersetzt hat ist Name natürlich ungleich dem Arrayelement aus deviceName. Damit weiss ich das ich zweimal Elemente anlegen muss und die Schleife zweimal zu durchlaufen ist (j=2) sonst einmal (j=1).
Innerhalb der Schleife prüfe ich nun noch ob die Schleife das erste Mal läuft (k=0), dann wird entweder für das Arrayelement wenn es keine Ersetzung gab die DPs angelegt, sonst für den ersetzten Wert. Beim zweiten Durchlauf (k=1) weiss ich dann das es hier schon eine Ersetzung gab und hole mir das Originalelement aus dem Array.
Also im Endeffekt ähnlich wie vorgeschlagen nur so angepasst das ich die anzulegenden DPs nur einmal beschreiben muss. -
@warhammer73 sagte in Schleife um einen Eintrag zurück setzen:
@Asgothian Wie geschrieben ist das Problem aktuell keine Racecondition (Wohnzimmer_2 wird nicht zu Wohnzimmer ersetzt was ja passieren würde wenn die Abfrage noch nicht erkennen würde das der DP da ist). Aber guter Hinweis, falls ich mal auf was schnelleres als den RP4 umsteige.
Die Aussage von @paul53 deutet für mich darauf hin das es sich doch um ein Ablauf Problem handelt. Nebenbei - mit etwa “schnellerem” würde das Problem eher kleiner.
CreateObject stößt einiges an arbeiten im Hintergrund an und kommt dann zurück.
Aber seis drum - es kann sein das ich das falsch gelesen habe. Nur - dann hast du ein größeres logisches Problem.
Die gepostete Methode sollte gehen, ist aber umständlich:
Warum nicht:- erst den Device für den exakten raumnamen anlegen
- dann schauen ob es einen übergeordneten raum gibt, wenn ja, Device für den übergeordneten raum anlegen.
Dann kannst du dir das “erst Namen anpassen, dann merken ob sich was geändert hat, dann mit kleiner for Schleife beides anlegen sparen.
-
@warhammer73 sagte in Schleife um einen Eintrag zurück setzen:
for (let a=0; a<deviceName.length; a++) { const room = deviceName[i]; const roomGroup = Room.split('_')[0]; const dArr = roomGroup == room ? [room] : [room, roomGroup] for (let i=0; i<dArr.length; i++) { let Room = dArr[i];
Erstelle ein 2. temporäres Array das aus dem Raum oder dem Raum und der Raumgruppe besteht.
-
@warhammer73 sagte in Schleife um einen Eintrag zurück setzen:
Name.Split("_")[0] als zusätzlichen Eintrag zu Name? Ja, mit zusätzlicher Abfrage ob das an der Stelle schon funktioniert sollte das funktionieren. Blöd ist halt das ich jeden anzulegenden DP doppeln müsste, denn da kommen noch einige die ich nur wegen der Übersichtlichkeit weggelassen habe.
Ich bin mir nicht sicher, ob ich deine Antwort jetzt ganz verstanden habe, aber an sich habe ich es so gemeint (noch etwas in der for-Schleife optimiert); da musst du mE nichts doppeln:
const deviceName = ['Arbeitszimmer','Lottizimmer','Wohnzimmer_1','Wohnzimmer_2']; function CreateDP() { for (const Room of deviceName) { if (Room.includes("_")) { let Main = Room.split("_")[0] + "_MAIN"; if (!existsObject(folderName + '.' + Main)) { createDevice(folderName + '.' + Main, Main); log("---- Main: " + Main); }; }; log("++++ Room: " + Room); createDevice(folderName + '.' + Room, Room); }; } .....
Das Einzige was hier ist, es läuft createDevice parallel ab; d.h. wenn du eine zeitliche Komponenten hast, wo du zuerst den Main brauchst bevor der "Reguläre" angelegt wird, dann müsste im createDevice ein async eingebaut werden und hier die entsprechenden await
-
@ofri2607 Ja, geht so auch. Aber an der Stelle habe ich schon das createDevice gedoppelt. Jetzt lege ich ja nicht einen Ordner an nur um einen Ordner zu haben. Dort drin werden noch einige DP angelegt (Ablauftechnisch eigentlich irrelevant, deswegen waren die mit unter den ... angedeutet).
Konkret geht das so weiter:createState(folderName + '.' + Room + ".Target_temperature_manual","15",{name: "Target_temperature_manual", type: 'number', role: 'value.temperature', unit: '°C'}, function () {}); createState(folderName + '.' + Room + ".Roomtemperature" ,"15",{name: "Roomtemperature", type: 'number', role: 'value.temperature', unit: '°C'}, function () {}); createState(folderName + '.' + Room + ".Thermostat_temperature","15",{name: "Thermostat_temperature", type: 'number', role: 'value.temperature', unit: '°C'}, function () {}); createState(folderName + '.' + Room + ".Target_temperature","15",{name: "Target_temperature", type: 'number', role: 'value.temperature', unit: '°C'}, function () {}); createState(folderName + '.' + Room + ".Thermostat","15",{name: "Thermostat_set", type: 'number', role: 'value.temperature', unit: '°C'}, function () {}); createState(folderName + '.' + Room + ".Temperature_manual_changed","false",{name: "Manual_changed", type: 'boolean', role: 'switch'}, function () {}); createState(folderName + '.' + Room + ".Lastchange","",{name: "Lastchange", type: 'string', role: 'date'}, function () {}); createState(folderName + '.' + Room + ".Dummy_Kontakt","CLOSED",{name: "Fenstersensor", type: 'string', role: 'sensor.window'}, function () {}); setState(folderName + "." + Room + ".Temperature_manual_changed",false,true); setState(folderName + "." + Room + ".Dummy_Kontakt","CLOSED",true);
Den ganzen Teil hätte ich dann entweder zweimal im Script oder müsste ihn getrennt auslagern und dann mit Parameter aufrufen der mal Main und mal Room beinhaltet. Würde natürlich auch gehen.
-
@asgothian
Bei "schneller" ist die Frage was schneller wird: Die Schleife im Verhältnis zu vorher oder das anlegen vom DP. Insofern, ja kann besser oder schlimmer werden.
Momentan ist CreateObject schnell genug wieder zurück um vor dem nächsten Wert abfragbar zu sein. Aber ja, vielleicht bau ich den Teil mal "sicherer" wenn der Rest vernünftig läuft.Ok,
ich kann auch erst die DPs für den exakten Namen anlegen. Aber wenn ich dann nicht nochmal createDevice schreiben will muss ich doch eh in eine Schleife springen (Und siehe letzter Beitrag, da kommen noch ein paar mehr DPs die zweimal im Code zu haben auch nicht toll ist.Aber wie gerade geschrieben, vielleicht lagere ich den ganzen "Anlegen" Teil nochmal auf und rufe ihn dann mit Parameter auf und sollte dann in der Tat ohne Schleife sondern nur mit if auskommen.
-
@warhammer73 sagte in Schleife um einen Eintrag zurück setzen:
Den ganzen Teil hätte ich dann entweder zweimal im Script oder müsste ihn getrennt auslagern und dann mit Parameter aufrufen der mal Main und mal Room beinhaltet. Würde natürlich auch gehen.
Wäre mE strukturierter im Code, wenn du es auf zwei Funktionen aufteilst. Du hast dann auch keine for-Schleife in einer for-Schleife (versuche ich immer so gut es nur geht zu vermeiden) und keine weiteren if-Abfrage und sollte doch ein Zeitproblem auftreten, ist es ganz einfach auf async umzustellen