AI Assistant
Detail Karya Portofolio

Sistem Monitoring Parkir Menggunakan Flask&MySQL

Rizki Mulyadi Oleh: Rizki Mulyadi

Ringkasan Portofolio

Projek ini merupakan backend sederhana yang berfungsi untuk mengelola data parkiran dalam sebuah sistem monitoring parkir. Sistem ini menggunakan tiga sensor ultrasonik untuk mendeteksi apakah tempat parkir sedang kosong atau terisi. Data dari sensor dikirim ke backend menggunakan protokol HTTP dan disimpan dalam database MySQL.

Deskripsi & Detail Proyek

MySQL merupakan salah satu software yang menggunakan bahasa query yaitu SQL. Pada pertengahan tahun 90-an, program ini dikembangkan oleh MySQL AB (perusahaan asal Swedia). Beberapa tahun kemudian, yaitu pada tahun 2010 perusahaan teknologi terbesar di Amerika Serikat (Oracle) mengakuisisinya sehingga MySQL sudah sepenuhnya milik Oracle. Terdapat berbagai aspek MySQL diantaranya adalah 

  • database, sekumpulan data yang terstruktur
  • open source, bersifat gratis atau bebas untuk digunakan
  • model client-server

Tujuan Membangun sistem monitoring parkir yang dapat berintegrasi dengan simulasi IoT untuk mengumpulkan data status parkir secara real-time, yang nantinya dapat diakses oleh pengguna melalui aplikasi web atau perangkat lainnya.Backend ini dibangun menggunakan Flask, sebuah framework web sederhana untuk Python, dan terhubung ke MySQL sebagai database. Aplikasi ini menyediakan tiga endpoint (GET, POST, PUT) yang memungkinkan pengguna untuk:

1. POST /api/parking/update: Menerima data dari sensor ultrasonik
2. GET /api/parking/status: Mendapatkan status semua spot parkir
3. PUT /api/parking/spot/<spot_number>: Mengubah status spot parkir tertentu
 

Aplikasi backend menggunakan Flask sebagai framework untuk menangani permintaan HTTP dan mengatur routing setiap endpoint, dengan MySQL sebagai database utama untuk menyimpan data parkiran, sehingga setiap perubahan data yang dikirim melalui endpoint langsung mempengaruhi database. Data dikirim dan diterima dalam format JSON, yang memudahkan integrasi dengan aplikasi frontend atau simulasi IoT.Sistem ini dapat diuji menggunakan alat seperti curl di command line atau Postman untuk memverifikasi bahwa data dikirim dan diterima dengan benar sesuai permintaan. Selain itu, data dari sensor simulasi di IoT Wokwi juga dapat diuji dengan menghubungkan data sensor ke backend melalui protokol HTTP.
 

Untuk membuat suatu backend pada VM itu menggunakan perintah nano, dengan file yang telah dibuat menggunakan perintah nano tersebut berisikan 3 endpoint.

  1. Membuat Backend Flask

from flask import Flask, request, jsonify
from flask_mysqldb import MySQL
from flask_cors import CORS
from dotenv import load_dotenv
import os

# Load environment variables
load_dotenv()

app = Flask(__name__)
CORS(app)

# MySQL configurations untuk remote database
app.config['MYSQL_HOST'] = os.getenv('MYSQL_HOST', '110.239.71.90')
app.config['MYSQL_USER'] = os.getenv('MYSQL_USER', 'root')
app.config['MYSQL_PASSWORD'] = os.getenv('MYSQL_PASSWORD', 'your_password')
app.config['MYSQL_DB'] = os.getenv('MYSQL_DB', 'parking_system')

mysql = MySQL(app)

# Test endpoint
@app.route('/', methods=['GET'])
def home():
   return jsonify({"message": "Backend is running!", "status": "OK"}), 200

@app.route('/test_db', methods=['GET'])
def test_db():
   try:
       cur = mysql.connection.cursor()
       cur.execute('SELECT 1')
       cur.close()
       return jsonify({"message": "Database connection successful!", "status": "OK"}), 200
   except Exception as e:
       return jsonify({"error": str(e), "status": "ERROR"}), 500

@app.route('/api/parking/update', methods=['POST'])
def update_parking():
   try:
       data = request.get_json()
       cur = mysql.connection.cursor()

       for spot in data['spots']:
           cur.execute('''
               INSERT INTO parking_spots (spot_number, distance, is_occupied)
               VALUES (%s, %s, %s)
               ON DUPLICATE KEY UPDATE
               distance = VALUES(distance),
               is_occupied = VALUES(is_occupied),
               last_updated = CURRENT_TIMESTAMP
           ''', (spot['number'], spot['distance'], spot['distance'] < 20))

       mysql.connection.commit()
       cur.close()
       return jsonify({"message": "Data updated successfully"}), 200

   except Exception as e:
       return jsonify({"error": str(e)}), 500

@app.route('/api/parking/status', methods=['GET'])
def get_parking_status():
   try:
       cur = mysql.connection.cursor()
       cur.execute('SELECT * FROM parking_spots ORDER BY spot_number')
       rows = cur.fetchall()

       spots = []
       for row in rows:
           spots.append({
               "id": row[0],
               "spot_number": row[1],
               "distance": row[2],
               "is_occupied": bool(row[3]),
               "last_updated": str(row[4])
           })

       cur.close()
       return jsonify({"spots": spots}), 200

   except Exception as e:
     return jsonify({"error": str(e)}), 500

@app.route('/api/parking/spot', methods=['PUT'])
def update_spot_status(spot_number):
   try:
       data = request.get_json()
       cur = mysql.connection.cursor()

       cur.execute('''
           UPDATE parking_spots
           SET is_occupied = %s,
               distance = %s
           WHERE spot_number = %s
       ''', (data['is_occupied'], data['distance'], spot_number))

       mysql.connection.commit()
       cur.close()

       if cur.rowcount > 0:
           return jsonify({"message": f"Spot {spot_number} updated successfully"}), 200
       else:
           return jsonify({"error": "Spot not found"}), 404

   except Exception as e:
       return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
   app.run(debug=True, host='0.0.0.0', port=4000)

2.  Buat database dan tabel di VM MySQL
 

a. Login ke MySQL
mysql -u root -p

b. Di dalam MySQL:
           CREATE DATABASE parking_system;
           USE parking_system;

           CREATE TABLE parking_spots (
           id INTEGER PRIMARY KEY AUTO_INCREMENT,
           spot_number INTEGER NOT NULL,
           distance FLOAT NOT NULL,
           is_occupied BOOLEAN NOT NULL,
           last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
           );

c. Keluar dari MySQL:
          quit;

3. Buat sketch ESP32 pada wokwi

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

// WiFi credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";

// Backend URL (ganti dengan VM yang anda serta portnya)
const char* serverUrl = "http://110.239.71.90:4000/api/parking/update";

// Ultrasonic sensor pins
const int TRIG_PIN1 = 5;
const int ECHO_PIN1 = 18;
const int TRIG_PIN2 = 19;
const int ECHO_PIN2 = 21;
const int TRIG_PIN3 = 22;
const int ECHO_PIN3 = 23;

// LED indicator pins
const int LED_PIN1 = 2;
const int LED_PIN2 = 4;
const int LED_PIN3 = 15;

void setup() {
 Serial.begin(115200);
 
 // Setup ultrasonic sensor pins
 pinMode(TRIG_PIN1, OUTPUT);
 pinMode(ECHO_PIN1, INPUT);
 pinMode(TRIG_PIN2, OUTPUT);
 pinMode(ECHO_PIN2, INPUT);
 pinMode(TRIG_PIN3, OUTPUT);
 pinMode(ECHO_PIN3, INPUT);
 
 // Setup LED pins
 pinMode(LED_PIN1, OUTPUT);
 pinMode(LED_PIN2, OUTPUT);
 pinMode(LED_PIN3, OUTPUT);
 
 // Connect to WiFi
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
   delay(1000);
   Serial.println("Connecting to WiFi...");
 }
 Serial.println("Connected to WiFi");
}

float getDistance(int trigPin, int echoPin) {
 digitalWrite(trigPin, LOW);
 delayMicroseconds(2);
 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10);
 digitalWrite(trigPin, LOW);
 
 long duration = pulseIn(echoPin, HIGH);
 float distance = duration * 0.034 / 2;
 
 return distance;
}

void updateLED(int ledPin, float distance) {
 if (distance < 20) {
   digitalWrite(ledPin, HIGH);
 } else {
   digitalWrite(ledPin, LOW);
 }
}

void sendDataToServer(float dist1, float dist2, float dist3) {
 if (WiFi.status() == WL_CONNECTED) {
   HTTPClient http;
   http.begin(serverUrl);
   http.addHeader("Content-Type", "application/json");
   
   StaticJsonDocument<200> doc;
   JsonArray spots = doc.createNestedArray("spots");
   
   JsonObject spot1 = spots.createNestedObject();
   spot1["number"] = 1;
   spot1["distance"] = dist1;
   
   JsonObject spot2 = spots.createNestedObject();
   spot2["number"] = 2;
   spot2["distance"] = dist2;
   
   JsonObject spot3 = spots.createNestedObject();
   spot3["number"] = 3;
   spot3["distance"] = dist3;
   
   String jsonString;
   serializeJson(doc, jsonString);
   
   int httpResponseCode = http.POST(jsonString);
   
   if (httpResponseCode > 0) {
     String response = http.getString();
     Serial.println("HTTP Response code: " + String(httpResponseCode));
     Serial.println(response);
   } else {
     Serial.println("Error on sending POST: " + String(httpResponseCode));
   }
   
   http.end();
 }
}

void loop() {
 float distance1 = getDistance(TRIG_PIN1, ECHO_PIN1);
 float distance2 = getDistance(TRIG_PIN2, ECHO_PIN2);
 float distance3 = getDistance(TRIG_PIN3, ECHO_PIN3);
 
 updateLED(LED_PIN1, distance1);
 updateLED(LED_PIN2, distance2);
 updateLED(LED_PIN3, distance3);
 
 sendDataToServer(distance1, distance2, distance3);
 
 Serial.println("Distance 1: " + String(distance1) + " cm");
 Serial.println("Distance 2: " + String(distance2) + " cm");
 Serial.println("Distance 3: " + String(distance3) + " cm");
 
 delay(1000);
}
 

Kesimpulan
Simulasi ini berhasil membangun backend sederhana untuk sistem monitoring parkiran yang terhubung dengan database MySQL. Dengan menggunakan endpoint GET, POST, dan PUT. Pengaplikasian backend ini memungkinkan pengguna untuk memonitor status parkiran secara real-time dan melakukan pembaruan data dengan mudah serta dapat dikembangkan lebih lanjut dengan menambahkan fitur seperti dashboard untuk tampilan data atau notifikasi ketika tempat parkir penuh.