Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. sendTo synchron verwenden

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    sendTo synchron verwenden

    This topic has been deleted. Only users with topic management privileges can see it.
    • C
      ceram last edited by

      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

      AlCalzone 1 Reply Last reply Reply Quote 0
      • AlCalzone
        AlCalzone Developer @ceram last edited by

        @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
        }
        
        1 Reply Last reply Reply Quote 0
        • First post
          Last post

        Support us

        ioBroker
        Community Adapters
        Donate

        887
        Online

        31.8k
        Users

        80.0k
        Topics

        1.3m
        Posts

        javascript
        2
        2
        1164
        Loading More Posts
        • Oldest to Newest
        • Newest to Oldest
        • Most Votes
        Reply
        • Reply as topic
        Log in to reply
        Community
        Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
        The ioBroker Community 2014-2023
        logo