{
  "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"
}