From 18114de70713e2a1e9d31bff4f8b4a850daee07c Mon Sep 17 00:00:00 2001 From: flems Date: Thu, 25 Jun 2026 18:32:41 +0700 Subject: [PATCH] Cleanup: Hapus folder Flutter yang tidak diperlukan di backend --- backend/README.md | 17 + backend/SOLUSI_DATA_TIDAK_MASUK_MYSQL.md | 414 +++++++++++++++++++++++ backend/deploy-to-railway.ps1 | 183 ---------- backend/migrate_database.js | 111 ++++++ backend/railway.toml | 2 + 5 files changed, 544 insertions(+), 183 deletions(-) create mode 100644 backend/README.md create mode 100644 backend/SOLUSI_DATA_TIDAK_MASUK_MYSQL.md delete mode 100644 backend/deploy-to-railway.ps1 create mode 100644 backend/migrate_database.js diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..6986b1e --- /dev/null +++ b/backend/README.md @@ -0,0 +1,17 @@ +# aplikasi_novil + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter) +- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/backend/SOLUSI_DATA_TIDAK_MASUK_MYSQL.md b/backend/SOLUSI_DATA_TIDAK_MASUK_MYSQL.md new file mode 100644 index 0000000..0a4e3a2 --- /dev/null +++ b/backend/SOLUSI_DATA_TIDAK_MASUK_MYSQL.md @@ -0,0 +1,414 @@ +# πŸ”§ SOLUSI: Data ESP32 Tidak Masuk ke MySQL Railway + +## 🎯 Masalah + +ESP32 sudah publish data ke MQTT, tapi data **tidak masuk ke MySQL** di Railway. + +--- + +## πŸ” Penyebab + +### Arsitektur yang Salah: + +``` +❌ SEBELUM: + +ESP32 β†’ HiveMQ (broker.hivemq.com) + ↓ + (data hilang di sini) + +Backend Railway (Aedes Broker Internal - DISABLED) + ↓ + MySQL (tidak ada data) +``` + +**Masalah:** +1. ESP32 publish ke **HiveMQ** public broker +2. Backend Railway menggunakan **Aedes** (MQTT broker internal) +3. Aedes **DISABLED** di Railway (tidak bisa bind port 1883) +4. Backend **TIDAK connect** ke HiveMQ +5. Backend **TIDAK subscribe** ke topic ESP32 +6. **Data hilang** karena tidak ada yang terima + +--- + +## βœ… Solusi + +### Arsitektur yang Benar: + +``` +βœ… SESUDAH: + +ESP32 β†’ HiveMQ (broker.hivemq.com) + ↓ + Backend Railway (MQTT Client) + ↓ (subscribe & save) + MySQL Database +``` + +**Perubahan:** +1. Backend connect ke **HiveMQ sebagai MQTT Client** +2. Backend **subscribe** ke topic ESP32 +3. Backend **terima data** dari ESP32 +4. Backend **save ke MySQL** + +--- + +## πŸ› οΈ Perubahan yang Sudah Dilakukan + +### 1. **Install Package MQTT Client** +```bash +npm install mqtt +``` + +### 2. **Update `server.js`** +- Tambah import `mqtt` client +- Connect ke HiveMQ sebagai client +- Subscribe ke topic: `novil/pengering/data`, `status`, `button` +- Handle message dan save ke MySQL +- Publish command via HiveMQ + +### 3. **Update `.env`** +- Tambah `MQTT_BROKER_URL=mqtt://broker.hivemq.com:1883` +- Tambah template untuk MySQL credentials + +--- + +## πŸš€ Cara Deploy + +### 1. **Test Lokal (Optional)** + +```bash +cd backend +npm install +npm start +``` + +**Expected Output:** +``` +βœ… Connected to MQTT Broker (HiveMQ) +βœ… Subscribed to topics: + - novil/pengering/data + - novil/pengering/status + - novil/pengering/button +πŸš€ REST API running on port 3000 +``` + +### 2. **Push ke GitHub** + +```bash +cd backend +git add . +git commit -m "Fix: Backend connect to HiveMQ as MQTT client" +git push +``` + +### 3. **Configure Railway** + +Di Railway Dashboard: + +1. Buka project β†’ **Variables** +2. Tambahkan variable baru: + - **Key:** `MQTT_BROKER_URL` + - **Value:** `mqtt://broker.hivemq.com:1883` +3. MySQL credentials sudah otomatis dari Railway MySQL Plugin (tidak perlu diubah) + +### 4. **Wait for Auto-Deploy** + +Railway akan otomatis deploy setelah push ke GitHub. + +--- + +## πŸ§ͺ Testing + +### 1. **Check MQTT Connection** + +```bash +curl https://your-app.railway.app/api/stats +``` + +**Expected Response:** +```json +{ + "success": true, + "stats": { + "mqttConnected": true, // ← HARUS TRUE + "sensorDataCount": 0, + "statusHistoryCount": 0, + ... + } +} +``` + +**Jika `mqttConnected: false`:** +- Check Railway logs +- Pastikan `MQTT_BROKER_URL` sudah ditambahkan +- Redeploy + +--- + +### 2. **Test dengan ESP32** + +1. **Upload sketch ESP32** (tidak perlu diubah) +2. **Buka Serial Monitor** (115200 baud) +3. **Tekan button** untuk start pengeringan +4. **Tunggu 5 detik** (scan berat) +5. **Check Serial Monitor:** +``` +MQTT Data Sent: {"suhu":28.5,"berat":450,"target":315} +MQTT Data Sent: {"suhu":28.6,"berat":448,"target":315} +``` + +--- + +### 3. **Check Data di MySQL** + +```bash +curl https://your-app.railway.app/api/data/latest +``` + +**Expected Response:** +```json +{ + "success": true, + "data": { + "suhu": 28.5, + "berat": 450.0, + "target": 315.0, + "status": "RUNNING", + "timestamp": "2026-05-28T10:30:00.000Z" + } +} +``` + +**Jika data masih kosong:** +- Check Railway logs untuk error +- Pastikan ESP32 sudah publish data +- Check MySQL credentials + +--- + +### 4. **Check History** + +```bash +curl https://your-app.railway.app/api/data/history?limit=10 +``` + +**Expected Response:** +```json +{ + "success": true, + "count": 10, + "data": [ + { + "id": 1, + "suhu": 28.5, + "berat": 450.0, + "target": 315.0, + "relay1": true, + "relay2": true, + "relay3": true, + "relay4": false, + "status": "RUNNING", + "timestamp": "2026-05-28 10:30:00" + }, + ... + ] +} +``` + +--- + +### 5. **Test Send Command** + +```bash +curl -X POST https://your-app.railway.app/api/control \ + -H "Content-Type: application/json" \ + -d '{"command":"HEATER_ON"}' +``` + +**Expected Response:** +```json +{ + "success": true, + "message": "Command sent successfully", + "command": "HEATER_ON" +} +``` + +**Check ESP32 Serial Monitor:** +``` +MQTT Message [novil/pengering/control] : HEATER_ON +HEATER ON +``` + +--- + +## πŸ“Š Monitoring + +### Railway Logs + +Di Railway Dashboard β†’ Deployments β†’ View Logs + +**Expected Logs:** +``` +πŸ”„ Connecting to MQTT Broker: mqtt://broker.hivemq.com:1883 +βœ… Connected to MQTT Broker (HiveMQ) +βœ… Subscribed to topics: + - novil/pengering/data + - novil/pengering/status + - novil/pengering/button + +πŸ“¨ MQTT Message received: + Topic: novil/pengering/data + Message: {"suhu":28.5,"berat":450,"target":315} +βœ… Data saved to MySQL database + +πŸ“¨ MQTT Message received: + Topic: novil/pengering/status + Message: PENGERINGAN DIMULAI +βœ… Status saved to MySQL database +``` + +--- + +## πŸ” Troubleshooting + +### Problem 1: `mqttConnected: false` + +**Penyebab:** Backend tidak bisa connect ke HiveMQ + +**Solusi:** +1. Check Railway logs untuk error message +2. Pastikan variable `MQTT_BROKER_URL` sudah ditambahkan +3. Pastikan value: `mqtt://broker.hivemq.com:1883` (bukan `http://`) +4. Redeploy + +--- + +### Problem 2: Data masih tidak masuk ke MySQL + +**Penyebab:** Database credentials salah atau database belum diinit + +**Solusi:** + +1. **Test database connection:** +```bash +curl https://your-app.railway.app/api/database/test +``` + +2. **Initialize database tables:** +```bash +curl -X POST https://your-app.railway.app/api/database/init +``` + +3. **Check MySQL credentials di Railway:** + - `MYSQLHOST` + - `MYSQLPORT` + - `MYSQLUSER` + - `MYSQLPASSWORD` + - `MYSQLDATABASE` + +--- + +### Problem 3: ESP32 tidak terima command + +**Penyebab:** ESP32 tidak subscribe atau MQTT disconnect + +**Solusi:** + +1. **Check ESP32 Serial Monitor:** +``` +MQTT Connected +Subscribed to: novil/pengering/control +``` + +2. **Restart ESP32** + +3. **Check WiFi connection** + +--- + +### Problem 4: Railway logs error "Cannot find module 'mqtt'" + +**Penyebab:** Package `mqtt` belum terinstall + +**Solusi:** + +1. **Pastikan `package.json` sudah update:** +```json +"dependencies": { + "mqtt": "^5.3.5", + ... +} +``` + +2. **Push ke GitHub lagi:** +```bash +git add package.json +git commit -m "Add mqtt package" +git push +``` + +--- + +## βœ… Checklist + +### Pre-Deploy: +- [x] Package `mqtt` sudah ditambahkan di `package.json` +- [x] `server.js` sudah diupdate dengan MQTT client +- [x] `.env` sudah ada template MySQL credentials +- [x] `npm install` berhasil + +### Deploy: +- [ ] Push ke GitHub +- [ ] Tambahkan `MQTT_BROKER_URL` di Railway Variables +- [ ] Wait for auto-deploy (2-3 menit) +- [ ] Check Railway logs untuk "Connected to MQTT Broker" + +### Testing: +- [ ] Test `/api/stats` β†’ `mqttConnected: true` +- [ ] Upload ESP32 sketch +- [ ] Test ESP32 publish data +- [ ] Test `/api/data/latest` β†’ ada data +- [ ] Test `/api/data/history` β†’ ada history +- [ ] Test send command β†’ ESP32 terima + +--- + +## πŸ“ Catatan Penting + +1. **ESP32 tidak perlu diubah** - sketch tetap sama +2. **MySQL credentials** sudah otomatis dari Railway MySQL Plugin +3. **HiveMQ** adalah public broker, gratis, tidak perlu registrasi +4. **Backend sekarang sebagai MQTT Client**, bukan broker +5. **Aedes broker tetap ada** tapi disabled (untuk future use) + +--- + +## 🎯 Expected Result + +Setelah deploy: + +1. βœ… Backend connect ke HiveMQ +2. βœ… Backend subscribe ke topic ESP32 +3. βœ… ESP32 publish data β†’ Backend terima +4. βœ… Backend save data ke MySQL +5. βœ… Data history tersimpan +6. βœ… Status history tersimpan +7. βœ… Command dari Flutter β†’ ESP32 berfungsi + +--- + +## πŸ“ž Support + +Jika masih ada masalah: + +1. **Check Railway Logs** untuk error detail +2. **Check ESP32 Serial Monitor** untuk MQTT status +3. **Test API endpoints** untuk verify data +4. **Baca dokumentasi lengkap** di `backend/FIX_MQTT_MYSQL.md` + +--- + +Selamat mencoba! πŸš€πŸŽ‰ diff --git a/backend/deploy-to-railway.ps1 b/backend/deploy-to-railway.ps1 deleted file mode 100644 index 283b9ab..0000000 --- a/backend/deploy-to-railway.ps1 +++ /dev/null @@ -1,183 +0,0 @@ -# ===================================================== -# Script Deploy Backend ke Railway -# ===================================================== - -Write-Host "========================================" -ForegroundColor Cyan -Write-Host " DEPLOY BACKEND KE RAILWAY" -ForegroundColor Cyan -Write-Host "========================================" -ForegroundColor Cyan -Write-Host "" - -# Cek apakah di folder yang benar -$currentPath = Get-Location -if (-not $currentPath.Path.EndsWith("backend")) { - Write-Host "❌ Error: Script harus dijalankan dari folder backend" -ForegroundColor Red - Write-Host " Current path: $currentPath" -ForegroundColor Yellow - Write-Host " Pindah ke folder backend dulu:" -ForegroundColor Yellow - Write-Host " cd backend" -ForegroundColor Yellow - exit 1 -} - -Write-Host "πŸ“ Current directory: $currentPath" -ForegroundColor Green -Write-Host "" - -# ===================================================== -# 1. CEK GIT STATUS -# ===================================================== -Write-Host "πŸ” Checking Git status..." -ForegroundColor Yellow -git status --short - -Write-Host "" -$confirm = Read-Host "Lanjutkan commit dan push? (y/n)" -if ($confirm -ne "y") { - Write-Host "❌ Deployment dibatalkan" -ForegroundColor Red - exit 0 -} - -# ===================================================== -# 2. GIT ADD -# ===================================================== -Write-Host "" -Write-Host "πŸ“¦ Adding files to Git..." -ForegroundColor Yellow -git add server.js -git add DEPLOY_PERBAIKAN.md -git add deploy-to-railway.ps1 -git add ../PERBAIKAN_CONTROL_COMMANDS.md - -Write-Host "βœ… Files added" -ForegroundColor Green - -# ===================================================== -# 3. GIT COMMIT -# ===================================================== -Write-Host "" -Write-Host "πŸ’Ύ Committing changes..." -ForegroundColor Yellow -$commitMessage = "Fix: Subscribe to control topic and save to database - -- Backend now subscribes to novil/pengering/control topic -- Added handler to save control commands to database -- Added handler to update relay status from ESP32 -- Status messages with STATUS: prefix saved to status_history -- Command messages saved to control_commands table" - -git commit -m $commitMessage - -if ($LASTEXITCODE -eq 0) { - Write-Host "βœ… Commit successful" -ForegroundColor Green -} else { - Write-Host "⚠️ No changes to commit or commit failed" -ForegroundColor Yellow -} - -# ===================================================== -# 4. GIT PUSH -# ===================================================== -Write-Host "" -Write-Host "πŸš€ Pushing to repository..." -ForegroundColor Yellow -git push origin main - -if ($LASTEXITCODE -eq 0) { - Write-Host "βœ… Push successful" -ForegroundColor Green -} else { - Write-Host "❌ Push failed" -ForegroundColor Red - Write-Host " Coba push manual: git push origin main" -ForegroundColor Yellow - exit 1 -} - -# ===================================================== -# 5. TUNGGU RAILWAY DEPLOY -# ===================================================== -Write-Host "" -Write-Host "⏳ Railway sedang deploy..." -ForegroundColor Yellow -Write-Host " Buka Railway Dashboard untuk monitor progress:" -ForegroundColor Cyan -Write-Host " https://railway.app/dashboard" -ForegroundColor Cyan -Write-Host "" -Write-Host " Tunggu hingga status: βœ… Deployed" -ForegroundColor Green -Write-Host "" - -$waitDeploy = Read-Host "Sudah selesai deploy? (y/n)" -if ($waitDeploy -ne "y") { - Write-Host "⏸️ Tunggu deploy selesai dulu, lalu jalankan test manual" -ForegroundColor Yellow - exit 0 -} - -# ===================================================== -# 6. TEST DEPLOYMENT -# ===================================================== -Write-Host "" -Write-Host "πŸ§ͺ Testing deployment..." -ForegroundColor Yellow -Write-Host "" - -$railwayUrl = Read-Host "Masukkan URL Railway (contoh: https://your-app.up.railway.app)" - -if ([string]::IsNullOrWhiteSpace($railwayUrl)) { - Write-Host "⚠️ URL tidak diisi, skip testing" -ForegroundColor Yellow - Write-Host " Test manual dengan:" -ForegroundColor Yellow - Write-Host " curl https://your-app.up.railway.app/" -ForegroundColor Cyan - exit 0 -} - -# Remove trailing slash -$railwayUrl = $railwayUrl.TrimEnd('/') - -Write-Host "" -Write-Host "πŸ“‘ Testing health check..." -ForegroundColor Yellow -try { - $response = Invoke-RestMethod -Uri "$railwayUrl/" -Method Get - Write-Host "βœ… Health check OK" -ForegroundColor Green - Write-Host " Status: $($response.status)" -ForegroundColor Cyan - Write-Host " Message: $($response.message)" -ForegroundColor Cyan - Write-Host " Version: $($response.version)" -ForegroundColor Cyan -} catch { - Write-Host "❌ Health check failed" -ForegroundColor Red - Write-Host " Error: $_" -ForegroundColor Red -} - -Write-Host "" -Write-Host "πŸ“Š Testing stats..." -ForegroundColor Yellow -try { - $response = Invoke-RestMethod -Uri "$railwayUrl/api/stats" -Method Get - Write-Host "βœ… Stats OK" -ForegroundColor Green - Write-Host " MQTT Connected: $($response.stats.mqttConnected)" -ForegroundColor Cyan - Write-Host " Sensor Data Count: $($response.stats.sensorDataCount)" -ForegroundColor Cyan - Write-Host " Status History Count: $($response.stats.statusHistoryCount)" -ForegroundColor Cyan - Write-Host " Control Commands Count: $($response.stats.controlCommandsCount)" -ForegroundColor Cyan -} catch { - Write-Host "❌ Stats failed" -ForegroundColor Red - Write-Host " Error: $_" -ForegroundColor Red -} - -Write-Host "" -Write-Host "πŸŽ›οΈ Testing control command..." -ForegroundColor Yellow -try { - $body = @{ - command = "HEATER_ON" - } | ConvertTo-Json - - $response = Invoke-RestMethod -Uri "$railwayUrl/api/control" -Method Post -Body $body -ContentType "application/json" - Write-Host "βœ… Control command OK" -ForegroundColor Green - Write-Host " Success: $($response.success)" -ForegroundColor Cyan - Write-Host " Message: $($response.message)" -ForegroundColor Cyan - Write-Host " Command: $($response.command)" -ForegroundColor Cyan -} catch { - Write-Host "❌ Control command failed" -ForegroundColor Red - Write-Host " Error: $_" -ForegroundColor Red -} - -# ===================================================== -# 7. SELESAI -# ===================================================== -Write-Host "" -Write-Host "========================================" -ForegroundColor Cyan -Write-Host " βœ… DEPLOYMENT SELESAI" -ForegroundColor Green -Write-Host "========================================" -ForegroundColor Cyan -Write-Host "" -Write-Host "πŸ“‹ Next Steps:" -ForegroundColor Yellow -Write-Host " 1. Cek Railway logs untuk memastikan subscribe ke control topic" -ForegroundColor White -Write-Host " 2. Upload kode ESP32 (esp32_pengering_ikan_v2.ino)" -ForegroundColor White -Write-Host " 3. Monitor Serial ESP32 untuk melihat status relay" -ForegroundColor White -Write-Host " 4. Cek database Railway untuk memastikan data masuk" -ForegroundColor White -Write-Host "" -Write-Host "πŸ“š Dokumentasi:" -ForegroundColor Yellow -Write-Host " - PERBAIKAN_CONTROL_COMMANDS.md" -ForegroundColor Cyan -Write-Host " - DEPLOY_PERBAIKAN.md" -ForegroundColor Cyan -Write-Host "" -Write-Host "πŸ”— Railway URL: $railwayUrl" -ForegroundColor Cyan -Write-Host "" diff --git a/backend/migrate_database.js b/backend/migrate_database.js new file mode 100644 index 0000000..8de7dd3 --- /dev/null +++ b/backend/migrate_database.js @@ -0,0 +1,111 @@ +// ===================================================== +// DATABASE MIGRATION SCRIPT +// Migrate data dari Railway lama ke Railway baru +// ===================================================== + +const mysql = require('mysql2/promise'); + +// Konfigurasi Database LAMA (Railway account lama) +const oldDB = { + host: process.env.OLD_DB_HOST || 'mysql.railway.internal', + port: process.env.OLD_DB_PORT || 3306, + user: process.env.OLD_DB_USER || 'root', + password: process.env.OLD_DB_PASSWORD || '', + database: process.env.OLD_DB_NAME || 'railway' +}; + +// Konfigurasi Database BARU (Railway account baru) +const newDB = { + host: process.env.NEW_DB_HOST || 'mysql.railway.internal', + port: process.env.NEW_DB_PORT || 3306, + user: process.env.NEW_DB_USER || 'root', + password: process.env.NEW_DB_PASSWORD || '', + database: process.env.NEW_DB_NAME || 'railway' +}; + +async function migrateData() { + let oldConnection, newConnection; + + try { + console.log('πŸ”„ Connecting to OLD database...'); + oldConnection = await mysql.createConnection(oldDB); + console.log('βœ… Connected to OLD database'); + + console.log('πŸ”„ Connecting to NEW database...'); + newConnection = await mysql.createConnection(newDB); + console.log('βœ… Connected to NEW database'); + + // ===================================================== + // 1. Migrate sensor_data + // ===================================================== + console.log('\nπŸ“Š Migrating sensor_data...'); + const [sensorData] = await oldConnection.query('SELECT * FROM sensor_data ORDER BY id'); + console.log(` Found ${sensorData.length} records`); + + for (const row of sensorData) { + await newConnection.query( + `INSERT INTO sensor_data (suhu, berat, target, relay1, relay2, relay3, relay4, status, timestamp) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, + [row.suhu, row.berat, row.target, row.relay1, row.relay2, row.relay3, row.relay4, row.status, row.timestamp] + ); + } + console.log('βœ… sensor_data migrated'); + + // ===================================================== + // 2. Migrate status_history + // ===================================================== + console.log('\nπŸ“ Migrating status_history...'); + const [statusHistory] = await oldConnection.query('SELECT * FROM status_history ORDER BY id'); + console.log(` Found ${statusHistory.length} records`); + + for (const row of statusHistory) { + await newConnection.query( + `INSERT INTO status_history (message, timestamp) VALUES (?, ?)`, + [row.message, row.timestamp] + ); + } + console.log('βœ… status_history migrated'); + + // ===================================================== + // 3. Migrate control_commands + // ===================================================== + console.log('\nπŸŽ›οΈ Migrating control_commands...'); + const [controlCommands] = await oldConnection.query('SELECT * FROM control_commands ORDER BY id'); + console.log(` Found ${controlCommands.length} records`); + + for (const row of controlCommands) { + await newConnection.query( + `INSERT INTO control_commands (command, source, timestamp) VALUES (?, ?, ?)`, + [row.command, row.source, row.timestamp] + ); + } + console.log('βœ… control_commands migrated'); + + console.log('\nπŸŽ‰ MIGRATION COMPLETED SUCCESSFULLY!'); + console.log('====================================='); + console.log(`Total sensor_data: ${sensorData.length}`); + console.log(`Total status_history: ${statusHistory.length}`); + console.log(`Total control_commands: ${controlCommands.length}`); + console.log('====================================='); + + } catch (error) { + console.error('❌ Migration Error:', error); + throw error; + } finally { + if (oldConnection) await oldConnection.end(); + if (newConnection) await newConnection.end(); + } +} + +// Run migration +console.log('πŸš€ Starting Database Migration...'); +console.log('====================================='); +migrateData() + .then(() => { + console.log('βœ… Migration script finished'); + process.exit(0); + }) + .catch((error) => { + console.error('❌ Migration failed:', error); + process.exit(1); + }); diff --git a/backend/railway.toml b/backend/railway.toml index 17f1d05..e8d3d5a 100644 --- a/backend/railway.toml +++ b/backend/railway.toml @@ -5,3 +5,5 @@ builder = "NIXPACKS" startCommand = "node server.js" restartPolicyType = "ON_FAILURE" restartPolicyMaxRetries = 10 + +# Force rebuild for relay fix v1.0.3