NEWS
sendTo & InfluxDB -> ??? [gelöst]
-
@mcu sagte in sendTo & InfluxDB -> ???:
@legro .. Zeig mal bitte die Abfragen. Wofür sind die unterschiedlichen table?
Mir gelang es nur mittels flux vernünftige Ergebnisse zu erzielen. Über 'history' - anstelle von 'query' - erhielt ich nur Unsinn oder gar nichts.
sendTo('influxdb.0', 'query', 'from(bucket: "db_iobroker") |> range(start: -745d, stop: -727d) |> filter(fn: (r) => r._measurement == "gasTag") |> filter(fn: (r) => r["_field"] == "value")', function (query) { let abfrage = JSON.stringify(query.result) let qry = JSON.parse(abfrage) console.log(qry)
Man kann mehrere Abfragen in einer query-Anweisung angeben. Diese werden dann in einem zweiten, dritten, .. Array abgespeichert. Die Angabe table reflektiert die jeweilige Abfrage.
Beispiele ..
qry[0][1] -> zweites Objekt {..} in der ersten Abfrage
qry[1][0] -> erstes Objekt in der zweiten Abfrage
qry[0].length -> Anzahl der Elemente in der ersten Abfrage -
@legro Dann bitte auch die Lösung schreiben. danke.
-
Die Lösung steht doch hier. Auch die möglichen Ergebnisse habe ich doch auch angegeben.
-
NACHTRAG
Die Zeitangaben können auch in der üblichen Linux-Notation erfolgen ..
sendTo('influxdb.0', 'query', //'from(bucket: "db_iobroker") |> range(start: -745d, stop: 0d) |> filter(fn: (r) => r._measurement == "gasTag") |> filter(fn: (r) => r["_field"] == "value")', 'from(bucket: "db_iobroker") |> range(start: 2023-01-24T00:00:00Z, stop: 2023-01-30T00:00:00Z) |> filter(fn: (r) => r._measurement == "gasTag") |> filter(fn: (r) => r["_field"] == "value")', function (query) { let qry = JSON.parse(JSON.stringify(query.result)) let werte = [] for (let i=0; i<qry[0].length; i++) { werte.push(qry[0][i]._value) } setState('0_userdata.0.Gaszähler.gasTag_Test', JSON.stringify(werte), true)
-
@mcu sagte in sendTo & InfluxDB -> ??? [gelöst]:
@legro Dann bitte auch die Lösung schreiben.
Apropos Lösung ..
Im Nachgang gestaltet sich alles viel schwieriger als gedacht. Der Grund liegt offensichtlich in dem asynchronen Verhalten von sendTo.
Hier meine Leidensgeschichte ..
Meine Versuche, die Min-/Max-Werte aus InfluxDB in der an sendTo übergebenen callback-Funktion zu ermitteln, waren zwar nicht erfolglos, aber aufs Äußerste frustrierend. Vieles hängt offenbar von den jeweiligen Gegebenheiten und - man mag es nicht glauben - auch vom Zufall ab.
function getMinMax(abfrage) { let tblMinMax = JSON.parse(getState('0_userdata.0.Gaszähler.Test_TempMinMax').val) sendTo('influxdb.0', 'query', abfrage, function (query) { let qry = JSON.parse(JSON.stringify(query.result)) let werte = [] let min = qry[0][0]._value let max = qry[0][0]._value for (let i=0; i<qry[0].length; i++) { werte.push(qry[0][i]._value) if (werte[i] < min) {min=werte[i]} if (max < werte[i]) {max=werte[i]} } let tblMinMax = JSON.parse(getState('0_userdata.0.Gaszähler.Test_TempMinMax').val) tblMinMax.push({min,max}) setState('0_userdata.0.Gaszähler.Test_TempMinMax', JSON.stringify(tblMinMax), true) }); setState('0_userdata.0.Gaszähler.Test_TempMinMax', JSON.stringify(tblMinMax), true) } let d = '' let tag = '' setState('0_userdata.0.Gaszähler.Test_TempMinMax', JSON.stringify([]), true) for (let i=1; i<32; i++ ) { d = '0' + i d = d.slice(-2) tag = `from(bucket: "db_iobroker") |> range(start: 2024-12-${d}T00:00:00.000Z, stop: 2024-12-${d}T23:59:59.999Z) |> filter(fn: (r) => r._measurement == "AußenTemperatur") |> filter(fn: (r) => r["_field"] == "value")` getMinMax(tag) }
An diesem Programm wird die Problematik deutlich.
Es wird in einer (äußeren) for-Schleife die Funktion getMinMax aufgerufen, die mittels sendTo die Min/Max-Temperaturwerte eines Tages ermitteln und an das Array im Datenpunkt Test_TempMinMax anfügen soll. Das funktioniert sogar, aber nur einzeln. Rufe ich für jeden Tag die Funktion getMinMax(..) einzeln auf, so baut sich das Array auf und enthält die Elemente {min: <Zahl>, max: <Zahl>} für die Tage, die beim Aufruf übergeben wurden.
Und nun das Verrückte: Rufe ich die Funktion getMinMax in der for-Schleife auf, so fehlen in dem Array jede Menge Wertepaare; mal sind 20, mal 15 und zuweilen gar weniger als 10 darin zu finden. Als wäre das nicht genug Chaos, JavaScript schafft es, die Reihenfolge wild durcheinander gewürfelt in dem Datenpunkt Test_TempMinMax abzulegen.
.. und hier die Auflösung des Rätsels ..
Mein Fazit: Die Aufrufe von sendTo werden offenbar durch die äußerste for-Schleife, in der die Aufrufe von getMinMax erfolgen, angestoßen und laufen parallel (asynchron zum Hauptprogramm) ab, wobei sie unterschiedlich lange Zeiten benötigen und zu verschiedenen Zeitpunkten fertig werden; hierdurch lässt sich die durcheinander gewirbelte Reihenfolge erklären. Darüber hinaus verschluckt sich das System, da vermutlich die Aufrufe von sendTo beim Abspeichern auf die gemeinsam genutzte Ressource (Datenpunkt mit dem Array) sich gegenseitig blockieren; was wiederum das Fehlen von Daten erklären mag.
Kann man ersteres nachvollziehen, so ist das Fehlen von Datensätzen jedoch ein absolutes Unding.
mein weiteres Vorgehen ..
Ich teste nun die Konstrukte asynch/await und die Verwendung promises sowie callback-Funktionen aus, um damit eine Lösung zurechtzuzimmern. Sollte mir dies gelingen, werde ich die Ergebnisse hier einstellen.
-
Wenigstens das Problem der verlorenen Datensätze konnte ich mit einer (weiteren) callback-Funktion in den Griff bekommen.
Mein Vorgehen ..
Innerhalb der sendTo übergebenen (anonymen) callback-Funktion habe ich eine weitere callback-Funktion getResults(..) (s. Zeile 16) eingefügt. Diese Funktion ermöglicht es sozusagen überhaupt erst, dass die Ergebnisse von sendTo an die Außenwelt gelangen können und somit eine Rückmeldung von sendTo zu erhalten.
Zur Kontrolle habe ich in getResults das an sendTo übergebene Datum der jeweiligen Tagesabfrage - neben den Min/Max-Werten - ebenfalls zurückliefern lassen.
Die modifizierte callback-Funktion getResults liefert leider nicht die korrekte Reihenfolge in dem Datenpunkt, die müsste ich somit noch dem Datum sortieren.
function getMinMax(abfrage) { sendTo('influxdb.0', 'query', abfrage, //'from(bucket: "db_iobroker") |> range(start: -745d, stop: 0d) |> filter(fn: (r) => r._measurement == "gasTag") |> filter(fn: (r) => r["_field"] == "value")', //'from(bucket: "db_iobroker") |> range(start: 2025-01-20T00:00:00.000Z, stop: 2025-01-20T23:59:59.999Z) |> filter(fn: (r) => r._measurement == "AußenTemperatur") |> filter(fn: (r) => r["_field"] == "value")', function (query) { let qry = query.result) let werte = [] let min = qry[0][0]._value let max = qry[0][0]._value for (let i=0; i<qry[0].length; i++) { werte.push(qry[0][i]._value) if (werte[i] < min) {min=werte[i]} if (max < werte[i]) {max=werte[i]} } getResults(abfrage.substring(44,55),{min,max}) } ); } let tblMinMax = [] setState('0_userdata.0.Gaszähler.Test_TempMinMax', JSON.stringify(tblMinMax), true) function getResults(Datum,MinMax) { //diese Funktion liefert die nach Datum sortierten Werte im Datenpunkt ' .. Test_TempMinMax' tblMinMax[Number(Datum.substring(8,10))-1] = MinMax setState('0_userdata.0.Gaszähler.Test_TempMinMax', JSON.stringify(tblMinMax), true) } /* function getResults(Datum,MinMax) { //Diese Funktion liefert die ungeordnete Ausgabe console.log(Datum + ' min: ' + MinMax.min + ', max: ' + MinMax.max) } */ let d = '' let tag = '' for (let i=1; i<32; i++ ) { d = ('0' + i).slice(-2) tag = `from(bucket: "db_iobroker") |> range(start: 2024-12-${d}T00:00:00.000Z, stop: 2024-12-${d}T23:59:59.999Z) |> filter(fn: (r) => r._measurement == "AußenTemperatur") |> filter(fn: (r) => r["_field"] == "value")` getMinMax(tag) }
Nun fehlt in den Ergebnissen kein Datensatz mehr ..
javascript.0 09:44:59.087 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-01T min: -1.3, max: 6.2 javascript.0 09:44:59.098 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-02T min: 4, max: 11.4 javascript.0 09:44:59.192 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-04T min: 2.7, max: 5.4 javascript.0 09:44:59.197 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-03T min: 2, max: 7 javascript.0 09:44:59.202 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-05T min: 2.8, max: 6.7 javascript.0 09:44:59.267 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-11T min: 2.1, max: 4.2 javascript.0 09:44:59.273 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-08T min: 0.5, max: 6.7 javascript.0 09:44:59.291 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-06T min: 3.2, max: 8.5 javascript.0 09:44:59.305 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-15T min: 2.2, max: 8.6 javascript.0 09:44:59.343 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-31T min: -5.1, max: 1.3 javascript.0 09:44:59.348 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-07T min: 4.4, max: 9.3 javascript.0 09:44:59.357 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-24T min: 1.8, max: 23.5 javascript.0 09:44:59.370 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-12T min: 0.2, max: 2.1 javascript.0 09:44:59.378 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-28T min: -2.8, max: 15.6 javascript.0 09:44:59.400 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-19T min: 2.8, max: 13.1 javascript.0 09:44:59.403 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-17T min: 5, max: 9.1 javascript.0 09:44:59.418 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-21T min: 4.5, max: 8.9 javascript.0 09:44:59.422 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-23T min: 1.9, max: 6.1 javascript.0 09:44:59.426 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-18T min: 5.1, max: 11.9 javascript.0 09:44:59.431 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-09T min: 3.6, max: 5.1 javascript.0 09:44:59.435 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-30T min: -2.3, max: 4.7 javascript.0 09:44:59.440 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-20T min: 1.9, max: 5.5 javascript.0 09:44:59.446 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-13T min: -3, max: 1.8 javascript.0 09:44:59.451 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-27T min: -1.5, max: 14.3 javascript.0 09:44:59.456 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-10T min: 4.1, max: 5.5 javascript.0 09:44:59.459 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-26T min: 0.1, max: 9.8 javascript.0 09:44:59.465 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-14T min: -3.5, max: 3.9 javascript.0 09:44:59.480 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-16T min: 8.3, max: 11.5 javascript.0 09:44:59.485 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-25T min: 4.9, max: 9 javascript.0 09:44:59.500 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-29T min: -2.1, max: 1 javascript.0 09:44:59.505 info script.js._Test.InfluxDB_Abfrage_1: 2024-12-22T min: 1.3, max: 8.3
Und hier die nach Datum geordneten Werte ..
[ { "min": -1.3, "max": 6.2 }, { "min": 4, "max": 11.4 }, { "min": 2, "max": 7 }, { "min": 2.7, "max": 5.4 }, { "min": 2.8, "max": 6.7 }, { "min": 3.2, "max": 8.5 }, { "min": 4.4, "max": 9.3 }, { "min": 0.5, "max": 6.7 }, { "min": 3.6, "max": 5.1 }, { "min": 4.1, "max": 5.5 }, { "min": 2.1, "max": 4.2 }, { "min": 0.2, "max": 2.1 }, { "min": -3, "max": 1.8 }, { "min": -3.5, "max": 3.9 }, { "min": 2.2, "max": 8.6 }, { "min": 8.3, "max": 11.5 }, { "min": 5, "max": 9.1 }, { "min": 5.1, "max": 11.9 }, { "min": 2.8, "max": 13.1 }, { "min": 1.9, "max": 5.5 }, { "min": 4.5, "max": 8.9 }, { "min": 1.3, "max": 8.3 }, { "min": 1.9, "max": 6.1 }, { "min": 1.8, "max": 23.5 }, { "min": 4.9, "max": 9 }, { "min": 0.1, "max": 9.8 }, { "min": -1.5, "max": 14.3 }, { "min": -2.8, "max": 15.6 }, { "min": -2.1, "max": 1 }, { "min": -2.3, "max": 4.7 }, { "min": -5.1, "max": 1.3 } ]
-
… asynchronen Verhalten von sendTo
Sieh‘ dir dazu sendToAsync an - https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#sendtoasync
Und für die Lösung im for-Loop findet sich unter dem Suchbegriff „javascript promise for loop“ zahlreiche Informationen, z.B. hier - https://stackoverflow.com/questions/40328932/javascript-es6-promise-for-loop
Pkt. 4 aus der ersten Antwort ist mE das was du benötigst. -
Vielen Dank für die vielen Hinweise. Bei den vielen Knoten, die ich im Kopf habe, kann ich jede Hilfe gebrauchen.
Mittlerweile bin ich dabei, das ganze Zeug rund um promises zu verstehen, um damit mir eine Lösung zusammen zu basteln. Die Problematik bei sendTo ist, dass dieser Aufruf ja nichts (direkt) zurückmeldet. Wenn ich die vielen Beispiele richtig überblicke, wird (immer) mit timeouts gearbeitet, die nach Ablauf einer vorgegebenen Zeitspanne auslösen. Das ist aber nicht das, was ich möchte. Mein Wunsch ist, eine Rückmeldung zu erhalten, die definitiv ein eindeutiges Ergebnis (à la: hat geklappt oder auch nicht) liefert.
Daher bin ich auf die oben beschriebene Idee gekommen, eine callback-Funktion getResults in die (anonyme) an sendTo übergebene Funktion einzusetzen. Diese versuche ich nur für resolve in einem promise zu nutzen.
Irgendwie sehe ich den Wald vor lauter Bäumen (immer noch) nicht.
-
Gerne.
Sieh dir dazu nochmal das Beispiel zu sentToAsync an:const res = await sendToAsync('sql.0', 'getEnabledDPs', {}); log(JSON.stringify(res));
Du wirst etwas vom Promis der sentToAsync Abfrage zurückbekommen.
In den Beispielen zu Promise wird meist das timeout verwendet, da es bei dem Thema um den zeitlichen Ablauf („Zeitverzögerung“) im Code geht. Sinngemäß ist das auch so bei dem sentToAsync; das hat seine „Bearbeitungszeit“ mit der Anfrage und Auswertung an die influxDB. Das ist das was du, vereinfacht gesagt, mit dem await im for-loop machst, du wartest damit bis die Rückmeldung vom Promise kommt und erst dann erfolgt der nächste Schleifendurchlauf. Ohne dem wird nicht gewartet, sonder es geht sofort in den nächsten Schleifendurchlauf.
Ich würde es in etwa so lösen:
Baue die Funktion getMinMax(abfrage) auf ein Promise um:function getMinMax(abfrage) return new Promise(async (resolve, reject) => { try { const query = await sentToAsync('influxdb.0', 'query', abfrage); log(query) //nur zum Testen let qry = JSON.parse(JSON.stringify(query.result)); //… usw. mit deinem Code resolve(true); } catch(err) { log(err.message, „warn“); reject(false); } }) }
Und in deiner for-Schleife, die in einer async function eingebettet ist, rufst du dann
const success = await getMinMax(tag); log((success ? „erfolgreich“ : „NICHT erfolgreich“), „info“);
auf.
-
Vielen Dank für deine Unterstützung. Dank deines entscheidenden Hinweises auf die Funktion sendToAsync konnte ich mein Vorhaben umsetzen. Da eine async function ja stets (implizit) mit einem promise verknüpft ist, fiel die Lösung erstaunlich kurz aus.
Auf die nachfolgende Basislösung aufbauend werde ich mir mein Vorhaben realisieren können.
Hier meine Basislösung ..
async function queryInfluxDB() { try { const query = 'from(bucket: "db_iobroker") |> range(start: 2025-01-20T00:00:00.000Z, stop: 2025-01-20T23:59:59.999Z) |> filter(fn: (r) => r._measurement == "AußenTemperatur") |> filter(fn: (r) => r["_field"] == "value")'; const result = await sendToAsync('influxdb.0', 'query', query); console.log(JSON.stringify(result)) } catch (error) { console.error('Fehler bei der Abfrage:', error); } } queryInfluxDB();
.. und das Ergebnis ..
{"result":"_result","table":0,"_start":"2025-01-20T00:00:00Z","_stop":"2025-01-20T23:59:59.999Z","_time":"2025-01-20T00:10:43.242Z","_value":-2.7,"_field":"value","_measurement":"AußenTemperatur","ts":1737331843242}, {"result":"_result","table":0,"_start":"2025-01-20T00:00:00Z","_stop":"2025-01-20T23:59:59.999Z","_time":"2025-01-20T00:20:43.924Z","_value":-2.7,"_field":"value","_measurement":"AußenTemperatur","ts":1737332443924}, {"result":"_result","table":0,"_start":"2025-01-20T00:00:00Z","_stop":"2025-01-20T23:59:59.999Z","_time":"2025-01-20T00:30:43.535Z","_value":-2.7,"_field":"value","_measurement":"AußenTemperatur","ts":1737333043535}, {"result":"_result","table":0,"_start":"2025-01-20T00:00:00Z","_stop":"2025-01-20T23:59:59.999Z","_time":"2025-01-20T00:40:43.189Z","_value":-2.7,"_field":"value","_measurement":"AußenTemperatur","ts":1737333643189}, [ .. und jede Menge weitere Ergebnisse .. ]
-
Zu früh gefreut.
Das ganze Zeug funktioniert noch immer nicht. Die Ergebnisse sind wild durcheinander gewürfelt. Der Zusatz await in Zeile 7 bewirkt offenbar rein gar nichts.
Das folgende Skript ..
async function queryInfluxDB(tag) { let d = tag try { const query = `from(bucket: "db_iobroker") |> range(start: 2025-01-${d}T00:00:00.000Z, stop: 2025-01-${d}T23:59:59.999Z) |> filter(fn: (r) => r._measurement == "AußenTemperatur") |> filter(fn: (r) => r["_field"] == "value")`; const result = await sendToAsync('influxdb.0', 'query', query); let qry = result.result let werte = [] let min = qry[0][0]._value let max = qry[0][0]._value for (let i=0; i<qry[0].length; i++) { werte.push(qry[0][i]._value) if (werte[i] < min) {min=werte[i]} if (max < werte[i]) {max=werte[i]} } console.log({tag, min,max}) //getResults(abfrage.substring(44,54),{min,max}) //der 1. Parameter liefert das Tagesatum String } catch (error) { console.error('Fehler bei der Abfrage:', error); } } let d = '' let tag = '' for (let i=1; i<32; i++ ) { queryInfluxDB(d = ('0' + i).slice(-2)) }
.. liefert folgende Ergebnisse ..
javascript.0 15:30:03.525 info script.js._Test.InfluxDB_Abfrage_3: { tag: '01', min: 0.7, max: 7.3 } javascript.0 15:30:03.545 info script.js._Test.InfluxDB_Abfrage_3: { tag: '02', min: 0.7, max: 6.8 } javascript.0 15:30:03.703 info script.js._Test.InfluxDB_Abfrage_3: { tag: '03', min: -0.1, max: 2.4 } javascript.0 15:30:03.729 info script.js._Test.InfluxDB_Abfrage_3: { tag: '05', min: -0.7, max: 10.5 } javascript.0 15:30:03.741 info script.js._Test.InfluxDB_Abfrage_3: { tag: '04', min: -0.5, max: 3.5 } javascript.0 15:30:03.755 info script.js._Test.InfluxDB_Abfrage_3: { tag: '06', min: 4.7, max: 12.9 } javascript.0 15:30:03.817 info script.js._Test.InfluxDB_Abfrage_3: { tag: '07', min: 2.3, max: 5.4 } javascript.0 15:30:03.835 info script.js._Test.InfluxDB_Abfrage_3: { tag: '13', min: -6.6, max: -0.4 } javascript.0 15:30:03.836 error script.js._Test.InfluxDB_Abfrage_3: Fehler bei der Abfrage: javascript.0 15:30:03.838 info script.js._Test.InfluxDB_Abfrage_3: { tag: '12', min: -1.6, max: 2.7 } javascript.0 15:30:03.855 info script.js._Test.InfluxDB_Abfrage_3: { tag: '08', min: 0, max: 3.9 } javascript.0 15:30:03.875 info script.js._Test.InfluxDB_Abfrage_3: { tag: '29', min: 5.2, max: 9.2 } javascript.0 15:30:03.949 info script.js._Test.InfluxDB_Abfrage_3: { tag: '25', min: 6.2, max: 13.2 } javascript.0 15:30:03.952 info script.js._Test.InfluxDB_Abfrage_3: { tag: '27', min: 6.3, max: 10.5 } javascript.0 15:30:03.977 info script.js._Test.InfluxDB_Abfrage_3: { tag: '18', min: -3.5, max: 2.5 } javascript.0 15:30:03.979 info script.js._Test.InfluxDB_Abfrage_3: { tag: '09', min: -0.8, max: 0.9 } javascript.0 15:30:03.999 info script.js._Test.InfluxDB_Abfrage_3: { tag: '24', min: 3, max: 9.4 } javascript.0 15:30:04.001 error script.js._Test.InfluxDB_Abfrage_3: Fehler bei der Abfrage: javascript.0 15:30:04.004 info script.js._Test.InfluxDB_Abfrage_3: { tag: '23', min: 2.8, max: 5.7 } javascript.0 15:30:04.010 info script.js._Test.InfluxDB_Abfrage_3: { tag: '28', min: 3.8, max: 9.4 } javascript.0 15:30:04.016 info script.js._Test.InfluxDB_Abfrage_3: { tag: '10', min: -1.6, max: 2.4 } javascript.0 15:30:04.020 info script.js._Test.InfluxDB_Abfrage_3: { tag: '11', min: -0.4, max: 1.5 } javascript.0 15:30:04.029 info script.js._Test.InfluxDB_Abfrage_3: { tag: '26', min: 2.9, max: 7.7 } javascript.0 15:30:04.038 info script.js._Test.InfluxDB_Abfrage_3: { tag: '21', min: -3.7, max: 3.7 } javascript.0 15:30:04.043 info script.js._Test.InfluxDB_Abfrage_3: { tag: '15', min: 0.9, max: 3.9 } javascript.0 15:30:04.049 info script.js._Test.InfluxDB_Abfrage_3: { tag: '22', min: -1.7, max: 4.6 } javascript.0 15:30:04.055 info script.js._Test.InfluxDB_Abfrage_3: { tag: '14', min: -7.5, max: 1.7 } javascript.0 15:30:04.070 info script.js._Test.InfluxDB_Abfrage_3: { tag: '20', min: -2.9, max: 0.6 } javascript.0 15:30:04.072 info script.js._Test.InfluxDB_Abfrage_3: { tag: '19', min: -4.7, max: -0.8 } javascript.0 15:30:04.075 info script.js._Test.InfluxDB_Abfrage_3: { tag: '16', min: -2.8, max: 3.8 } javascript.0 15:30:04.077 info script.js._Test.InfluxDB_Abfrage_3: { tag: '17', min: -2.8, max: 1.1 }
.. und funktioniert damit schlechter als zuvor - fehlt wenigstens bei dieser Lösung kein Datensatz.
Mich frustriert das Ganze mittlerweile gewaltig. JavaScript kommt mir vor wie eine Art Agrarinformatik: Kraut&Rüben
-
Ich würde es so machen (wie ich in meinem obigen Post schon geschrieben) - mit Promise in der Funktion und for in einer async function mit await im loop::
let minMaxObj = {}; function queryInfluxDB(tag) { return new Promise(async (resolve, reject) => { //let d = tag für was hast du das eingebaut? try { const query = `from(bucket: "db_iobroker") |> range(start: 2025-01-${tag}T00:00:00.000Z, stop: 2025-01-${tag}T23:59:59.999Z) |> filter(fn: (r) => r._measurement == "AußenTemperatur") |> filter(fn: (r) => r["_field"] == "value")`; const result = await sendToAsync('influxdb.0', 'query', query); let qry = result.result let werte = [] let min = qry[0][0]._value let max = qry[0][0]._value for (let i=0; i<qry[0].length; i++) { werte.push(qry[0][i]._value) if (werte[i] < min) {min=werte[i]} if (max < werte[i]) {max=werte[i]} } log({tag, min,max}) minMaxObj[tag] = { min: min, max: max }; //getResults(abfrage.substring(44,54),{min,max}) //der 1. Parameter liefert das Tagesatum String resolve(true); } catch (error) { log("Fehler bei der Abfrage Tag " + tag + ":" + error.message, "error"); //reject(false); EDIT: => liefert ohne Behandlung mit try-catch im Aufruf einen unbehandelten Fehler, daher resolve(false); } }) } async function callLoop() { for (let i=1; i<32; i++) { const success = await queryInfluxDB(('0' + i).slice(-2)); log(i + " = " + (success ? „erfolgreich“ : „NICHT erfolgreich“), „info“); } log("Datensätze: " + JSON.stringify(minMaxObj), "info"); } callLoop();
Das durcheinander gewürfelte ist klar, denn bei deiner Lösung "feuert" der for-Loop eines nach dem anderen sofort ab und wartet nicht bis die aufgerufene Funktion fertig abgearbeitet wurde. Welche aufgerufene Funktion queryInfluxDB dann schneller ist, hat gewonnen.
Daher die Lösung mit dem await im for-Loop, damit wird, vereinfacht gesagt, gewartet bis das Promise aus der Funktion zurückgemeldet hat.Die Frage die sich mir nur auch stellt ist, warum ist dir die Reihenfolge überhaupt so wichtig?
Wenn du ein Object ausserhalb der Funktion queryInfluxDB definierst, dass du mit der Funktion befüllst, ist die Reihenfolge an sich irrelevant, habe es dir oben als Beispiel dazu eingebaut.EDIT: reject(false) im obigen Code-Beispiel durch resolve(false) ausgetauscht => siehe auch mein unten folgendes Post
-
@ofri2607 sagte in sendTo & InfluxDB -> ??? [gelöst]:
Die Frage die sich mir nur auch stellt ist, warum ist dir die Reihenfolge überhaupt so wichtig?
Die Reihenfolge wird zum Erstellen von Diagrammen benötigt, wie ich sie zur Überwachung unserer Hybridheizung benötige.
Wenn du ein Object ausserhalb der Funktion queryInfluxDB definierst, dass du mit der Funktion befüllst, ist die Reihenfolge an sich irrelevant, habe es dir oben als Beispiel dazu eingebaut.
Vielen Dank für deine detaillierten Vorschläge. Ich versuche einmal nachzuvollziehen, wie du dies konstruiert hast.
-
@ofri2607 sagte in sendTo & InfluxDB -> ??? [gelöst]:
Daher die Lösung mit dem await im for-Loop, damit wird, vereinfacht gesagt, gewartet bis das Promise aus der Funktion zurückgemeldet hat.
Nun habe ich mich bereits einige Tage mit promises und async/await herumgeschlagen. Da spricht man von der callback-hell, aber diese beiden Konstrukte kommen mir nicht viel weniger diabolisch daher. Was mich offenbar durcheinander bringt, ist die gleichzeitige Verwendung dieser beiden Methoden in deinem Lösungsvorschlag.
Dennoch: Ganz langsam scheinen sich das Dunkel und die Knoten in meinem Kopf aufzulösen. Hier meine (vorläufigen?) Einsichten:
Du verwendest sowohl ein promise [und somit hatte ich erwartet, dass die Weiterverarbeitung mittels .then(), .catch() und finally() erfolgt] als auch async/await [wobei durch try die eigentliche Verarbeitung des Ergebnisses erfolgen sollte].
Liege ich damit richtig, oder habe ich‘s immer noch nicht richtig verstanden?
-
Vorweg einmal für alle ggf. mitlesenden Profis. Für mich ist Javascript nur Hobby und Spaß und bin da sehr weit weg ein Profi zu sein. Daher verzeiht mir bitte ggf. unsaubere oder laienhafte Beschreibungen
@legro
Wir nähern uns. Du vermischt jedoch noch zwei Dinge - das eine sind Callbacks und das andere sind Promises.
Im Ergebnis liefern sie für dich dann das selbe, sind aber zwei unterschiedliche Techniken. Soweit ich es weiß, ist Promise die neuere und modernen Technik um "Abfragen" bzw. "Zeitlichkeiten" in eine gesteuerte, serielle Reihenfolge zu bekommen. Ohne der Verwendung des Callback bzw. Promise laufen die Dinge sinngemäß ungesteuert und tlw. parallel ab.Ein Beispiel: Du möchtest Gerätedaten über ein API abfragen: Oft musst du da als erstes einen Sicherheitsschlüssel abholen, mit dem so erhaltenen Sicherheitsschlüssel holst du dir ein Token, mit dem Token die Geräteliste, aus der Geräteliste ein spezielles Gerät und dann die Gerätedaten.
Da hast du dann plötzlich fünf Abfragen, die seriell laufen müssen, weil immer das Ergebnis der vorhergehenden Abfrage für die nächste benötigt wird. Du weißt aber nicht (hast keinen Einfluss darauf), wie lange es dauert bis nach der Abfrage die Rückmeldung eingetroffen ist; daher musst du auf diese warten.Lösung mit Callbacks:
Machst du das jetzt mit Callbacks, bist du hier ganz schnell in den Untiefen der sog. Callback-Hell verschwunden. Das ist die Bezeichnung dafür, das ein Callback in einen anderen Callback, usw. verschachtelt ist. Es funktioniert an sich, aber der Code ist da tlw. fast nicht mehr lesbar bzw. nachvollziehbar.Lösung mit Promise:
Mit Promises hast du da die Möglichkeit es in der sog. Promise-Chain aufzubauen; d.h. du verschachtelst den Code nicht sondern du hast es auf "einer Ebene" untereinander (sinngemäß in der Darstellung im Code keine Einrücken).
Bei den Promises hast du hier zwei Möglichkeiten der Schreibweise:- Entweder mit
.then() (hier können mehrere nacheinander erfolgen => das ist dann die Promise-Chain) und dann mit
.catch() (dient der Fehlerbehandlung wenn in einem der .then() ein Fehler auftritt und bei Bedarf ganz zum Schluss mit
.finally() (hier kannst du definieren was immer - auf nach einem Fehler der im catch behandelt wurde - im Code weiter erfolgen soll. - oder mit async / await
async dient hier "nur" zum Definieren bei einer Funktion das im folgenden Ablauf ein await erfolgt.
Du kannst dann z.B. auch mehrere awaits untereinander schreiben - sprich sinngemäß eine Chain, wie o.a. mit den .then().
Bei await hast du aber keine direkte Fehlerbehandlung, daher musst du das dann in ein try - catch packen um Fehlerrückmeldungen vom Promise (= reject) sauber abzufangen. Sinngemäß ist es das gleiche wie o.a. das .catch()
Das heißt async/await und .then(), .catch, .finally() sind beides sinngemäß das Selbe (= Promise) nur in einer anderen Schreibweise.
Dementsprechend nutze ich in meinem Beispiel im obigen Post nur Promise (und kein Callback). Kurz zur Erklärung dazu:
Mit demreturn new Promise(async (resolve, reject) => {
wird der Rückgabewert der Funktion queryInfluxDB(tag) als Promise "erzeugt". Das async darinnen ist erforderlich, da im nachfolgenden Code mit
const result = await sendToAsync('influxdb.0', 'query', query);
ein "anderes/eigenes" Promise von sendToAsync verwendet wird.
Bei Aufruf der Funktion im for-Loop dann, wird das oben in der Funktion queryInfluxDB(tag) erzeugte Promise mit
const success = await queryInfluxDB(('0' + i).slice(-2));
aufgerufen, daher ist die Kennzeichnung der Funktion callLoop mit async erforderlich.
Einen Fehler habe ich meinem Code im obigen Post:
In der Funktion queryInfluxDB(tag) im catch-Block ist einreject(false);
Das ist ohne Fehlerbehandlung mit try-catch im Aufruf beim loop "falsch" bzw. unsauber programmiert, da würde der Code dann mit einem unbehandelten Fehler stoppen.
Das zu lösen gibt es zwei Möglichkeiten: entweder in der Funktion callLoop() auch ein try-catch einbauen, oder anstelle von reject hier auch resolve verwenden. Ich habe das im obigen Post auf resolve geändert - inkl. Editanmerkung.
Probiere es einfach mal aus, damit du siehst was da jeweils passiert.
Ich hatte dir im Beispiel im obigen Post bewusst ein paar Logausgaben eingebaut, damit du die zeitliche Abfolge siehst. Wenn du es ausprobierts, lasse dann z.B. mal das await bei Aufruf von queryInfluxDB im for-Loop weg und sieh die dann die Log-Ausgabe an, dann solltest du den Unterschied gut erkennen können, bzw. denke ich, verstehen was das await bewirkt. - Entweder mit
-
@ofri2607 sagte in sendTo & InfluxDB -> ??? [gelöst]:
Vorab vielen Dank, dass du mich bei meinem Kampf mit den Elementen so tatkräftig unterstützt hast.
Wir nähern uns. Du vermischt jedoch noch zwei Dinge - das eine sind Callbacks und das andere sind Promises.
Das denke ich nicht. Lediglich innerhalb der Lösungen promise versus async/await hatte ich noch Zweifel. Die Sache mittels callback zu lösen, ist mir ja hier bereits gelungen.
Im Ergebnis liefern sie für dich dann das selbe, sind aber zwei unterschiedliche Techniken. ..
Dank deiner Unterstützung dürfte ich ja auch dies (schon) verstanden haben.
Mittels meines (hoffentlich richtigen) Verständnisses habe ich mich an eine eigene Lösung gewagt. Sie ist erstaunlich kurz geraten.
async function getDataInfluxDB(tag,monat,jahr) { const fluxTxt = `from(bucket: "db_iobroker") |> range(start: ${jahr}-${monat}-${tag}T00:00:00.000Z, stop: ${jahr}-${monat}-${tag}T23:59:59.999Z) |> filter(fn: (r) => r._measurement == "AußenTemperatur") |> filter(fn: (r) => r["_field"] == "value")`; const dataQry = await sendToAsync('influxdb.0', 'query', fluxTxt); let qry = dataQry.result let werte = [] let min = qry[0][0]._value let max = qry[0][0]._value for (let i=0; i<qry[0].length; i++) { werte.push(qry[0][i]._value) if (werte[i] < min) {min=werte[i]} if (max < werte[i]) {max=werte[i]} } return {tag,min,max} } for (let i=1; i<32; i++) { console.log(await getDataInfluxDB(('0' + i).slice(-2),'12','2024')) }
Das gewünschte Ergebnis ..
avascript.0 13:07:27.510 info script.js._Test.InfluxDB_Abfrage_4: { tag: '01', min: -1.3, max: 6.2 } javascript.0 13:07:27.542 info script.js._Test.InfluxDB_Abfrage_4: { tag: '02', min: 4, max: 11.4 } javascript.0 13:07:27.570 info script.js._Test.InfluxDB_Abfrage_4: { tag: '03', min: 2, max: 7 } javascript.0 13:07:27.599 info script.js._Test.InfluxDB_Abfrage_4: { tag: '04', min: 2.7, max: 5.4 } javascript.0 13:07:27.630 info script.js._Test.InfluxDB_Abfrage_4: { tag: '05', min: 2.8, max: 6.7 } javascript.0 13:07:27.658 info script.js._Test.InfluxDB_Abfrage_4: { tag: '06', min: 3.2, max: 8.5 } javascript.0 13:07:27.692 info script.js._Test.InfluxDB_Abfrage_4: { tag: '07', min: 4.4, max: 9.3 } javascript.0 13:07:27.767 info script.js._Test.InfluxDB_Abfrage_4: { tag: '08', min: 0.5, max: 6.7 } javascript.0 13:07:27.847 info script.js._Test.InfluxDB_Abfrage_4: { tag: '09', min: 3.6, max: 5.1 } javascript.0 13:07:27.939 info script.js._Test.InfluxDB_Abfrage_4: { tag: '10', min: 4.1, max: 5.5 } javascript.0 13:07:27.969 info script.js._Test.InfluxDB_Abfrage_4: { tag: '11', min: 2.1, max: 4.2 } javascript.0 13:07:28.008 info script.js._Test.InfluxDB_Abfrage_4: { tag: '12', min: 0.2, max: 2.1 } javascript.0 13:07:28.039 info script.js._Test.InfluxDB_Abfrage_4: { tag: '13', min: -3, max: 1.8 } javascript.0 13:07:28.071 info script.js._Test.InfluxDB_Abfrage_4: { tag: '14', min: -3.5, max: 3.9 } javascript.0 13:07:28.120 info script.js._Test.InfluxDB_Abfrage_4: { tag: '15', min: 2.2, max: 8.6 } javascript.0 13:07:28.165 info script.js._Test.InfluxDB_Abfrage_4: { tag: '16', min: 8.3, max: 11.5 } javascript.0 13:07:28.195 info script.js._Test.InfluxDB_Abfrage_4: { tag: '17', min: 5, max: 9.1 } javascript.0 13:07:28.235 info script.js._Test.InfluxDB_Abfrage_4: { tag: '18', min: 5.1, max: 11.9 } javascript.0 13:07:28.284 info script.js._Test.InfluxDB_Abfrage_4: { tag: '19', min: 2.8, max: 13.1 } javascript.0 13:07:28.323 info script.js._Test.InfluxDB_Abfrage_4: { tag: '20', min: 1.9, max: 5.5 } javascript.0 13:07:28.366 info script.js._Test.InfluxDB_Abfrage_4: { tag: '21', min: 4.5, max: 8.9 } javascript.0 13:07:28.413 info script.js._Test.InfluxDB_Abfrage_4: { tag: '22', min: 1.3, max: 8.3 } javascript.0 13:07:28.457 info script.js._Test.InfluxDB_Abfrage_4: { tag: '23', min: 1.9, max: 6.1 } javascript.0 13:07:28.499 info script.js._Test.InfluxDB_Abfrage_4: { tag: '24', min: 1.8, max: 23.5 } javascript.0 13:07:28.543 info script.js._Test.InfluxDB_Abfrage_4: { tag: '25', min: 4.9, max: 9 } javascript.0 13:07:28.584 info script.js._Test.InfluxDB_Abfrage_4: { tag: '26', min: 0.1, max: 9.8 } javascript.0 13:07:28.631 info script.js._Test.InfluxDB_Abfrage_4: { tag: '27', min: -1.5, max: 14.3 } javascript.0 13:07:28.677 info script.js._Test.InfluxDB_Abfrage_4: { tag: '28', min: -2.8, max: 15.6 } javascript.0 13:07:28.720 info script.js._Test.InfluxDB_Abfrage_4: { tag: '29', min: -2.1, max: 1 } javascript.0 13:07:28.772 info script.js._Test.InfluxDB_Abfrage_4: { tag: '30', min: -2.3, max: 4.7 } javascript.0 13:07:28.816 info script.js._Test.InfluxDB_Abfrage_4: { tag: '31', min: -5.1, max: 1.3 }
.. lässt mich hoffen, das Ganze mittlerweile auch in der Praxis zu beherrschen.
Allerdings hat diese Lösung noch einen gewaltigen Haken: Mit der Fehlerbehandlung steht es nicht nur nicht zum Besten - schlimmer noch! - ich vermag damit die JavaScript-Instanz abzuschießen, liegt im Flux-Text ein Fehler vor. Da hilft dann doch nur promise mit .then(), .. oder async/await mit try {..} zu verwenden.
-
@legro
Gerne, sieht gut aus.
Das await ohne Einbindung in eine async function auch geht, hätte ich nicht gedacht.Ja, das ist einer der wichtigen Punkte beim Arbeiten mit den Promises - für mich aber auch immer bei Programmieren - das man sich auch die Gedanken um die saubere Fehlerbehandlung macht. Lässt sich aber, in deinem Beispiel leicht mit try-catch ergänzen.
-
@ofri2607 sagte in sendTo & InfluxDB -> ??? [gelöst]:
@legro
Gerne, sieht gut aus.
Das await ohne Einbindung in eine async function auch geht, hätte ich nicht gedacht.Ich vermute, dass du hiermit das await in Zeile 20 meinst?! Der Aufruf ist doch in console.log eingebunden.
Das meckert der Editor (ich nutze jenen aus dem JavaScript-Adaper) auch an, was mich allerdings nicht weiter gestört hat. Ständig wird in diesem Editor etwas angemahnt, ohne dass ich nachvollziehen kann, warum dies geschieht. Noch verrückter wird‘s, wenn tags drauf auf einmal diese (scheinbaren) Fehlermeldungen ohne jegliches Zutun meinerseits verschwinden. Ich verstehe vieles bei JavaScript einfach (noch) nicht.
Über vier Jahre habe ich gebraucht, bis ich mich zu Beginn dieses Jahres endlich ans Programmieren in JavaScript dran traute. All mein Wissen über die mir vertrauten Programmiersprachen über Board werfend, vermochte ich schnell Erfolge zu erzielen. Noch immer weiß ich nicht so recht, ob ich mich darüber freuen oder davor fürchten sollte.
Ja, das ist einer der wichtigen Punkte beim Arbeiten mit den Promises - für mich aber auch immer bei Programmieren - das man sich auch die Gedanken um die saubere Fehlerbehandlung macht. Lässt sich aber, in deinem Beispiel leicht mit try-catch ergänzen.
Ja, da muss ich nochmals ran. Aber wenn man auf diese Weise den gesamten JavaScript-Adapter abschießen kann, wird mir dann doch angst und bange.