NEWS
getState ohne/mit await
-
@paul53 sagte in getState ohne/mit await:
@hub01 sagte: Was ist der Unterschied der beiden Varianten?
Das Holen direkt vom js-controller ist aufwändiger. Dafür kann man den Puffer in den Einstellungen der Javascript-Instanz deaktivieren, was aber die Verwendung der synchronen Version von getState(id) und getObject(id) ausschließt.
Da gehen mir wohl noch ein paar Grundkenntnisse und Zusammenhänge ab.
Welchen Weg nehmen die Daten?
Datenpunkt, Javascript-Adapter, Puffer, js-controller, Variable im Skript, … -
@hub01 sagte in getState ohne/mit await:
Datenpunkt, Javascript-Adapter, Puffer, js-controller, Variable im Skript, …
- alle datenpunkte werden je nach konfiguration entweder in der jsonl oder in redis gespeichert.
- nur der js-controller arbeitet mit diesem backend.
- der js-controller stellt allen adaptern standardfunktionen zum zugriff auf diesen daten bereit: getState,setState.
- der javascript baut für sich noch diesen puffer auf und spiegelt für die skripte mehr oder weniger diese befehle getState,setState, die die Skripte nutzen können um Daten in Variablen zu schreiben oder aus Variablen in einen Datenpunkt zu schreiben
-
@hub01 sagte: Welchen Weg nehmen die Daten?
Der Zustand eines Datenpunktes existiert im Original im js-controller. Manche Adapter-Instanzen (Javascript, Admin) haben eigene Puffer, die ein Abbild aller Datenpunktzustände und Objekte enthalten. Das synchrone getState(id) holt den Zustand eines DP aus dem Zustände-Puffer der Javascript-Instanz. Das synchrone getObject(id) holt sich das adressierte Objekt aus dem Objekte-Puffer.
-
@oliverio sagte: alle datenpunkte werden je nach konfiguration entweder in der jsonl oder in redis gespeichert.
Im laufenden Betrieb werden die Zustände (states) und Objekte nur in die DB geschrieben, damit sie bei Neustart von ioBroker von dort wieder hergestellt werden können.
-
ich habe mal versucht, das Ganze aus den bisherigen Infos zu erfassen.
Liege ich da richtig?
-> der Zugriff auf die js-controller-Datenbank erfolgt immer asynchron
-> der Zugriff auf den js-Adapter-Puffer erfolgt immer synchronUnklar ist mir noch der Puffer.
-> welche Daten werden dort gehalten?
-> wie/wann erfolgt ein Abgleich mit der Datenbank? -
@hub01 sagte: wie/wann erfolgt ein Abgleich mit der Datenbank?
Der JS-Adapter abonniert alle Zustände beim js-controller und wird so synchron gehalten.
@hub01 sagte in getState ohne/mit await:
welche Daten werden dort gehalten?
Alle Objekte und Zustände des js-controllers.
@hub01 sagte in getState ohne/mit await:
Liege ich da richtig?
-> der Zugriff auf die js-controller-Datenbank erfolgt immer asynchron
-> der Zugriff auf den js-Adapter-Puffer erfolgt immer synchronNein.
setState() schreibt immer in den eigenen Puffer (wenn vorhanden) und in den js-controller und arbeitet immer asynchron.
await getStateAsync(id) liefert den Zustand synchron aus dem js-controller. -
Wenn "Do not subscribe all states on start" nicht aktiv ist (default), dann benötigt man keine callback bzw await für getState. Das ist dann immer synchron.
-
@fernetmenta sagte: Wenn "Do not subscribe all states on start" nicht aktiv ist (default), dann benötigt man keine callback
Ja, dann wird gepuffert.
-
@paul53
korrigierte Fassung,
nur gültig, wenn beim Start alle Zustände abonniert werden (mit Puffer)
-
@hub01 Das stimmt so nicht ganz, wenn ich den code vom javascript adapter richtig gelesen habe. Wenn alle Zustände aboniert sind, holt der Adapter die Werte immer aus dem Puffer. Es ist egal welchen Befehl man verwendet.
-
@fernetmenta sagte: Wenn alle Zustände aboniert sind, holt der Adapter die Werte immer aus dem Puffer. Es ist egal welchen Befehl man verwendet.
Nein. Auszug "sandbox.js" (Zeile 2479 ff.):
getState: function (id, callback) { if (typeof id !== 'string') { sandbox.log(`getState has been called with id of type "${typeof id}" but expects a string`, 'error'); return undefined; } if (typeof callback === 'function') { if (!id.includes('.')) { adapter.getState(id, (err, state) => callback(err, context.convertBackStringifiedValues(id, state)), ); } else { adapter.getForeignState(id, (err, state) => callback(err, context.convertBackStringifiedValues(id, state)), ); } } else { if (adapter.config.subscribe) { sandbox.log( 'The "getState" method cannot be used synchronously, because the adapter setting "Do not subscribe to all states on start" is enabled.', 'error', );
getStateAsync(id):
getStateAsync: async function (id) { let state; if (id.includes('.')) { state = await adapter.getForeignStateAsync(id); } else { state = await adapter.getStateAsync(id); } return context.convertBackStringifiedValues(id, state); },
-
@paul53 danke, da hab ich wohl den Code zu schnell und falsch gelesen
-
@paul53
Erst mal ein großes Danke, weil du auf jede Frage eingehst und richtig stellst.Wenn meine letzte Aufstellung passt, würde ich gern noch die weiteren Varianten betrachten.
Ich hoffe, dass ich alles richtig verstanden und eingetragen habe.EDIT: get/setStateAsync durchgestrichen
Noch eine Frage zu get/setState mit Callback:
die Funktion arbeitet zwar asynchron, die Callbackfunktion wird aber erst aufgerufen, wenn der DP gelesen wurde? -
@hub01 sagte: Noch eine Frage zu get/setState mit Callback:
die Funktion arbeitet zwar asynchron, die Callbackfunktion wird aber erst aufgerufen, wenn der DP gelesen wurde?Ja, das Ergebnis (Zustand) wird an die Callback-Funktion übergeben.
@hub01 sagte in getState ohne/mit await:
die weiteren Varianten betrachten.
Wozu setStateAsync gut ist, erschließt sich mir nicht.
Die ...Async Funktionen kann man nicht ohne await aufrufen. Ergebnis bei getStateAsync ohne await:Promise { <pending> }
Die Callback-Funktion bei setState() dient nur einer möglichen Fehlerauswertung. Sie unterscheidet sich ansonsten nicht von setState() ohne Callback und wird so gut wie nie verwendet.
EDIT: Folgende Funktionen sind sinnvoll:
- const state = getState(id) nur mit Puffer
- getState(id, cb) Aufruf mit cb(err, state)
- const state = await getStateAsync(id)
- setState(id, state)
-
@paul53
„await setStateAsync“ wäre auch noch brauchbar, oder? -
@hub01 sagte: „await setStateAsync“ wäre auch noch brauchbar, oder?
Wofür?
-
Wenn man States in einer so hohen Frequenz ändert, das die Möglichkeit besteht einen "Rückstau" zu erzeugen. Mit await setStateAsync() würde man den neuen Schreibvorgang immer erst dann auslösen, wenn der alte abgeschlossen ist.
-
@paul53 sagte in getState ohne/mit await:
@hub01 sagte: „await setStateAsync“ wäre auch noch brauchbar, oder?
Wofür?
ich dachte, z.B. wegen Post #9
Wird aber vermutlich selten bis gar nicht gebraucht.
Da es die Funktion gibt, und diese macht, was sie machen soll, lasse ich sie vollständigkeitshalber in meiner Aufstellung drin.
(aber mit Anmerkung) -
@paul53 sagte in getState ohne/mit await:
@hub01 sagte: „await setStateAsync“ wäre auch noch brauchbar, oder?
Wofür?
ich will 1x pro Tag den Energiewert der PV-Anlage in einen Datenpunkt speichern,
und danach den Energiewert löschen.
Dabei war mir nicht klar, ob ich dafür ein setStateAsync bzw. getStateAsync benötige.// ==================================================== // um 23:59:55 // - akt. Tagesenergie als 1 Tageswert sichern // - alle Energiewerte löschen // // PVGes = PV1+PV2 // EnergieTag = aktuelle aufsummierte Tagesenergie // EnergieTag2 = 1 gesicherter Wert/Tag (Tageswert) // ==================================================== schedule({hour:23, minute:58, second:0}, async() => { await setStateAsync((prePVAllg +".PVGesEnergieTag2"), await getStateAsync(prePVAllg +".PVGesEnergieTag"), true); // Ges-Energie als Tageswert sichern console.log("Gesamt-Energie als Tageswert gesichert") // danach: setState((prePVAllg +".PVGesEnergieTag"), 0, true); // CLR Gesamt-Energie setState((preWR1 +".TodayYield"), 0, true); // CLR Energie Haus setState((preWR2 +".dailyEnergyYield"), 0, true); // CLR Energie Garage console.log("Energiewerte gelöscht") });
-
@hub01 sagte: 1x pro Tag den Energiewert der PV-Anlage in einen Datenpunkt speichern
Du speicherst nicht nur den Wert, sondern den kompletten Zustand in "Tag2".
@hub01 sagte in getState ohne/mit await:
setStateAsync bzw. getStateAsync benötige.
Wenn der Puffer der JS-Instanz nicht deaktiviert wurde, weder - noch
setState(prePVAllg + ".PVGesEnergieTag2", getState(prePVAllg + ".PVGesEnergieTag").val, true); // Ges-Energie als Tageswert sichern
Was stört daran, dass das Skript durchgelaufen ist, bevor setState() für "Tag2" fertig ist?
Aus "Tag" wird synchron gelesen und danach werden die DP auf 0 gesetzt.