[Solverd] Filter min and max value on last 24hr

Hi, I’m trying to use the history node to receive the data of sensor temperature of last 24hours but I don’t understand how to filter the data. I understand the values are in payload[X].state, but how can i filter it?
image

Maybe another approach could be the statistic node? But I totally don’t understand how ir work
Screenshot-from-2020-06-12-17-46-13 Screenshot-from-2020-06-12-17-46-19

Thanks for any advice!

You’re going to have to clarify what you mean by filter as that is pretty vague. To start with I’d probably suggest you take a look at the split node. If you pass that message to a split node it will create a message out of each element in the array. There’s not a whole lot of ways to interact with an array of objects outside of a function node but once you split it into individual messages then there’s a whole lot of things you can do:

  • The statistics node can collect numeric values from across messages into a data set and output calculated statistical values when the data set reaches a certain size
  • The smooth node has similar functionality or can also be used as a high/low pass filter
  • The simple switch node is probably the easiest and most generic filter at this point, you can filter out the individual messages based on whatever criteria you want.

I could go on but it would definitely help if you described your use case a bit more so I could give more specific examples. But yea my biggest piece of advice would probably be start with the split node as that output seems designed for it.

Ok so I just realized your title is “min and max value” so I get what you’re filtering on now.

Been doing some testing and came up with something. One challenge I faced though is the statistical nodes I mentioned all seem to work best when you have a continuous stream of data and are looking to reduce the stream. Like if you have a constant stream of data on power consumption from an IOT device and want to reduce the noise there’s a lot of tools for that. But getting the max over a whole set of data regardless of length is a bit trickier. I found a way but its probably worth considering whether you’d be better off just using a function node in this spot, the code is probably significantly simpler.

But anyway, without a function node here’s what you can do.

  1. Run the output through a split node
  2. Set payload to payload.state converted to float (state is stored as a string even when numeric)
  3. Use the statistics node with input property set to payload and output property set to result (note: input property seems to have to be payload for some reason or I got errors, dunno why, payload.state didn’t work). Uncheck the box that says “Only output result message” so each message going through the node is output
  4. Add a switch node which sends the output to a join when result is null and a debug node that outputs the complete message object when its not. This way your statistical calculations will be debugged and your join node will wait to output anything until the original message has been fully reconstructed (i.e. everything has gone through the statistics node)
  5. After the join node split to two separate change nodes. One sets topic to max and the other sets topic to min. Feed these nodes back into the statistics nodes. When a statistics node gets a message with a topic set to a statistical function it will output the result of that calculation over its data set. This will then head back to your debug node and give you the result.

In the end it looks like this:

Here’s code you can import that does this to try it out for yourself. Just put in the name of your sensor in the Get History node and then you can play around with it from there:

[{"id":"6eaacbaa.36fe64","type":"api-get-history","z":"a74fee2d.ac9068","name":"Get history","server":"cc03735a.94933","startdate":"","enddate":"","entityid":"","entityidtype":"is","useRelativeTime":true,"relativeTime":"24 h","flatten":true,"output_type":"array","output_location_type":"msg","output_location":"payload","x":270,"y":1800,"wires":[["42163f5a.825ce"]]},{"id":"51d7d72a.3dbf28","type":"inject","z":"a74fee2d.ac9068","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":1800,"wires":[["6eaacbaa.36fe64"]]},{"id":"42163f5a.825ce","type":"split","z":"a74fee2d.ac9068","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":440,"y":1800,"wires":[["b6c1affe.7755a"]]},{"id":"5e3e26b6.18525","type":"statistics","z":"a74fee2d.ac9068","name":"","dataSetSize":0,"inputField":"payload","inputFieldType":"msg","resultField":"result","resultFieldType":"msg","parameterField":"","parameterFieldType":"msg","stripFunction":true,"resultOnly":false,"x":760,"y":1800,"wires":[["ed881de4.4eb048"]]},{"id":"546a03ff.cf8d8c","type":"join","z":"a74fee2d.ac9068","name":"","mode":"auto","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":1090,"y":1780,"wires":[["6b265a54.f425ac"]]},{"id":"c1e4911f.3e568","type":"debug","z":"a74fee2d.ac9068","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1090,"y":1820,"wires":[]},{"id":"6b265a54.f425ac","type":"link out","z":"a74fee2d.ac9068","name":"","links":["3bff4735.4bd658","c33b8fe4.2b9ab8"],"x":1215,"y":1780,"wires":[]},{"id":"3bff4735.4bd658","type":"link in","z":"a74fee2d.ac9068","name":"","links":["6b265a54.f425ac"],"x":415,"y":1860,"wires":[["1a92b252.6b5896"]]},{"id":"1a92b252.6b5896","type":"change","z":"a74fee2d.ac9068","name":"Get Max","rules":[{"t":"delete","p":"payload","pt":"msg"},{"t":"set","p":"topic","pt":"msg","to":"max","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":1860,"wires":[["5e3e26b6.18525"]]},{"id":"ed881de4.4eb048","type":"switch","z":"a74fee2d.ac9068","name":"Result or no","property":"result","propertyType":"msg","rules":[{"t":"null"},{"t":"nnull"}],"checkall":"true","repair":false,"outputs":2,"x":930,"y":1800,"wires":[["546a03ff.cf8d8c"],["c1e4911f.3e568"]]},{"id":"b6c1affe.7755a","type":"string","z":"a74fee2d.ac9068","name":"Make float","methods":[{"name":"toFloat","params":[{"type":"num","value":""}]}],"prop":"payload.state","propout":"payload","object":"msg","objectout":"msg","x":590,"y":1800,"wires":[["5e3e26b6.18525"]]},{"id":"c33b8fe4.2b9ab8","type":"link in","z":"a74fee2d.ac9068","name":"","links":["6b265a54.f425ac"],"x":415,"y":1900,"wires":[["d684aca8.d849a8"]]},{"id":"d684aca8.d849a8","type":"change","z":"a74fee2d.ac9068","name":"Get Min","rules":[{"t":"delete","p":"payload","pt":"msg"},{"t":"set","p":"topic","pt":"msg","to":"min","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":1900,"wires":[["5e3e26b6.18525"]]},{"id":"cc03735a.94933","type":"server","z":"","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

Here’s a possible example using the function node.

const [min, max] = msg.payload.reduce((acc, current) => {
    return [
        Math.min(current.state, acc[0]), 
        Math.max(current.state, acc[1])
    ];
}, [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ]);

msg.payload = {min, max};
return msg;

or

const values = msg.payload.map(v => Number(v.state));
const min = Math.min(...values);
const max = Math.max(...values);
msg.payload = {min, max};
return msg;

1 Like

Lol yea that definitely looks simpler to me. I love Node RED and its diverse toolkit but sometimes things are just easier to do in code. Fortunately, there’s a node for that!

@CentralCommand Thanks for your great answer and approach, join for sure is the right tool, will try your flows

@Kermit, the first function node worked immediately! Need to learn how to write functions!

Thanks both for your great answers and quick help!

Today I found that the function is not working anymore, always throw value NaN
I checked the data of my temperature sensor and sometimes I have a state: "unknown" Could this state be a problem? Maybe the function need a instruction to avoid those values?
I tried making this but without success

Any advice welcome

const [min, max] = msg.payload.reduce((acc, current) => {
    if(isNaN(current.state)) return [acc[0], acc[1]];
    return [
        Math.min(current.state, acc[0]), 
        Math.max(current.state, acc[1])
    ];
}, [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ]);

msg.payload = {min, max};
return msg;

Works perfect! Thanks again