NEWS
Selektor $ Datenpunkte refresh Problem
-
Hi Leute, dies ist mein erster Post, wenn also was nicht ganz konform ist pls have mercy
Zu aller erst einmal mein usecase:
Ich möchte ein Skript schreiben, dass auf einen Channel schaut und darauf reagiert, wenn neue Objekte angelegt werden. In dem Fall ein Alexa Device, welches im Channel Alarms die Alarme drin hat. Wenn ich das Skript starte, soll es also alle Datenpunkte im Alarm Channel durchsehen, ob es einen aktiven Alarm gibt. Wenn ja soll ein schedule erstellt werden, der mir das Licht schon 30 Min vor dem Wecker an macht.
Das Problem
Jetzt ist mit beim Verwenden des $ selektors aber aufgefallen, dass dieser einmal beim JS-Adapter restart alle Objekte zu merken scheint und sich danach nicht mehr updated. Wenn ich also einen Alarm lösche oder einen neuen hinzufüge, merkt dies der $ Selektor nicht. Sogar wenn ich das Skript neu starte, erkennt der Selektor die neuen Werte nicht. Erst bei einem kompletten Adapter restart werden die neuen Werte erkannt.
Ist das per design so? Gibts da einen Workaround?
Trying to fix it
Wenn ich nun die
on()
subscribe Funktion mit einer Regex verwende, geht dies einwandfrei neue noch nicht existierende Objekte zu erkennen. Jedoch kann dieon
methode ja nicht bei script start schon alle Alarme des devices durchsehen, sondern nur auf changes reagierenLet's see the code
Ich denke ein paar Zeilen code sagen mehr als 1000 worte, deswegen hier mein Skript code:
const timeSelector = $(`channel[state.id=${ECHO_ALARM_PFAD}.*.time]`); // gibt mir nur die alarme aus, die zum JS-Adapter restart verfügbar waren timeSelector.each(async (val) => { const enabledId = val.replace('time', 'enabled'); const devicePath = val.replace('.time', ''); const enabled = (await getStateAsync(enabledId)).val; const time = (await getStateAsync(val)).val.split(':'); removeOrRefreshSchedule(devicePath, time, enabled); });
Was allerdings schon funzt ist, wenn das script mal läuft, dann kann ich mit der
on
Funktion auf neu hinzugefügte Alarme sehr wohl reagieren, doch das problem ist, sobald man das Script restarted, werden die neuen Alarme wieder gelöscht, weil die Datenpunkte ja erst im nachhinein hinzugefügt wurden// das hier funzt einwandfrei wenn man neue datenpunkte added/removed on({ id: enabledRegex, change: 'ne' }, async ({ id, state: { val } }) => { const timeId = id.replace('enabled', 'time'); const devicePath = id.replace('.enabled', ''); const time = (await getStateAsync(timeId)).val.split(':'); removeOrRefreshSchedule(devicePath, time, val); });
Vielen Dank im Voraus schon mal für eure Antworten
-
@zaunermax sagte:
mit der on Funktion auf neu hinzugefügte Alarme sehr wohl reagieren, doch das problem ist, sobald man das Script restarted, werden die neuen Alarme wieder gelöscht, weil die Datenpunkte ja erst im nachhinein hinzugefügt wurden
Man kann sich die IDs in einem Array-Datenpunkt merken, der bei jedem neuen Datenpunkt aktualisiert wird. Etwa so:
const idDps = '...'; // Array const idUptime = 'system.adapter.javascript.' + instance + '.uptime'; const ECHO_ALARM_PFAD = '...'; var ids = []; if(getState(idUptime).val < 10) { // Instanz gestartet const sel = $(ECHO_ALARM_PFAD + '.*.time'); for(let id in sel) { ids[id] = sel[id]; } setState(idDps, ids, true); } else ids = getState(idDps).val; on({id: /RegExp/}, function(dp) { if(!ids.includes(dp.id)) { // DP ist neu ids.push(dp.id); setState(idDps, ids, true); } // Auswertung });
-
@paul53 Ja so in etwa hätte ich das gemacht, nur gibts dann das Problem, dass beim Skript restart wieder die "alten" Datenpunkte auftauchen, also hätte ich einmal alle 5 Alarme gelöscht und 3 neue hinzugefügt, so würde der
$
mir die 5 alten bereits gelöschten datenpunkte liefern, solange, bis ich den ganzen JS adapter restarte.Da hilfts ja auch nicht, wenn ich mir die Datenpunkte zwischendurch merke, weil ich ja während dem Development das script auch manchmal neu starten muss.
-
@zaunermax sagte:
$ mir die 5 alten bereits gelöschten datenpunkte liefern, solange, bis ich den ganzen JS adapter restarte.
Ja, gelöschte Datenpunkte triggern nicht mehr.
-
@zaunermax sagte:
$ mir die 5 alten bereits gelöschten datenpunkte liefern, solange, bis ich den ganzen JS adapter restarte.
Man kann die gelöschten Datenpunkte mit deleteObject(id) aus dem Javascript-Puffer löschen, wenn man deren Nicht-Existenz mit der asynchronen Funktion existsState(id) abfragt.
for(let i = 0; i < ids.length; i++) { existsState(ids[i], function(err, exists) { if(!err && !exists) { deleteObject(ids[i]); ids.splice(i, 1); i--; } }); } setState(idDps, ids, true);
-
@zaunermax
Habe noch eine Methode getestet, mit der der Javascript-Puffer bei Skriptstart und bei neuen Datenpunkten aktuell gehalten wird.const ECHO_ALARM_PFAD = '...'; const sel = $(ECHO_ALARM_PFAD + '.*.time'); const ids = []; sel.each(function(id, i) { existsState(id, function(err, exists) { if(!err) { if(exists) ids.push(id); else deleteObject(id); // in beiden Puffern löschen } }); }); on({id: /REgExp/}, function(dp) { if(!ids.includes(dp.id)) { // DP ist neu ids.push(dp.id); let obj = {}; obj.type = 'state'; obj.common = dp.common; obj.native = dp.native; setObject(dp.id, obj); // in objects buffer setState(dp.id, dp.state.val, true); // in states buffer } // Auswertung });