Join messages from individual ''sensors'' into one json object

Let's imagine that I am having two inject nodes to simulate two temperature sensors. I'd like to join them into one json object as follows:

{
   "sensor1":22,
   "sensor2":21
}

and to update the object if any one value changes. That means, i might get 5 messages from sensor2, but none for sensor1.

Set a topic for each inject, connect them to a join node set to manual mode, count of 2 & key/value output --> debug node.

Play with the join node settings - you will soon understand what it does.

Great. I didn't played with join mode enough to figure it by myself. Setting the topic for each sensor was the key.

Got this working! Thank you.

Problem now is, that when I restart Node-Red, I need to get both messages to generate the object. Is there some workaround please?

where do they come from - MQTT? Set the topics to retained & then when you restart & re-connect, they will be resent.

Alternatively, you will have to look into persistent storage (storing value to file and recover on startup)

All makes sense now. I might use MQTT to transfer the values, to simplifying it.
Thank you.

If you set the join node to require just 1 value instead of 2 then it will give you a message after the first one, containing only that value obviously.
I presume you have already selected And After Every Subsequent so that you get a new message even if only one of them is sent after you get going.

I went the hardcore route... all my remote sensors send back MQTT messages on schedule or demand, these are parsed/mapped into a DB table via insert SQL, and then... I use DB query to pull consolidated data. If you get fancy you can even use a stored procedure to do the data merge as you want, so NR just pulls the resulting data set and displays it. Since I already had the MQTT messaging setup in python, and database as the consolidation point for the raw data, I did not need NR to do the bulk of the work. I still find, that as newer sensors are released, it is easier to incorporate them into python than using i2c nodes directly (if applicable). Even the Pi dtoverly methods for supporting sensors have no 'clean' bridge to NR at this time (at least that I have found), sure using exec nodes or such works, but when you can have almost any remote device send MQTT back to NR, not using that is sometimes like ice-skating uphill (sorry for the Blade reference, just seemed applicable). :slight_smile:

I agree, this is hardcore! :sweat_smile:

I moved forward littlebit with my "problem" and got now joining messages as follow:

[{"id":"c14ed17f.70b7a","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"a2ff22c.40424e","type":"inject","z":"c14ed17f.70b7a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"main_time","payload":"","payloadType":"date","x":220,"y":120,"wires":[["21aeb3df.901b6c"]]},{"id":"3b443659.2f5a5a","type":"inject","z":"c14ed17f.70b7a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"bedroom_state","payload":"0","payloadType":"num","x":200,"y":280,"wires":[["96e0dcfd.3a082"]]},{"id":"7d05e6e.6f34e18","type":"inject","z":"c14ed17f.70b7a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"main_state","payload":"1","payloadType":"num","x":190,"y":160,"wires":[["21aeb3df.901b6c"]]},{"id":"c9266feb.9b0cb","type":"inject","z":"c14ed17f.70b7a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"bedroom_time","payload":"","payloadType":"date","x":230,"y":240,"wires":[["96e0dcfd.3a082"]]},{"id":"21aeb3df.901b6c","type":"join","z":"c14ed17f.70b7a","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":"","reduceFixup":"","x":470,"y":160,"wires":[["faf7569b.77cd18"]]},{"id":"96e0dcfd.3a082","type":"join","z":"c14ed17f.70b7a","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":"","reduceFixup":"","x":470,"y":240,"wires":[["faf7569b.77cd18"]]},{"id":"faf7569b.77cd18","type":"join","z":"c14ed17f.70b7a","name":"","mode":"custom","build":"merged","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":true,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":630,"y":200,"wires":[["2bbfd490.2511dc"]]},{"id":"2bbfd490.2511dc","type":"debug","z":"c14ed17f.70b7a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":820,"y":200,"wires":[]}]

it produces JSON object:

{
   "main_state":{
      "main_time":1598850426209,
      "main_state":1
   },
   "bedroom_state":{
      "bedroom_time":1598850427518,
      "bedroom_state":0
   }
}

but what I would like to do is:

{
   "main":{
      "time":1598850426209,
      "state":1
   },
   "bedroom":{
      "time":1598850427518,
      "state":0
   }
}

Is it possible please?

Can you change the topics and attribute names in the data coming in?
Otherwise you can use a change node to do it. Set it to Move msg.payload.main_state To msg.payload.main, Move msg.payload.main.main_time To msg.payload.main.time and so on. Alternatively you could write some javascript to iterate the keys in msg.payload and change all the xxx_state to xxx and all the sub attributes xxx_time to time and xxx_state to state. Not particularly difficult but would need a certain level of js experience.

1 Like

OMG. Thanks to all so far for help.

Somehow, and don't ask me how, I got this.

[{"id":"1414279f.2ef558","type":"key-value-read","z":"c14ed17f.70b7a","store":"92d5edb.a2aa81","key":"main_timestamp","name":"main_timestamp","x":380,"y":400,"wires":[["b1aae43c.24e418"]]},{"id":"92d5edb.a2aa81","type":"key-value-store","z":"","filepath":"doors.json","namespace":"","name":""}]

The goal is to produce JSON object for 2 doors. Main and bedroom (for example). For every state change it needs to store a timestamp and be persietent to node-red restarts. I am using node-red-contrib-persist.

Final JSON looks as follows:

{
   "main":[
      1598873690,
      1
   ],
   "bedroom":[
      1598873688,
      1
   ]
}

which I am more than happy with. The only problem is, that it takes two refreshes of /endpoint to read changed values.

Any idea someone how to make it to just one refresh only please? I know, it's a mess.

I have been playing around with json-db as well for persistent state stuff.

Does that have any advantages over the persistent context provided by node red core?
https://nodered.org/docs/user-guide/context

The same question there, does that have advantages over the core persistent context?
I notice it is nearly three years since it was last updated. Also I note that the readme instructions to install it will actually install json-db-node-red which is a different node. There doesn't appear to be an Issues tab for the node so one cannot submit an issue.

[Edit] Although it isn't clear which one you are actually playing with, json-db-node-red or node-red-contrib-json-db.

I am not aware of any advantages, but it's easier for me to use. It's this one actually: https://flows.nodered.org/node/node-red-contrib-persist

But I guess, to use context will be more efficient to use without external nodes.

Json-db has a nice tree structure for organization of variable context. Thus, the original use was to keep context variables persistent, as variables, not a data structure. This fit the current flow I had in place. But I decided to improve the flow, so the state of flow is now an object structure, i.e. a single variable (which is a complex data structure). This new design provides more flexibility when it comes to saving the entire datastructure as persistent.

Can you share an example of the flexibility it gives over what is available with the built-in context?

You can save objects in context storage. Here is an example I use:

Each of these objects represents a different water station - a WeMos D1 Pro connected to some sensors and a battery with a solar panel to recharge it.

I am not sure what you mean by flexibility, the current context model is flexible. I am using json-db to provide persistence. Just so happens json-db can let you structure data anyway you want just like context does.

The built in context also provides persistence when required.

Like I said, I was playing around with it. The one draw back with it... the actual file created does not seem to be human readable. The test file I looked at, was not actually a json formatted file. Which seemed odd. Maybe somehow I broke it? LOL.