NEWS

sendTo synchron verwenden


  • Starter

    Liebe Community,

    für ein paar mit dem SQL-Adapter geloggte Datenpunkte möchte ich den Mittelwert über eine definierte Zeitspanne berechnen. Das folgende Beispielscript berechnet die mittlere Anwesenheit (in %, wenn man meanval * 100 nimmt) während der letzten 48 Stunden und tut dies auch korrekt:

    async function getMeanValFromSQL(datapoint, table, t_beg)
    {
        var Query = 'SELECT ts,val FROM iobroker.'+table+' WHERE id IN (SELECT id FROM iobroker.datapoints WHERE name="'+datapoint+'") and (ts>'+t_beg+' or ts = (SELECT MAX(ts) FROM iobroker.'+table+' WHERE id IN (SELECT id FROM iobroker.datapoints WHERE name="'+datapoint+'") AND ts <= '+t_beg+'))';
        var t_end = Date.now();
        var meanval = 0;
    
        sendTo('sql.0', 'query', Query, function (result) {
            if (result.error) {
                console.error(result.error);
            } else {
                // Berechne Mittelwert
                var rs = result.result;
                var timespan = t_end - t_beg;
                for(var i = 0; i<rs.length; i++)
                {
                    var sec_cur = 0;
                    if (i==0){
                        if(rs.lenght == 1){
                            sec_cur = t_end - t_beg;
                        }else{
                            sec_cur = rs[i+1].ts - t_beg;
                        }
                    }else if(i == rs.length-1){
                        sec_cur = t_end - rs[i].ts;
    
                    }else{
                        sec_cur = rs[i+1].ts - rs[i].ts;
    
                    }
    
                    meanval += rs[i].val*sec_cur/timespan;
    
                }
            log("Mittelwert nested: "+meanval);
            }
        }
        );
        //await sleep(30)
        log("Mittelwert: "+meanval);
    
    }
    
    function sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }
    
    log("Start");
    getMeanValFromSQL("javascript.0.Eigene_Datenpunkte.Presence", "ts_bool", Date.now()-(2*24*60*60*1000));
    log("Ende");
    

    Problem ist nur: Die (anonyme) callback-Funktion läuft natürlich asynchron. Deshalb kann die Hauptfunktion getMeanValFromSQL mit dem Mittelwert zunächst nicht weiterarbeiten, versucht das aber.

    Logausgabe des obigen Scripts:

    08:44:16.081	info	javascript.0 (655) script.js.Test.DatabaseTest: Start
    08:44:16.082	info	javascript.0 (655) script.js.Test.DatabaseTest: Ende
    08:44:16.082	info	javascript.0 (655) script.js.Test.DatabaseTest: registered 0 subscriptions and 0 schedules
    08:44:16.083	info	javascript.0 (655) script.js.Test.DatabaseTest: Mittelwert: 0
    08:44:16.131	info	javascript.0 (655) script.js.Test.DatabaseTest: Mittelwert nested: 0.6609056365740742
    

    Wenn ich die sleep-Zeile (38) aktiviere, funktioniert es:

    08:53:01.142	info	javascript.0 (655) script.js.Test.DatabaseTest: Start
    08:53:01.144	info	javascript.0 (655) script.js.Test.DatabaseTest: Ende
    08:53:01.144	info	javascript.0 (655) script.js.Test.DatabaseTest: registered 0 subscriptions and 0 schedules
    08:53:01.176	info	javascript.0 (655) script.js.Test.DatabaseTest: Mittelwert nested: 0.6609056385364256
    08:53:01.176	info	javascript.0 (655) script.js.Test.DatabaseTest: Mittelwert: 0.6609056385364256
    

    Das ist natürlich keine Lösung, denn im Vorhinein weiß man nicht, wie lange die callback function benötigt, um ihr Ergebnis zu berechnen.

    Deshalb möchte ich auf die Abarbeitung der callback function warten und dann in der Hauptfunktion weitermachen. Geht das irgendwie?

    Einen Umweg über Datenpunkte will ich nicht gehen, um die Funktion universell und skalierbar zu halten (Später soll die Funktion aus einer Schleife heraus aufgerufen werden und Resultate für verschiedene Zeitspannen in ein Array speichern).

    Viele Grüße und besten Dank

    ceram


  • Developer

    @ceram Du kannst grundsätzlich jede Funktion mit Callback promisifizieren, um sie anschließend per await aufzurufen. Das Prinzip ist immer gleich, hier mal für deinen Fall:

    function sendToAsync(adapter, command, options) {
      return new Promise((resolve, reject) => {
        sendTo(adapter, command, options, result => {
          if (result.error) { reject(result.error); }
          else { resolve(result.result) }
        });
      });
    }
    
    // Nutzung in der aufrufenden Funktion:
    try {
      const result = await sendToAsync(...)
      // mit result weiterarbeiten
    } catch (e) {
      // Fehler behandeln
    }
    

Log in to reply
 

Suggested Topics

1.1k
Online

32.4k
Users

39.0k
Topics

528.1k
Posts