[
{
"id": "ea088d9e256f2e4a",
"type": "tab",
"label": "Raspi",
"disabled": false,
"info": "",
"env": []
},
{
"id": "ea803f6a2965854b",
"type": "mqtt-broker",
"name": "Broker fuera casa",
"broker": "mqtt.maliountech.com.mx",
"port": "1883",
"clientid": "raspi-maquina1",
"autoConnect": true,
"usetls": false,
"protocolVersion": 4,
"keepalive": "30",
"cleansession": false,
"autoUnsubscribe": true,
"birthTopic": "",
"birthQos": "0",
"birthRetain": "false",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closeRetain": "false",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willRetain": "false",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
},
{
"id": "615493954251cda9",
"type": "ui_tab",
"name": "Home",
"icon": "dashboard",
"disabled": false,
"hidden": true
},
{
"id": "6fe5cca8f548047a",
"type": "ui_group",
"name": "HMI Dashboard",
"tab": "615493954251cda9",
"order": 1,
"disp": false,
"width": "25",
"collapse": false,
"className": ""
},
{
"id": "044327e0d3d61535",
"type": "ui_base",
"theme": {
"name": "theme-light",
"lightTheme": {
"default": "#0094CE",
"baseColor": "#0094CE",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
"edited": true,
"reset": false
},
"darkTheme": {
"default": "#097479",
"baseColor": "#097479",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
"edited": false
},
"customTheme": {
"name": "Untitled Theme 1",
"default": "#4B7930",
"baseColor": "#4B7930",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
},
"themeState": {
"base-color": {
"default": "#0094CE",
"value": "#0094CE",
"edited": false
},
"page-titlebar-backgroundColor": {
"value": "#0094CE",
"edited": false
},
"page-backgroundColor": {
"value": "#fafafa",
"edited": false
},
"page-sidebar-backgroundColor": {
"value": "#ffffff",
"edited": false
},
"group-textColor": {
"value": "#1bbfff",
"edited": false
},
"group-borderColor": {
"value": "#ffffff",
"edited": false
},
"group-backgroundColor": {
"value": "#ffffff",
"edited": false
},
"widget-textColor": {
"value": "#111111",
"edited": false
},
"widget-backgroundColor": {
"value": "#0094ce",
"edited": false
},
"widget-borderColor": {
"value": "#ffffff",
"edited": false
},
"base-font": {
"value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
}
},
"angularTheme": {
"primary": "indigo",
"accents": "blue",
"warn": "red",
"background": "grey",
"palette": "light"
}
},
"site": {
"name": "Node-RED Dashboard",
"hideToolbar": "false",
"allowSwipe": "false",
"lockMenu": "false",
"allowTempTheme": "true",
"dateFormat": "DD/MM/YYYY",
"sizes": {
"sx": 48,
"sy": 48,
"gx": 6,
"gy": 6,
"cx": 6,
"cy": 6,
"px": 0,
"py": 0
}
}
},
{
"id": "c195f94afd7183e6",
"type": "ui_template",
"z": "ea088d9e256f2e4a",
"group": "6fe5cca8f548047a",
"name": "HMI Dashboard Template",
"order": 0,
"width": "25",
"height": "25",
"format": "\n\n\n
\n \n \n Industrial HMI Dashboard\n \n \n \n\n\n\n \n \n \n\n \n
\n\n \n
\n
\n \n
\n
\n
\n
\n
\n
\n\n \n
\n\n \n
\n
\n
\n
\n
\n \n Online\n —\n
\n
\n \n Running\n —\n
\n
\n
\n\n \n \n
\n
\n\n \n
\n
\n \n
\n
\n \n \n | ID | \n SKU | \n Description | \n Target Qty | \n Completed | \n Progress | \n Status | \n Due Date | \n
\n \n \n \n | WO-2024-001 | \n SKU-ABC123 | \n Plastic Housing - Black | \n 2000 | \n 1200 | \n \n \n | \n In Progress | \n 2024-10-15 | \n
\n \n | WO-2024-002 | \n SKU-DEF456 | \n Cover Panel - White | \n 1500 | \n 0 | \n \n \n | \n Pending | \n 2024-10-20 | \n
\n \n | WO-2024-003 | \n SKU-GHI789 | \n Mounting Bracket - Grey | \n 800 | \n 800 | \n \n \n | \n Completed | \n 2024-09-28 | \n
\n \n
\n
\n
\n
\n\n \n
\n\n \n
\n\n \n
\n
\n \n
\n
\n \n
\n
\n
\n
Machine Started
\n
2 minutes ago
\n
\n
Info\n
\n
\n
\n
\n
Work Order Progress: 75%
\n
5 minutes ago
\n
\n
Update\n
\n
\n
\n
\n
Quality Alert: Scrap rate increasing
\n
15 minutes ago
\n
\n
Warning\n
\n
\n
\n
\n
\n\n \n
\n
\n \n
\n
\n \n
\n Dashboard View: Main HMI showing real-time machine data, OEE metrics,\n and production counters.
\n Navigation: Use the sidebar on the left to switch between different\n views.
\n Real-time Updates: All data updates automatically via MQTT connection.\n
\n
\n\n
\n \n
\n No Data Showing:
\n • Check MQTT broker connection
\n • Verify Node-RED is running
\n • Check browser console (F12)
\n Slow Updates:
\n • Check network connection
\n • Restart local MQTT broker\n
\n
\n\n
\n \n
\n \n | F11 | \n Toggle Fullscreen | \n
\n \n | F12 | \n Developer Console | \n
\n \n | Ctrl+R | \n Refresh Dashboard | \n
\n
\n
\n\n
\n \n
\n Version: 1.0.0
\n MQTT Broker: localhost:9001
\n Update Rate: 1 second
\n Browser: \n
\n
\n
\n
\n
\n\n \n
\n
\n \n
\n
\n \n
\n \n \n
\n
\n \n \n
\n
\n\n
\n \n
\n \n \n
\n
\n
\n\n
\n \n
\n \n \n
\n
\n
\n\n
\n \n
\n \n \n \n
\n
\n
\n
\n
\n\n
\n
\n\n \n\n\n",
"storeOutMessages": true,
"fwdInMessages": true,
"resendOnRefresh": true,
"templateScope": "local",
"className": "",
"x": 790,
"y": 320,
"wires": [
[]
]
},
{
"id": "d9407fca93d82949",
"type": "function",
"z": "ea088d9e256f2e4a",
"name": "Machine status function",
"func": "// Get previous state\nconst previousStatus = global.get(\"machine_status\") || {\n state: 'Running',\n isOnline: true,\n isRunning: true\n};\n\nlet state = previousStatus.state;\n\n// Random transitions\nif (Math.random() < 0.5) {\n state = state === 'Running' ? 'Stopped' : 'Running';\n}\n\n// Create status data\nconst statusData = {\n state: state,\n isOnline: state !== 'Error',\n isRunning: state === 'Running',\n timestamp: new Date().toISOString()\n};\n\n// Store in global\nglobal.set(\"machine_status\", statusData);\n\n// Send to UI\nmsg.payload = statusData;\nmsg.topic = \"pimsa/maquina1/status\";\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 470,
"y": 120,
"wires": [
[
"aaf07ca380495b06",
"c195f94afd7183e6"
]
]
},
{
"id": "547062128fa6337a",
"type": "inject",
"z": "ea088d9e256f2e4a",
"name": "Machine Data Timer",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "1",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 140,
"y": 300,
"wires": [
[
"d9407fca93d82949",
"207fdc449918affd",
"031c7ccb3125177b",
"2a35e2907dc04de0",
"global_data_reader"
]
]
},
{
"id": "4f66d69c5bce7ba0",
"type": "mqtt out",
"z": "ea088d9e256f2e4a",
"name": "MQTT Out - Work Order",
"topic": "pimsa/erp/workorder/current",
"qos": "1",
"retain": "true",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "ea803f6a2965854b",
"x": 810,
"y": 540,
"wires": []
},
{
"id": "aaf07ca380495b06",
"type": "mqtt out",
"z": "ea088d9e256f2e4a",
"name": "MQTT Out - Machine Status",
"topic": "pimsa/maquina1/status",
"qos": "1",
"retain": "true",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "ea803f6a2965854b",
"x": 820,
"y": 100,
"wires": []
},
{
"id": "fee4e024db51e661",
"type": "mqtt out",
"z": "ea088d9e256f2e4a",
"name": "MQTT Out - Machine OEE",
"topic": "pimsa/maquina1/oee",
"qos": "0",
"retain": "false",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "ea803f6a2965854b",
"x": 800,
"y": 260,
"wires": []
},
{
"id": "12c37a80895dcc3e",
"type": "mqtt out",
"z": "ea088d9e256f2e4a",
"name": "MQTT Out - Production",
"topic": "pimsa/maquina1/production",
"qos": "1",
"retain": "false",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "ea803f6a2965854b",
"x": 810,
"y": 400,
"wires": []
},
{
"id": "207fdc449918affd",
"type": "function",
"z": "ea088d9e256f2e4a",
"name": "OEE Function",
"func": "// OEE Function\nconst oeeData = {\n oee: 85 + Math.random() * 15,\n availability: 90 + Math.random() * 10,\n performance: 80 + Math.random() * 20,\n quality: 95 + Math.random() * 5,\n timestamp: new Date().toISOString()\n};\n\n// Store in global context (NEW!)\nglobal.set(\"oeeData\", oeeData);\n\nmsg.payload = oeeData;\nmsg.topic = \"pimsa/maquina1/oee\";\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 440,
"y": 260,
"wires": [
[
"fee4e024db51e661",
"c195f94afd7183e6"
]
]
},
{
"id": "031c7ccb3125177b",
"type": "function",
"z": "ea088d9e256f2e4a",
"name": "Production Function",
"func": "// Production Function with Auto-Reset for Demo\nconst targetQty = 2000;\n\n// Initialize or get current values\nlet goodParts = context.get('goodParts') || 100; // Start at 100 instead of 1200\nlet scrapParts = context.get('scrapParts') || 5;\n\n// Increment production\ngoodParts += Math.floor(Math.random() * 3) + 1;\nscrapParts += Math.floor(Math.random() * 2);\n\n// Calculate progress\nconst progress = Math.min(100, (goodParts / targetQty) * 100);\n\n// Auto-reset when reaching 100% (for continuous demo)\nif (goodParts >= targetQty) {\n goodParts = 100; // Reset to beginning\n scrapParts = 5;\n node.warn(\"Production cycle completed! Resetting for next work order...\");\n}\n\n// Save updated values\ncontext.set('goodParts', goodParts);\ncontext.set('scrapParts', scrapParts);\n\n// Create production data object\nconst productionData = {\n goodParts: goodParts,\n scrapParts: scrapParts,\n totalParts: goodParts + scrapParts,\n progress: progress,\n cycleTime: (45 + Math.random() * 10).toFixed(1) + \"s\",\n timestamp: new Date().toISOString()\n};\n\n// Store in global context (NEW!)\nglobal.set(\"productionData\", productionData);\n\nmsg.payload = productionData;\nmsg.topic = \"pimsa/maquina1/production\";\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 460,
"y": 400,
"wires": [
[
"12c37a80895dcc3e",
"c195f94afd7183e6"
]
]
},
{
"id": "2a35e2907dc04de0",
"type": "function",
"z": "ea088d9e256f2e4a",
"name": "Work Order Function",
"func": "// Work Order Function\nconst workOrder = {\n id: 'WO-2024-001',\n sku: 'SKU-ABC123',\n description: 'Plastic Housing - Black',\n targetQty: 2000,\n dueDate: '2024-10-15'\n};\n\n// Create work order data object\nconst workOrderData = {\n workOrder: workOrder.id,\n sku: workOrder.sku,\n description: workOrder.description,\n targetQty: workOrder.targetQty,\n completedQty: context.get('goodParts') || 1200,\n dueDate: workOrder.dueDate,\n timestamp: new Date().toISOString()\n};\n\n// Store in global context (NEW!)\nglobal.set(\"workOrderData\", workOrderData);\n\nmsg.payload = workOrderData;\nmsg.topic = \"pimsa/erp/workorder/current\";\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 460,
"y": 540,
"wires": [
[
"4f66d69c5bce7ba0",
"c195f94afd7183e6"
]
]
},
{
"id": "global_data_reader",
"type": "function",
"z": "ea088d9e256f2e4a",
"name": "Global Data Reader",
"func": "// Read all global values and send to template\nconst globalData = {\n machine_status: global.get(\"machine_status\") || {},\n oeeData: global.get(\"oeeData\") || {},\n productionData: global.get(\"productionData\") || {},\n workOrderData: global.get(\"workOrderData\") || {}\n};\n\n// Create a script that will update the dashboard\nconst updateScript = `\n window.globalData = ${JSON.stringify(globalData)};\n if (window.app && window.app.updateFromGlobalValues) {\n window.app.updateFromGlobalValues();\n }\n`;\n\n// Send the update script to the template\nmsg.payload = updateScript;\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 500,
"y": 320,
"wires": [
[
"c195f94afd7183e6"
]
]
}
]