AutomationFlowsAI & RAG › AI-Powered SCADA Data Analysis Workflow

AI-Powered SCADA Data Analysis Workflow

Original n8n title: Scada Sim Subworkflow

SCADA Sim Subworkflow. Uses lmChatGoogleGemini, agent, postgres, outputParserStructured. Scheduled trigger; 16 nodes.

Cron / scheduled trigger★★★★☆ complexityAI-powered16 nodesGoogle Gemini ChatAgentPostgresOutput Parser StructuredEmail SendGrafanaHTTP Request
AI & RAG Trigger: Cron / scheduled Nodes: 16 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Agent → Emailsend recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "active": false,
  "activeVersion": null,
  "activeVersionId": null,
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Fetch SCADA Data": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Fetch SCADA Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert rows in a table": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Insert rows in a table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript1": {
      "main": [
        [
          {
            "node": "If1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send email": {
      "main": [
        []
      ]
    },
    "HTML": {
      "main": [
        [
          {
            "node": "Send email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If1": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "HTML",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get a dashboard",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get a dashboard": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "createdAt": "2025-11-17T21:08:28.002Z",
  "id": "w300VNo8XkpwXGsk",
  "isArchived": false,
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "SCADA Sim Subworkflow",
  "nodes": [
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        304,
        -288
      ],
      "id": "7b7836bf-1ba3-4975-aee5-14cc3c8db1db",
      "name": "Google Gemini Chat Model",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=> *Eres un Analista Industrial Senior especializado en monitoreo IoT, diagn\u00f3stico predictivo y an\u00e1lisis de series temporales para sistemas hidr\u00e1ulicos y de presi\u00f3n. Tu responsabilidad es detectar condiciones anormales que puedan indicar fugas, fallas cr\u00edticas o comportamientos peligrosos en dispositivos industriales. Est\u00e1s manejando un caso de urgencia operativa y tu respuesta debe ser precisa, t\u00e9cnica y accionable.*\n\n\nQuiero que analices los siguientes datos provenientes de sensores industriales. La situaci\u00f3n es de car\u00e1cter urgente y se requiere un diagn\u00f3stico inmediato.\n\nLos datos incluyen:\n\n* Valores del sensor\n* Fecha/Hora de lectura\n* L\u00edmites m\u00ednimos y m\u00e1ximos permitidos\n* Distancia a los l\u00edmites (above_max / below_min)\n* Delta de variaci\u00f3n\n* Media m\u00f3vil y desviaci\u00f3n est\u00e1ndar\n* Z-score\n* Informaci\u00f3n del dispositivo y del tag asociado\n\nAqu\u00ed est\u00e1n los datos (en formato JSON):\n\n{{ JSON.stringify($json) }}\n\n### **Criterios para considerar posible falla o fuga (will_fail = true):**\n\n* Tendencia descendente constante en presi\u00f3n o nivel.\n* Ca\u00eddas abruptas (delta_value negativo pronunciado).\n* Z-score menor a -2 o mayor a +2 indicando comportamiento anormal.\n* Valores repetidamente fuera de rango o muy cercanos al m\u00ednimo/m\u00e1ximo permitido.\n* Variabilidad anormal detectada en la media m\u00f3vil de 1 hora (std_1h elevada).\n* Evidencia correlacionada con alarmas o eventos recientes.\n\n### **Criterios para marcar como normal (will_fail = false):**\n\n* Variaci\u00f3n dentro de tolerancias operativas normales.\n* Oscilaciones esperadas del sistema.\n* Cambios explicables por operaciones registradas (ej. comandos previos).\n\n**Responde \u00fanicamente con un array de objetos JSON**, sin texto adicional, con el siguiente formato:\n\n```php\nResponde \u00daNICAMENTE con un array JSON v\u00e1lido. \nNo incluyas texto antes ni despu\u00e9s.\nNo agregues claves como \"output\", \"result\" o similares.\n\nEl formato exacto es:\n\n[\n  {\n    \"device_id\": <number>,\n    \"will_fail\": <true|false>,\n    \"description\": \"<texto>\"\n  }\n]\n```",
        "hasOutputParser": true,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3,
      "position": [
        304,
        -480
      ],
      "id": "9438ab63-81df-48b5-bc80-6f241b4c128b",
      "name": "AI Agent"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "WITH\nvalues_today AS (\n    SELECT \n        tv.tag_id,\n        tv.timestamp,\n        tv.value,\n        LAG(tv.value) OVER (PARTITION BY tv.tag_id ORDER BY tv.timestamp) AS prev_value\n    FROM TagValues tv\n    WHERE tv.timestamp >= CURRENT_DATE\n),\n\ntag_stats AS (\n    SELECT\n        t.device_id,\n        t.tag_id,\n        t.tag_name,\n        MIN(v.value) AS min_value_day,\n        MAX(v.value) AS max_value_day,\n        AVG(v.value) AS avg_value_day,\n        MAX(ABS(v.value - v.prev_value)) AS max_variation\n    FROM values_today v\n    JOIN Tags t ON v.tag_id = t.tag_id\n    GROUP BY t.device_id, t.tag_id, t.tag_name\n),\n\nout_of_range AS (\n    SELECT \n        v.tag_id,\n        COUNT(*) AS out_of_range_count\n    FROM values_today v\n    JOIN Tags t ON v.tag_id = t.tag_id\n    WHERE (v.value < t.min_value OR v.value > t.max_value)\n    GROUP BY v.tag_id\n),\n\nalarms_today AS (\n    SELECT \n        t.tag_id,\n        COUNT(*) AS alarm_count\n    FROM Alarms a\n    JOIN Tags t ON a.tag_id = t.tag_id\n    WHERE a.timestamp >= CURRENT_DATE\n    GROUP BY t.tag_id\n)\n\nSELECT \n    d.device_id,\n    d.device_name,\n    ts.tag_id,\n    ts.tag_name,\n    ts.min_value_day,\n    ts.max_value_day,\n    ts.avg_value_day,\n    ts.max_variation,\n    COALESCE(o.out_of_range_count, 0) AS out_of_range_count,\n    COALESCE(a.alarm_count, 0) AS alarm_count\nFROM tag_stats ts\nJOIN Devices d ON ts.device_id = d.device_id\nLEFT JOIN out_of_range o ON ts.tag_id = o.tag_id\nLEFT JOIN alarms_today a ON ts.tag_id = a.tag_id\nORDER BY d.device_id, ts.tag_name;\n",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -336,
        -464
      ],
      "id": "b5977f22-9f1d-4811-b60f-733ddfa219c8",
      "name": "Fetch SCADA Data",
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"type\": \"array\",\n  \"items\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"device_id\": { \"type\": \"number\" },\n      \"will_fail\": { \"type\": \"boolean\" },\n      \"description\": { \"type\": \"string\" }\n    },\n    \"required\": [\"device_id\", \"will_fail\", \"description\"],\n    \"additionalProperties\": false\n  }\n}"
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        448,
        -288
      ],
      "id": "35ca90af-42f3-405b-9995-bd0c2d2473cf",
      "name": "Structured Output Parser"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -544,
        -464
      ],
      "id": "fce25b71-80dc-497e-b308-2ca5a3ad0951",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "jsCode": "function formatJSON(arr) {\n  return JSON.stringify(arr, null, 2)\n    .replace(/\\\\\"/g, '\"');  \n}\n\nconst unified = formatJSON(\n  $input.all().map(item => item.json)\n);\n\nreturn [\n  { json: { unified } }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        112,
        -480
      ],
      "id": "78e9b903-d65a-4c13-825e-26938364e94f",
      "name": "Code in JavaScript"
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\n\nlet failingDevices = [];\n\nfor (const item of items) {\n    const data = item.json;\n\n    if (data.will_fail === true) {\n        failingDevices.push({\n            device_id: data.device_id,\n            will_fail: data.will_fail,\n            description: data.description\n        });\n    }\n}\n\nreturn failingDevices.map(d => ({ json: d }));\n\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        912,
        -480
      ],
      "id": "104ddacf-2423-4f90-864f-862c75aaa68a",
      "name": "Code in JavaScript1"
    },
    {
      "parameters": {
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "failure_logs",
          "mode": "list",
          "cachedResultName": "failure_logs"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "will_fail": "={{ $json.will_fail }}",
            "created_at": "={{ new Date().toISOString() }}",
            "device_id": "={{ $json.device_id }}",
            "description": "={{ $json.description }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true
            },
            {
              "id": "device_id",
              "displayName": "device_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true
            },
            {
              "id": "will_fail",
              "displayName": "will_fail",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "boolean",
              "canBeUsedToMatch": true
            },
            {
              "id": "description",
              "displayName": "description",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        768,
        -480
      ],
      "id": "d51ac115-a8dd-4c4f-932b-2c87f87add8a",
      "name": "Insert rows in a table",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "fieldToSplitOut": "output",
        "options": {}
      },
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        592,
        -480
      ],
      "id": "2292636f-07c6-49c9-bfb3-9153338b663a",
      "name": "Split Out"
    },
    {
      "parameters": {
        "html": "<html>\n  <body style=\"font-family: Arial, Helvetica, sans-serif; background-color:#f4f8fb; padding: 20px; color:#003049;\">\n\n    <div style=\"max-width: 700px; margin: auto; background: #ffffff; padding: 25px; border-radius: 8px; border: 1px solid #dce6ee;\">\n\n      <h2 style=\"color:#005f99; margin-bottom: 10px; font-weight: 600;\">\n        Reporte de Dispositivos con Fallas\n      </h2>\n\n      <p style=\"font-size: 15px; color:#003049; line-height: 1.5;\">\n        Se ha detectado actividad an\u00f3mala en los siguientes dispositivos. Este informe ha sido generado de forma autom\u00e1tica por el sistema de monitoreo.\n      </p>\n\n      <div style=\"margin-top: 25px;\">\n        {{\n          $input.all().map(i => i.json.data).flat().map(item => `\n            <div style=\"\n              border-left: 4px solid #4bb3fd;\n              padding: 12px 15px;\n              margin-bottom: 15px;\n              background: #f0f7fc;\n              border-radius: 6px;\n            \">\n              <strong style=\"font-size: 15px; color:#003049;\">\n                Dispositivo ID: ${item.device_id}\n              </strong>\n              <p style=\"margin: 6px 0 0 0; font-size: 14px; color:#003049;\">\n                ${item.description}\n              </p>\n            </div>\n          `).join(\"\")\n        }}\n      </div>\n\n      <p style=\"margin-top: 30px; font-size: 13px; color:#6c7a86; text-align: center;\">\n        Este es un aviso autom\u00e1tico generado por el sistema de supervisi\u00f3n de infraestructura.  \n      </p>\n\n    </div>\n\n  </body>\n</html>\n"
      },
      "type": "n8n-nodes-base.html",
      "typeVersion": 1.2,
      "position": [
        1568,
        -496
      ],
      "id": "1110ebae-aeef-4e60-ade7-c003b94e4f15",
      "name": "HTML"
    },
    {
      "parameters": {
        "fromEmail": "andresfelipecalderonramirez@gmail.com",
        "toEmail": "andres.calderon-r@mail.escuelaing.edu.co, santiago.botero-g@mail.escuelaing.edu.co, ricardo.ayala-g@mail.escuelaing.edu.co, santiago.amaya-z@mail.escuelaing.edu.co, laura.perilla-q@mail.escuelaing.edu.co",
        "subject": "Advertencia: Condiciones Irregulares en Equipos H\u00eddricos",
        "html": "={{ $json.html }}",
        "options": {}
      },
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        1792,
        -496
      ],
      "id": "107d128e-2ab2-4b3f-bb6b-ff64e55475a9",
      "name": "Send email",
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "5493e406-d608-49ba-ae3c-cb35c845cd34",
              "leftValue": "={{ $('Fetch SCADA Data').item.json }}",
              "rightValue": true,
              "operator": {
                "type": "object",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -96,
        -464
      ],
      "id": "d4c6e179-a7f2-4e87-8643-f510e81b0396",
      "name": "If"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "25874bfc-d965-4a09-8e97-a9f45d9d0110",
              "leftValue": "={{ $items().length }}",
              "rightValue": 0,
              "operator": {
                "type": "number",
                "operation": "notEquals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1072,
        -480
      ],
      "id": "ab5de91c-3f50-41b8-849c-4cb853bd98c2",
      "name": "If1"
    },
    {
      "parameters": {
        "aggregate": "aggregateAllItemData",
        "options": {}
      },
      "type": "n8n-nodes-base.aggregate",
      "typeVersion": 1,
      "position": [
        1360,
        -496
      ],
      "id": "8c936118-6ba5-4c9c-a581-9031304edf84",
      "name": "Aggregate"
    },
    {
      "parameters": {
        "operation": "get",
        "dashboardUidOrUrl": "https://andrescalderonr.grafana.net/d/anzptgl/aquasense"
      },
      "type": "n8n-nodes-base.grafana",
      "typeVersion": 1,
      "position": [
        1520,
        -288
      ],
      "id": "6683d6ae-d7a1-4ed3-8db2-8f0e72da87dc",
      "name": "Get a dashboard",
      "credentials": {
        "grafanaApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://andrescalderonr.grafana.net/api/dashboards/db",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "grafanaApi",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"meta\": {{ JSON.stringify(Object.assign({}, $json.meta, { version: $json.meta.version - 1 })) }},\n  \"dashboard\": {{ JSON.stringify(Object.assign({}, $json.dashboard, { version: $json.dashboard.version - 1 })) }},\n  \"overwrite\": true\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        1728,
        -288
      ],
      "id": "bac0eab6-4445-4c52-afb7-24796438015a",
      "name": "HTTP Request",
      "credentials": {
        "grafanaApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "settings": {
    "executionOrder": "v1"
  },
  "shared": [
    {
      "updatedAt": "2025-11-17T21:08:28.022Z",
      "createdAt": "2025-11-17T21:08:28.022Z",
      "role": "workflow:owner",
      "workflowId": "w300VNo8XkpwXGsk",
      "projectId": "xno20arzPonor2IK"
    }
  ],
  "staticData": null,
  "tags": [
    {
      "updatedAt": "2025-12-06T23:02:35.568Z",
      "createdAt": "2025-12-06T23:02:35.568Z",
      "id": "S3087lgPcaOEorMk",
      "name": "SCADA"
    }
  ],
  "triggerCount": 0,
  "updatedAt": "2025-12-15T06:01:31.118Z",
  "versionId": "3dae4b04-185d-43ec-be90-81110908d8f1"
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

SCADA Sim Subworkflow. Uses lmChatGoogleGemini, agent, postgres, outputParserStructured. Scheduled trigger; 16 nodes.

Source: https://github.com/LePeanutButter/n8n-workflows-aquasense/blob/main/workflows/w300VNo8XkpwXGsk.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

ERM Financiero Consolidado. Uses postgres, lmChatGoogleGemini, agent, outputParserStructured. Scheduled trigger; 20 nodes.

Postgres, Google Gemini Chat, Agent +4
AI & RAG

This workflow automates end-to-end patient care coordination by monitoring appointment schedules, clinical events, and care milestones while orchestrating personalized communications across multiple c

HTTP Request, Agent, OpenAI Chat +5
AI & RAG

This workflow automates satellite data processing by ingesting raw geospatial data, applying AI analysis, and submitting formatted reports to regulatory authorities. Designed for environmental agencie

HTTP Request, Agent, OpenAI Chat +4
AI & RAG

This workflow automates enterprise claims cost leakage detection by identifying overpayments, policy deviations, and pricing inconsistencies across claims data. It supports claims operations, finance,

HTTP Request, Agent, OpenAI Chat +4
AI & RAG

The system uses a three-stage pipeline architecture: automated paper retrieval from ArXiv's API AI-powered relevance filtering and analysis via Google Gemini Intelligent summarization with HTML format

Google Gemini Chat, Output Parser Structured, Email Send +5