Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Einsteigerfragen
    4. Aufzeichnung Temperatur im History Adapter

    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

    Aufzeichnung Temperatur im History Adapter

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

      Hallo Forum,

      viele Forumsbeiträge haben mir in den letzten Monaten sehr geholfen und ich konnte einige Fortschritte machen und ein bischen herumspielen, was ja am meisten Spass macht.

      Aus aktuellem Anlass möchte ich jetzt meinen Energieverbrauch tracken. Ich habe dazu folgende Sensoren ans Laufen gebracht:

      Gas: Xiaomi Fenstersensor. Passte nach Entfernung des Gehäuses direkt in den Aufnahmeschacht meines Gaszählers. Läuft sehr zuverlässigt und überträgt auch über 2000 Impulse am Tag klaglos. 1 Impuls = 10 Liter

      Strom: IR Lesekopf (Hichi) an ESP 8266 mit Tasmota. Super einfach und zuverlässig. Das größte Problem war noch die korrekte Ausrichtung des Kopfes.

      Außentemperatur: Xiaomi Temperatursensor. Sehr zuverlässig, Batterie hält länger als ein Jahr.

      Heizung Vorlauf / Rücklauf: 2 x DS18B20 an ESP 8266 WEMOS mit Tasmota. Unschlagbar günstig! Die Fühler habe ich einfach hinter die Rohrisolierung geschoben. Sehr feinfülig - die Hysterese lässt sich sauber ablesen im Verlauf.

      Ich mache bereits ein Datenlogging mit dem Node Red Dashboard, aber das ist ja alles nur temporär, wenngleich ich so auch schon einige Erkenntnisse gewonnen habe.

      Das Auslesen der Daten und die Aufbereitung mache ich mit Node Red, möglichst grafisch. Jetzt habe ich mir entsprechende Datenpunkte im iobroker angelegt und schiebe die Daten dorthin.

      Für Gas und Strom ist das sehr einfach. Ich habe einen täglichen Trigger auf 23:59 Uhr, der die holt und in die Datenpunkte schiebt.

      Bei der Außentemperatur ist das schon schwieriger. Ich möchte hier die mittlere Tagestemperatur loggen um diese dann später mit dem Gasverbrauch ins Verhälnis zu setzen. So möchte ich eine Heizlastkurve für mein Haus ermittel.

      Der Temp - Sensor liefert ja immer dann Werte, wenn sich die Temperatur ändert. Eine starke Änderung liefert also viele Werte. Für den Mittelwert eher schlecht. Ich habe dazu in Node Red den Aggregator Node verwendet. In der ersten Stufe je eine Stunde, in der zweiten Stufe je einTag. Die Ergebnisse sehen nicht schlecht aus. Ohne das MIttel über eine Stunde kommt ein um ein paar Zehntel anderes Ergebnis heraus.

      Jetzt das Problem: Der Aggregator Node sendet nachdem der Tag abgeschlossen ist. Der Wert kommt ein paar msec nach 24:00 im Datenpunkt an. Der History Adapter fügt diesem Wert jetzt das Datum vom Folgetag zu, das möchte ich nicht.

      Meine Fragen:

      • Kann man den Zeitstempel im History Adapter irgendwie überschreiben (z.B. auch auf 23:59) ? Das wäre für mich am einfachsten.

      • Kann man dem Aggrgator Node "beibringen" einen anderen Zeitraum als zur vollen Stunde und zum vollem Tag zu verwenden?

      • Gibt es einen anderen Node der den ungewichteten Mittelwert über einen bestimmten Zeitraum ermittelt?

      Ich weiß, es gibt natürlich alle Möglichkeuten wenn man im Funktionsnote selber programmiert, aber das kann ich nicht. Will ich lernen, ist aber nicht mein Focus.

      Für Tipps wäre ich euch sehr dankbar!

      Viele Grüße aus dem Sauerland, Thomas

      mickym 1 Reply Last reply Reply Quote 0
      • mickym
        mickym Most Active @thomashsk last edited by mickym

        @thomashsk Dies ist eine der wenigen Fälle, wo es keine wirklich geeignete Node gibt und man das selbst programmiert. Sonst vermeide ich function Nodes wo es nur geht. In diesem Fall, wird das auch in dem Node Kontext gespeichert.

        Ich hab das schnell für Dich gemacht.

        aaa89fd3-15b7-44f0-9d80-c8f638b31d0a-image.png

        Anstelle der oberen Inject Node (hier 3) flanscht Du die Node dran, die Deine Werte liefert.

        Wenn msg.reset = true gesetzt wird, dann wird alles zurückgesetzt und der Mittelwert ausgegeben. Da Du mit der Inject Node selbst triggern kannst, das die um 23:59 jeden Tag triggert - wird somit um 23:59 täglich ein msg.reset = true ausgegeben und damit der Mittelwert ausgegeben.

        Hier der Flow:

        [
           {
               "id": "312b30368688d654",
               "type": "function",
               "z": "75f805a6f70b6a33",
               "name": "Mittelwert",
               "func": "var arr = context.get(\"values\") || [];\n\nif (msg.reset) {\n\n    msg.payload = arr.reduce((/** @type {any} */ total,/** @type {any} */ value) => total + value ) / arr.length; \n    context.set(\"values\", []);\n    return msg;\n}\n\nvar value = Number(msg.payload);\nif (!isNaN(value)){\n    arr.push(value);\n    context.set(\"values\", arr);\n}\n",
               "outputs": 1,
               "noerr": 0,
               "initialize": "",
               "finalize": "",
               "libs": [],
               "x": 480,
               "y": 200,
               "wires": [
                   [
                       "b5a8e6d648d9ff98"
                   ]
               ]
           },
           {
               "id": "b5a8e6d648d9ff98",
               "type": "debug",
               "z": "75f805a6f70b6a33",
               "name": "Ausgabe Mittelwert",
               "active": true,
               "tosidebar": true,
               "console": false,
               "tostatus": false,
               "complete": "payload",
               "targetType": "msg",
               "statusVal": "",
               "statusType": "auto",
               "x": 670,
               "y": 200,
               "wires": []
           },
           {
               "id": "38011f1a68961bc5",
               "type": "inject",
               "z": "75f805a6f70b6a33",
               "name": "",
               "props": [
                   {
                       "p": "payload"
                   }
               ],
               "repeat": "",
               "crontab": "",
               "once": false,
               "onceDelay": 0.1,
               "topic": "",
               "payload": "3",
               "payloadType": "num",
               "x": 290,
               "y": 160,
               "wires": [
                   [
                       "312b30368688d654"
                   ]
               ]
           },
           {
               "id": "8da2f3ad1ffce675",
               "type": "inject",
               "z": "75f805a6f70b6a33",
               "name": "reset gibt Mittelwert aus",
               "props": [
                   {
                       "p": "reset",
                       "v": "true",
                       "vt": "bool"
                   }
               ],
               "repeat": "",
               "crontab": "59 23 * * *",
               "once": false,
               "onceDelay": 0.1,
               "topic": "",
               "x": 250,
               "y": 200,
               "wires": [
                   [
                       "312b30368688d654"
                   ]
               ]
           }
        ]
        

        Der Code ist relativ simple und Du kannst das aktuelle Array im Node-Kontext der Function Node sehen. Hier nur zur Info der Code - ist aber beim Import bereits enthalten:

        var arr = context.get("values") || [];
        
        if (msg.reset  && arr.length > 0) {
        
            msg.payload = arr.reduce((/** @type {any} */ total,/** @type {any} */ value) => total + value ) / arr.length; 
            context.set("values", []);
            return msg;
        }
        
        var value = Number(msg.payload);
        if (!isNaN(value)){
            arr.push(value);
            context.set("values", arr);
        }
        
        
        1 Reply Last reply Reply Quote 0
        • T
          thomashsk last edited by

          WOW,

          prompter Service hier! Ich habe den Flow importiert, errechnet den Mittelwert wie gewünscht. Der Code selber ist aber ein absolutes Rätsel für mich 😬 Nah ja, werde ich auch mal lernen.

          Es wird hier ja der arithmetische Mittelwert berechnet, d. h. es werden ALLE Werte berücksichtigt. Ich benötige aber eher das geometrische Mittel über die Zeit. Deswegen werde ich die Temperatur in ein Flow-Variable schreiben und diese alle 5 Minuten in den Funktionsnote schreiben. Das sollte ich hinkriegen.

          Kann man die Funktion auch so umschreiben, dass das Maximum und das Minimum ermittelt wird?

          Vielen Dank noch mal für die freundliche Hilfe!

          Thomas

          mickym 3 Replies Last reply Reply Quote 0
          • mickym
            mickym Most Active @thomashsk last edited by mickym

            @thomashsk Ich hab 2 Nodes die ich selbst nutze - die geben bei jedem Eingang das Max bzw. Min aus:

            [
               {
                   "id": "aa25146b.40b388",
                   "type": "function",
                   "z": "e6ec2a6.3220fd8",
                   "name": "max",
                   "func": "if (msg.reset) {\n    context.set('max', undefined);\n    msg.payload = \"-.-\";\n    return msg;\n}\nvar max = context.get('max')||0;\n\nmax = (msg.payload > max) ? msg.payload : max;\ncontext.set ('max',max);\n\nmsg.payload = max;\nreturn msg;",
                   "outputs": 1,
                   "noerr": 0,
                   "initialize": "",
                   "finalize": "",
                   "libs": [],
                   "x": 4370,
                   "y": 560,
                   "wires": [
                       [
                           "d9d65629.6e2068"
                       ]
                   ]
               },
               {
                   "id": "6750dfb7.337c8",
                   "type": "function",
                   "z": "e6ec2a6.3220fd8",
                   "name": "min",
                   "func": "if (msg.reset) {\n    context.set('min', undefined);\n    msg.payload = \"-.-\";\n    return msg;\n}\n\nvar min = context.get('min')||msg.payload;\n\nmin = (msg.payload < min) ? msg.payload : min;\ncontext.set ('min',min);\n\nmsg.payload = min;\nreturn msg;",
                   "outputs": 1,
                   "noerr": 0,
                   "initialize": "",
                   "finalize": "",
                   "libs": [],
                   "x": 4370,
                   "y": 600,
                   "wires": [
                       [
                           "f800e838.33bc98"
                       ]
                   ]
               }
            ]
            

            Auch hier setzt msg.reset - das Ganze zurück.

            Ich setze das auch immer um Mitternacht zurück, um den Kühlschrank zu überwachen:

            d1947b5e-55db-46d9-94d8-7233e32b0309-image.png

            Falls Du die Ausgabe "-.-" nach dem Zurücksetzen nicht magst musst halt diese Zeile 3 entsprechend ändern:

               msg.payload = "-.-";
            
            1 Reply Last reply Reply Quote 0
            • mickym
              mickym Most Active @thomashsk last edited by mickym

              @thomashsk sagte in Aufzeichnung Temperatur im History Adapter:

              Deswegen werde ich die Temperatur in ein Flow-Variable schreiben und diese alle 5 Minuten in den Funktionsnote schreiben. Das sollte ich hinkriegen.

              Das machst einfach mit einer Change und einer Trigger Node. Wie gesagt über den Kontext der Node kannst Du sehen, welche Werte aktuell im Array stehen.

              1 Reply Last reply Reply Quote 0
              • mickym
                mickym Most Active @thomashsk last edited by mickym

                @thomashsk Hier auch nochmal eine Version mit geometrischen und arithmetischem Mittelwert:

                92f303dc-b2ee-41de-84b9-21227adc5e8d-image.png

                [
                   {
                       "id": "312b30368688d654",
                       "type": "function",
                       "z": "289f539dcc33814e",
                       "name": "arithm. Mittelwert",
                       "func": "var arr = context.get(\"values\") || [];\n\nif (msg.reset && arr.length > 0) {\n\n    msg.payload = arr.reduce((/** @type {any} */ total,/** @type {any} */ value) => total + value ) / arr.length; \n    context.set(\"values\", []);\n    return msg;\n}\n\nvar value = Number(msg.payload);\nif (!isNaN(value)){\n    arr.push(value);\n    context.set(\"values\", arr);\n}\n",
                       "outputs": 1,
                       "noerr": 0,
                       "initialize": "",
                       "finalize": "",
                       "libs": [],
                       "x": 650,
                       "y": 3120,
                       "wires": [
                           [
                               "b5a8e6d648d9ff98"
                           ]
                       ]
                   },
                   {
                       "id": "b5a8e6d648d9ff98",
                       "type": "debug",
                       "z": "289f539dcc33814e",
                       "name": "Ausgabe arith Mittelwert",
                       "active": true,
                       "tosidebar": true,
                       "console": false,
                       "tostatus": false,
                       "complete": "payload",
                       "targetType": "msg",
                       "statusVal": "",
                       "statusType": "auto",
                       "x": 910,
                       "y": 3120,
                       "wires": []
                   },
                   {
                       "id": "38011f1a68961bc5",
                       "type": "inject",
                       "z": "289f539dcc33814e",
                       "name": "",
                       "props": [
                           {
                               "p": "payload"
                           }
                       ],
                       "repeat": "",
                       "crontab": "",
                       "once": false,
                       "onceDelay": 0.1,
                       "topic": "",
                       "payload": "6",
                       "payloadType": "num",
                       "x": 350,
                       "y": 3100,
                       "wires": [
                           [
                               "62f8d65a3c45681f"
                           ]
                       ]
                   },
                   {
                       "id": "8da2f3ad1ffce675",
                       "type": "inject",
                       "z": "289f539dcc33814e",
                       "name": "reset gibt Mittelwert aus",
                       "props": [
                           {
                               "p": "reset",
                               "v": "true",
                               "vt": "bool"
                           }
                       ],
                       "repeat": "",
                       "crontab": "59 23 * * *",
                       "once": false,
                       "onceDelay": 0.1,
                       "topic": "",
                       "x": 310,
                       "y": 3180,
                       "wires": [
                           [
                               "4fefb2a427b83dcd"
                           ]
                       ]
                   },
                   {
                       "id": "fc708604b390381a",
                       "type": "function",
                       "z": "289f539dcc33814e",
                       "name": "geom. Mittelwert",
                       "func": "var arr = context.get(\"values\") || [];\n\nif (msg.reset && arr.length > 0) {\n\n    msg.payload = Math.pow(arr.reduce((/** @type {any} */ total,/** @type {any} */ value) => total * value ), 1 / arr.length); \n    context.set(\"values\", []);\n    return msg;\n}\n\nvar value = Number(msg.payload);\nif (!isNaN(value)){\n    arr.push(value);\n    context.set(\"values\", arr);\n}\n",
                       "outputs": 1,
                       "noerr": 0,
                       "initialize": "",
                       "finalize": "",
                       "libs": [],
                       "x": 640,
                       "y": 3160,
                       "wires": [
                           [
                               "b7832abc04318141"
                           ]
                       ]
                   },
                   {
                       "id": "b7832abc04318141",
                       "type": "debug",
                       "z": "289f539dcc33814e",
                       "name": "Ausgabe geom. Mittelwert",
                       "active": true,
                       "tosidebar": true,
                       "console": false,
                       "tostatus": false,
                       "complete": "payload",
                       "targetType": "msg",
                       "statusVal": "",
                       "statusType": "auto",
                       "x": 890,
                       "y": 3160,
                       "wires": []
                   },
                   {
                       "id": "4fefb2a427b83dcd",
                       "type": "junction",
                       "z": "289f539dcc33814e",
                       "x": 460,
                       "y": 3180,
                       "wires": [
                           [
                               "fc708604b390381a",
                               "312b30368688d654"
                           ]
                       ]
                   },
                   {
                       "id": "62f8d65a3c45681f",
                       "type": "junction",
                       "z": "289f539dcc33814e",
                       "x": 460,
                       "y": 3100,
                       "wires": [
                           [
                               "fc708604b390381a",
                               "312b30368688d654"
                           ]
                       ]
                   }
                ]
                

                Das geometrische Mittel wird einfach berechnet nach indem alle Werte multipliziert werden und die n-te Wurzel gezogen wird, wobei n die Anzahl der Elemente sind.

                var arr = context.get("values") || [];
                
                if (msg.reset && arr.length > 0) {
                
                    msg.payload = Math.pow(arr.reduce((/** @type {any} */ total,/** @type {any} */ value) => total * value ), 1 / arr.length); 
                    context.set("values", []);
                    return msg;
                }
                
                var value = Number(msg.payload);
                if (!isNaN(value)){
                    arr.push(value);
                    context.set("values", arr);
                }
                

                Zusätzlich noch eine kleine Verbesserung in dem Code - so dass reset beim leeren Array keine Fehler mehr schmeisst.

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post

                Support us

                ioBroker
                Community Adapters
                Donate

                919
                Online

                31.9k
                Users

                80.2k
                Topics

                1.3m
                Posts

                aggregator mittelwert history
                2
                6
                286
                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