Skip to content

Hands-On IoT

Rangkaian Pemantau Suhu dan Kelembapan

Alat-alat:

Kode program untuk ESP32
# include <DHT.h>

#define DHTPIN 5 // Pin digital yang terhubung ke sensor DHT11
#define DHTTYPE DHT11 // Tipe sensor DHT yang digunakan (DHT11)
DHT dht(DHTPIN, DHTTYPE);

#define BUZZER_PIN 13 // Pin untuk buzzer

// ----- Thresholds -----
const float SUHU_MAKSIMUM = 32.0;
const float KELEMBAPAN_MAKSIMUM = 70.0;


// ----- Variabel Waktu-----
unsigned long sebelumnya = 0;
const unsigned long intervalPembacaan = 2000; // interval 2 detik

void setup() {
    Serial.begin(115200);
    dht.begin();
    pinMode(BUZZER_PIN, OUTPUT);
}

void loop() {
    unsigned long sekarang = millis();

    if (sekarang - sebelumnya >= intervalPembacaan) {
        sebelumnya = sekarang;

        // Membaca suhu dan kelembapan dari sensor DHT11
        float suhu = dht.readTemperature();
        float kelembapan = dht.readHumidity();

        // Memeriksa apakah pembacaan berhasil
        if (isnan(suhu) || isnan(kelembapan)) {
        Serial.println("Gagal membaca dari sensor DHT11!");
        return;
        }

        // Menampilkan hasil pembacaan di Serial Monitor
        Serial.print("Suhu: ");
        Serial.print(suhu);
        Serial.print(" °C, Kelembapan: ");
        Serial.print(kelembapan);
        Serial.println(" %");

        // Memeriksa apakah suhu atau kelembapan melebihi threshold
        if (suhu > SUHU_MAKSIMUM || kelembapan > KELEMBAPAN_MAKSIMUM) {
        tone(BUZZER_PIN, 2000); // Nyalakan buzzer dengan frekuensi 1000 Hz
        delay(1000); // Buzzer menyala selama 1 detik
        noTone(BUZZER_PIN); // Matikan buzzer
        delay(1000); // Jeda sebelum pembacaan berikutnya
        } else {
        noTone(BUZZER_PIN); // Pastikan buzzer mati jika kondisi normal
        }
    }
}

Rangkaian Kontrol Aktuator Dengan Relay

Alat-alat:

Kode program untuk ESP32
const int pinRelay = 10;

void setup() {
    Serial.begin(115200);
    pinMode(pinRelay, OUTPUT);
    digitalWrite(pinRelay, HIGH); // Pastikan relay dalam keadaan mati (HIGH)
    Serial.println("Kontrol Pompa Siap!");
}

void loop() {
    // Menyalakan pompa
    Serial.println("Menyalakan Pompa...");
    digitalWrite(pinRelay, LOW); // Relay aktif (LOW)
    delay(5000); // Pompa menyala selama 5 detik

    // Mematikan pompa
    Serial.println("Mematikan Pompa...");
    digitalWrite(pinRelay, HIGH); // Relay mati (HIGH)
    delay(5000); // Pompa mati selama 5 detik
}

Rangkaian Kontrol Aktuator Pompa DC Dengan Relay

Alat-alat:

Kode program untuk ESP32
#define MOISTURE_PIN 34
#define RELAY_PIN 18

int moistureAnalog = 0;
int moisture = 0;

#define MOISTURE_ON 30
#define MOISTURE_OFF 45

void readMoistureSensor() {
    moistureAnalog = analogRead(MOISTURE_PIN);
    moisture = 100 - ((moistureAnalog / 4095.0) * 100);
    moisture = constrain(moisture, 0, 100);
}

void setup() {
    Serial.begin(115200);
    pinMode(MOISTURE_PIN, INPUT);
    pinMode(RELAY_PIN, OUTPUT);

    digitalWrite(RELAY_PIN, HIGH); // Pastikan relay dalam keadaan mati (HIGH)
    Serial.println("=== Sistem Kontrol Pompa Berbasis Moisture (%) ===");
}

