NEWS
[gelöst] SQL getHistory Abfrage
-
@fastfoot sagte in SQL getHistory Abfrage:
Abhilfe schafft eine Vezögerung in Zeile 18: setTimeout(()=>{log('PV Wert'+ pvwert)}, 100), in diesem Fall 100ms.
Ääähhmm ... neeee weil auch 100ms nicht sichchergestellt sind ... entweder "await sendToAsync" oder weitere Logik einfach im Callback des SendTo
-
@apollon77 sagte in SQL getHistory Abfrage:
"await sendToAsync"
damit bist Du deiner Zeit weit voraus Aber hast völlig Recht, man sollte das nicht so propagieren da es letztlich zu Fehlern führen kann. Andererseits, packe ich das in eine Funktion mit Promise dann nimmt der TE Reissaus
-
@fastfoot Jupp. Daher einfach die Logik in den callback der query-sendTo rein und Ende
-
@apollon77 und @fastfoot
Euer wissen und können in allen Ehren, Hut ab und gar nicht gegen euch gemeint.
Eigentlich wollte ich nur nen Durchschnittswert der letzten x Minuten in eine Variable lesen mit der ich weiterarbeiten kann.Das es nur so kompliziert geht und immer noch eine Hürde dazu kommt, sagt mir innerlich das am Grundprinzip etwas verbesserungsfähig ist. Es gibt viele dieser und ähnlicher Fragen und unterschiedliche Lösungsvorschläge im Forum.
ioBroker hätte echt das Zeug zu mehr wenn's Bausteine zu den meisten Frage gäbe. Bei SQL mit gethistory schon sehr Nahe,
aber haut doch bitte Euer Wissen um diese Anfängerfallstricke (asyncron, callback, promise) eines einfachen zuweisens zu einer Variable mit in die Funktion oder in ein Beispiel rein.
Nicht das ich zu faul bin mir das anzueignen, aber wieviel Zeit würdet Ihr und andere in Zukunft für die Beantwortung solcher Fragen sparen@fastfoot von daher freue ich mich auf die neuen Beispiele ich probiere sie auch gern aus
-
Also ich geb's jetzt auf das Ergebnis der Abfrage in eine Variable zu bekommen mit der ich im weiteren Scriptverlauf und ausserhalb von setTimeout Funktionen arbeiten kann.
-
@ostseeskipper warum packst du deine Logik denn nicht einfach in den Callback(Zeile 13)?
-
@ostseeskipper sagte in SQL getHistory Abfrage:
Eigentlich wollte ich nur nen Durchschnittswert der letzten x Minuten in eine Variable lesen mit der ich weiterarbeiten kann.
Hast Du dir mal Adapter wie "statistics" angeschaut? Vllt gibt es ja da eine Möglichkeit einfach einen Adapter deinen gewünschten Wert berechnen zu lassen ...
-
@apollon77
statistic hab ich mir angeschaut, der zählt nur und ich habe nicht erkannt wir ich da kontinierlich den Durchschnitt der letzten x Minuten abholen kann.
und SQL Queries liefert mir ja was ich brauche nur eben nicht in eine Variable mit der ich ausserhalb von Callback weiterarbeiten kann.@fastfoot weil ich den Inhalt der Variable(Durchschnitt der letzten x Minuten) oft brauche, es noch mehr solcher Datenpunkte gibt die ich abfragen will und damit gerechnet werden soll. Möchte eine modular erweiterbare PV Überschußverwendung aufbauen. Daher will ich den Wert in einer "normal" verwendbaren Variable. Von mir aus warte ich auch auf das Ergebnis und mach dann weiter wenn es da ist, sofern ich wüsste wie das geht. Hab mit asyncron bisher nie was zu tun gehabt. eher hexenwerk für mich
Alternativ schreib ich den wert in einen Datenpunkt und lese den ein, was ja eigentlich quatsch wäre, da die Info ja da ist. -
@ostseeskipper ja, das asynchrone ist Hexenwerk, aber so langsam gewöhne ich mich daran. Im folgenden Beispiel kannst du das Ergebnis einer Variablen zuordnen, allerdings musst du auch da deine Logik in eine Funktion packen, denn ohne ist kein Warten auf das Ergebnis möglich.
/** * Zweck: Abfrage der History eines DP mit SQL Adapter und MySql-DB * Autor: @fastfoot * Datum: 05.04.2022 * Forum: https://forum.iobroker.net/post/787442 */ let dpId = "smartmeter.0.1-0:16_7_0__255.value"; const Minutes = 3; let startTime = new Date(); startTime.setMinutes(startTime.getMinutes() - Minutes); let queryString = "SELECT AVG(n.val) AS wert " + "FROM iobroker.ts_number n " + "JOIN iobroker.datapoints d ON n.id = d.id AND d.name = '" + dpId + "' " + "WHERE n.ts >= " + startTime.getTime(); function sendToAsync() { return new Promise((resolve, reject) => { sendTo("sql.0", "query", queryString, result => { log(result) if (result.error) log(result.error, 'error'); else resolve(result.result[0]); }); }) } async function main() { let Ergebnis = (await sendToAsync()).wert; if (Ergebnis) log("PV Wert: " + Ergebnis.toFixed(3)); //hier weitere Logik } main();
-
@fastfoot
vielen lieben Dank
werde ich gleich mal ausprobieren. -
Toll soweit läuft es. Prinzip asyncron verstanden ist was anderes.
Den Abfragestring selbst hast in eine Variable gebracht und dann genialerweise mit JOIN die eigentlich erste Abfrage nach der ID gleich mit erschlagenWürden nun nur noch kurz wissen bevor ich anfange umzubauen?:
Wenn ich nun noch weitere Datenpunkte mit Durchschnittswerten der letzten x Minuten einbinden möchte, um mit denen zu rechnen, würde ich eine Schleife in async function main() einbauen und überlet Ergebnis = (await sendToAsync()).wert;
mehrfach sendToAsync ausführen.
Nun ist der querystring mit Datenpunkt aber fest in sendToAsync() drin
Die Funktion sendToAsync() kann man theoretisch auch ändern nur den gewünschten Datenpunkt/Query dpId zu übergeben oder lassen das die 'async' nicht zu? -
Und noch eine Frage. Wenn ich den 3 Minuten Durchschnitt für andere Funktionen triggern will wäre es sicher besser den doch in einen Datenpunkt zu schreiben, oder?
-
@ostseeskipper das würde ich dann zB so machen:
/** * Zweck: Abfrage der History eines DP mit SQL Adapter und MySql-DB * Autor: @fastfoot * Datum: 06.04.2022 * Forum: https://forum.iobroker.net/post/787442 */ function sendToAsync(queryString) { return new Promise((resolve, reject) => { sendTo("sql.0", "query", queryString, result => { //log(result) if (result.error) log(result.error, 'error'); else resolve(result.result[0]); }); }) } async function main() { let dpId = ''; dpId = "smartmeter.0.1-0:16_7_0__255.value"; let Ergebnis1 = (await sendToAsync(buildQueryString(dpId))).wert; if (Ergebnis1) log("PV Wert: " + Ergebnis1.toFixed(3)); dpId = "smartmeter.0.2-0:16_7_0__255.value"; let Ergebnis2 = (await sendToAsync(buildQueryString(dpId, 5))).wert; if (Ergebnis2) log("PV Wert2: " + Ergebnis2.toFixed(3)); setStateAsync('your_dp1', Ergebnis1); setStateAsync('your_dp2', Ergebnis2); //hier weitere Logik } function buildQueryString(dpId, Minutes = 3) { let startTime = new Date(); startTime.setMinutes(startTime.getMinutes() - Minutes); let queryString = "SELECT AVG(n.val) AS wert " + "FROM iobroker.ts_number n " + "JOIN iobroker.datapoints d ON n.id = d.id AND d.name = '" + dpId + "' " + "WHERE n.ts >= " + startTime.getTime(); return queryString; } main();
und das ist dann auch schon die Antwort auf dein Statement
aber haut doch bitte Euer Wissen um diese Anfängerfallstricke (asyncron, callback, promise) eines einfachen zuweisens zu einer Variable mit in die Funktion oder in ein Beispiel rein.
das war ein einfaches Beispiel und dennoch war es nicht 'genug', will heissen es gibt da einfach keine universellen Lösungen, schon gar nicht welche die dann alle Benutzer zufrieden stellen q.e.d.
-
@ostseeskipper sagte in SQL getHistory Abfrage:
Und noch eine Frage. Wenn ich den 3 Minuten Durchschnitt für andere Funktionen triggern will wäre es sicher besser den doch in einen Datenpunkt zu schreiben, oder?
ja, da man nur auf Datenpunkte triggern kann, nicht auf Variablen. Siehe das neue erweiterte Beispiel...
-
@fastfoot said in SQL getHistory Abfrage:
und das ist dann auch schon die Antwort auf dein Statement
aber haut doch bitte Euer Wissen um diese Anfängerfallstricke (asyncron, callback, promise) eines einfachen zuweisens zu einer Variable mit in die Funktion oder in ein Beispiel rein.
das war ein einfaches Beispiel und dennoch war es nicht 'genug', will heissen es gibt da einfach keine universellen Lösungen, schon gar nicht welche die dann alle Benutzer zufrieden stellen q.e.d.
Das erste Beispiel von vorgestern wäre ein "super Beispiel" in der Adapterbeschreibung um das "Hexenwerk" asyncron, callback und promise etwas zu verstehen und daran etwas zu lernen. Das 2te mit buildQueryString ist schon etwas für Fortgeschrittenere
Top und super vielen Dank
-
@fastfoot
musste erst mal schauen was das setStateAsync ist, Cool super mitgedacht, das wäre meine nächste Baustelle geworden.
Du hast dich da echt gut reingearbeitet wie ich einem Thread aus 2020 entnehmen konnte. Da war allerdings noch await vor dem setStateAsync
Egal, ich denk ich komm nun klar und setzt den Thread auf gelöst.Danke @apollon77 @paul53 und dir @fastfoot für die tolle Hilfe
-
@ostseeskipper bei wenigen setState kann man das await weglassen. Ist ok