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
);
}
}