Pendahuluan

Dari artikel-artikel sebelumnya kita sudah belajar:

Kali ini kita menggabungkan keduanya dalam satu sketch — pola yang dipakai di smart home nyata: ESP32 mengirim data sensor sekaligus menerima perintah kontrol dari broker yang sama.

Hasil akhirnya: kamu bisa lihat suhu di MQTT Explorer dan nyalakan/matikan lampu dari HP, tanpa upload ulang kode yang berbeda.

Yang Kamu Butuhkan

  • ESP32 DevKit + kabel jumper
  • Sensor DHT22 + resistor pull-up 10kΩ
  • Modul relay 1 channel (5V)
  • Lampu kecil untuk latihan (LED/soket aman)
  • Library: DHT sensor library, PubSubClient, ArduinoJson (v6 atau v7)
  • MQTT Explorer

Keamanan listrik: Untuk latihan gunakan lampu LED kecil atau lampu desk aman. Jangan menyentuh kabel AC 220V tanpa pengalaman — sama seperti artikel relay (#8).

Prasyarat: Sudah paham dasar MQTT, wiring DHT22, dan modul relay. Baca Membaca Sensor DHT22 (#5), MQTT ESP32 (#7), dan Kontrol Lampu Relay (#8) jika belum.

Topologi MQTT Proyek Ini

Kita pakai broker publik Eclipse Mosquitto test.mosquitto.org:1883 (sama seperti artikel sebelumnya):

DHT22 · GPIO 4 suhu · kelembaban Relay · GPIO 26 lampu ON/OFF ESP32 — satu sketch publish + subscribe Mosquitto · :1883 test.mosquitto.org PUB · .../dht22/data SUB · .../lampu/kontrol telemetri keluar · perintah masuk · satu broker
Publish JSON dari DHT22 (#5) + subscribe kontrol dari relay (#8) — pola MQTT (#7).
ArahTopicIsi pesan
ESP32 → Broker (publish)kodingindonesia/esp32/dht22/dataJSON: {"suhu":28.5,"kelembaban":65.2}
Broker → ESP32 (subscribe)kodingindonesia/esp32/lampu/kontrolON atau OFF

Catatan: Di artikel MQTT (#7) topic sensor adalah kodingindonesia/esp32/dht22 (payload teks). Di proyek gabungan kita pakai subtopic .../dht22/data + JSON agar lebih terstruktur. Topic kontrol relay sama dengan artikel relay (#8).

Broker bukan websitetest.mosquitto.org tidak dibuka di browser. Gunakan ESP32 atau MQTT Explorer.

Pro tip: Ganti segmen topic dengan nama unik, misalnya kodingindonesia/anton/esp32/..., agar tidak bentrok dengan peserta tutorial lain. Jangan kontrol perangkat produksi lewat broker publik tanpa autentikasi.

Wiring Ringkas

Pin konsisten dengan DHT22 (#5) dan relay (#8):

ESP32 DevKit 3.3V 5V GND GPIO 4 DATA GPIO 26 RELAY DHT22 1-wire · 3.3V VCC GND DATA Relay 1ch modul 5V VCC GND IN 3.3V→DHT VCC · 5V→Relay VCC · GPIO4→DATA · GPIO26→IN · GND common Pull-up 10kΩ DATA→3.3V (modul breakout biasanya sudah ada)
Wiring pin-ke-pin: DHT22 di 3.3V/GPIO 4; relay di 5V/GPIO 26; GND bersama.
  • DHT22 DATA → GPIO 4 (+ pull-up 10kΩ ke 3.3V)
  • DHT22 VCC → 3.3V · GND → GND
  • Relay IN → GPIO 26 · VCC → 5V · GND → GND

Kode Lengkap: Publish Suhu + Subscribe Relay

Ganti placeholder GANTI_SSID_WIFI / GANTI_PASSWORD_WIFI, lalu upload. Untuk produksi tanpa hardcode, lihat NVS + WiFiManager (#12).

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <ArduinoJson.h>

const char* ssid     = "GANTI_SSID_WIFI";
const char* password = "GANTI_PASSWORD_WIFI";

const char* mqttServer    = "test.mosquitto.org";
const int   mqttPort      = 1883;
const char* topicSensor   = "kodingindonesia/esp32/dht22/data";
const char* topicKontrol    = "kodingindonesia/esp32/lampu/kontrol";

#define DHT_PIN   4
#define DHT_TYPE  DHT22
#define RELAY_PIN 26

const bool RELAY_ON  = LOW;   // sesuaikan jika modul active HIGH
const bool RELAY_OFF = HIGH;

DHT dht(DHT_PIN, DHT_TYPE);
WiFiClient espClient;
PubSubClient mqttClient(espClient);

bool lampuMenyala = false;
unsigned long terakhirPublish = 0;
const unsigned long intervalPublish = 10000; // 10 detik

void setLampu(bool nyala) {
  lampuMenyala = nyala;
  digitalWrite(RELAY_PIN, nyala ? RELAY_ON : RELAY_OFF);
  Serial.println(nyala ? "Lampu: ON" : "Lampu: OFF");
}

void callbackMQTT(char* topic, byte* payload, unsigned int length) {
  String pesan;
  for (unsigned int i = 0; i < length; i++) {
    pesan += (char)payload[i];
  }
  pesan.trim();
  pesan.toUpperCase();

  Serial.print("Perintah di ");
  Serial.print(topic);
  Serial.print(": ");
  Serial.println(pesan);

  if (pesan == "ON") {
    setLampu(true);
  } else if (pesan == "OFF") {
    setLampu(false);
  }
}

void koneksiWiFi() {
  Serial.print("Menghubungkan ke WiFi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi terhubung!");
}

void koneksiMQTT() {
  mqttClient.setServer(mqttServer, mqttPort);
  mqttClient.setCallback(callbackMQTT);
  mqttClient.setBufferSize(512);

  while (!mqttClient.connected()) {
    Serial.print("MQTT connect...");
    String clientId = "ESP32-Combo-" + String(random(0xffff), HEX);

    if (mqttClient.connect(clientId.c_str())) {
      Serial.println(" OK");
      mqttClient.subscribe(topicKontrol);
      Serial.print("Subscribe: ");
      Serial.println(topicKontrol);
    } else {
      Serial.print(" gagal rc=");
      Serial.println(mqttClient.state());
      delay(5000);
    }
  }
}

void publishSensor() {
  float suhu = dht.readTemperature();
  float kelembaban = dht.readHumidity();

  if (isnan(suhu) || isnan(kelembaban)) {
    Serial.println("Gagal baca DHT22");
    return;
  }

  StaticJsonDocument<128> doc;
  doc["suhu"] = round(suhu * 10) / 10.0;
  doc["kelembaban"] = round(kelembaban * 10) / 10.0;

  char buffer[128];
  serializeJson(doc, buffer);

  if (mqttClient.publish(topicSensor, buffer)) {
    Serial.print("Publish ");
    Serial.print(topicSensor);
    Serial.print(": ");
    Serial.println(buffer);
  } else {
    Serial.println("Publish gagal");
  }

  // Bonus: matikan lampu otomatis jika suhu > 30°C
  if (suhu > 30.0 && lampuMenyala) {
    Serial.println("Suhu tinggi — lampu dimatikan otomatis");
    setLampu(false);
  }
}

void setup() {
  Serial.begin(115200);
  randomSeed(micros());
  pinMode(RELAY_PIN, OUTPUT);
  setLampu(false);
  dht.begin();

  koneksiWiFi();
  koneksiMQTT();
  delay(2000); // stabilkan DHT22 sebelum baca pertama
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    koneksiWiFi();
  }
  if (!mqttClient.connected()) {
    koneksiMQTT();
  }
  mqttClient.loop();

  unsigned long sekarang = millis();
  if (sekarang - terakhirPublish >= intervalPublish) {
    terakhirPublish = sekarang;
    publishSensor();
  }
}

Library ArduinoJson: Install via Library Manager — cari ArduinoJson by Benoit Blanchon. Kode di bawah memakai sintaks v6 (StaticJsonDocument). Jika pakai v7, ganti dengan JsonDocument doc; — lihat dokumentasi ArduinoJson.

Uji Coba

  1. Upload kode, buka Serial Monitor (115200 baud)
  2. Pastikan muncul log Publish kodingindonesia/esp32/dht22/data: {"suhu":...} setiap 10 detik
  3. Buka MQTT Explorer → connect ke test.mosquitto.org:1883
  4. Lihat topic kodingindonesia/esp32/dht22/data — payload JSON suhu & kelembaban
  5. Publish ke kodingindonesia/esp32/lampu/kontrol pesan ON / OFF → relay bereaksi
  6. Tiup panas ke DHT22 (atau pegang sensor) — jika suhu > 30°C dan lampu nyala, lampu mati otomatis

Alternatif: mosquitto_sub / mosquitto_pub (Terminal)

# Lihat data sensor (subscribe)
mosquitto_sub -h test.mosquitto.org -t "kodingindonesia/esp32/dht22/data" -v

# Nyalakan / matikan lampu (publish)
mosquitto_pub -h test.mosquitto.org -t "kodingindonesia/esp32/lampu/kontrol" -m "ON"
mosquitto_pub -h test.mosquitto.org -t "kodingindonesia/esp32/lampu/kontrol" -m "OFF"

Tool CLI dari paket Mosquitto — Linux, Mac, dan Windows setelah install Mosquitto.

Alur Program

  1. setup() — WiFi, MQTT connect, subscribe topic kontrol
  2. loop()mqttClient.loop() memproses pesan subscribe
  3. Setiap 10 detik — baca DHT22, publish JSON ke topic sensor
  4. callbackMQTT() — terima ON/OFF, ubah relay
  5. Logika bonus — auto-off lampu saat suhu tinggi

Ini pola edge device klasik di IoT: telemetri + kontrol dalam satu firmware.

Tips & Troubleshooting

  • Publish OK, subscribe tidak jalan: Pastikan mqttClient.loop() dipanggil di setiap iterasi loop().
  • JSON terpotong: Naikkan setBufferSize(512) atau lebih.
  • Compile error ArduinoJson: Pastikan versi library cocok — v6 pakai StaticJsonDocument, v7 pakai JsonDocument.
  • rc=-2 saat connect MQTT: WiFi atau broker tidak terjangkau — cek internet.
  • rc=4 (bad credentials): test.mosquitto.org port 1883 tidak perlu auth.
  • ESP32 restart saat relay + WiFi aktif: Power supply relay terpisah 5V, GND common dengan ESP32.
  • Suhu selalu NaN: Cek wiring DHT22, pull-up 10kΩ, dan tunggu 2 detik setelah dht.begin().
  • Topic tidak muncul di Explorer: Topic case-sensitive — harus sama persis. Coba wildcard kodingindonesia/esp32/#.
  • Ingin interval lebih cepat: Ubah intervalPublish — jangan terlalu agresif di broker publik (hormati resource bersama).

Langkah Selanjutnya

Selamat! Dengan artikel ini, kamu sudah menyelesaikan rangkaian proyek ESP32 + MQTT dari sensor hingga aktuator. Ini fondasi solid sebelum masuk ke platform cloud atau home automation lengkap.

Langkah Selanjutnya — Firmware Lanjut (Seri 2)

Sketch gabungan ini memakai satu loop() — cocok untuk belajar. Saat proyek butuh sensor dan MQTT berjalan paralel tanpa saling blocking, lanjut ke FreeRTOS multi-task (#31): task sensor, task WiFi/MQTT, dan antrean data.