Modbus data aggregation for plotting

Hi everyone,
I'm currently working with Node-RED to build a dashboard. I have three Modbus requests that return energy data from different sources (here transformed to functions). My goal is to create a line or bar chart that visualizes these individual values as well as the total combined value.

I thought I had it working with the current flow, but in the debug output I’m receiving 12 values (3 trafos * 4 values) instead of the four I need. I suspect the issue might be related to trafo 7a, but I’m not entirely sure where the problem is.

Any insights or suggestions would be greatly appreciated.
Thanks a lot for your help!

[
    {
        "id": "21297489339be1a6",
        "type": "group",
        "z": "63fc936c1bc6a015",
        "name": "total energy",
        "style": {
            "label": true
        },
        "nodes": [
            "0de4975323a54482",
            "12956cb651baf94a",
            "f6588068a9b9ea02",
            "72c65f466ad950a8",
            "95eb25d73301aceb",
            "9097e0b15a6490e6",
            "c0069a539bc50eb6",
            "013f33106ceb7d94",
            "0a09dd6719ee601c",
            "68c7e8081c4d8de9"
        ],
        "x": 294,
        "y": 799,
        "w": 1412,
        "h": 162
    },
    {
        "id": "0de4975323a54482",
        "type": "function",
        "z": "63fc936c1bc6a015",
        "g": "21297489339be1a6",
        "name": "parse energy float",
        "func": "let registers = msg.payload;\nconst label =  \"totalenergy\";\n\nconst bytes = [];\nfor (const reg of registers) {\n    bytes.push((reg >> 8) & 0xFF);\n    bytes.push(reg & 0xFF);\n}\n\nconst buf = Buffer.from(bytes);\nconst value = buf.readBigInt64BE(0); //big int 64!!\n\nmsg.payload = { [label]: value };\nmsg.deviceId = msg.deviceId || \"trafo8\"; \n\n//sets msg.deviceId to its current value otherwise trafo 8\nreturn msg;\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 890,
        "y": 840,
        "wires": [
            [
                "12956cb651baf94a"
            ]
        ]
    },
    {
        "id": "12956cb651baf94a",
        "type": "function",
        "z": "63fc936c1bc6a015",
        "g": "21297489339be1a6",
        "name": "aggregate and timestamp ",
        "func": "// Aggregate energy readings per device\n\n// retrieve current global energy data\nlet allData = flow.get(\"allEnergy\") || {};\n\n// check if there is energy data already \nlet deviceData = allData[msg.deviceId] || {};\n\n// store totalenergy under device data\ndeviceData.totalenergy = msg.payload.totalenergy;\n\n//store timestamp\ndeviceData.timestamp = new Date().toISOString();\n\n//update allData object \nallData[msg.deviceId] = deviceData;\n\n//save in flow context\nflow.set(\"allEnergy\", allData);\n\n//combines device ID and all data for that device in a single object \nmsg.payload = { deviceId: msg.deviceId, totalenergy: deviceData.totalenergy, timestamp: deviceData.timestamp };\nreturn msg;\n\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "flow.set(\"allEnergy\", {});",
        "finalize": "",
        "libs": [],
        "x": 1130,
        "y": 880,
        "wires": [
            [
                "9097e0b15a6490e6"
            ]
        ]
    },
    {
        "id": "f6588068a9b9ea02",
        "type": "inject",
        "z": "63fc936c1bc6a015",
        "g": "21297489339be1a6",
        "name": "Start Trafos",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 410,
        "y": 880,
        "wires": [
            [
                "c0069a539bc50eb6",
                "013f33106ceb7d94",
                "0a09dd6719ee601c"
            ]
        ]
    },
    {
        "id": "72c65f466ad950a8",
        "type": "function",
        "z": "63fc936c1bc6a015",
        "g": "21297489339be1a6",
        "name": "parse energy float",
        "func": "let registers = msg.payload;\nconst label = \"totalenergy\";\n\nconst bytes = [];\nfor (const reg of registers) {\n    bytes.push((reg >> 8) & 0xFF);\n    bytes.push(reg & 0xFF);\n}\nconst buf = Buffer.from(bytes);\nconst value = buf.readBigInt64BE(0); //big int 64!!\nmsg.payload = { [label]: value };\nmsg.deviceId = msg.deviceId || \"trafo 7a\";\nreturn msg;\n\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 890,
        "y": 880,
        "wires": [
            [
                "12956cb651baf94a"
            ]
        ]
    },
    {
        "id": "95eb25d73301aceb",
        "type": "function",
        "z": "63fc936c1bc6a015",
        "g": "21297489339be1a6",
        "name": "parse energy float",
        "func": "let registers = msg.payload;\nconst label = \"totalenergy\";\n\nconst bytes = [];\nfor (const reg of registers) {\n    bytes.push((reg >> 8) & 0xFF);\n    bytes.push(reg & 0xFF);\n}\nconst buf = Buffer.from(bytes);\nconst value = buf.readBigInt64BE(0); //big int 64!!\nmsg.payload = { [label]: value };\nmsg.deviceId = msg.deviceId || \"trafo 7b\";\nreturn msg;\n\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 890,
        "y": 920,
        "wires": [
            [
                "12956cb651baf94a"
            ]
        ]
    },
    {
        "id": "9097e0b15a6490e6",
        "type": "function",
        "z": "63fc936c1bc6a015",
        "g": "21297489339be1a6",
        "name": "message for individual chart",
        "func": "let allEn = flow.get(\"allEnergy\") || {};\nlet messages = [];\nlet total = 0n; // BigInt\n\nfor (let key in allEn) {\n    let value = allEn[key]?.totalenergy || 0n;\n    total += value;\n\n    // push single values \n    let roundedValue = Math.round((Number(value) / 1000) * 100) / 100;\n    messages.push({\n        payload: roundedValue,\n        topic: key\n    });\n}\n\n// push total only once \nlet totalRounded = Math.round((Number(total) / 1000) * 100) / 100;\nmessages.push({\n    payload: totalRounded,\n    topic: \"total\"\n});\n\nreturn [messages];\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1380,
        "y": 880,
        "wires": [
            [
                "68c7e8081c4d8de9"
            ]
        ]
    },
    {
        "id": "c0069a539bc50eb6",
        "type": "function",
        "z": "63fc936c1bc6a015",
        "g": "21297489339be1a6",
        "name": "modbus simulation trafo 8",
        "func": "msg.payload = [0, 0, 5041, 61918];\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 630,
        "y": 840,
        "wires": [
            [
                "0de4975323a54482"
            ]
        ]
    },
    {
        "id": "013f33106ceb7d94",
        "type": "function",
        "z": "63fc936c1bc6a015",
        "g": "21297489339be1a6",
        "name": "modbus simulation trafo 7a",
        "func": "msg.payload= [0,0,2562,55629] ;\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 640,
        "y": 880,
        "wires": [
            [
                "72c65f466ad950a8"
            ]
        ]
    },
    {
        "id": "0a09dd6719ee601c",
        "type": "function",
        "z": "63fc936c1bc6a015",
        "g": "21297489339be1a6",
        "name": "modbus simulation trafo 7b",
        "func": "msg.payload = [0,0,363,2726] ;\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 640,
        "y": 920,
        "wires": [
            [
                "95eb25d73301aceb"
            ]
        ]
    },
    {
        "id": "68c7e8081c4d8de9",
        "type": "debug",
        "z": "63fc936c1bc6a015",
        "g": "21297489339be1a6",
        "name": "message",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1600,
        "y": 840,
        "wires": []
    }
]

Hi and welcome to the forum.

For the first few days, you will be limited to how many replies/posts you can make.

Fair enough you have a problem displaying the data, but posting the flow - I'm guessing that's what you posted - not many people will be keen in getting it as it is going to mess with their set ups.

Dashboards, foreign nodes - not sure if you have any.

What I'd suggest you do is make a sample flow with only the non graphic nodes.
Rather than graphs/charts, put debug nodes.

Rather than receiving data from ..... what ever: use inject nodes with nominal values.
(So that is quite a few of them all with different values)

Hi,
Thanks for the welcoming and your recommendation.
I already exchanged the nodes that are unusable for others and as a "preview" I added a screenshot of the flow. I think that is what you suggested right?

Add debug nodes to work out which node is sending the extra messages.

The "message" debug, the one that I added at the last function sends the additional messages. But I think the problem could be in the beginning because three modbus nodes are called.

Rather then doing the modbus fetches in parallel, do the first one, extract the data, and store the result in, for example, msg.trafo8. Then use that to trigger the next modbus fetch (which should not destroy msg.traf08), and save that in msg.trafo7a, and so on. Then at the end you can access all the data in one message. So the flow will look something like