How to calculate average daily temperature from one single sensor

Hi, I'm struggling to find a suitable node to calculate the average daily temperature coming from one single external sensor. This value has to be stored in influxdb each day at midnight together with home energy consumptions.
I tried both "Aggregator" and "Average", but for different reasons they are not suitable:

  • Aggregator outputs its value only after the time span that in my case should be "daily (see configuration) , but I would like to have it in pseudo-real time so the user can see how it fluctuates along the day. Basically you see at 00:01 of a new day the average temperature of the day before and its value remains static until midnight! At least for me it's useless.

  • Average: it works only with multiple sources with different topic, but I have one sensor only with one fixed topic. It looks buggy too, it works only with the first messages and then it displays the same value permanently no matter which new topics with different values you inject.

Is there a node that performs the average value coming from one single source (single topic) and displays it "in near real time" from its output and can be programmatically reset at 00:00?
Or should I calculate it with a function node? In this case can somebody provide a working example node?

Many thanks in advance

Possibly better to store all the samples in the db and then run a
Continuous Query daily to downsample it. Downsample and retain data | InfluxDB OSS 1.8 Documentation

I don't know what you mean by displaying the value (dashboard?) but the Smooth node will calculate a rolling mean.

Also it seems a little odd to aggregate data before storing it in a database.

Hi Colin,
Thank you for the tip. Yes it can be a possible solution, maybe an overkill, but I will consider it if I will not find a NR native solution.

I would not say so, I am sure it would be the most reliable, certainly the most simple to implement.

Certainly as @jbudd says the smooth node will do it, that's exactly how I do my sensor averaging.

Hi Gerry,
the smooth node looks interesting and very simple to implement, but how can I reset its internal value at midnight so it will start calculating the average of the next day starting from the temperature at 00:00?

I can't scratch in my brain now, but I would say the correct approach is the query the average from influxdb

That would require some digging into the node I'm afraid. I only use it to smooth out the values in my system so there isn't any need for me to reset anything.

Hi Gerry,
ok the smooth node isn't suitable for my needs.
I ended up writing a custom function node with a built-in reset feature.
I'm more than happy to share it with anyone interested in getting the daily (weighted of course) average of any incoming message.payload (temperature in my case) and outputting in real-time the current avg. value.
Tipically at midnight a timed inject node sends a msg.payload = "reset" and a new average for the new day is started. The function node has of course some self-explanatory custom context variable that can be easily customized to suit own needs. The actual temperature value is red from a flow var "CurTemp" written periodically by the sensor via mqtt.

The code is pretty simple (albeit verbose for clarity):

let curticks = new Date().getTime();
let curtemp = flow.get("CurTemp");
let oldtemp = flow.get("OldTemp")||0;
if (msg.payload == "reset") {
    context.set("OldTimeIntervals", 0);
    context.set("OldTemperatureIntervals", 0);
    context.set("oldticks", curticks);
    msg.payload = flow.get("averagedailytemp");
} else {   
    let oldticks = context.get("oldticks")||0;
    let curinterval = curticks - oldticks;
    let OldTimeIntervals = context.get("OldTimeIntervals")||0;
    let OldTemperatureIntervals = context.get("OldTemperatureIntervals") || 0;
    let curTemperatureInterval = oldtemp*curinterval;
    let newTimeIntervals = OldTimeIntervals + curinterval;
    let newTemperatureIntervals = OldTemperatureIntervals + curTemperatureInterval;
    context.set("OldTimeIntervals", newTimeIntervals);
    context.set("OldTemperatureIntervals", newTemperatureIntervals);
    let curAvg = newTemperatureIntervals/newTimeIntervals;
    curAvg = Number(curAvg.toFixed(2));
    flow.set("curTempAvg", curAvg);
    context.set("oldticks", curticks);  
    msg.payload = curAvg; 
}
flow.set("OldTemp", curtemp);
return msg;

The complete function node is here:

[
    {
        "id": "b0ce2f864acbd719",
        "type": "function",
        "z": "641efd2eb7d562cf",
        "name": "avg_temp",
        "func": "let curticks = new Date().getTime();\nlet curtemp = flow.get(\"CurTemp\");\nlet oldtemp = flow.get(\"OldTemp\")||0;\nif (msg.payload == \"reset\") {\n    context.set(\"OldTimeIntervals\", 0);\n    context.set(\"OldTemperatureIntervals\", 0);\n    context.set(\"oldticks\", curticks);\n    msg.payload = flow.get(\"averagedailytemp\");\n} else {   \n    let oldticks = context.get(\"oldticks\")||0;\n    let curinterval = curticks - oldticks;\n    let OldTimeIntervals = context.get(\"OldTimeIntervals\")||0;\n    let OldTemperatureIntervals = context.get(\"OldTemperatureIntervals\") || 0;\n    let curTemperatureInterval = oldtemp*curinterval;\n    let newTimeIntervals = OldTimeIntervals + curinterval;\n    let newTemperatureIntervals = OldTemperatureIntervals + curTemperatureInterval;\n    context.set(\"OldTimeIntervals\", newTimeIntervals);\n    context.set(\"OldTemperatureIntervals\", newTemperatureIntervals);\n    let curAvg = newTemperatureIntervals/newTimeIntervals;\n    curAvg = Number(curAvg.toFixed(2));\n    flow.set(\"curTempAvg\", curAvg);\n    context.set(\"oldticks\", curticks);  \n    msg.payload = curAvg; \n}\nflow.set(\"OldTemp\", curtemp);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 900,
        "y": 2920,
        "wires": [
            [
                "10106e15ee054dab",
                "6536caec0c01fcc2",
                "5b4f447c90c720df"
            ]
        ]
    }
]
1 Like

Hi Johan,
Thank you for your suggestion. As I wrote to Gerry I ended up writing a custom function node that output the current daily average (average up to current time) with a built-in reset features using a flow.var where Matt writes the current temperature from a sensor.
Maybe you can find it interesting.

1 Like

I would, if it were me, store the 'raw' data in influxdb and then do a average for the day quarry.

You node looks good :+1:t2:

Too late now because you have written your code based solution but it would be interesting to know why this is not suitable for your requirements.

[{"id":"417f9a6c763a6e88","type":"inject","z":"f77cbf8b5446a20e","name":"Reset @ 00:00","props":[{"p":"reset","v":"true","vt":"bool"}],"repeat":"","crontab":"00 00 * * *","once":false,"onceDelay":0.1,"topic":"","x":140,"y":160,"wires":[["a1a9fdf047b47f2c","6c0d2af370c3dcd0"]]},{"id":"a1a9fdf047b47f2c","type":"smooth","z":"f77cbf8b5446a20e","name":"","property":"payload","action":"mean","count":"10000","round":"","mult":"single","reduce":false,"x":320,"y":120,"wires":[["17d65f21af7676c7"]]},{"id":"7cc3affaf2d8977b","type":"link in","z":"f77cbf8b5446a20e","name":"Temperatures in","links":[],"x":140,"y":120,"wires":[["a1a9fdf047b47f2c"]],"l":true},{"id":"6c0d2af370c3dcd0","type":"change","z":"f77cbf8b5446a20e","name":"flow.dailyaverage = 0","rules":[{"t":"set","p":"dailyaverage","pt":"flow","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":160,"wires":[[]]},{"id":"17d65f21af7676c7","type":"change","z":"f77cbf8b5446a20e","name":"","rules":[{"t":"set","p":"dailyaverage","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":120,"wires":[["bdd66400d7d181a7"]]},{"id":"bdd66400d7d181a7","type":"debug","z":"f77cbf8b5446a20e","name":"Todays Average","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":740,"y":120,"wires":[]},{"id":"6637bf4c20679026","type":"comment","z":"f77cbf8b5446a20e","name":"smooth over \"n\" messages more than 1 day's worth","info":"","x":250,"y":80,"wires":[]}]

Hi jbudd,
no problem if the smooth proves useful. I didn't investigate more deeply in this node when Gerry wrote me that " for a reset function the node required some digging into the node" and I assumed that it had to be done by the node programmer.
The node documentation didn't mention that a msg.reset could be injected to reset calculation.
In your example you have put a reset at midnight as I need. So I will test it and let you know.
Thanks for the kind assistance

In hindsight I could have been clearer. I meant looking into the node documentation further as that was a feature I didn't use.

Never mind Gerry. I gave a fast look into the documentation, and I didn't notice that a reset feature was included. I'm reconsidering it.
Thank you anyway for your kind assistance.

Yes you are right, I red the doc too fast and I missed that paragraph.

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.