{
  "nodes": [
    {
      "parameters": {
        "promptType": "define",
        "text": "=Please answer non-technical way.\n====\nUSER QUESTION: {{ $json.message.text }} ",
        "options": {
          "systemMessage": "\ud83e\udde0 HydroFarm DB Assistant (Expert Level)\n\ud83c\udfaf Tujuan\nAnda adalah asisten database khusus untuk tim hidroponik \u2014 mulai dari agronomis, manajer greenhouse, hingga peneliti.\nTugas Anda adalah menjalankan query SQL untuk membaca dan mengelola data sensor hidroponik, agar mendukung keputusan operasional berbasis data.\n\n\ud83d\udd27 Alur Eksekusi Tool (WAJIB dan BERURUTAN)\n\u2757 Selalu jalankan Tool 1 dan Tool 2 sebelum Tool 3 \u2014 kecuali hanya membaca cache/metainfo sebelumnya.\n\n1_Get DB Schema and Tables List\n\u2192 Validasi bahwa tabel sensor_data tersedia di skema db_remote.\n\n2_Get Table Definition\n\u2192 Periksa definisi kolom dan tipe data tabel sensor_data.\n\n3_Execute actual query\n\u2192 Jalankan perintah SQL sesuai kebutuhan:\n\n\u2705 SELECT: untuk analisis dan visualisasi data\n\n\n4. MQTT TOOL kamu bisa publish message ke topic dan message yang ditentuka user, selalu tanya terlebih dahulu untuk topic dan messagenya\n\n\u26a0\ufe0f INSERT, UPDATE, DELETE: hanya jika konteksnya membersihkan data duplikat, menambahkan data valid, atau menyesuaikan data yang salah format\n\n\u2699\ufe0f Aturan Query\nGunakan wildcard (%) dan LOWER() untuk pencarian berbasis teks.\n\nGunakan agregasi (AVG, MIN, MAX) untuk ringkasan data.\n\nTerapkan filter waktu seperti:\n\n\u201chari ini\u201d, \u201c24 jam terakhir\u201d, \u201cminggu ini\u201d, dll.\n\nGunakan batasan query (LIMIT, WHERE) saat membersihkan data.\n\n\ud83e\udde0 Contoh Interpretasi\nPertanyaan\tJawaban Ringkasan\n\u201cApakah EC melebihi 2.5 dalam 3 hari terakhir?\u201d\t\u2705 \u201cYa, EC mencapai puncak 2.8 pada 14 Juni pukul 13.00.\u201d\n\u201cBerapa suhu rata-rata hari ini?\u201d\t\ud83c\udf21\ufe0f \u201cSuhu rata-rata hari ini adalah 26.3\u00b0C.\u201d\n\u201cAdakah pH turun di bawah 5.5 minggu ini?\u201d\t\ud83d\udd0d \u201cTidak, pH tetap stabil di atas 5.8 selama 7 hari terakhir.\u201d\n\u201cHapus entri kosong dari kolom suhu\u201d\t\ud83e\uddf9 \u201c5 entri tanpa nilai suhu berhasil dihapus.\u201d\n\n\u274c Larangan Keras\n\ud83d\udeab Jangan tampilkan SQL mentah, nama kolom, atau istilah teknis (varchar, schema, dll.) ke pengguna.\n\n\ud83d\udeab Jangan lakukan perubahan data tanpa konteks bersih-bersih atau validasi format.\n\n\ud83d\udeab Jangan jalankan query destruktif secara otomatis tanpa analisis.\n\n\u2705 Karakter Asisten\nCerdas, efisien, dan ramah untuk non-teknikal user.\n\nFokus pada pemahaman praktis dan manfaat langsung untuk petani, teknisi lapangan, dan tim greenhouse.\n\n"
        }
      },
      "id": "5a1bab70-ce24-499e-adb4-e27733e0394c",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        440,
        740
      ],
      "typeVersion": 1.8
    },
    {
      "parameters": {
        "modelName": "models/gemini-2.0-flash-thinking-exp",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        260,
        940
      ],
      "id": "6b10cc8c-05f9-4523-ae5a-be5c94e5123b",
      "name": "Google Gemini Chat Model",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $json.message.chat.id }}"
      },
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1.3,
      "position": [
        380,
        940
      ],
      "id": "986d70a8-e80a-4d08-9b0a-da3b728fc83c",
      "name": "Simple Memory"
    },
    {
      "parameters": {
        "topic": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Topic', ``, 'string') }}",
        "sendInputData": false,
        "message": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Message', ``, 'string') }}",
        "options": {
          "qos": 0,
          "retain": false
        }
      },
      "type": "n8n-nodes-base.mqttTool",
      "typeVersion": 1,
      "position": [
        940,
        880
      ],
      "id": "0c35eab8-c41f-415d-a936-715d3c8ea09a",
      "name": "MQTT",
      "retryOnFail": true,
      "executeOnce": false,
      "alwaysOutputData": false,
      "credentials": {
        "mqtt": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "topics": "n8n/p5/#",
        "options": {
          "jsonParseBody": false
        }
      },
      "type": "n8n-nodes-base.mqttTrigger",
      "typeVersion": 1,
      "position": [
        40,
        360
      ],
      "id": "964f2c57-1626-41f7-96a9-99521504dfa7",
      "name": "MQTT Trigger",
      "credentials": {
        "mqtt": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const topic = $input.item.json.topic;\nconst topicParts = topic.split(\"/\");\nconst farmNameIndex = topicParts.indexOf(\"p5\") + 1;\nconst farmName = farmNameIndex < topicParts.length ? topicParts[farmNameIndex] : \"unknown\";\n\nconst sensorType = topicParts[topicParts.length - 1];\nreturn {\n  json: {\n    fullTopic: topic,\n    subTopic: topicParts.slice(2).join(\"/\"), \n    payload: $input.item.json.message,\n    farmName: farmName,\n    sensorType: sensorType,\n    value: parseFloat($input.item.json.message) || $input.item.json.message\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        260,
        360
      ],
      "id": "69e91683-788c-465e-a2fa-3d41b4daee3a",
      "name": "Slicing Topic"
    },
    {
      "parameters": {
        "content": "## \ud83d\udd04 Sensor Stream\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nMenerima data dari MQTT, parsing payload, dan simpan ke database.  ",
        "height": 340,
        "width": 740,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -40,
        240
      ],
      "id": "4b8a1d35-35b7-46c1-a8f3-4e5dbe269226",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Get list of all tables with their schema in the database",
        "operation": "executeQuery",
        "query": "SELECT \n    table_schema,\n    table_name\nFROM \n    information_schema.tables\nWHERE \n    table_type = 'BASE TABLE'\n    AND table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')\nORDER BY \n    table_schema, table_name;\n",
        "options": {}
      },
      "type": "n8n-nodes-base.mySqlTool",
      "typeVersion": 2.4,
      "position": [
        560,
        940
      ],
      "id": "cb418184-427e-446f-bafa-d4dcea210be9",
      "name": "get_db_schema_and_tables",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Get table definition to find all columns and types",
        "operation": "executeQuery",
        "query": "\nSELECT \n    c.column_name,\n    c.column_comment,\n    c.data_type,\n    c.is_nullable,\n    c.column_default,\n    tc.constraint_type,  \n    kcu.table_name AS referenced_table,\n    kcu.column_name AS referenced_column\nFROM \n    information_schema.columns c\nLEFT JOIN \n    information_schema.key_column_usage kcu\n    ON c.table_name = kcu.table_name\n    AND c.column_name = kcu.column_name\nLEFT JOIN \n    information_schema.table_constraints tc\n    ON kcu.constraint_name = tc.constraint_name\n    AND tc.constraint_type = 'FOREIGN KEY'\nWHERE \n  c.table_name = '{{ $fromAI(\"table_name\") }}'\n  AND c.table_schema = '{{ $fromAI(\"schema_name\") }}'\nORDER BY \n    c.ordinal_position;",
        "options": {}
      },
      "type": "n8n-nodes-base.mySqlTool",
      "typeVersion": 2.4,
      "position": [
        720,
        920
      ],
      "id": "746fd554-ad9e-410d-a20f-754485c12da8",
      "name": "get_table_definition",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Get all the data from sql, make sure you append the tables with correct schema. Every table is associated with some schema in the database.",
        "operation": "executeQuery",
        "query": "{{ $fromAI(\"sql_query\", \"SQL Query\") }}",
        "options": {}
      },
      "type": "n8n-nodes-base.mySqlTool",
      "typeVersion": 2.4,
      "position": [
        860,
        940
      ],
      "id": "5d74d8f6-44aa-46cf-a2e4-f9ed2dfdb088",
      "name": "execute_actual_query",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "table": {
          "__rl": true,
          "value": "sensor_readings",
          "mode": "list",
          "cachedResultName": "sensor_readings"
        },
        "dataMode": "defineBelow",
        "valuesToSend": {
          "values": [
            {
              "column": "farmId",
              "value": "={{ $json.farmName }}"
            },
            {
              "column": "sensor_type",
              "value": "={{ $json.sensorType }}"
            },
            {
              "column": "value",
              "value": "={{ $json.value }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [
        480,
        360
      ],
      "id": "6cc07d03-e1cf-4c80-ae7f-7cdf896b80f2",
      "name": "Saving -> DB",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "## \ud83d\udc7e AI Agent\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\nStill need a lil adjustment:",
        "height": 500,
        "width": 1180,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        660
      ],
      "id": "9f46de06-77f6-49ac-8691-1acd36131fd4",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1.2,
      "position": [
        160,
        740
      ],
      "id": "54c97c79-df67-412b-b94d-d8484f34112d",
      "name": "Telegram Trigger",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $('Telegram Trigger').item.json.message.chat.id }}",
        "text": "={{ $json.output }}",
        "additionalFields": {
          "appendAttribution": false,
          "parse_mode": "Markdown"
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        800,
        740
      ],
      "id": "6e7bec75-388b-45ef-a9ec-86f2100a59ef",
      "name": "Telegram",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "Telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "MQTT": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "MQTT Trigger": {
      "main": [
        [
          {
            "node": "Slicing Topic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slicing Topic": {
      "main": [
        [
          {
            "node": "Saving -> DB",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "get_db_schema_and_tables": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "get_table_definition": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "execute_actual_query": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "meta": {
    "templateCredsSetupCompleted": true
  }
}