void loop() {

    readMoistureSensor();
    Serial.print("Moisture Analog: ");
    Serial.print(moistureAnalog);
    Serial.print(" | Moisture (%): ");
    Serial.print(moisture);
    Serial.println(" %");

    if (moisture < MOISTURE_ON) {
        Serial.println("Tanah Kering -> Pompa MENYALA");
        digitalWrite(RELAY_PIN, LOW); // Relay aktif (LOW)
    } else if (moisture > MOISTURE_OFF) {
        Serial.println("Tanah Lembap -> Pompa MATI");
        digitalWrite(RELAY_PIN, HIGH); // Relay mati (HIGH)
    }
    Serial.println("-----------------------------------");
    delay(2000); // Delay untuk pembacaan berikutnya
}

Rangkaian Sensor Ultrasonic dan Buzzer

Alat-alat:

Kode program untuk ESP32
// ----- Pin Ultrasonik -----
#define TRIG_PIN 5
#define ECHO_PIN 18

// ----- Pin Buzzer -----
#define BUZZER_PIN 13

// ----- Threshold Jarak (cm) -----
const float JARAK_MINIMUM = 10.0; // Jika objek lebih dekat dari 10 cm, buzzer bunyi

// ----- Variabel Waktu -----
unsigned long sebelumnya = 0;
const unsigned long intervalPembacaan = 2000; // 2 detik

void setup() {
  Serial.begin(115200);

  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
}

void loop() {
  unsigned long sekarang = millis();

  if (sekarang - sebelumnya >= intervalPembacaan) {
    sebelumnya = sekarang;

    // Kirim trigger 10 mikrodetik
    digitalWrite(TRIG_PIN, LOW);
    delayMicroseconds(2);
    digitalWrite(TRIG_PIN, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG_PIN, LOW);

    // Baca durasi pantulan
    long durasi = pulseIn(ECHO_PIN, HIGH);

    // Hitung jarak (cm)
    float jarak = durasi * 0.034 / 2;

    Serial.print("Jarak: ");
    Serial.print(jarak);
    Serial.println(" cm");

    // Cek apakah jarak kurang dari threshold
    if (jarak < JARAK_MINIMUM && jarak > 0) {
      tone(BUZZER_PIN, 2000);  // Bunyi 2000 Hz
      delay(1000);
      noTone(BUZZER_PIN);
      delay(1000);
    } else {
      noTone(BUZZER_PIN);
    }
  }
}

Rangkaian Sensor Ultrasonic, Buzzer, dan Penyimpanan Data di Server

Alat-alat:

Kode program untuk ESP32
#include <WiFi.h>
#include <HTTPClient.h>

// ----- WIFI -----
const char *ssid = "Nama_wifi";
const char *password = "password";

// ----- SERVER -----
const char *serverURL = "http://ip-device:5000/data"; // Ubah dengan URL dan port server yang sesuai

// ----- DEVICE ID -----
const char *device_id = "IoT-1";

// ----- Pin Ultrasonik -----
#define TRIG_PIN 5
#define ECHO_PIN 18

// ----- Pin Buzzer -----
#define BUZZER_PIN 13

// ----- Threshold -----
const float JARAK_MINIMUM = 10.0;

// ----- Waktu -----
unsigned long sebelumnya = 0;
const unsigned long intervalPembacaan = 5000;

void setup()
{

    Serial.begin(115200);

    pinMode(TRIG_PIN, OUTPUT);
    pinMode(ECHO_PIN, INPUT);
    pinMode(BUZZER_PIN, OUTPUT);

    WiFi.begin(ssid, password);

    Serial.print("Menghubungkan WiFi");

    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }

    Serial.println("\nWiFi Terhubung");
}

void loop()
{

    unsigned long sekarang = millis();

    if (sekarang - sebelumnya >= intervalPembacaan)
    {

        sebelumnya = sekarang;

        // Trigger ultrasonik
        digitalWrite(TRIG_PIN, LOW);
        delayMicroseconds(2);

        digitalWrite(TRIG_PIN, HIGH);
        delayMicroseconds(10);
        digitalWrite(TRIG_PIN, LOW);

        long durasi = pulseIn(ECHO_PIN, HIGH);

        float jarak = durasi * 0.034 / 2;

        Serial.print("Jarak: ");
        Serial.print(jarak);
        Serial.println(" cm");

        // ----- STATUS BUZZER -----
        String statusBuzzer = "OFF";

        if (jarak < JARAK_MINIMUM && jarak > 0)
        {
            tone(BUZZER_PIN, 2000);
            statusBuzzer = "ON";
        }
        else
        {
            noTone(BUZZER_PIN);
            statusBuzzer = "OFF";
        }

        // ----- KIRIM DATA KE SERVER -----
        if (WiFi.status() == WL_CONNECTED)
        {

            HTTPClient http;

            http.begin(serverURL);
            http.addHeader("Content-Type", "application/json");

            String json = "{";
            json += "\"device_id\":\"";
            json += device_id;
            json += "\",";
            json += "\"jarak\":";
            json += jarak;
            json += ",";
            json += "\"buzzer\":\"";
            json += statusBuzzer;
            json += "\"}";

            Serial.println("Data dikirim:");
            Serial.println(json);

            int httpResponseCode = http.POST(json);

            Serial.print("Response: ");
            Serial.println(httpResponseCode);

            http.end();
        }
    }
}
Kode program untuk server (Python) tanpa penyimpanan data ke database
import json
import csv
import os
from datetime import datetime
from http.server import BaseHTTPRequestHandler, HTTPServer

FILE_NAME = "data_sensor_http.csv"

class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):

    # ===== GET : Tampilkan data =====
    def do_GET(self):
        if self.path == '/tampil-data':
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()

            if os.path.isfile(FILE_NAME):
                with open(FILE_NAME, mode='r') as f:
                    content = f.read()
                self.wfile.write(content.encode('utf-8'))
            else:
                self.wfile.write(b"Belum ada data sensor di file CSV.")
        else:
            self.send_error(404, "Endpoint tidak ditemukan. Gunakan /tampil-data")

    # ===== POST : Menerima data JSON dari ESP32 =====
    def do_POST(self):
        if self.path == '/data':
            content_length = int(self.headers['Content-Length'])
            post_data = self.rfile.read(content_length)

            try:
                # Parse JSON yang dikirim ESP32
                data = json.loads(post_data.decode('utf-8'))

                # Ambil data sesuai format baru
                device_id = data.get('device_id', 'Unknown') # Menangkap device_id
                jarak = data.get('jarak')
                buzzer = data.get('buzzer')
                waktu = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

                file_exists = os.path.isfile(FILE_NAME)

                # Simpan ke CSV
                with open(FILE_NAME, mode='a', newline='') as f:
                    writer = csv.writer(f)

                    # Tambahkan kolom Device ID di header jika file baru dibuat
                    if not file_exists:
                        writer.writerow(["Waktu", "Device ID", "Jarak (cm)", "Status Buzzer"])

                    writer.writerow([waktu, device_id, jarak, buzzer])

                # Log ke Console Server
                print(f"[{waktu}] ID: {device_id} | Jarak: {jarak} cm | Buzzer: {buzzer}")

                # Kirim respon balik ke ESP32
                self.send_response(200)
                self.send_header('Content-type', 'application/json')
                self.end_headers()
                self.wfile.write(b'{"status":"success"}')

            except Exception as e:
                print("Error parsing data:", e)
                self.send_response(400)
                self.end_headers()
                self.wfile.write(f'{{"status":"error", "message":"{str(e)}"}}'.encode())
        else:
            self.send_error(404)

def run(server_class=HTTPServer, handler_class=SimpleHTTPRequestHandler, port=5000): # Ubah port jika tidak bisa digunakan
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)

    print(f"Server HTTP berjalan di port {port}")
    print(f"Lihat data: http://localhost:{port}/tampil-data")
    print("Menunggu data dari ESP32...\n")

    httpd.serve_forever()

if __name__ == '__main__':
    run()
Kode program untuk server (Python) dengan penyimpanan data ke database PostgreSQL
import json
import os
from datetime import datetime
from http.server import BaseHTTPRequestHandler, HTTPServer

import psycopg2
from dotenv import load_dotenv

load_dotenv()  # Memuat variabel lingkungan dari file .env

connection = psycopg2.connect(
    host="localhost",
    port=5432,
    database="mahasiswa_db",
    user="postgres",
    password=os.environ.get("password"),
)

# Membuat tabel jika belum ada.
with connection.cursor() as cursor:
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS data_sensor (
            id SERIAL PRIMARY KEY,
            device_id VARCHAR(50) DEFAULT 'ESP32',
            waktu TIMESTAMP,
            jarak INTEGER,
            buzzer INTEGER
        )
    """)
connection.commit()  # Commit untuk menyimpan perubahan ke database


class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
    def _set_cors_headers(self):
        self.send_header("Access-Control-Allow-Origin", "*")
        self.send_header("Access-Control-Allow-Methods", "*")
        self.send_header("Access-Control-Allow-Headers", "Content-Type")

    def do_OPTIONS(self):
        self.send_response(204)
        self._set_cors_headers()
        self.end_headers()

    # ===== GET : tampilkan data =====
    def do_GET(self):
        if self.path == "/":
            self.send_response(200)
            self._set_cors_headers()
            self.send_header("Content-type", "text/html")
            self.end_headers()
            html_content = """
                <html>
                    <head><title>Data Sensor</title></head>
                    <body>
                        <h1>Data Sensor</h1>
                        <p>Gunakan endpoint <code>/tampil-data</code> untuk melihat data sensor dalam format JSON.</p>
                    </body>
                </html>
            """
            self.wfile.write(html_content.encode("utf-8"))
        elif self.path == "/tampil-data":
            try:
                with connection.cursor() as cursor:
                    cursor.execute(
                        """
                        SELECT id, device_id, waktu, jarak, buzzer
                        FROM data_sensor
                        ORDER BY id DESC
                        """
                    )
                    rows = cursor.fetchall()

                payload = [
                    {
                        "id": row[0],
                        "device_id": row[1],
                        "waktu": row[2].strftime("%Y-%m-%d %H:%M:%S")
                        if row[2]
                        else None,
                        "jarak": row[3],
                        "buzzer": row[4],
                    }
                    for row in rows
                ]

                self.send_response(200)
                self._set_cors_headers()
                self.send_header("Content-type", "application/json")
                self.end_headers()
                self.wfile.write(json.dumps(payload).encode("utf-8"))
            except Exception as e:
                print("Error GET:", e)
                self.send_response(500)
                self._set_cors_headers()
                self.send_header("Content-type", "application/json")
                self.end_headers()
                self.wfile.write(b'{"status":"error","message":"Gagal mengambil data"}')
        else:
            self.send_error(404, "Endpoint tidak ditemukan. Gunakan /tampil-data")

    # ===== POST : menerima data dari ESP32 =====
    def do_POST(self):
        if self.path == "/data":
            content_length = int(self.headers["Content-Length"])
            post_data = self.rfile.read(content_length)

            try:
                data = json.loads(post_data.decode("utf-8"))
                device_id = data.get(
                    "device_id", "ESP32"
                )  # Default ke 'ESP32' jika tidak ada
                jarak = data.get("jarak")
                buzzer = data.get("buzzer")

                if jarak is None or buzzer is None:
                    self.send_response(400)
                    self._set_cors_headers()
                    self.send_header("Content-type", "application/json")
                    self.end_headers()
                    self.wfile.write(
                        b'{"status":"error","message":"Field jarak dan buzzer wajib diisi"}'
                    )
                    return

                jarak = int(jarak)
                buzzer = int(buzzer)

                waktu_obj = datetime.now()
                waktu = waktu_obj.strftime("%Y-%m-%d %H:%M:%S")

                with connection.cursor() as cursor:
                    cursor.execute(
                        "INSERT INTO data_sensor (device_id, waktu, jarak, buzzer) VALUES (%s, %s, %s, %s)",
                        (device_id, waktu_obj, jarak, buzzer),
                    )
                connection.commit()

                print(
                    f"[{waktu}] Device ID: {device_id} | Jarak: {jarak} cm | Buzzer: {buzzer}"
                )

                self.send_response(201)
                self._set_cors_headers()
                self.send_header("Content-type", "application/json")
                self.end_headers()

                self.wfile.write(b'{"status":"success"}')

            except Exception as e:
                connection.rollback()

                print("Error:", e)

                self.send_response(400)
                self._set_cors_headers()
                self.send_header("Content-type", "application/json")
                self.end_headers()
                self.wfile.write(
                    b'{"status":"error","message":"Data tidak valid atau gagal disimpan"}'
                )

        else:
            self.send_error(404)


def run(server_class=HTTPServer, handler_class=SimpleHTTPRequestHandler, port=5001):
    server_address = ("", port)
    httpd = server_class(server_address, handler_class)

    print(f"Server HTTP berjalan di port {port}")
    print(f"Lihat data: http://localhost:{port}/tampil-data")
    print("Menunggu data dari ESP32...\n")

    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("\nServer dihentikan.")
    finally:
        connection.close()


if __name__ == "__main__":
    run()
Kode program untuk client (Python) untuk mengambil data dari server
import requests
import json


def get_data_from_server():
    url = "http://127.0.0.1:5001/tampil-data"

    try:
        response = requests.get(url, timeout=3)

        if response.status_code == 200:
            content_type = response.headers.get("Content-Type", "")
            print("Data berhasil diterima dari server:")

            if "application/json" in content_type:
                print(json.dumps(response.json(), indent=4))
            elif "text/plain" in content_type:
                print(response.text)
            else:
                print(response.text)
        else:
            print(f"Gagal menerima data. Status code: {response.status_code}")
    except Exception as e:
        print("Error menerima data:", e)


if __name__ == "__main__":

    get_data_from_server()
Kode program untuk client (Python) untuk mengirim data ke server
import requests


def send_data_to_server(data):
    url = "http://127.0.0.1:5001/data"

    try:
        response = requests.post(url, json=data, timeout=3)

        if response.status_code == 201:
            print("Data berhasil dikirim ke server.")
        else:
            print(f"Gagal mengirim data. Status code: {response.status_code}")
    except Exception as e:
        print("Error saat mengirim data:", e)


if __name__ == "__main__":
    # Contoh data yang akan dikirim
    data = {"device_id": "rangkaian-2", "jarak": 15, "buzzer": 1}

    send_data_to_server(data)

Blynk Sensor Ultrasonic dan Buzzer

Alat-alat:

Kode program untuk ESP32
// ================= BLYNK CONFIG =================
#define BLYNK_TEMPLATE_ID "sda"
#define BLYNK_TEMPLATE_NAME "dada"
#define BLYNK_AUTH_TOKEN "dada"

#define BLYNK_PRINT Serial

#include <WiFi.h>
#include <BlynkSimpleEsp32.h>

// ================= WIFI =================
const char* ssid = "dadad";
const char* password = "defer";

// ================= PIN =================
#define TRIG_PIN    5
#define ECHO_PIN    18
#define BUZZER_PIN  19

// ================= CONFIG =================
const float JARAK_MINIMUM = 10.0;
const unsigned long intervalPembacaan = 5000;

unsigned long sebelumnya = 0;

// ================= STATE =================
bool manualBuzzer = false;

// ================= BLYNK HANDLER =================
// Switch manual buzzer (V3)
BLYNK_WRITE(V3) {
  manualBuzzer = param.asInt(); // 0 atau 1
}

// ================= SETUP =================
void setup() {
  Serial.begin(115200);

  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);

  // Koneksi ke Blynk
  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, password);
}

// ================= LOOP =================
void loop() {
  Blynk.run();

  unsigned long sekarang = millis();

  if (sekarang - sebelumnya >= intervalPembacaan) {
    sebelumnya = sekarang;

    // ===== BACA SENSOR ULTRASONIK =====
    digitalWrite(TRIG_PIN, LOW);
    delayMicroseconds(2);

    digitalWrite(TRIG_PIN, HIGH);
    delayMicroseconds(10);

    digitalWrite(TRIG_PIN, LOW);

    long durasi = pulseIn(ECHO_PIN, HIGH);
    float jarak = durasi * 0.034 / 2;

    // Validasi jarak
    if (jarak > 400 || jarak <= 0) {
      jarak = 0;
    }

    // ===== LOGIKA BUZZER =====
    bool kondisiAuto = (jarak < JARAK_MINIMUM && jarak > 0);
    bool isBuzzerActive = false;

    if (kondisiAuto || manualBuzzer) {
      tone(BUZZER_PIN, 500); // frekuensi default
      isBuzzerActive = true;
    } else {
      noTone(BUZZER_PIN);
      isBuzzerActive = false;
    }

    // ===== KIRIM KE BLYNK =====
    Blynk.virtualWrite(V1, jarak);                  // Jarak
    Blynk.virtualWrite(V2, isBuzzerActive ? 1 : 0); // Status buzzer

    // ===== DEBUG SERIAL =====
    Serial.printf(
      "Jarak: %.2f cm | Auto: %d | Manual: %d | Buzzer: %d\n",
      jarak,
      kondisiAuto,
      manualBuzzer,
      isBuzzerActive
    );
  }
}