Thanks for your hints. Still getting new bars for each payload. Will keep working on this.
I might be missing something obvious.
please show us what data you are sending to the bar chart and how you have the bar chart configured.
payload I m sending in a function every time it starts as screengrab from debug:
Screengrab of current setting in chart below.
I have tried Action: replace and sGroup by: side by side
Th rest of the settings are for the persistence function quoted earlier in the thread, and it works
very well with some 20 or so line charts in use. Thanks!
ok, so not sure why you have set categoy or other key and TBH, Iam not even 100% certain what you want the bar chart to look like! A simple gauge or tile is better suited to a number - but I assume you are going to be seeing other "start counts" to this graph so wantto see side-by-side bars???
Any how. Since you are setting msg.topic to "pump drift" and msg.payload to a number, these should be reflected in the chart settings
DEMO:
Demo Flow (Use CTRL+I
to import)
[{"id":"2ee2a2a2fc7ee074","type":"ui-chart","z":"5f26939bbac6427a","group":"2dbfd7f52fa47e21","name":"","label":"Machine Starts","order":1,"chartType":"bar","category":"topic","categoryType":"msg","xAxisLabel":"","xAxisProperty":"Item","xAxisPropertyType":"str","xAxisType":"category","xAxisFormat":"","xAxisFormatType":"auto","xmin":"","xmax":"","yAxisLabel":"","yAxisProperty":"payload","yAxisPropertyType":"msg","ymin":"","ymax":"","bins":10,"action":"append","stackSeries":false,"pointShape":"circle","pointRadius":4,"showLegend":true,"removeOlder":1,"removeOlderUnit":"3600","removeOlderPoints":"","colors":["#0095ff","#ff0000","#ff7f0e","#2ca02c","#a347e1","#d62728","#ff9896","#9467bd","#c5b0d5"],"textColor":["#666666"],"textColorDefault":true,"gridColor":["#e5e5e5"],"gridColorDefault":true,"width":6,"height":8,"className":"","interpolation":"linear","x":980,"y":2140,"wires":[[]]},{"id":"730f34909d968281","type":"inject","z":"5f26939bbac6427a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"pump drift","payload":"1","payloadType":"num","x":700,"y":2140,"wires":[["2ee2a2a2fc7ee074"]]},{"id":"b07642db58a288f7","type":"inject","z":"5f26939bbac6427a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"pump drift","payload":"10","payloadType":"num","x":700,"y":2180,"wires":[["2ee2a2a2fc7ee074"]]},{"id":"038e12a4d6444a8e","type":"inject","z":"5f26939bbac6427a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"pump drift","payload":"25","payloadType":"num","x":700,"y":2220,"wires":[["2ee2a2a2fc7ee074"]]},{"id":"2b6aa492c5587370","type":"inject","z":"5f26939bbac6427a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"waffle sprocket","payload":"7","payloadType":"num","x":720,"y":2300,"wires":[["2ee2a2a2fc7ee074"]]},{"id":"45dec71397199616","type":"inject","z":"5f26939bbac6427a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"waffle sprocket","payload":"22","payloadType":"num","x":730,"y":2340,"wires":[["2ee2a2a2fc7ee074"]]},{"id":"50231827103ae223","type":"inject","z":"5f26939bbac6427a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"waffle sprocket","payload":"29","payloadType":"num","x":730,"y":2380,"wires":[["2ee2a2a2fc7ee074"]]},{"id":"2dbfd7f52fa47e21","type":"ui-group","name":"Group Name","page":"8f5aa1455c92c632","width":6,"height":1,"order":1,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"8f5aa1455c92c632","type":"ui-page","name":"Page Name","ui":"a171c8195c1b8e57","path":"/page3","icon":"home","layout":"grid","theme":"9d8bfd7e0d216779","breakpoints":[{"name":"Default","px":"0","cols":"3"},{"name":"Tablet","px":"576","cols":"6"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":1,"className":"","visible":"true","disabled":"false"},{"id":"a171c8195c1b8e57","type":"ui-base","name":"My Dashboard","path":"/dashboard","includeClientData":true,"acceptsClientConfig":["ui-control","ui-gauge","ui-chart","ui-form","ui-text-input","ui-file-input","ui-button","ui-button-group","ui-dropdown","ui-radio-group","ui-slider","ui-switch","ui-text","ui-table","ui-markdown","ui-notification","ui-template"],"showPathInSidebar":false,"navigationStyle":"icon","titleBarStyle":"fixed"},{"id":"9d8bfd7e0d216779","type":"ui-theme","name":"Default Theme","colors":{"surface":"#ffffff","primary":"#15617e","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}},{"id":"b55042f65505932d","type":"global-config","env":[],"modules":{"@flowfuse/node-red-dashboard":"1.23.0"}}]
What happens if you change the âActionâ to replace? I would expect it to create a new data point if in âAppendâ mode, but the chart should be completely refreshed if in âReplaceâ mode . Are you using the function node logic that I had sent earlier?
Thanks, this demo flow works if I skip the mentioned persistence flow and send a counter number counting up for each star, which I already also have in place.
I assume it will not start a new bar at midnight though. But that is some progress. Thanks.
I think I could either use append and send a number:1 or a count-up with replace.
It would stil need to create a new bar at midnight. somehow. Thanks.
I did post a link to the function I am using for persistence.
Here it is again:
I appreciate all input and will digest it and see if I can make some progress.
Many thanks!
Why not just send your running total and set the topic to day name e.g. Sat then at midnight reset your counter and change topic to Sun ?
You could just leave it at that as it would overwrite the days when it wraps around, or you could wipe the chart and start again.
Hello.
Just spent some more time on this and have something working that shows more clearly what we are after if someone wants to take a look.
It uses the function in this thread from @rakgupta (Thanks!) and a slightly modified version of the persistence subflow from here. So far unable to see anything other than UNIX time in the chart axis but other than that it appears to pretty much do what we want. Have not real-world tried the midnight turnover to create a new bar yet. and it needs polish..but it's a start
I would prefer to do it without the counter and do the summing in the flow, as that would probably be more robust but unable to make that work so far.
I assume it would need some code in the function to do the summing there and then use append in the chart rather than release,
[
{
"id": "a2474b2214d6b686",
"type": "subflow",
"name": "Chart Persistence replace",
"info": "",
"category": "",
"in": [
{
"x": 60,
"y": 200,
"wires": [
{
"id": "b2695d4f3e716f6c"
}
]
}
],
"out": [
{
"x": 770,
"y": 120,
"wires": [
{
"id": "22fa4bf0d7dd0698",
"port": 0
},
{
"id": "119d2ef8e89cd608",
"port": 0
}
]
}
],
"env": [
{
"name": "SIZE_NUM",
"type": "num",
"value": "0"
},
{
"name": "SIZE_HRS",
"type": "num",
"value": "0"
}
],
"meta": {},
"color": "#FFCC66",
"inputLabels": [
"single item added to the buffer"
],
"outputLabels": [
"chart data V1",
"chart data V2"
],
"icon": "font-awesome/fa-floppy-o"
},
{
"id": "119d2ef8e89cd608",
"type": "function",
"z": "a2474b2214d6b686",
"name": "Add data with timestamp and limit array length",
"func": "const now = new Date().getTime();\n\nvar buffer = flow.get(\"_bufferV2\");\n\nif (!Array.isArray(buffer))\n{\n buffer = [];\n}\n\nconst topic = ('topic' in msg) ? msg.topic : '';\n\nvar idx = buffer.length;\nfor (const item of buffer)\n{\n if (topic === item[0].category)\n {\n idx = buffer.indexOf(item);\n break;\n }\n}\n\nif (idx === buffer.length)\n{\n buffer.push([]);\n}\n\nconst datapoint = { category: topic, x: now, y: msg.payload };\nbuffer[idx].push(datapoint);\n\nconst SIZE_NUM = env.get('SIZE_NUM');\nif ( SIZE_NUM > 0 )\n{\n buffer[idx].splice(0, buffer[idx].length - SIZE_NUM);\n}\n\nconst SIZE_HRS = env.get('SIZE_HRS');\nif ( SIZE_HRS > 0 )\n{\n for (const [idx] of buffer.entries())\n {\n let i = 0;\n while ((i < buffer[idx].length) && (buffer[idx][i].x < (now - (SIZE_HRS * 36e5)))) // 1 hour = 60 * 60 * 1000 = 36e5 milliseconds\n {\n i++;\n }\n buffer[idx].splice(0, i);\n }\n}\n\nflow.set(\"_bufferV2\", buffer);\n\nreturn {payload: datapoint, action: 'replace'};\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 460,
"y": 180,
"wires": [
[]
]
},
{
"id": "22fa4bf0d7dd0698",
"type": "function",
"z": "a2474b2214d6b686",
"name": "clean buffer",
"func": "if ( !Array.isArray(msg.payload) )\n{\n return msg;\n}\n\n// feeding V1 data\nif ( 'series' in msg.payload[0] )\n{\n let bufferV2 = [];\n for (const [idx, data] of msg.payload[0].data.entries() )\n {\n bufferV2.push([]);\n for ( const item of data )\n {\n bufferV2[idx].push({category: msg.payload[0].series[idx], ...item});\n }\n }\n msg.payload = bufferV2;\n}\n\nvar indices2Delete = [];\n\nfor ( const [idx] of msg.payload.entries() )\n{\n if ( (msg.payload[idx].length === 0) || !('category' in msg.payload[idx][0]) )\n {\n indices2Delete.push(idx);\n }\n else\n {\n msg.payload[idx] = msg.payload[idx].sort((a, b) => a.x - b.x);\n }\n}\n\nfor ( const idx of indices2Delete )\n{\n msg.payload.splice(idx, 1);\n}\n\nflow.set('_bufferV2', msg.payload);\n\nreturn {payload: msg.payload.flat(), action: 'replace'};\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 570,
"y": 120,
"wires": [
[]
]
},
{
"id": "b2695d4f3e716f6c",
"type": "switch",
"z": "a2474b2214d6b686",
"name": "",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "istype",
"v": "number",
"vt": "number"
},
{
"t": "istype",
"v": "array",
"vt": "array"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 170,
"y": 200,
"wires": [
[
"119d2ef8e89cd608"
],
[]
]
},
{
"id": "3ca3c4798c91834b",
"type": "inject",
"z": "a2474b2214d6b686",
"name": "",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "0.1",
"topic": "",
"payload": "_bufferV2",
"payloadType": "flow",
"x": 380,
"y": 120,
"wires": [
[
"22fa4bf0d7dd0698"
]
]
},
{
"id": "d84b176e12749a08",
"type": "tab",
"label": "Flow 1",
"disabled": false,
"info": "",
"env": []
},
{
"id": "277f18b9ad3b9208",
"type": "counter",
"z": "d84b176e12749a08",
"name": "Counter",
"init": "0",
"step": "1",
"lower": null,
"upper": null,
"mode": "increment",
"outputs": 2,
"x": 580,
"y": 220,
"wires": [
[
"31806e697f531027",
"635e08363a2a4501"
],
[]
]
},
{
"id": "877cc93985027ebe",
"type": "function",
"z": "d84b176e12749a08",
"name": "msg.payload = 10;",
"func": "msg.payload = 10;\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 610,
"y": 160,
"wires": [
[
"277f18b9ad3b9208"
]
]
},
{
"id": "cdcb31eb2f25ce22",
"type": "inject",
"z": "d84b176e12749a08",
"name": "machine start test",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 390,
"y": 160,
"wires": [
[
"877cc93985027ebe"
]
]
},
{
"id": "a0979d8af4ac6499",
"type": "inject",
"z": "d84b176e12749a08",
"name": "reset",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 350,
"y": 260,
"wires": [
[
"7f09457c0b80cd69"
]
]
},
{
"id": "7f09457c0b80cd69",
"type": "function",
"z": "d84b176e12749a08",
"name": "reset 0",
"func": "msg.reset = {\n \"string\":0};\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 350,
"y": 220,
"wires": [
[
"277f18b9ad3b9208"
]
]
},
{
"id": "298ff033d4c7e091",
"type": "subflow:a2474b2214d6b686",
"z": "d84b176e12749a08",
"name": "",
"x": 930,
"y": 320,
"wires": [
[
"decc3956e0aa485b"
]
]
},
{
"id": "decc3956e0aa485b",
"type": "ui-chart",
"z": "d84b176e12749a08",
"group": "fd6045295841c382",
"name": "chart starts",
"label": "starts",
"order": 1,
"chartType": "bar",
"category": "category",
"categoryType": "property",
"xAxisLabel": "",
"xAxisProperty": "x",
"xAxisPropertyType": "property",
"xAxisType": "category",
"xAxisFormat": "",
"xAxisFormatType": "auto",
"xmin": "",
"xmax": "",
"yAxisLabel": "",
"yAxisProperty": "y",
"yAxisPropertyType": "property",
"ymin": "",
"ymax": "",
"bins": 10,
"action": "replace",
"stackSeries": false,
"pointShape": "circle",
"pointRadius": 4,
"showLegend": true,
"removeOlder": 1,
"removeOlderUnit": "3600",
"removeOlderPoints": "",
"colors": [
"#0095ff",
"#ff0000",
"#ff7f0e",
"#2ca02c",
"#a347e1",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"textColor": [
"#666666"
],
"textColorDefault": true,
"gridColor": [
"#e5e5e5"
],
"gridColorDefault": true,
"width": "30",
"height": "6",
"className": "",
"interpolation": "linear",
"x": 890,
"y": 360,
"wires": [
[]
]
},
{
"id": "31806e697f531027",
"type": "ui-text",
"z": "d84b176e12749a08",
"group": "fd6045295841c382",
"order": 3,
"width": 2,
"height": 1,
"name": "starts count",
"label": "",
"format": "",
"layout": "row-left",
"style": true,
"font": "Arial,Arial,Helvetica,sans-serif",
"fontSize": "15",
"color": "#ffffff",
"wrapText": false,
"className": "",
"x": 890,
"y": 140,
"wires": []
},
{
"id": "635e08363a2a4501",
"type": "change",
"z": "d84b176e12749a08",
"name": "set topic start",
"rules": [
{
"t": "set",
"p": "topic",
"pt": "msg",
"to": "start",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 900,
"y": 200,
"wires": [
[
"a3e7dd21ae7cc9c6"
]
]
},
{
"id": "f93aa849d2691722",
"type": "function",
"z": "d84b176e12749a08",
"name": "Get Chart Data",
"func": "var tempArray = flow.get('chartdata') || [];\nvar startDate = msg.payload.date;\nvar oldDate = flow.get('oldDate');\nvar oldCount = flow.get('oldCount') || 0;\nvar count = 0;\n\n// If this is the first time, initialize array\nif (tempArray.length === 0) {\n tempArray.push({ date: startDate, starts: 0 });\n }\n\nvar lastIndex = tempArray.length - 1;\n\nif (startDate === oldDate) {\n count = oldCount + 1;\n flow.set(\"oldCount\", count);\n // Update last element\n tempArray[lastIndex].date = startDate;\n tempArray[lastIndex].starts = count;\n} else {\n count = 1;\n flow.set(\"oldCount\", count);\n flow.set(\"oldDate\", startDate);\n // Add new element\n tempArray.push({ date: startDate, starts: count});\n}\n\n// Save to flow and msg\nflow.set(\"chartdata\", tempArray);\nmsg.chartData = tempArray;\n\nreturn msg;\n",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nvar count = flow.get('count1');",
"finalize": "",
"libs": [],
"x": 900,
"y": 280,
"wires": [
[
"298ff033d4c7e091"
]
]
},
{
"id": "a3e7dd21ae7cc9c6",
"type": "change",
"z": "d84b176e12749a08",
"name": "Today's Data",
"rules": [
{
"t": "set",
"p": "payload.date",
"pt": "msg",
"to": "$moment().tz(\"America/Chicago\").add(1, \"days\").format(\"MM-DD\")",
"tot": "jsonata"
},
{
"t": "set",
"p": "payload.count",
"pt": "msg",
"to": "1",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 890,
"y": 240,
"wires": [
[
"f93aa849d2691722"
]
]
},
{
"id": "02a77727a0cd3526",
"type": "ui-text",
"z": "d84b176e12749a08",
"group": "fd6045295841c382",
"order": 2,
"width": 2,
"height": 1,
"name": "starts count",
"label": "starts count",
"format": "",
"layout": "row-left",
"style": true,
"font": "Arial,Arial,Helvetica,sans-serif",
"fontSize": "15",
"color": "#ffffff",
"wrapText": false,
"className": "",
"x": 890,
"y": 100,
"wires": []
},
{
"id": "fd6045295841c382",
"type": "ui-group",
"name": "db2 bar wip share",
"page": "ccc312f7c9d7a917",
"width": "30",
"height": 1,
"order": 1,
"showTitle": true,
"className": "",
"visible": "true",
"disabled": "false",
"groupType": "default"
},
{
"id": "ccc312f7c9d7a917",
"type": "ui-page",
"name": "db2 bar wip share",
"ui": "388b8b8310e87685",
"path": "/page26",
"icon": " ",
"layout": "grid",
"theme": "3a38f453283ba387",
"breakpoints": [
{
"name": "Default",
"px": "0",
"cols": "9"
},
{
"name": "Tablet",
"px": "576",
"cols": "9"
},
{
"name": "Small Desktop",
"px": "768",
"cols": "9"
},
{
"name": "Desktop",
"px": "1024",
"cols": "12"
}
],
"order": 1,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "388b8b8310e87685",
"type": "ui-base",
"name": " /",
"path": "/dashboard",
"appIcon": "",
"includeClientData": true,
"acceptsClientConfig": [
"ui-notification",
"ui-control"
],
"showPathInSidebar": false,
"headerContent": "none",
"navigationStyle": "default",
"titleBarStyle": "default",
"showReconnectNotification": false,
"notificationDisplayTime": 5,
"showDisconnectNotification": false,
"allowInstall": false
},
{
"id": "3a38f453283ba387",
"type": "ui-theme",
"name": "dark jtm",
"colors": {
"surface": "#000000",
"primary": "#919191",
"bgPage": "#000000",
"groupBg": "#000000",
"groupOutline": "#000000"
},
"sizes": {
"pagePadding": "1px",
"groupGap": "1px",
"groupBorderRadius": "1px",
"widgetGap": "1px",
"density": "comfortable"
}
},
{
"id": "ae7a92ea9c24ff27",
"type": "global-config",
"env": [],
"modules": {
"node-red-contrib-counter": "0.1.6",
"@flowfuse/node-red-dashboard": "1.26.0"
}
}
]
@houser - here is a flow that seems to work. I changed the function node (ui-chart only takes the data in msg.payload) and added some additional checks.
Basic Logic:
There are 3 inject nodes - each sends in the current timestamp and a machine name (not used in this flow but could be modified to allow you to plot multiple machines on the same chart) and a count of 10.
The 3 change nodes convert the timestamp into a readable date in the format âmm-ddâ. The last 2 change nodes add 1 and 2 days to the current date (to show that if the date changes, there is a new 'âbarâ shown on the chart).
The function node compares the incoming date and if it is different than the old date, adds a record for a new date and assigns it the incoming âcountâ. If it is an existing date, it adds the new count to the old one.
The data is sent in msg.payload looks like this (each date has a different count). The flow also does away with the counter node as it stores the updated count in flow variables (you can see that in the context variables panel)
[{"date":"08-17","starts":10},{"date":"08-17","starts":20},{"date":"08-18","starts":20},{"date":"08-19","starts":50}]
This is what the chart looks like:
Here is the updated flow:
[{"id":"cdcb31eb2f25ce22","type":"inject","z":"d84b176e12749a08","name":"Machine Starts Day 1","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 1","x":400,"y":160,"wires":[["a778b74aafec4062"]]},{"id":"a778b74aafec4062","type":"change","z":"d84b176e12749a08","name":"Today's Count","rules":[{"t":"set","p":"date","pt":"msg","to":"$moment(timestamp).tz(\"America/Chicago\").format(\"MM-DD\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":600.1286468505859,"y":159.88603401184082,"wires":[["f93aa849d2691722"]]},{"id":"f93aa849d2691722","type":"function","z":"d84b176e12749a08","name":"Get Chart Data","func":"var tempArray = flow.get('chartdata') || [];\nvar startDate = msg.date;\nvar oldDate = flow.get('oldDate');\nvar oldCount = flow.get('oldCount') || 0;\nvar count = msg.count;\n\n// If this is the first time, initialize array\nif (tempArray.length === 0) {\n oldDate = startDate;\n tempArray.push({ date: startDate, starts: 0 });\n }\n\nvar lastIndex = tempArray.length - 1;\n\nif (startDate === oldDate) {\n count = oldCount + count;\n flow.set(\"oldCount\", count);\n // Update last element\n tempArray[lastIndex].date = startDate;\n tempArray[lastIndex].starts = count;\n} else {\n count = count;\n flow.set(\"oldCount\", count);\n flow.set(\"oldDate\", startDate);\n // Add new element\n tempArray.push({ date: startDate, starts: count});\n}\n\n// Save to flow and msg\nflow.set(\"chartdata\", tempArray);\nmsg.payload = tempArray;\nmsg.series = startDate;\nmsg.count = count;\n\n\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nvar count = flow.get('count1');","finalize":"","libs":[],"x":897.0000305175781,"y":296,"wires":[["c7d0f3708a5187da","d66e4f7c17fc116d"]]},{"id":"dd40a0c12802d59f","type":"change","z":"d84b176e12749a08","name":"Day + 1","rules":[{"t":"set","p":"date","pt":"msg","to":"$moment(timestamp).tz(\"America/Chicago\").add(1, \"days\").format(\"MM-DD\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":588.2573089599609,"y":223.772066116333,"wires":[["f93aa849d2691722"]]},{"id":"dcc2741547a1f307","type":"change","z":"d84b176e12749a08","name":"Day + 2","rules":[{"t":"set","p":"date","pt":"msg","to":"$moment(timestamp).tz(\"America/Chicago\").add(2, \"days\").format(\"MM-DD\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":591.25732421875,"y":290.7720489501953,"wires":[["f93aa849d2691722"]]},{"id":"c7d0f3708a5187da","type":"debug","z":"d84b176e12749a08","name":"Debug Chart Data","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1110.6545295715332,"y":296.16357421875,"wires":[]},{"id":"d66e4f7c17fc116d","type":"ui-chart","z":"d84b176e12749a08","group":"fd6045295841c382","name":"Count STarts","label":"Machine Starts","order":3,"chartType":"bar","category":"Daily Machine Starts","categoryType":"str","xAxisLabel":"Date","xAxisProperty":"date","xAxisPropertyType":"property","xAxisType":"category","xAxisFormat":"","xAxisFormatType":"auto","xmin":"","xmax":"","yAxisLabel":"Starts","yAxisProperty":"starts","yAxisPropertyType":"property","ymin":"","ymax":"","bins":"","action":"replace","stackSeries":false,"pointShape":"circle","pointRadius":4,"showLegend":true,"removeOlder":1,"removeOlderUnit":"3600","removeOlderPoints":"","colors":["#0095ff","#ff0000","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"textColor":["#ffffff"],"textColorDefault":false,"gridColor":["#e5e5e5"],"gridColorDefault":true,"width":6,"height":8,"className":"","interpolation":"linear","x":906.1286468505859,"y":368.8860034942627,"wires":[[]]},{"id":"407676baf1fbb4af","type":"inject","z":"d84b176e12749a08","name":"machine starts (Day 2)","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 1","x":396.12864685058594,"y":222.88603401184082,"wires":[["dd40a0c12802d59f"]]},{"id":"d383e08133f2cd78","type":"inject","z":"d84b176e12749a08","name":"machine starts (Day 3)","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 1","x":399.128662109375,"y":289.8860168457031,"wires":[["dcc2741547a1f307"]]},{"id":"1fc05c88906e8a89","type":"change","z":"d84b176e12749a08","name":"Delete Flow Variables","rules":[{"t":"delete","p":"oldCount","pt":"flow"},{"t":"delete","p":"oldDate","pt":"flow"},{"t":"delete","p":"chartdata","pt":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":608.6580657958984,"y":433.1378173828125,"wires":[["d66e4f7c17fc116d"]]},{"id":"dcd1f46bcbe83c0f","type":"inject","z":"d84b176e12749a08","name":"Clear Data","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[]","payloadType":"json","x":384.71690368652344,"y":432.4154357910156,"wires":[["1fc05c88906e8a89"]]},{"id":"fd6045295841c382","type":"ui-group","name":"db2 bar wip share","page":"ccc312f7c9d7a917","width":"30","height":1,"order":1,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"ccc312f7c9d7a917","type":"ui-page","name":"db2 bar wip share","ui":"de5759a313e7ad79","path":"/page26","icon":" ","layout":"grid","theme":"3a38f453283ba387","breakpoints":[{"name":"Default","px":"0","cols":"9"},{"name":"Tablet","px":"576","cols":"9"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":22,"className":"","visible":"true","disabled":"false"},{"id":"de5759a313e7ad79","type":"ui-base","name":"Node-RED Dashboard DB2","path":"/dashboard","appIcon":"","includeClientData":false,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"headerContent":"dashboard","navigationStyle":"fixed","titleBarStyle":"default","showReconnectNotification":true,"notificationDisplayTime":5,"showDisconnectNotification":true,"allowInstall":true},{"id":"3a38f453283ba387","type":"ui-theme","name":"dark jtm","colors":{"surface":"#000000","primary":"#919191","bgPage":"#000000","groupBg":"#000000","groupOutline":"#000000"},"sizes":
{"pagePadding":"1px","groupGap":"1px","groupBorderRadius":"1px","widgetGap":"1px","density":"comfortable"}}]
Hope this helps. I have left out your âpersistenceâ sub-flow but you could connect that to the output of the function node.
Many thanks @rakgupta
Will try this asap!
I got curious how this would work so decided to try it out. It was beyond my javascript capabilities but with ChatGPTâs help it worked! Putting it out here in case you need it
[{"id":"cdcb31eb2f25ce22","type":"inject","z":"d84b176e12749a08","name":"Machine 1 Day 1","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 1","x":360.8345642089844,"y":120.00000286102295,"wires":[["a778b74aafec4062"]]},{"id":"a778b74aafec4062","type":"change","z":"d84b176e12749a08","name":"Day 1","rules":[{"t":"set","p":"date","pt":"msg","to":"$moment(timestamp).tz(\"America/Chicago\").format(\"MM-DD\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":574.1286926269531,"y":163.88603496551514,"wires":[["f93aa849d2691722","fbac3545753cd5a2"]]},{"id":"d0cd9e4acb65a21f","type":"inject","z":"d84b176e12749a08","name":"Machine 2 Day 1","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 2","x":360.8345642089844,"y":160.94485759735107,"wires":[["a778b74aafec4062"]]},{"id":"525c671130d800e0","type":"inject","z":"d84b176e12749a08","name":"Machine 3 Day 1","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 3","x":360.8345642089844,"y":206.94485759735107,"wires":[["a778b74aafec4062"]]},{"id":"f93aa849d2691722","type":"function","z":"d84b176e12749a08","name":"Get Chart Data","func":"// --- Retrieve or initialize stored data ---\nlet chartData = flow.get('chartdata') || [];\n\n// Optional reset\nif (msg.reset || msg.topic === 'reset') {\n chartData = [];\n}\n\n// Extract incoming message\nconst date = String(msg.date);\nconst machine = String(msg.topic); // machine name\nconst count = Number(msg.count) || 0;\n\n// --- Update or insert record ---\nlet found = false;\nfor (let row of chartData) {\n if (row.date === date && row.machine === machine) {\n row.starts += count; // accumulate count\n found = true;\n break;\n }\n}\n\nif (!found) {\n chartData.push({ date: date, machine: machine, starts: count });\n}\n\n// Save updated data in flow\nflow.set('chartdata', chartData);\n\n// --- Output flat array for Dashboard 2 ---\nmsg.payload = chartData;\n\n// Optional debug\nmsg.chartData = chartData;\n\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nvar count = flow.get('count1');","finalize":"","libs":[],"x":808.0000915527344,"y":291.00000286102295,"wires":[["c7d0f3708a5187da","d66e4f7c17fc116d"]]},{"id":"fbac3545753cd5a2","type":"debug","z":"d84b176e12749a08","name":"Day 1 debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":762.6543884277344,"y":144.1635972910156,"wires":[]},{"id":"dd40a0c12802d59f","type":"change","z":"d84b176e12749a08","name":"Day 2","rules":[{"t":"set","p":"date","pt":"msg","to":"$moment(timestamp).tz(\"America/Chicago\").add(1, \"days\").format(\"MM-DD\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":574.1286926269531,"y":296.7720670700073,"wires":[["f93aa849d2691722"]]},{"id":"dcc2741547a1f307","type":"change","z":"d84b176e12749a08","name":"Day 3","rules":[{"t":"set","p":"date","pt":"msg","to":"$moment(timestamp).tz(\"America/Chicago\").add(2, \"days\").format(\"MM-DD\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":574.1286926269531,"y":435.77204990386963,"wires":[["f93aa849d2691722"]]},{"id":"c7d0f3708a5187da","type":"debug","z":"d84b176e12749a08","name":"Debug Chart Data","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":865.6545715332031,"y":235.16357707977295,"wires":[]},{"id":"d66e4f7c17fc116d","type":"ui-chart","z":"d84b176e12749a08","group":"fd6045295841c382","name":"Count STarts","label":"Machine Starts","order":3,"chartType":"bar","category":"machine","categoryType":"property","xAxisLabel":"Date","xAxisProperty":"date","xAxisPropertyType":"property","xAxisType":"category","xAxisFormat":"","xAxisFormatType":"auto","xmin":"","xmax":"","yAxisLabel":"Starts","yAxisProperty":"starts","yAxisPropertyType":"property","ymin":"","ymax":"","bins":"","action":"replace","stackSeries":false,"pointShape":"circle","pointRadius":4,"showLegend":true,"removeOlder":1,"removeOlderUnit":"3600","removeOlderPoints":"","colors":["#0095ff","#ff0000","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"textColor":["#ffffff"],"textColorDefault":false,"gridColor":["#e5e5e5"],"gridColorDefault":true,"width":6,"height":8,"className":"","interpolation":"linear","x":1096.1286926269531,"y":291.8860197067261,"wires":[[]]},{"id":"407676baf1fbb4af","type":"inject","z":"d84b176e12749a08","name":"Machine 1 (Day 2)","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 1","x":370.8345642089844,"y":257.88605308532715,"wires":[["dd40a0c12802d59f"]]},{"id":"a2fe8cb06e81a09b","type":"inject","z":"d84b176e12749a08","name":"Machine 2 (Day 2)","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 2","x":370.8345642089844,"y":295.9448575973511,"wires":[["dd40a0c12802d59f"]]},{"id":"92e078556e16bb49","type":"inject","z":"d84b176e12749a08","name":"Machine 3 (Day 2)","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 2","x":370.8345642089844,"y":331.9448575973511,"wires":[["dd40a0c12802d59f"]]},{"id":"e027ea0db2f5ae23","type":"inject","z":"d84b176e12749a08","name":"Machine 1 (Day 3)","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 1","x":370.8345642089844,"y":392.9448575973511,"wires":[["dcc2741547a1f307"]]},{"id":"dfe39f75f1fddffe","type":"inject","z":"d84b176e12749a08","name":"Machine 2 (Day 3)","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 2","x":370.8345642089844,"y":434.00366592407227,"wires":[["dcc2741547a1f307"]]},{"id":"8fb8c001a9735507","type":"inject","z":"d84b176e12749a08","name":"Machine 3 (Day 3)","props":[{"p":"timestamp","v":"","vt":"date"},{"p":"topic","vt":"str"},{"p":"count","v":"10","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Machine 2","x":370.8345642089844,"y":476.00366497039795,"wires":[["dcc2741547a1f307"]]},{"id":"1fc05c88906e8a89","type":"change","z":"d84b176e12749a08","name":"Delete Flow Variables","rules":[{"t":"delete","p":"oldCount","pt":"flow"},{"t":"delete","p":"oldDate","pt":"flow"},{"t":"delete","p":"chartdata","pt":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":956.6582336425781,"y":434.13782024383545,"wires":[["d66e4f7c17fc116d"]]},{"id":"dcd1f46bcbe83c0f","type":"inject","z":"d84b176e12749a08","name":"Clear Data","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[]","payloadType":"json","x":759.7170104980469,"y":434.4154386520386,"wires":[["1fc05c88906e8a89"]]},{"id":"fd6045295841c382","type":"ui-group","name":"db2 bar wip share","page":"ccc312f7c9d7a917","width":"30","height":1,"order":1,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"ccc312f7c9d7a917","type":"ui-page","name":"db2 bar wip share","ui":"de5759a313e7ad79","path":"/page26","icon":" ","layout":"grid","theme":"3a38f453283ba387","breakpoints":[{"name":"Default","px":"0","cols":"9"},{"name":"Tablet","px":"576","cols":"9"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":22,"className":"","visible":"true","disabled":"false"},{"id":"de5759a313e7ad79","type":"ui-base","name":"Node-RED Dashboard DB2","path":"/dashboard","appIcon":"","includeClientData":false,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"headerContent":"dashboard","navigationStyle":"fixed","titleBarStyle":"default","showReconnectNotification":true,"notificationDisplayTime":5,"showDisconnectNotification":true,"allowInstall":true},{"id":"3a38f453283ba387","type":"ui-theme","name":"dark jtm","colors":{"surface":"#000000","primary":"#919191","bgPage":"#000000","groupBg":"#000000","groupOutline":"#000000"},"sizes":{"pagePadding":"1px","groupGap":"1px","groupBorderRadius":"1px","widgetGap":"1px","density":"comfortable"}}]
This is what the chart looks like: