Help on handling MQTT data

Hi guys,

I need some help to transform data form MQTT Trigger.

As I need to extract data (room name) from Topic name, I only activate JSON Parse Body option.

Then, I would like to transform the JSON form message to a table, exactly like if I had activated the message option in the MQTT Trigger. Do I need a function for this, or is there a node able to do so ?

If it’s a function, can you help with an example ?

I search the node or function called function1 in the following flow :

 {
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "message",
              "value": "{ \"battery\": 40, \"humidity\": 54.64, \"linkquality\": 255, \"pressure\": 1009, \"temperature\": 20.01, \"voltage\": 2885 },"
            },
            {
              "name": "topic",
              "value": "zigbee2mqtt/BureauGuillaume/Ambiance"
            }
          ]
        },
        "options": {}
      },
      "name": "Set",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "values": {
          "number": [
            {
              "name": "timestamp",
              "value": "={{new Date()}}"
            }
          ]
        },
        "options": {}
      },
      "name": "Now",
      "type": "n8n-nodes-base.set",
      "position": [
        640,
        300
      ],
      "typeVersion": 1
    },
    {
      "parameters": {
        "functionCode": "const topic_path = $json[\"topic\"]\n\nreturn [\n  {\n    json: {\n      room: topic_path.split('/')[1]\n    }\n  }\n]\n"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        840,
        300
      ]
    },
    {
      "parameters": {
        "mode": "multiplex"
      },
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 1,
      "position": [
        1130,
        210
      ]
    },
    {
      "parameters": {
        "functionCode": "Custom function ?\n\n\n"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        830,
        80
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Set",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set": {
      "main": [
        [
          {
            "node": "Now",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Now": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Function1": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Thanks a lot for your help !

I think it would be a function quite close to that :

const message_body = $json["message"];

const result = [ ];

result.push(message_body);

return result;

But I get this error :

ERROR: All returned items have to contain a property named “json”!

Any idea to solve it ?

You don’t have a property called json, you would need to have result[index].json.message.

Take a look at Function | Docs for a couple of examples.

Thanks @jon for your help, I did try this :

const message_body = $json["topic"]
;
const array = JSON.parse(message_body);
const result = [ ];

result.push({json : {array}});

return result;

I think I’m not doing the right javascript.

I need to find the right function that just provide a table with humidity, temperature, … as column.

It’s certainly obvious with javascript/json skills, but I can’t find it :sob:

If I was near a computer I would pop an example together for you it is a bit tricky from a mobile device.

When you say a table what do you mean? Are you planning to pop the data in a spreadsheet?

Likely, I want to insert it into a TimescaleDB instance.

This N8N flow is to add “one column” with a room name to the result I would get if I activate JSON Pase Body / Only message.

I have the right function to extract the room name from the topic path, here it is :

const topic_path = $json["topic"]

return [
  {
    json: {
      room: topic_path.split('/')[1]
    }
  }
]

Now I just want to extract on the other hand the differents values from the body message, and the. multiplex it so it gets ready to insert into TimeScaleDB. I need the same exact result I easily get with options JSON Pase Body / Only message activated (but if I do this, I miss the topic path to get the room name).

Quite frustrating !

If it is just posting and the visuals don’t matter in n8n what about just using $json[“message”].temperature, it looks like it is already an object so you should be able to just call it as it is whenever you need it or do it in a set node. You could also use {{$json[“topic”].split("/")[1]}} in the expression editor at any point as well.

Could be worth a go and you wouldn’t need to use a function node.

It looks like a nice idea @jon.

You mean like this :

{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "room",
              "value": "={{$json[topic].split(\"/\")[1]}}"
            }
          ],
          "number": [
            {
              "name": "temperature",
              "value": "={{$json[\"message\"].temperature}}"
            }
          ]
        },
        "options": {}
      },
      "name": "Set1",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        850,
        300
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "message",
              "value": "{ \"battery\": 40, \"humidity\": 54.64, \"linkquality\": 255, \"pressure\": 1009, \"temperature\": 20.01, \"voltage\": 2885 },"
            },
            {
              "name": "topic",
              "value": "zigbee2mqtt/BureauGuillaume/Ambiance"
            }
          ]
        },
        "options": {}
      },
      "name": "Mockup MQTT Trigger",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "values": {
          "number": [
            {
              "name": "timestamp",
              "value": "={{new Date()}}"
            }
          ]
        },
        "options": {}
      },
      "name": "Add timestamp",
      "type": "n8n-nodes-base.set",
      "position": [
        640,
        300
      ],
      "typeVersion": 1
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Mockup MQTT Trigger",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mockup MQTT Trigger": {
      "main": [
        [
          {
            "node": "Add timestamp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add timestamp": {
      "main": [
        [
          {
            "node": "Set1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

I got something empty.

Bit hard to read on mobile but the theory looks good, if you use the expression builder to select the node you should be able to browse to the value you want.

Probably easier or you to read with a screenshot :wink:

My last set is like this :

And like this :

Both return Not found

Shouldn’t topic have the ’ around it?

Shame on me ! Yes, you are right. Now I get the Room name.

But still not the temperature.

On the plus side half way there and no function node :slightly_smiling_face:

What do you get if you just put {{$json[‘message’]}} does that show the full string?

A real ugly solution could be…

{{JSON.parse($json[‘message’]).temperature}}

If I do this, I get full string :

If I do the “ugly” stuff : I have this error

If I do it regular : not found

Argh !

Can you try changing the ’ to " it is hard to see if it is the right character :slightly_smiling_face:

I would have thought that would do it as well, if you drop the .temperature does it return the same data with object at the start?

Id did try with “” => {{JSON.parse($json[“message”]).temperature}}

I still get [not found].

I did simplify the flow to put this Set after the data mockup, still the same issue.

It seems quite strange

What if you remove the .temperature what do you get?

{{$json[“message”]}} give { “battery”: 40, “humidity”: 54.64, “linkquality”: 255, “pressure”: 1009, “temperature”: 20.01, “voltage”: 2885 },

It seems the issue is my Data mockup, your idea works quite well with data coming fron MQTT Trigger. Thanks a lot @jon :slight_smile:

1 Like

Alright that is good to hear :+1: