Timing 2 different MQTT inputs

Hi all,

Quite new with Node-Red and programming in general, but have spent now quite some evenings and hours into figuring out some data read-up from my air to water heatpump with great help of other people.

Now I am stuck, since I have no clue how to continue, and would like to ask some help to at least get me going again.

Below is the flow I currently have, at it works, but can be better to get better values out of it.
What happens is the following:
The first MQTT inject (kamstrup) is set to every 1 minute, the second (youless) is set to every 10 seconds. This cannot be changed due to other reasons in other flows.

Both come out as object, with an array of data.
I have them to join, limit the message to 1/min and run a calculation with 1 value from each array.
This works, and I have the data which I am mostly happy with.

Only 1 thing.
The data belongs together in time, and sometimes the kamstrup data (1 per min) is rather old data vs the youless (1 per 10sec), so the number that comes out is in-accurate when these figures are changes.
I have been trying with trigger and delay nodes, but without success. Is it somehow possible to trigger the flow only when the kamstrup comes in, and then use the latest received youless data?

Would appreciate the help!

[{"id":"e6ae10c6.8eb36","type":"mqtt out","z":"86e20de3.66077","name":"COP MQTT","topic":"cop","qos":"","retain":"","broker":"b7ad9d90.0babc","x":530,"y":340,"wires":[]},{"id":"e58011df.8fb57","type":"change","z":"86e20de3.66077","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"payload.copcurrent","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":190,"y":360,"wires":[["e6ae10c6.8eb36","f06035f3.f93bd8"]]},{"id":"3d9d88c0.fa0ca8","type":"function","z":"86e20de3.66077","name":"","func":"msg.payload = Number(parseFloat(msg.payload).toFixed(1))\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":860,"y":280,"wires":[["e58011df.8fb57"]]},{"id":"e83fea40.7dbfe8","type":"change","z":"86e20de3.66077","name":"COP calc.","rules":[{"t":"set","p":"payload","pt":"msg","to":"(payload.kamstrup.powerinstvalue/payload.youless.powers0)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":280,"wires":[["3d9d88c0.fa0ca8"]]},{"id":"e3d060d2.202c8","type":"delay","z":"86e20de3.66077","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":520,"y":280,"wires":[["e83fea40.7dbfe8","2838b39b.d0101c"]]},{"id":"7be34ea6.4f5dd","type":"join","z":"86e20de3.66077","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":true,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":470,"y":220,"wires":[["e3d060d2.202c8"]]},{"id":"83c793b3.b2a8f","type":"change","z":"86e20de3.66077","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"youless","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":240,"y":240,"wires":[["7be34ea6.4f5dd"]]},{"id":"cc432643.b339f8","type":"change","z":"86e20de3.66077","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"kamstrup","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":240,"y":180,"wires":[["7be34ea6.4f5dd"]]},{"id":"92476a14.dcdc58","type":"mqtt in","z":"86e20de3.66077","name":"kamstrup","topic":"kamstrup","qos":"2","datatype":"json","broker":"d6503b94.421bc8","x":60,"y":180,"wires":[["cc432643.b339f8","dc896133.74871"]]},{"id":"bb41908f.5b5c1","type":"mqtt in","z":"86e20de3.66077","name":"","topic":"youless","qos":"2","datatype":"json","broker":"d6503b94.421bc8","x":50,"y":240,"wires":[["83c793b3.b2a8f","55db603e.712c3"]]},{"id":"b7ad9d90.0babc","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"d6503b94.421bc8","type":"mqtt-broker","z":"","name":"MQTT","broker":"127.0.0.1","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

Welcome to the forum Robin...

Have you considered saving the youless data as flow context, and then retrieving it from context when the kamstrup data arrives?
This is just the front end...

[{"id":"9432ae9.d962c5","type":"mqtt in","z":"af38db0e.4cb458","name":"kamstrup","topic":"kamstrup","qos":"2","datatype":"json","broker":"f2d074d.d0a7588","x":80,"y":320,"wires":[["839de3ab.3c77f"]]},{"id":"1f060384.8ce2cc","type":"mqtt in","z":"af38db0e.4cb458","name":"","topic":"youless","qos":"2","datatype":"json","broker":"f2d074d.d0a7588","x":70,"y":260,"wires":[["5f654de5.9436f4"]]},{"id":"5f654de5.9436f4","type":"change","z":"af38db0e.4cb458","name":"","rules":[{"t":"set","p":"youless","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":260,"y":260,"wires":[[]]},{"id":"839de3ab.3c77f","type":"change","z":"af38db0e.4cb458","name":"","rules":[{"t":"set","p":"youless","pt":"msg","to":"youless","tot":"flow"},{"t":"set","p":"kamstrup","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":260,"y":320,"wires":[["d8e87235.ec582"]]},{"id":"d8e87235.ec582","type":"debug","z":"af38db0e.4cb458","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":430,"y":320,"wires":[]},{"id":"f2d074d.d0a7588","type":"mqtt-broker","z":"","name":"MQTT","broker":"127.0.0.1","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

kam

Or
send msg.complete with kamstrup.

e.g.

[{"id":"7760f563.ea0324","type":"tab","label":"Flow 6","disabled":false,"info":""},{"id":"7b74d061.dabd9","type":"mqtt out","z":"7760f563.ea0324","name":"COP MQTT","topic":"cop","qos":"","retain":"","broker":"bc9f32c4.bbb918","x":520,"y":240,"wires":[]},{"id":"22a94b5e.158ecc","type":"change","z":"7760f563.ea0324","name":"COP calc.","rules":[{"t":"set","p":"payload.copcurrent","pt":"msg","to":"$round(payload.kamstrup.powerinstvalue/payload.youless.powers0, 1)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":180,"wires":[["b7b75c67.b4beb","7b74d061.dabd9"]]},{"id":"a4fb7373.782ed8","type":"join","z":"7760f563.ea0324","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":true,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":480,"y":180,"wires":[["22a94b5e.158ecc"]]},{"id":"3fc94e71.9acc4a","type":"change","z":"7760f563.ea0324","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"youless","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":250,"y":200,"wires":[["a4fb7373.782ed8"]]},{"id":"e1eaea83.5a6dd","type":"change","z":"7760f563.ea0324","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"kamstrup","tot":"str"},{"t":"set","p":"complete","pt":"msg","to":"any value","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":250,"y":140,"wires":[["a4fb7373.782ed8"]]},{"id":"abb68234.6d21b8","type":"mqtt in","z":"7760f563.ea0324","name":"kamstrup","topic":"kamstrup","qos":"2","datatype":"json","broker":"d6bac844.cdb7a8","x":70,"y":140,"wires":[["e1eaea83.5a6dd"]]},{"id":"c900562.a919528","type":"mqtt in","z":"7760f563.ea0324","name":"","topic":"youless","qos":"2","datatype":"json","broker":"d6bac844.cdb7a8","x":60,"y":200,"wires":[["3fc94e71.9acc4a"]]},{"id":"43557065.dd5c08","type":"inject","z":"7760f563.ea0324","name":"","props":[{"p":"payload.powerinstvalue","v":"4","vt":"num"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":true,"onceDelay":0.1,"topic":"","x":120,"y":100,"wires":[["e1eaea83.5a6dd"]]},{"id":"eaaebf94.5241f8","type":"inject","z":"7760f563.ea0324","name":"","props":[{"p":"payload.powers0","v":"$round($random() * 4)","vt":"jsonata"},{"p":"topic","vt":"str"}],"repeat":"10","crontab":"","once":true,"onceDelay":0.1,"topic":"","x":100,"y":260,"wires":[["3fc94e71.9acc4a"]]},{"id":"b7b75c67.b4beb","type":"debug","z":"7760f563.ea0324","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":480,"y":400,"wires":[]},{"id":"bc9f32c4.bbb918","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"d6bac844.cdb7a8","type":"mqtt-broker","z":"","name":"MQTT","broker":"127.0.0.1","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

If you set the join node to output on Every Subsequent Message then you will get an output every time there is an input message (after the first two). Then you can check the topic of the output message to see which input has just been received, so if you add a Switch node to only pass the kamstrup topic then you will get an output each time a kamstrup input is received, and it will also contain the latest value from the other input.

Thank you Paul-Reed!

Interesting, wasn't too much into flow and global context yet. For this application that seems to be very useful and the most neat looking from the comments I believe, thanks a lot! Opens my eyes to play around for the next project to achieve :slight_smile:
From the debug I do see and an array in the payload, and both youless + kamstrup in there as objects. Seems a bit doubling up, but probably doesn't really matter?

Screenshot 2020-10-08 at 22.44.15

Wasn't aware yet of msg.complete and what it does, thanks a lot for mentioning!
And also thank you for the tip on the rounding of the value in the same node :wink:

Thank you Colin, also this one seems to work and is also the smallest adjustment to the current flow that I had.
I have added this one directly in my flow, and will use the others in my future plans!

You could remove the set msg.payload to msg.kamstrup in the change node, and just use the existing msg payload if you wished.
I only included that change to make it easier to see the result.

One potential issue with that is that if, on startup, the kamstrup message appears before the first of the other one then the join node will pass on a message with only the kamstrup data. That may or may not be a problem.

No issue with this flow, but could in other situations. I like Paul's idea best i think, cleaner

The reason I don't like using context in situations like this is that is not obvious from looking at the flow what the data flow is. In the flow using context there is effectively a hidden wire joining the node setting the variable and one using it. Using a Join node the data flow is clear.

I prefer to use context for the opposite reasons!
It's easy in a flow to see where data has 'come from' or 'gone to' because there is a flow.set or flow.get in the flow, and the status and value, of that data can easily be identified & viewed by looking at the 'sidebar > context data'. So it's very easy to troubleshoot, and resolve issues.
Whilst using a Join node, it all happens within the node, so if things don't work as expected, it means adding debug nodes and looking at the timing of the data, as you can't see the internal status of the node.

I guess there are lots of ways to achieve a solution Colin, with benefits & trade off's with each - that's the beauty of javascript, and in the end it comes down to personal preference. :+1:

4 Likes

As Paul says each to their own.

Sorry Paul-Reed, that was a bit of a beginner mistake :slight_smile:

Thank you all for the suggestions and also mentioning what you think are the pros and cons. Helpful for the rest I still need to program.
Next up is counting the difference of a value at a start and end (triggered by data also) and then use that in a formula. Perhaps in a few days I will be stuck and back here again .. :slight_smile:

2 Likes

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