Pendahuluan — Penutup Seri 2 ESP32/IoT Lanjutan

Selamat! Kamu sudah menempuh 28 artikel Seri 2 — dari deep sleep (#11) hingga HTTPS (#38). Artikel ini adalah capstone penutup yang menggabungkan sensor, aktuator, broker MQTT, dan dashboard ke dalam satu proyek nyata: smart greenhouse (rumah kaca pintar).

Di capstone Seri 1 (#10), kamu membangun dashboard hybrid Web + MQTT untuk satu sensor DHT22. Di capstone Seri 2, skala naik: multi-sensor (udara + tanah + cahaya), multi-aktuator (pompa air + ventilasi), multi-node (gateway utama + node kebun hemat baterai), dan dashboard histori di Grafana (#19).

Prasyarat wajib: Sudah paham BME280 I2C (#13), broker Mosquitto (#16), soil moisture ADC (#35), dan idealnya sudah baca PIR (#24) serta deep sleep (#11).

Apa yang Akan Kamu Bangun?

Sistem greenhouse skala rumahan / UMKM kecil dengan komponen berikut:

  • Gateway utama — ESP32 di dalam rumah kaca: BME280 (suhu, kelembaban udara, tekanan) + soil moisture capacitive + LDR cahaya
  • Node aktuator — ESP32 + relay modul: kontrol pompa irigasi dan lampu grow (opsional)
  • Node kebun (opsional) — ESP32 deep sleep di ujung lahan: kirim data tanah periodik
  • Sensor gerak (opsional) — PIR di pintu greenhouse untuk lampu koridor
  • Broker MQTT — Mosquitto pribadi di Raspberry Pi / VPS (#16)
  • Dashboard — Grafana panel suhu, kelembaban tanah, status pompa; alert Telegram opsional
  • Backup offline — log CSV ke SD Card (#37) saat WiFi putus

Arsitektur Sistem Greenhouse

┌─────────────────────────────────────────────────────────────────┐
│  Broker Mosquitto 192.168.1.50:1883 (auth kindo_esp32)          │
│  Topic: kodingindonesia/esp32/...                               │
└────────────┬───────────────────────────────────────┬──────────────┘
             │ publish sensor                       │ subscribe kontrol
    ┌────────▼────────┐                    ┌────────▼────────┐
    │ Gateway utama   │                    │ Node aktuator   │
    │ BME280 + soil   │                    │ Relay pompa     │
    │ + LDR (GPIO)    │                    │ + lampu grow    │
    └────────┬────────┘                    └────────┬────────┘
             │                                      │
    ┌────────▼────────┐                    ┌────────▼────────┐
    │ Node deep sleep │                    │ Servo flap (#33)│
    │ (opsional)      │                    │ ventilasi       │
    └─────────────────┘                    └─────────────────┘
             │
    ┌────────▼────────────────────────────────────────┐
    │ InfluxDB + Grafana (#19) · HA (#21) · Node-RED  │
    └─────────────────────────────────────────────────┘

Alur data: sensor publish JSON ke MQTT → subscriber Python/InfluxDB menyimpan histori → Grafana menampilkan grafik → otomasi (Node-RED / HA / firmware) mengontrol pompa berdasarkan threshold kelembaban tanah.

Estimasi Biaya Hardware

KomponenQtyEstimasi (IDR)
ESP32 DevKit2–3~90.000–135.000
BME280 module I2C1~35.000
Soil moisture capacitive1–2~25.000–50.000
LDR + resistor 10kΩ1~5.000
Relay modul 2-ch1~20.000
Pompa DC mini + power supply1~40.000–80.000
Raspberry Pi / VPS broker1~500.000+ (atau pakai PC lama)
Total minimal~215.000 (tanpa broker baru)

Software stack (Mosquitto, InfluxDB, Grafana, ESP32 firmware) gratis open source. Biaya listrik broker 24/7 diperhitungkan terpisah.

Hierarki Topic MQTT Greenhouse

Konvensi Seri 2 — semua node memakai prefix kodingindonesia/esp32/:

TopicArahPayloadSumber artikel
.../bme280/datapublish{"suhu":28.1,"kelembaban":72.0,"tekanan":1008.5,"unix":1782977400}#13
.../tanah/datapublish{"kelembaban_tanah":42,"unix":1782977400}#35
.../cahaya/datapublish{"cahaya_percent":78,"unix":1782977400}#35
.../pompa/kontrolsubscribeON / OFF / AUTOcapstone
.../pir/gerakpublish{"gerak":true,"lampu":"ON"}#24
.../servo/sudutsubscribe120 (derajat flap)#33

Timestamp unix: 1782977400 = 2026-07-02T14:30:00 UTC — konsisten dengan NTP (#34) di seluruh Seri 2.

Catatan topic pompa: di #35, relay pompa masih memakai kodingindonesia/esp32/lampu/kontrol. Di capstone ini kita pakai .../pompa/kontrol agar irigasi terpisah dari lampu koridor PIR (.../lampu/kontrol) — pola relay tetap sama seperti #8.

Persiapan Broker Mosquitto

Gunakan broker pribadi yang sudah dikonfigurasi di artikel #16:

  • Host: 192.168.1.50 (ganti IP broker kamu)
  • Port: 1883 (plain) atau 8883 dengan TLS (#17)
  • User: kindo_esp32 · Password: GANTI_PASSWORD_MQTT
mosquitto_sub -h 192.168.1.50 -u kindo_esp32 -P GANTI_PASSWORD_MQTT \
  -t "kodingindonesia/esp32/#" -v

Wildcard # memudahkan debug seluruh traffic greenhouse sekaligus.

Gateway Utama — BME280 + Soil + LDR

Node ini menggabungkan pola BME280 (#13) dan ADC soil/LDR (#35) dalam satu firmware.

Wiring I2C BME280

BME280ESP32
VCC3.3V
GNDGND
SDAGPIO 21
SCLGPIO 22

Wiring Soil Moisture & LDR

SensorESP32Catatan
Soil VCC3.3VCapacitive — hindari korosi probe resistif
Soil OUTGPIO 34 (ADC1)Kalibrasi kering/basah
LDR + dividerGPIO 35 (ADC1)Resistor 10kΩ ke GND

Sketch Gateway — Publish Multi-Sensor

#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_BME280.h>

#define SOIL_PIN 34
#define LDR_PIN  35

const char* ssid = "GANTI_NAMA_WIFI";
const char* pass = "GANTI_PASSWORD_WIFI";
const char* mqtt_host = "192.168.1.50";
const char* mqtt_user = "kindo_esp32";
const char* mqtt_pass = "GANTI_PASSWORD_MQTT";
const char* topic_bme   = "kodingindonesia/esp32/bme280/data";
const char* topic_tanah = "kodingindonesia/esp32/tanah/data";
const char* topic_cahaya = "kodingindonesia/esp32/cahaya/data";

const int SOIL_DRY = 3200;
const int SOIL_WET = 1400;

Adafruit_BME280 bme;
WiFiClient wifiClient;
PubSubClient mqtt(wifiClient);

int soilPercent(int raw) {
  return constrain(map(raw, SOIL_DRY, SOIL_WET, 0, 100), 0, 100);
}

int readFiltered(uint8_t pin) {
  long sum = 0;
  for (int i = 0; i < 10; i++) { sum += analogRead(pin); delay(5); }
  return (int)(sum / 10);
}

void reconnectMqtt() {
  while (!mqtt.connected()) {
    if (mqtt.connect("kindo-greenhouse-gw", mqtt_user, mqtt_pass)) {
      Serial.println("MQTT OK");
    } else { delay(2000); }
  }
}

void setup() {
  Serial.begin(115200);
  analogReadResolution(12);
  Wire.begin(21, 22);
  if (!bme.begin(0x76)) { Serial.println("BME280 fail"); while(1); }
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) delay(300);
  mqtt.setServer(mqtt_host, 1883);
  reconnectMqtt();
}

void loop() {
  if (!mqtt.connected()) reconnectMqtt();
  mqtt.loop();

  static unsigned long last = 0;
  if (millis() - last < 15000) return;
  last = millis();

  float t = bme.readTemperature();
  float h = bme.readHumidity();
  float p = bme.readPressure() / 100.0F;
  int soil = soilPercent(readFiltered(SOIL_PIN));
  int ldr  = constrain(map(readFiltered(LDR_PIN), 500, 3500, 0, 100), 0, 100);

  char buf[128];
  snprintf(buf, sizeof(buf),
    "{\"suhu\":%.1f,\"kelembaban\":%.1f,\"tekanan\":%.1f,\"unix\":1782977400}",
    t, h, p);
  mqtt.publish(topic_bme, buf);

  snprintf(buf, sizeof(buf), "{\"kelembaban_tanah\":%d,\"unix\":1782977400}", soil);
  mqtt.publish(topic_tanah, buf);

  snprintf(buf, sizeof(buf), "{\"cahaya_percent\":%d,\"unix\":1782977400}", ldr);
  mqtt.publish(topic_cahaya, buf);

  Serial.printf("GW: suhu=%.1f tanah=%d%% cahaya=%d%%\n", t, soil, ldr);
}

PlatformIO — Gateway

lib_deps =
  knolleary/PubSubClient
  adafruit/Adafruit BME280 Library
  adafruit/Adafruit Unified Sensor

Node Aktuator — Relay Pompa & Lampu

Ikuti pola relay MQTT (#8) dengan topic khusus pompa:

  • GPIO relay pompa: GPIO 26 (active LOW — sesuaikan modul kamu)
  • GPIO relay lampu grow: GPIO 27
  • Subscribe: kodingindonesia/esp32/pompa/kontrol
const char* topicPompa = "kodingindonesia/esp32/pompa/kontrol";
#define RELAY_POMPA 26
#define RELAY_LAMPU 27

void mqttCallback(char* topic, byte* payload, unsigned int len) {
  char msg[8] = {0};
  memcpy(msg, payload, min(len, (unsigned)7));
  if (strcmp(msg, "ON") == 0) {
    digitalWrite(RELAY_POMPA, LOW);
    digitalWrite(RELAY_LAMPU, LOW);
  } else if (strcmp(msg, "OFF") == 0) {
    digitalWrite(RELAY_POMPA, HIGH);
    digitalWrite(RELAY_LAMPU, HIGH);
  }
  // AUTO: logika threshold di Node-RED / HA
}

void setup() {
  pinMode(RELAY_POMPA, OUTPUT);
  pinMode(RELAY_LAMPU, OUTPUT);
  digitalWrite(RELAY_POMPA, HIGH);
  digitalWrite(RELAY_LAMPU, HIGH);
  mqtt.setCallback(mqttCallback);
  reconnectMqtt();
  mqtt.subscribe(topicPompa);
}

void loop() {
  if (!mqtt.connected()) reconnectMqtt();
  mqtt.loop();
}

Pola lengkap WiFi + mqtt.connect sama seperti relay (#8) — pastikan mqtt.loop() dipanggil setiap iterasi agar callback kontrol pompa responsif.

Otomasi Pompa — Threshold Kelembaban Tanah

Logika irigasi dengan hysteresis anti-flicker (sama prinsip debounce PIR (#24)):

  • Jika kelembaban_tanah < 30% → publish ON ke kodingindonesia/esp32/pompa/kontrol
  • Jika kelembaban_tanah > 60% → publish OFF
  • Zona 30–60%: pertahankan status terakhir

Implementasi bisa di Node-RED (#23): mqtt in kodingindonesia/esp32/tanah/data → function node cek threshold → mqtt out kodingindonesia/esp32/pompa/kontrol. Atau di Home Assistant (#21) dengan automation for: 2 minutes agar pompa tidak cepat on/off.

Ventilasi Servo Flap (Opsional)

Tambahkan servo SG90 (#33) untuk membuka flap saat suhu BME280 > 32°C:

  • Subscribe kodingindonesia/esp32/servo/sudut — payload angka 0–180
  • Sudut 0° = tertutup · 120° = ventilasi cukup · 180° = terbuka penuh

Ramp perlahan (2° per 20 ms) melindungi engsel plastik — detail di artikel #33.

Node Deep Sleep di Ujung Kebun (Opsional)

Untuk probe tanah jauh dari stop kontak, pakai pola deep sleep (#11):

  • Bangun tiap 15 menit (timer wakeup)
  • Baca soil moisture → publish kodingindonesia/esp32/tanah/data dengan field node: "kebun-barat"
  • Matikan WiFi → esp_deep_sleep(15 * 60 * 1000000ULL)

Baterai 18650 + modul charge bisa bertahan berminggu-minggu — cocok untuk kebun luas tanpa kabel listrik.

PIR di Pintu Greenhouse (Opsional)

Integrasikan PIR (#24) untuk lampu koridor: gerak terdeteksi → publish ke kodingindonesia/esp32/pir/gerak → relay lampu ON selama 60 detik (hold time). Topic kontrol tetap kompatibel dengan kodingindonesia/esp32/lampu/kontrol dari artikel #8.

Backup SD Card Saat WiFi Putus

Tambahkan modul microSD SPI seperti artikel #37 pada gateway utama. Saat mqtt.publish() gagal, append baris CSV ke /greenhouse.csv:

unix,suhu,kelembaban_udara,kelembaban_tanah,cahaya_percent
1782977400,28.1,72.0,42,78

Saat WiFi kembali, baca file dan publish batch ke MQTT — data histori tidak hilang.

Dashboard Grafana — Panel Greenhouse

Setelah data masuk InfluxDB lewat subscriber Python (#18), buat dashboard di Grafana (#19):

  1. Panel Time series — suhu BME280 (suhu) + kelembaban udara
  2. Panel Gauge — kelembaban tanah real-time (threshold merah < 30%)
  3. Panel Stat — status pompa (ON/OFF dari topic kontrol)
  4. Alert rule — suhu > 35°C selama 10 menit → notifikasi Telegram

Query Flux contoh: from(bucket:"sensor") |> range(start:-24h) |> filter(fn:(r) => r._measurement == "tanah")

Integrasi Home Assistant & Node-RED

Home Assistant — entity dari MQTT discovery:

  • sensor.greenhouse_suhu ← topic bme280/data · template {{ value_json.suhu }}
  • sensor.greenhouse_tanah ← topic kodingindonesia/esp32/tanah/data
  • switch.greenhouse_pompa ← topic kodingindonesia/esp32/pompa/kontrol · command ON/OFF

Node-RED — flow visual: gauge tanah + tombol manual pompa + automasi threshold — lihat pola lengkap di #23.

Keamanan Produksi

  • MQTT auth — jangan pakai broker tanpa password di production (#16)
  • TLS — aktifkan port 8883 untuk traffic terenkripsi (#17)
  • Webhook HTTPS — alert Grafana ke Telegram via WiFiClientSecure (#38) jika perlu notifikasi dari ESP32 langsung
  • OTA — update firmware node tanpa kabel USB (#15)
  • WiFiManager — ganti SSID tanpa reflash (#12)

Pro tip: Pisahkan VLAN atau SSID khusus IoT di router rumah — node greenhouse tidak perlu akses ke laptop/kantor. Broker Mosquitto cukup expose ke LAN, bukan internet publik, kecuali kamu sudah paham hardening TLS + firewall.

Perbandingan Jalur yang Digabung

Jalur Seri 2ArtikelPeran di Greenhouse
A — Hardware#11, #13, #24, #35Sensor + deep sleep + PIR
B — Infrastruktur#16, #17, #18, #19Broker, TLS, histori, Grafana
C — Smart home#21, #23HA entity + Node-RED otomasi
D — Jarak jauh#26, #28LoRa node kebun luas (opsional)
E — Tooling#29, #31PlatformIO monorepo + FreeRTOS
Tier 2#33, #37, #38Servo flap, SD backup, HTTPS alert

Checklist Uji Coba End-to-End

  1. Broker Mosquitto hidup — systemctl status mosquitto
  2. mosquitto_sub -t "kodingindonesia/esp32/#" -v menampilkan traffic
  3. Gateway publish BME280 + tanah + cahaya setiap 15 detik
  4. Node aktuator merespons mosquitto_pub -h 192.168.1.50 -u kindo_esp32 -P GANTI_PASSWORD_MQTT -t "kodingindonesia/esp32/pompa/kontrol" -m ON
  5. Pompa fisik menyala — cek arus relay sebelum sambung ke pompa besar
  6. Grafana panel menampilkan data histori 1 jam terakhir
  7. Otomasi threshold: tanah < 30% → pompa ON tanpa intervensi manual
  8. (Opsional) SD Card mencatat saat WiFi dimatikan sementara
  9. (Opsional) Alert Grafana Telegram saat suhu > 35°C

Troubleshooting

  • BME280 tidak terbaca: Cek alamat I2C 0x76 vs 0x77 — ganti di bme.begin()
  • Soil selalu 0% atau 100%: Kalibrasi ulang SOIL_DRY / SOIL_WET di air vs tanah kering
  • Pompa tidak mati: Cek hysteresis — mungkin threshold terlalu dekat; tambah for: 2 minutes di HA
  • MQTT rc=-2: Broker tidak terjangkau — ping 192.168.1.50 dari ESP32 serial monitor
  • Grafana kosong: Pastikan subscriber Python jalan dan bucket InfluxDB menerima measurement tanah
  • Relay terbalik: Banyak modul active LOW — LOW = ON, HIGH = OFF

Indeks Lengkap Seri 2 ESP32/IoT Lanjutan (29 Artikel)

Ini adalah indeks resmi Seri 2 — diselaraskan dengan capstone Seri 1 (#10):

  1. Deep sleep ESP32 + DHT22 hemat baterai
  2. NVS + WiFiManager
  3. Broker Mosquitto pribadi + autentikasi
  4. I2C + sensor BME280
  5. OLED SSD1306
  6. OTA update firmware ESP32
  7. Home Assistant + ESP32 MQTT
  8. ESPHome flash ESP32 tanpa Arduino
  9. Node-RED dashboard IoT MQTT
  10. Sensor gerak PIR + lampu MQTT
  11. MQTT TLS + QoS + LWT
  12. NTP & timestamp ESP32
  13. Subscriber Python → MySQL
  14. InfluxDB + Grafana
  15. REST API vs MQTT
  16. ESP-NOW antar ESP32 tanpa router WiFi
  17. LoRa ESP32 + SX1278 jarak jauh
  18. ESP32-CAM MJPEG streaming
  19. Gateway LoRa → MQTT
  20. Migrasi ke PlatformIO di VS Code
  21. ESP32 + Firebase Realtime Database
  22. FreeRTOS multi-task Sensor + WiFi + MQTT
  23. Bluetooth BLE kirim data sensor ke smartphone
  24. Kontrol Servo & PWM gerakan presisi via MQTT
  25. ADC ESP32: Soil Moisture & LDR via MQTT
  26. ESP8266 / NodeMCU vs ESP32
  27. SD Card & SPI logging offline
  28. HTTPS & sertifikat ESP32 (WiFiClientSecure)
  29. Smart Greenhouse capstone — artikel ini (penutup Seri 2)

FAQ — Pertanyaan Umum Greenhouse IoT

Apakah bisa pakai satu ESP32 untuk semua sensor dan relay?
Ya untuk prototipe skala kecil — gateway utama di artikel ini sudah menggabungkan BME280 + soil + LDR. Untuk produksi, pisahkan node aktuator agar reset sensor tidak mematikan pompa secara tidak sengaja.
Broker test.mosquitto.org cukup untuk greenhouse?
Tidak untuk data produksi — pakai broker sendiri (#16). Broker publik cocok hanya untuk uji coba 15 menit pertama.
Soil moisture resistif vs capacitive?
Capacitive lebih awet di tanah basah — sudah dibahas di #35. Probe resistif murah tapi korosi dalam berminggu-minggu.
Berapa lama baterai node deep sleep?
Dengan 18650 3000 mAh dan wake tiap 15 menit, estimasi 2–4 minggu — tergantung durasi WiFi connect. Optimasi: kurangi payload JSON, matikan LED board.
Apakah Seri 2 berakhir setelah artikel ini?
Ya — 29/29 artikel inti selesai. Topik Fase 3 (MicroPython, GPRS, Zigbee) akan ditulis jika ada permintaan komunitas.

Penutup — Terima Kasih Mengikuti Seri 2!

Kamu sekarang punya fondasi lengkap IoT embedded: dari sensor digital & analog, protokol MQTT & HTTPS, broker & dashboard, hingga smart home & cloud. Proyek greenhouse ini bisa dikembangkan ke skala komersial — tambah kamera (#27), gateway LoRa (#28), atau Firebase (#30) untuk monitoring mobile.

Seri 2 selesai — 29/29 artikel. Share proyek greenhouse kamu ke komunitas, dan pantau artikel baru di Koding Indonesia untuk topik Fase 3 (MicroPython, GPRS, Zigbee, dan lainnya).