Tutorial MQTT ESP32: Mosquitto, Home Assistant, dan ESPHome
Tutorial MQTT ESP32: instal Mosquitto, kirim data sensor dan kendalikan relay dengan PubSubClient, MQTT Discovery Home Assistant, contoh YAML ESPHome, dan QoS.
Memasangkan ESP32 dengan MQTT adalah cara paling umum agar sensor dan relay di rumahmu bisa saling berbicara dan terhubung ke sistem rumah pintar seperti Home Assistant. MQTT adalah protokol pesan ringan yang dirancang untuk perangkat kecil: ESP32 menaruh suhu yang diukurnya ke sebuah topic seperti “ev/salon/sicaklik”, dan setiap program yang mendengarkan topic itu langsung menerima nilainya. Dengan cara yang sama, ketika kamu mengetuk tombol di aplikasi Home Assistant di ponselmu, perintah “ON” sampai ke ESP32 dalam waktu jauh di bawah satu detik dan menghidupkan relay. Berbeda dengan HTTP, MQTT tidak membuka koneksi baru untuk setiap request; ia bekerja lewat satu koneksi yang tetap terbuka dengan header sekecil dua byte, jadi cepat dan ringan bagi Wi-Fi maupun prosesor.
Di panduan ini kamu akan membuat node rumah pintar yang berfungsi dari nol. Pertama kamu akan mempelajari konsep MQTT: broker, topic, publish, dan subscribe, lalu menginstal broker Mosquitto di Home Assistant atau di Raspberry Pi. Berikutnya kamu akan memakai library PubSubClient untuk mengirim pembacaan suhu dan kelembapan DHT22 dari ESP32, mendengarkan perintah relay, dan menambahkan MQTT Discovery agar perangkat muncul sendiri di Home Assistant. Kita juga akan membahas QoS dan retain, pesan last will (LWT) yang menandai perangkat sebagai “unavailable” ketika koneksi putus, alternatif ESPHome yang mengerjakan hal yang sama tanpa satu baris C++ pun, perbedaan di ESP8266 dan Raspberry Pi Pico W, serta error yang paling umum satu per satu.

Apa itu MQTT dan bagaimana cara kerjanya?
MQTT (Message Queuing Telemetry Transport) memakai model publish/subscribe. Di tengahnya ada server yang disebut broker; ESP32, Home Assistant, ponselmu, atau program di komputermu terhubung ke broker sebagai klien. Klien tidak saling mengenal dan tidak tahu alamat IP satu sama lain: satu klien mem-publish pesan ke sebuah topic, dan broker meneruskannya ke semua yang subscribe ke topic itu. Bayangkan seperti kantor pos: ESP32 memasukkan surat ke kotak beralamat “ev/salon/sicaklik”, dan Home Assistant, yang mengawasi kotak itu, langsung menerimanya. Karena koneksi selalu dibuka oleh klien, ESP32 tidak butuh IP statis atau port yang terbuka di router-mu; yang perlu diketahuinya hanya alamat broker.
| Konsep | Fungsinya | Contoh |
|---|---|---|
| Broker | Server yang menerima pesan dan membagikannya ke para subscriber | Mosquitto, broker Mosquitto di Home Assistant |
| Klien | Perangkat atau program apa pun yang terhubung ke broker; masing-masing punya client ID yang unik | ESP32, Home Assistant, MQTT Explorer |
| Topic | Alamat sebuah pesan, terdiri dari level-level yang dipisahkan garis miring | ev/salon/sicaklik |
| Publish | Mengirim pesan ke sebuah topic | Mengirim nilai “23.4” ke ev/salon/sicaklik |
| Subscribe | Mendaftar untuk menerima pesan di sebuah topic | ESP32 mendengarkan ev/salon/role/komut |
| Payload | Isi sebuah pesan; teks, angka, atau JSON | ON, 23.4, {"sicaklik":23.4} |
| Retain | Broker menyimpan pesan terakhir di sebuah topic dan langsung memberikannya ke subscriber baru | Status relay: ON |
| LWT (last will) | Pesan yang di-publish broker atas nama klien jika klien itu terputus secara tak terduga | ev/salon/baglanti: offline (status koneksi) |
| QoS | Tingkat jaminan pengiriman sebuah pesan (0, 1, atau 2) | QoS 1 untuk perintah relay |
Kenapa MQTT? Dibandingkan dengan web server, Blynk, dan Telegram
| Metode | Kelebihan | Kekurangan | Paling cocok untuk |
|---|---|---|---|
| MQTT + Home Assistant | Lokal dan cepat, dua arah; ratusan perangkat dalam satu dasbor, otomatisasi | Kamu perlu menjalankan broker | Mengelola seluruh rumah dari satu tempat |
| Web server ESP32 | Tanpa server tambahan, terbuka di browser | Setiap perangkat punya halaman sendiri, tanpa otomatisasi antarperangkat | Panel kendali untuk satu perangkat |
| Blynk IoT | Dasbor ponsel siap pakai, akses lewat internet | Bergantung pada cloud, ada batasan di paket gratis | Prototipe mobile yang cepat |
| Bot Telegram | Notifikasi instan gratis, tanpa port forwarding | Tanpa grafik atau dasbor | Alarm dan perintah sederhana |
| ESP-NOW | Board ESP saling berbicara tanpa router atau broker | Hanya antar-board ESP, tidak langsung sampai ke Home Assistant | Membawa data dari sensor berbaterai ke gateway |
Singkatnya, MQTT makin unggul ketika jumlah perangkat bertambah: ketika kamu menambahkan sensor baru, kamu tidak menyentuh kode yang sudah ada, cukup mulai mem-publish ke topic baru. Kalau kamu ingin mengendalikan satu perangkat dari browser, panduan web server asinkron ESP32 dan WebSocket lebih cepat membawamu ke sana; untuk notifikasi ponsel lihat bot Telegram ESP32, dan untuk dasbor mobile siap pakai lihat Blynk IoT dengan ESP32. Untuk sensor taman yang di luar jangkauan router-mu, memakai ESP-NOW untuk membawa data ke ESP32 gateway yang terhubung ke MQTT adalah solusi yang bagus.
Struktur topic MQTT dan wildcard
Topic terlihat seperti path folder: “ev/salon/sicaklik” (bahasa Turki untuk rumah/ruang tamu/suhu) punya tiga level dan peka huruf besar-kecil, jadi “Ev/Salon” dan “ev/salon” adalah dua topic yang berbeda. Jangan diawali garis miring (“/ev/salon” membuat level pertama yang kosong), dan hindari spasi serta huruf beraksen; huruf biasa, angka, tanda hubung, dan garis bawah sudah cukup. Ketika subscribe, kamu bisa memakai dua wildcard: + menggantikan tepat satu level (“ev/+/sicaklik” mengembalikan suhu setiap ruangan), sedangkan # mencakup semua yang ada sesudahnya dan hanya boleh muncul di akhir (“ev/#” mengembalikan semua pesan di rumah). Wildcard hanya berlaku ketika subscribe; pesan selalu di-publish ke satu topic yang pasti. Topic yang diawali $ (seperti $SYS) dicadangkan untuk statistik broker sendiri dan tidak ikut tertangkap oleh subscription #. Untuk proyek di panduan ini kita akan memakai susunan berikut:
| Topic | Di-publish oleh | Didengarkan oleh | Retain |
|---|---|---|---|
| ev/salon/sicaklik | ESP32 (setiap 30 detik) | Home Assistant | Ya |
| ev/salon/nem | ESP32 (setiap 30 detik) | Home Assistant | Ya |
| ev/salon/role/komut (perintah relay) | Home Assistant, ponsel, otomatisasi | ESP32 | Tidak |
| ev/salon/role/durum (status relay) | ESP32 (setiap kali berubah) | Home Assistant | Ya |
| ev/salon/baglanti | ESP32 (pesan online), broker (pesan offline) | Home Assistant | Ya |
| homeassistant/status | Home Assistant (online ketika mulai) | ESP32 | Tidak |
Menginstal broker MQTT: Mosquitto
Broker MQTT gratis yang paling populer adalah Eclipse Mosquitto; bahkan di Raspberry Pi pun ia dengan mudah menangani ratusan pesan per detik. Ada tiga cara mudah untuk menginstalnya: aplikasi resmi Mosquitto broker kalau kamu memakai Home Assistant OS, paket apt di Raspberry Pi atau komputer Linux terpisah, atau installer Mosquitto di Windows. Apa pun pilihanmu, broker memakai port 1883 untuk MQTT tanpa enkripsi dan 8883 untuk MQTT terenkripsi TLS, dan broker hanya perlu berada di jaringan rumah yang sama dengan ESP32. Di Home Assistant, pemasangannya seperti ini:
- Di Home Assistant, buka Settings > Apps (di versi lama namanya Add-ons), klik Install app, lalu pilih Mosquitto broker dari daftar.
- Klik Install; setelah selesai, klik Start dan biarkan opsi mulai otomatis ketika booting tetap aktif.
- Buat pengguna terpisah untuk ESP32: di Settings > People > Users, tambahkan pengguna bernama “esp32” dengan kata sandi yang kuat. Kalau tab ini tidak terlihat, aktifkan Advanced mode di profilmu. Nama “homeassistant” dan “addons” dicadangkan untuk broker, jadi jangan dipakai.
- Di halaman Settings > Devices & services, integrasi MQTT biasanya muncul sebagai “Discovered”; klik Configure lalu konfirmasi. Kalau tidak muncul, pakai Add integration, cari MQTT, dan pilih opsi yang mengonfigurasi Mosquitto secara otomatis.
- Di kode ESP32 kamu akan memasukkan alamat IP Home Assistant sebagai alamat broker (misalnya 192.168.1.10), 1883 sebagai port, dan pengguna yang baru saja kamu buat.
Di mesin Linux seperti Raspberry Pi atau Ubuntu, pemasangannya hanya butuh beberapa perintah. Instal broker dan alat ujinya dengan sudo apt install mosquitto mosquitto-clients. Buat pengguna “esp32” dengan sudo mosquitto_passwd -c /etc/mosquitto/passwd esp32 lalu ketik kata sandinya dua kali; opsi -c membuat file dari nol, jadi jangan dipakai ketika menambahkan pengguna kedua, kalau tidak pengguna yang sudah ada akan terhapus. Setelah itu buat file bernama local.conf di folder /etc/mosquitto/conf.d/, isi dengan tiga baris di bawah, lalu restart layanannya dengan sudo systemctl restart mosquitto. Di Windows, tambahkan baris yang sama ke file mosquitto.conf di folder instalasi Mosquitto, lalu restart layanan Mosquitto Broker.
| Baris | Artinya |
|---|---|
| listener 1883 | Mendengarkan di port 1883 pada semua antarmuka jaringan; tanpa baris ini, Mosquitto 2.x hanya menerima koneksi dari komputer yang sama |
| allow_anonymous false | Menolak koneksi tanpa nama pengguna dan kata sandi; di 2.x ini sudah bawaan, tapi menuliskannya secara eksplisit adalah kebiasaan yang baik |
| password_file /etc/mosquitto/passwd (file kata sandi) | Memakai file kata sandi yang kamu buat dengan mosquitto_passwd; kata sandi disimpan di dalamnya dalam bentuk hash |
Sebelum beralih ke ESP32, uji broker dari komputermu; memisahkan masalah broker dari masalah kode sejak awal menghemat banyak waktu. Di satu terminal, mulai dengarkan semua topic di rumah dengan mosquitto_sub -h 192.168.1.10 -u esp32 -P yourpassword -t "ev/#" -v. Di terminal kedua, ketik mosquitto_pub -h 192.168.1.10 -u esp32 -P yourpassword -t ev/salon/test -m hello. Kalau baris “ev/salon/test hello” muncul di terminal pertama, broker berjalan dan kata sandinya benar. Opsi -v mencetak topic setiap pesan di depannya, dan opsi -r mengirim pesan sebagai retained.
Daftar komponen dan diagram pengkabelan
Untuk proyek ini kamu butuh board pengembangan ESP32, sensor suhu dan kelembapan DHT22, modul relay yang bisa dipicu pada 3,3 V, breadboard, dan kabel jumper. DHT22 lebih presisi daripada DHT11: mengukur suhu sampai ±0,5 °C dan kelembapan kira-kira ±2–5%, serta bekerja dari -40 sampai 80 °C; keluarga sensor ini kami bahas detail di Sensor Suhu dan Kelembapan DHT11. Kalau kamu punya DHT11, cukup ganti DHT22 menjadi DHT11 di kode. Untuk tes koneksi pertama, ESP32 dan kabel USB sudah cukup; sensor dan relay bisa ditambahkan belakangan.



| Sambungan | ESP32 | ESP8266 (NodeMCU) | Raspberry Pi Pico W |
|---|---|---|---|
| DHT22 VCC | 3V3 | 3V3 | 3V3(OUT) |
| DHT22 DATA | GPIO 4 | D2 (GPIO 4) | GP15 |
| DHT22 GND | GND | GND | GND |
| VCC relay | VIN (5V) | VIN (5V) | VBUS (5V) |
| IN relay | GPIO 26 | D1 (GPIO 5) | GP14 |
| GND relay | GND | GND | GND |
Menginstal PubSubClient di Arduino IDE
- Kalau paket board ESP32 belum terinstal di Arduino IDE, instal dulu; langkah-langkahnya ada di Apa Itu ESP32?.
- Buka Tools > Manage Libraries, ketik PubSubClient di kotak pencarian, lalu instal library buatan Nick O'Leary. Kode di panduan ini dikompilasi dengan versi 2.8.
- Di jendela yang sama, cari DHT sensor library dan instal library Adafruit; ketika ditanya soal dependensi, pilih Install all agar Adafruit Unified Sensor ikut terinstal.
- Kalau kamu mengalami masalah ketika menginstal library, lihat panduan Cara Instal Library Arduino.
Tes pertama: menghubungkan ESP32 ke broker MQTT
Sebelum menambahkan sensor, mari pastikan dengan kode yang paling sederhana bahwa data Wi-Fi, alamat broker, dan kata sandinya benar. Kode di bawah terhubung ke broker, mem-publish “merhaba” (bahasa Turki untuk “halo”) ke topic “test/esp32/durum”, dan mencetak setiap pesan yang datang di “test/esp32/komut” ke Serial Monitor. Ganti nama Wi-Fi, kata sandi, IP broker, dan pengguna MQTT dengan milikmu, upload kodenya, lalu buka Serial Monitor di 115200 baud:
1#include <WiFi.h>
2#include <PubSubClient.h>
3
4const char* WIFI_SSID = "AgAdi"; // Wi-Fi adın (yalnız 2,4 GHz) / your Wi-Fi name (2.4 GHz only)
5const char* WIFI_PASS = "Sifre123"; // Wi-Fi şifren / your Wi-Fi password
6const char* MQTT_SUNUCU = "192.168.1.10"; // broker'ın IP adresi / broker IP address
7const int MQTT_PORT = 1883; // şifresiz MQTT portu / unencrypted MQTT port
8const char* MQTT_KULLANICI = "esp32"; // broker kullanıcı adı / broker username
9const char* MQTT_SIFRE = "mqttSifre"; // broker şifresi / broker password
10
11WiFiClient wifiIstemci; // TCP bağlantısı / TCP connection
12PubSubClient mqtt(wifiIstemci); // MQTT istemcisi / MQTT client
13
14// Abone olunan konuya mesaj gelince çalışır / runs when a subscribed topic receives a message
15void mesajGeldi(char* topic, byte* payload, unsigned int length) {
16 Serial.print("Mesaj [");
17 Serial.print(topic);
18 Serial.print("] ");
19 for (unsigned int i = 0; i < length; i++) {
20 Serial.print((char)payload[i]); // payload sonunda \0 yoktur / payload is not null-terminated
21 }
22 Serial.println();
23}
24
25void setup() {
26 Serial.begin(115200);
27 WiFi.mode(WIFI_STA);
28 WiFi.begin(WIFI_SSID, WIFI_PASS);
29 while (WiFi.status() != WL_CONNECTED) {
30 delay(500);
31 Serial.print(".");
32 }
33 Serial.print("\nIP: ");
34 Serial.println(WiFi.localIP());
35
36 mqtt.setServer(MQTT_SUNUCU, MQTT_PORT); // broker adresi / broker address
37 mqtt.setCallback(mesajGeldi); // gelen mesaj fonksiyonu / incoming message handler
38}
39
40void loop() {
41 if (!mqtt.connected()) {
42 Serial.print("MQTT baglaniyor... ");
43 if (mqtt.connect("esp32-test", MQTT_KULLANICI, MQTT_SIFRE)) { // istemci kimliği benzersiz olmalı / client ID must be unique
44 Serial.println("baglandi");
45 mqtt.subscribe("test/esp32/komut"); // bu konuyu dinle / listen to this topic
46 mqtt.publish("test/esp32/durum", "merhaba"); // ilk mesaj / first message
47 } else {
48 Serial.print("hata, rc=");
49 Serial.println(mqtt.state()); // hata kodu / error code
50 delay(5000);
51 return;
52 }
53 }
54 mqtt.loop(); // mesajları işle, bağlantıyı canlı tut / process messages, keep the connection alive
55}Begitu kamu melihat “baglandi” (“terhubung”) di Serial Monitor, kirim mosquitto_pub -h 192.168.1.10 -u esp32 -P yourpassword -t test/esp32/komut -m hi dari terminal di komputermu; dalam beberapa milidetik baris “Mesaj [test/esp32/komut] hi” (Mesaj = “pesan”) muncul di Serial Monitor. Kalau koneksinya gagal, kode mencetak kode error dengan mqtt.state() dan mencoba lagi setelah 5 detik. Kode-kode ini memberi tahu dengan tepat di mana masalahnya:
| rc | Nama di PubSubClient | Arti dan solusi |
|---|---|---|
| -4 | MQTT_CONNECTION_TIMEOUT | Broker tidak menjawab tepat waktu; jaringan lemah atau broker kelebihan beban |
| -3 | MQTT_CONNECTION_LOST | Koneksi yang sudah terjalin putus; biasanya karena loop() lama tidak dipanggil atau Wi-Fi hilang |
| -2 | MQTT_CONNECT_FAILED | Koneksi TCP tidak pernah terbuka: IP atau port salah, broker tidak berjalan, Mosquitto dalam mode local-only, atau firewall memblokir 1883 |
| -1 | MQTT_DISCONNECTED | Koneksi ditutup dengan rapi (disconnect dipanggil) atau memang belum pernah terhubung |
| 2 | MQTT_CONNECT_BAD_CLIENT_ID | Client ID ditolak; yang dipakai client ID kosong atau tidak valid |
| 4 | MQTT_CONNECT_BAD_CREDENTIALS | Nama pengguna atau kata sandi salah (beberapa broker mengembalikan kode ini) |
| 5 | MQTT_CONNECT_UNAUTHORIZED | Tidak diizinkan; Mosquitto mengembalikan kode ini baik untuk kata sandi yang salah maupun untuk upaya terhubung tanpa kredensial |
Mengirim data sensor dan mendengarkan perintah relay dengan ESP32
Sekarang mari buat proyek yang sebenarnya. Kode di bawah membaca DHT22 setiap 30 detik dan mem-publish suhu dan kelembapan dengan flag retain, mengendalikan relay dengan perintah ON, OFF, dan TOGGLE yang datang di “ev/salon/role/komut”, lalu melaporkan status baru relay ke “ev/salon/role/durum”. Ketika terhubung, kode menitipkan last will ke broker, memperkenalkan diri ke Home Assistant lewat MQTT Discovery, dan kalau koneksi putus, mencoba lagi setiap 5 detik tanpa memblokir loop(). Berkat blok #if defined(ESP8266) di bagian atas, kode yang sama juga bisa dikompilasi di NodeMCU tanpa perubahan apa pun.
1#if defined(ESP8266)
2#include <ESP8266WiFi.h>
3#else
4#include <WiFi.h>
5#endif
6#include <PubSubClient.h>
7#include <DHT.h>
8
9// ---- Ayarlar / Settings ----
10const char* WIFI_SSID = "AgAdi";
11const char* WIFI_PASS = "Sifre123";
12const char* MQTT_SUNUCU = "192.168.1.10"; // broker IP (Home Assistant ya da Raspberry Pi) / broker IP (Home Assistant or Raspberry Pi)
13const int MQTT_PORT = 1883;
14const char* MQTT_KULLANICI = "esp32";
15const char* MQTT_SIFRE = "mqttSifre";
16const char* ISTEMCI_ID = "esp32-salon"; // her cihazda farklı olmalı / must be different on every device
17
18#if defined(ESP8266)
19const int DHT_PIN = 4; // NodeMCU D2
20const int ROLE_PIN = 5; // NodeMCU D1
21#else
22const int DHT_PIN = 4; // ESP32 GPIO 4
23const int ROLE_PIN = 26; // ESP32 GPIO 26
24#endif
25const bool ROLE_AKTIF_LOW = true; // çoğu röle modülü LOW ile çeker / most relay modules switch on LOW
26const unsigned long OLCUM_ARALIGI = 30000; // 30 saniyede bir ölçüm / one reading every 30 s
27
28// ---- Konular (topic) / Topics ----
29const char* T_SICAKLIK = "ev/salon/sicaklik";
30const char* T_NEM = "ev/salon/nem";
31const char* T_KOMUT = "ev/salon/role/komut"; // ON, OFF ya da TOGGLE / ON, OFF or TOGGLE
32const char* T_DURUM = "ev/salon/role/durum";
33const char* T_BAGLANTI = "ev/salon/baglanti"; // online / offline (son vasiyet / last will)
34const char* T_HA_DURUM = "homeassistant/status"; // HA açılınca "online" yayınlar / HA publishes "online" when it starts
35
36WiFiClient wifiIstemci;
37PubSubClient mqtt(wifiIstemci);
38DHT dht(DHT_PIN, DHT22);
39
40bool roleAcik = false;
41unsigned long sonOlcum = 0;
42unsigned long sonDeneme = 0;
43
44// Röleyi sür ve yeni durumu kalıcı (retain) yayınla / drive the relay and publish the new state as retained
45void roleAyarla(bool acik) {
46 roleAcik = acik;
47 bool seviye = ROLE_AKTIF_LOW ? !acik : acik;
48 digitalWrite(ROLE_PIN, seviye ? HIGH : LOW);
49 mqtt.publish(T_DURUM, acik ? "ON" : "OFF", true);
50 Serial.println(acik ? "Role: ON" : "Role: OFF");
51}
52
53// Tek bir Home Assistant keşif mesajı gönder / send one Home Assistant discovery message
54void kesifYayinla(const char* tur, const char* nesne, const char* ad, const char* ekAlanlar) {
55 char konu[96];
56 snprintf(konu, sizeof(konu), "homeassistant/%s/%s/%s/config", tur, ISTEMCI_ID, nesne);
57 char json[600];
58 snprintf(json, sizeof(json),
59 "{\"name\":\"%s\",\"unique_id\":\"%s_%s\",%s,\"availability_topic\":\"%s\","
60 "\"device\":{\"identifiers\":[\"%s\"],\"name\":\"Salon ESP32\",\"model\":\"ESP32 + DHT22\"}}",
61 ad, ISTEMCI_ID, nesne, ekAlanlar, T_BAGLANTI, ISTEMCI_ID);
62 if (!mqtt.publish(konu, json, true)) { // false: tampon küçük ya da bağlantı yok / false: buffer too small or not connected
63 Serial.println("Kesif mesaji gonderilemedi");
64 }
65}
66
67// Sıcaklık, nem ve röleyi Home Assistant'a tanıt / announce temperature, humidity and relay to Home Assistant
68void haKesifGonder() {
69 char ek[200];
70 snprintf(ek, sizeof(ek), "\"state_topic\":\"%s\",\"device_class\":\"temperature\",\"unit_of_measurement\":\"°C\",\"state_class\":\"measurement\"", T_SICAKLIK);
71 kesifYayinla("sensor", "sicaklik", "Sıcaklık", ek);
72 snprintf(ek, sizeof(ek), "\"state_topic\":\"%s\",\"device_class\":\"humidity\",\"unit_of_measurement\":\"%%\",\"state_class\":\"measurement\"", T_NEM);
73 kesifYayinla("sensor", "nem", "Nem", ek);
74 snprintf(ek, sizeof(ek), "\"state_topic\":\"%s\",\"command_topic\":\"%s\"", T_DURUM, T_KOMUT);
75 kesifYayinla("switch", "role", "Röle", ek);
76}
77
78// DHT22'yi oku ve değerleri yayınla / read the DHT22 and publish the values
79void olcumGonder() {
80 float t = dht.readTemperature();
81 float h = dht.readHumidity();
82 if (isnan(t) || isnan(h)) {
83 Serial.println("DHT22 okunamadi");
84 return;
85 }
86 char deger[12];
87 snprintf(deger, sizeof(deger), "%.1f", t); // 23.4 gibi / like 23.4
88 mqtt.publish(T_SICAKLIK, deger, true);
89 snprintf(deger, sizeof(deger), "%.0f", h); // 45 gibi / like 45
90 mqtt.publish(T_NEM, deger, true);
91 Serial.printf("Sicaklik %.1f C, nem %.0f %%\n", t, h);
92}
93
94// Abone olunan konulara mesaj gelince çalışır / runs when a subscribed topic receives a message
95void mesajGeldi(char* topic, byte* payload, unsigned int length) {
96 // Önce kopyala: yayın yapınca kütüphane aynı tamponu kullanır / copy first: publishing reuses the same buffer
97 String konu = topic;
98 String mesaj;
99 for (unsigned int i = 0; i < length; i++) mesaj += (char)payload[i];
100 mesaj.trim();
101
102 if (konu == T_KOMUT) {
103 if (mesaj == "ON") roleAyarla(true);
104 else if (mesaj == "OFF") roleAyarla(false);
105 else if (mesaj == "TOGGLE") roleAyarla(!roleAcik);
106 } else if (konu == T_HA_DURUM && mesaj == "online") {
107 haKesifGonder(); // HA yeniden başladı, tanıtımı yenile / HA restarted, announce again
108 mqtt.publish(T_DURUM, roleAcik ? "ON" : "OFF", true);
109 }
110}
111
112bool mqttBaglan() {
113 Serial.print("MQTT baglaniyor... ");
114 // Bağlantı koparsa broker T_BAGLANTI'ya "offline" yazar / if we drop, the broker publishes "offline" to T_BAGLANTI
115 if (!mqtt.connect(ISTEMCI_ID, MQTT_KULLANICI, MQTT_SIFRE, T_BAGLANTI, 1, true, "offline")) {
116 Serial.print("hata, rc=");
117 Serial.println(mqtt.state());
118 return false;
119 }
120 Serial.println("baglandi");
121 mqtt.publish(T_BAGLANTI, "online", true);
122 mqtt.subscribe(T_KOMUT, 1); // komutları QoS 1 ile dinle / listen to commands with QoS 1
123 mqtt.subscribe(T_HA_DURUM);
124 haKesifGonder();
125 mqtt.publish(T_DURUM, roleAcik ? "ON" : "OFF", true);
126 return true;
127}
128
129void setup() {
130 Serial.begin(115200);
131 pinMode(ROLE_PIN, OUTPUT);
132 roleAyarla(false); // güvenli başlangıç: röle kapalı / safe start: relay off
133 dht.begin();
134
135 WiFi.mode(WIFI_STA);
136 WiFi.begin(WIFI_SSID, WIFI_PASS);
137 Serial.print("Wi-Fi");
138 while (WiFi.status() != WL_CONNECTED) {
139 delay(500);
140 Serial.print(".");
141 }
142 Serial.print(" IP: ");
143 Serial.println(WiFi.localIP());
144
145 mqtt.setServer(MQTT_SUNUCU, MQTT_PORT);
146 mqtt.setCallback(mesajGeldi);
147 mqtt.setBufferSize(1024); // keşif JSON'u varsayılan 256 bayta sığmaz / discovery JSON doesn't fit the default 256 bytes
148}
149
150void loop() {
151 if (!mqtt.connected()) {
152 unsigned long simdi = millis();
153 if (sonDeneme == 0 || simdi - sonDeneme >= 5000) { // 5 sn'de bir dene, loop'u kilitleme / retry every 5 s without blocking
154 sonDeneme = simdi;
155 if (mqttBaglan()) sonOlcum = simdi - OLCUM_ARALIGI; // bağlanınca hemen ölç / measure right after connecting
156 }
157 return;
158 }
159 mqtt.loop(); // gelen komutlar ve keep-alive / incoming commands and keep-alive
160
161 if (millis() - sonOlcum >= OLCUM_ARALIGI) {
162 sonOlcum = millis();
163 olcumGonder();
164 }
165}| Baris | Fungsinya |
|---|---|
| mqtt.connect(ISTEMCI_ID, ..., T_BAGLANTI, 1, true, "offline") (terhubung dengan last will) | Mendaftarkan last will sambil terhubung: kalau ESP32 terputus secara tak terduga, broker menulis “offline” yang retained ke ev/salon/baglanti |
| mqtt.publish(T_BAGLANTI, "online", true) (status online) | Mengatur status menjadi “online” tepat setelah terhubung; Home Assistant menampilkan perangkat sebagai tersedia lagi |
| mqtt.subscribe(T_KOMUT, 1) | Mendengarkan perintah relay dengan QoS 1; PubSubClient hanya mendukung QoS 0 dan 1 untuk subscription |
| mqtt.setBufferSize(1024) | Memperbesar buffer paket dari bawaan 256 byte; paket discovery terbesar sekitar 355 byte |
| mqtt.loop() | Membaca pesan yang masuk dan mengirim paket keep-alive (PINGREQ); harus dipanggil di setiap putaran loop |
| ROLE_AKTIF_LOW | Kebanyakan modul relay menyala dengan sinyal LOW; atur ke false kalau relay-mu menyala dengan HIGH |
| OLCUM_ARALIGI | Seberapa sering mengukur (interval pengukuran); DHT22 paling cepat bisa dibaca setiap 2 detik, dan 30–60 detik ideal untuk suhu ruangan |
Beberapa detail di kode ini sengaja dibuat begitu. Fungsi mesajGeldi() (“pesan datang”) menyalin topic dan payload ke String terlebih dulu, karena PubSubClient memakai satu buffer untuk pesan masuk sekaligus keluar: begitu kamu memanggil publish() di dalam callback, data yang ditunjuk pointer topic dan payload tertimpa. Payload juga tidak punya penutup \0 seperti string C, jadi kita membaca tepat sebanyak length karakter. Kita memakai retain untuk pembacaan sensor dan status relay agar Home Assistant langsung melihat nilai terakhir setelah restart, bukan menunggu 30 detik. Pengaturan waktu juga memakai millis(): delay() yang panjang di dalam loop() akan menahan paket keep-alive dan broker akan memutus koneksi. Teknik ini kami jelaskan detail di Arduino millis() vs delay().
Tampilannya di Home Assistant: MQTT Discovery
Home Assistant terus-menerus mendengarkan topic yang diawali prefiks homeassistant/. Ketika sebuah perangkat mem-publish konfigurasi JSON ke topic berbentuk homeassistant/[component]/[node]/[object]/config, Home Assistant membuat entity itu secara otomatis; inilah yang disebut MQTT Discovery. Kode kita mengirim tiga pesan: dua untuk sensor (suhu dan kelembapan) di bawah homeassistant/sensor/esp32-salon/... dan satu untuk relay di homeassistant/switch/esp32-salon/role/config. Karena retained, pesan-pesan ini tetap ada setelah Home Assistant restart. Kode juga subscribe ke homeassistant/status: Home Assistant menulis “online” di sana ketika mulai, dan ESP32 mengumumkan dirinya lagi. Kalau perangkatmu banyak, dokumentasi Home Assistant menyarankan menambahkan jeda acak yang kecil sebelum pengumuman ulang ini.
| Field JSON | Artinya | Nilai kita |
|---|---|---|
| name | Nama tampilan entity; nama perangkat ditambahkan di depannya | Sıcaklık (tampil sebagai Salon ESP32 Sıcaklık; bahasa Turki untuk “suhu”) |
| unique_id | ID permanen entity; tanpanya, nama dan area entity tidak bisa diedit di antarmuka | esp32-salon_sicaklik |
| state_topic | Topic tempat nilai dibaca | ev/salon/sicaklik |
| command_topic | Topic tujuan perintah switch | ev/salon/role/komut (perintah relay) |
| device_class | Menentukan ikon, pilihan satuan, dan jenis grafik | temperature, humidity |
| unit_of_measurement | Satuan ukur | °C dan % |
| state_class | Nilai measurement mengaktifkan statistik jangka panjang dan grafik | measurement |
| availability_topic | Topic tempat status online/offline dibaca; payload bawaannya online dan offline | ev/salon/baglanti |
| device | Mengelompokkan entity ke dalam satu kartu perangkat | identifiers, name, model (ID, nama, model) |
Beberapa detik setelah kode di-upload, perangkat bernama “Salon ESP32” muncul di Settings > Devices & services > MQTT. Kartu perangkatnya berisi sensor suhu dan kelembapan serta satu switch relay; klik suhu untuk membuka grafik riwayatnya, balik switch-nya, dan relay pun berbunyi klik. Kamu bisa menambahkan entity ini ke dasbor, membukanya untuk asisten suara, atau memakainya di otomatisasi: misalnya, aturan seperti “kalau ruang tamu di atas 27 °C, nyalakan relay tempat kipas dicolokkan, dan matikan di bawah 25 °C” hanya butuh beberapa klik. Kalau kamu mencabut ESP32, entity berubah menjadi “Unavailable” paling lama sekitar 22 detik kemudian, tanda bahwa pesan last will bekerja. Kalau kamu tidak ingin memakai discovery, kamu juga bisa mendefinisikan entity yang sama secara manual di configuration.yaml sebagai entri sensor dan switch di bawah mqtt:.
QoS dan retain: pakai yang mana, dan kapan?
QoS (Quality of Service) menentukan seberapa yakin kamu ingin sebuah pesan sampai ke pihak lain. Satu detail penting: QoS berlaku terpisah di dua ruas. Antara publisher dan broker berlaku QoS publisher, dan antara broker dan subscriber berlaku QoS subscription; jaminan yang didapat subscriber adalah yang lebih rendah dari keduanya. PubSubClient hanya mendukung QoS 0 untuk publish dan QoS 0 serta 1 untuk subscription. Di Wi-Fi rumah, pesan yang hilang dengan QoS 0 sangat jarang, tapi menjadikan subscription perintah QoS 1 tetap asuransi yang murah.
| QoS | Jaminan | Cara kerjanya | Kapan dipakai |
|---|---|---|---|
| 0 | Paling banyak sekali | Pesan dikirim sekali tanpa konfirmasi; bisa hilang kalau koneksi putus pada momen itu | Pembacaan sensor yang sering |
| 1 | Paling sedikit sekali | Penerima mengonfirmasi dengan PUBACK, dan pesan dikirim ulang kalau konfirmasi tidak datang; pesan bisa sampai dua kali | Perintah relay, alarm |
| 2 | Tepat sekali | Jabat tangan (handshake) empat langkah dengan PUBREC, PUBREL, dan PUBCOMP; level paling lambat | Hal seperti penghitung, di mana duplikat merugikan; tidak didukung PubSubClient |
Flag retain lebih soal ingatan daripada pengiriman: broker hanya menyimpan pesan retained terakhir dari setiap topic dan langsung mengirimkannya ke siapa pun yang subscribe. Flag ini ideal untuk pesan “status terkini” seperti nilai sensor, status relay, dan status online, tapi berbahaya untuk perintah dan kejadian sekali jalan. Last will (LWT) melengkapinya: kalau broker tidak menerima paket apa pun dari sebuah klien selama 1,5 kali periode keep-alive, broker memutuskan koneksi itu hilang dan mem-publish pesan will. Keep-alive bawaan PubSubClient adalah 15 detik, jadi ESP32 yang dicabut tampil sebagai “offline” paling lama sekitar 22 detik kemudian. Kamu bisa mengubahnya dengan baris seperti mqtt.setKeepAlive(30), tapi makin panjang nilainya, makin terlambat kamu menyadari koneksi yang putus.
Alternatif tanpa kode: ESPHome
ESPHome adalah alat gratis yang mengubah perangkat yang kamu deskripsikan di file YAML menjadi firmware ESP32 yang siap di-flash; kamu tidak menulis satu baris C++ pun. Di Home Assistant, instal ESPHome Device Builder dari Settings > Apps, buka antarmukanya, lalu buat konfigurasi dengan wizard New device. Upload pertama dilakukan sekali lewat USB: Chrome atau Edge bisa langsung memprogram board, dan kalau itu tidak berhasil, kamu bisa mem-flash file yang diunduh wizard dengan halaman ESPHome Web. Semua pembaruan berikutnya lewat Wi-Fi (OTA). Konfigurasi di bawah sama dengan proyek Arduino di atas: membaca DHT22 di GPIO 4 setiap 30 detik dan menampilkan relay aktif LOW di GPIO 26 sebagai switch. Data Wi-Fi dan kata sandi dibaca dari file secrets.yaml terpisah dengan !secret:
1esphome:
2 name: salon-sensor # küçük harf, rakam ve tire / lowercase, digits and hyphens
3 friendly_name: Salon Sensör
4
5esp32:
6 board: esp32dev
7
8logger:
9
10api: # Home Assistant ile doğrudan bağlantı / direct link to Home Assistant
11 encryption:
12 key: !secret api_anahtari
13
14ota:
15 - platform: esphome
16 password: !secret ota_sifresi
17
18wifi:
19 ssid: !secret wifi_ssid
20 password: !secret wifi_sifresi
21 ap: # Wi-Fi yoksa kendi ağını açar / opens its own network if Wi-Fi fails
22 ssid: "Salon-Sensor"
23 password: "yedek1234"
24
25captive_portal:
26
27sensor:
28 - platform: dht
29 pin: GPIO4
30 model: DHT22
31 update_interval: 30s
32 temperature:
33 name: "Sıcaklık"
34 humidity:
35 name: "Nem"
36
37switch:
38 - platform: gpio
39 name: "Röle"
40 pin:
41 number: GPIO26
42 inverted: true # aktif LOW röle / active-LOW relay
43 restore_mode: ALWAYS_OFF # açılışta kapalı / off at boot
44
45# MQTT ile kullanmak için api: bloğunu sil, bunu aç / to use MQTT, delete api: and uncomment this
46# mqtt:
47# broker: 192.168.1.10
48# username: esp32
49# password: !secret mqtt_sifresiAda satu perbedaan yang perlu diingat: secara bawaan ESPHome tidak memakai MQTT, melainkan native API terenkripsinya sendiri. Home Assistant menemukan perangkat itu di jaringan dengan sendirinya dan sama sekali tidak butuh broker. Pilih MQTT hanya kalau kamu ingin sistem lain seperti Node-RED membaca data yang sama, atau kalau kamu tidak memakai Home Assistant. Untuk itu, hapus tanda komentar di baris mqtt: di akhir file dan hapus blok api:; kalau tidak, perangkat akan me-reboot dirinya sendiri setiap kali tidak ada yang terhubung ke native API selama 15 menit (itulah pengaturan reboot_timeout). Dalam mode MQTT, ESPHome mengirim pesan discovery Home Assistant dan pesan online/offline di salon-sensor/status sendiri, jadi semua yang kita kerjakan manual di kode Arduino dilakukannya secara otomatis.
| Fitur | PubSubClient (kode Arduino) | ESPHome (YAML) |
|---|---|---|
| Menulis kode | Kamu menulis semuanya dalam C++ | Hanya YAML; firmware dikompilasi otomatis |
| Menambahkan ke Home Assistant | Kamu mengirim JSON discovery sendiri | Ditemukan otomatis |
| Fleksibilitas | Tanpa batas; library dan logika apa pun bisa dipakai | Terbatas pada komponen siap pakai, tapi ratusan sensor didukung; C++ bisa ditambahkan dengan lambda |
| Pembaruan lewat udara (OTA) | Kamu menambahkan ArduinoOTA ke kode sendiri | Sudah bawaan |
| Butuh broker | Ya | Tidak, dengan native API |
| Nilai belajar | Mengajarkan protokol MQTT dan pemrograman | Hasil cepat, menyembunyikan apa yang terjadi di baliknya |
MQTT dengan ESP8266 dan Raspberry Pi Pico W
Kode lengkap di atas berjalan tanpa perubahan di board ESP8266 NodeMCU dan Wemos D1 Mini: ketika kamu memilih NodeMCU 1.0 di Tools > Board, blok #if defined(ESP8266) otomatis memilih ESP8266WiFi.h alih-alih WiFi.h, beserta pin D2 dan D1. Di sisi Raspberry Pi Pico W kita memakai modul umqtt.simple dari MicroPython. Modul ini tidak termasuk dalam firmware MicroPython Pico W; instal di Thonny dengan mencari umqtt.simple di Tools > Manage packages, atau ketik import mip; mip.install("umqtt.simple") di REPL ketika sudah terhubung ke Wi-Fi. Sebaliknya, modul dht yang dibutuhkan untuk DHT22 sudah ikut di firmware. Kode di bawah membuat Pico W di dapur mengerjakan tugas pengukuran dan relay yang sama. Agar ringkas, pesan discovery kami tinggalkan; untuk melihat Pico W di Home Assistant, publish JSON discovery yang sama seperti di kode ESP32 dengan topic ev/mutfak (mutfak = “dapur”), atau definisikan entity secara manual di bawah mqtt: di configuration.yaml. Simpan file sebagai main.py dan kode akan berjalan setiap kali board dinyalakan:
1import network, time, dht
2from machine import Pin
3from umqtt.simple import MQTTClient # önce mip ile kur / install with mip first
4
5WIFI_SSID = "AgAdi" # Wi-Fi adın / your Wi-Fi name
6WIFI_PASS = "Sifre123" # Wi-Fi şifren / your Wi-Fi password
7MQTT_SUNUCU = "192.168.1.10" # broker IP / broker IP
8ISTEMCI_ID = "pico-mutfak" # benzersiz olmalı / must be unique
9
10T_SICAKLIK = b"ev/mutfak/sicaklik"
11T_NEM = b"ev/mutfak/nem"
12T_KOMUT = b"ev/mutfak/role/komut"
13T_DURUM = b"ev/mutfak/role/durum"
14T_BAGLANTI = b"ev/mutfak/baglanti"
15
16sensor = dht.DHT22(Pin(15)) # DHT22 DATA -> GP15
17role = Pin(14, Pin.OUT, value=1) # aktif LOW röle kapalı başlar / active-LOW relay starts off
18led = Pin("LED", Pin.OUT) # Pico W dahili LED / Pico W onboard LED
19
20wlan = network.WLAN(network.STA_IF)
21wlan.active(True)
22wlan.connect(WIFI_SSID, WIFI_PASS)
23while not wlan.isconnected():
24 time.sleep(0.5)
25print("IP:", wlan.ifconfig()[0])
26
27def mesaj_geldi(konu, mesaj): # ikisi de bytes gelir / both arrive as bytes
28 if konu == T_KOMUT and mesaj in (b"ON", b"OFF"):
29 acik = mesaj == b"ON"
30 role.value(0 if acik else 1)
31 led.value(1 if acik else 0)
32 istemci.publish(T_DURUM, mesaj, retain=True)
33
34istemci = MQTTClient(ISTEMCI_ID, MQTT_SUNUCU, user="esp32", password="mqttSifre", keepalive=60) # Mosquitto kullanıcısı / Mosquitto user
35istemci.set_callback(mesaj_geldi)
36istemci.set_last_will(T_BAGLANTI, b"offline", retain=True) # son vasiyet / last will
37
38def baglan():
39 while True:
40 try:
41 if not wlan.isconnected(): # Wi-Fi koptuysa yeniden bağlan / reconnect Wi-Fi if it dropped
42 wlan.connect(WIFI_SSID, WIFI_PASS)
43 time.sleep(5)
44 istemci.connect()
45 istemci.publish(T_BAGLANTI, b"online", retain=True)
46 istemci.publish(T_DURUM, b"OFF" if role.value() else b"ON", retain=True)
47 istemci.subscribe(T_KOMUT)
48 print("MQTT baglandi")
49 return
50 except Exception as e: # MQTTException(5): yetki yok / not authorized
51 print("MQTT hatasi:", e)
52 time.sleep(5)
53
54baglan()
55son = time.ticks_add(time.ticks_ms(), -30000) # ilk ölçüm hemen / first reading right away
56while True:
57 try:
58 istemci.check_msg() # bekleyen komut var mı? / any pending command?
59 if time.ticks_diff(time.ticks_ms(), son) >= 30000:
60 son = time.ticks_ms()
61 try:
62 sensor.measure()
63 except OSError:
64 print("DHT22 okunamadi")
65 istemci.ping() # veri yoksa da bağlantıyı canlı tut / keep the link alive without data
66 else:
67 istemci.publish(T_SICAKLIK, "{:.1f}".format(sensor.temperature()).encode(), retain=True)
68 istemci.publish(T_NEM, "{:.0f}".format(sensor.humidity()).encode(), retain=True)
69 except OSError:
70 print("Baglanti koptu, yeniden baglaniliyor")
71 time.sleep(5)
72 baglan()
73 time.sleep_ms(100)Ide proyek MQTT ESP32
- Peta suhu per ruangan: Pasang ESP32 dengan DHT22 atau BME280 di setiap ruangan dan pantau seluruh rumah dalam satu grafik dengan subscription ev/+/sicaklik.
- Lampu dan stopkontak pintar: Hubungkan relay ke otomatisasi Home Assistant yang menyalakannya ketika matahari terbenam dan mematikannya tengah malam.
- Sensor pintu dan jendela: Pakai reed switch untuk mengirim pesan MQTT ketika pintu terbuka dan terima notifikasi di ponsel ketika tidak ada orang di rumah.
- Lampu lorong yang menyala karena gerakan: Biarkan sensor PIR mem-publish gerakan dan otomatisasi Home Assistant menyalakan lampunya.
- Stasiun penyiram tanaman: Publish nilai sensor kelembapan tanah dan jalankan pompa dengan perintah MQTT ketika tanahnya kering.
- Pemantauan energi: Ukur arus yang ditarik sebuah alat dengan sensor arus ACS712 dan buat grafik konsumsi hariannya.
- Sensor bertenaga baterai: Buat node yang mengambil pembacaan, mengirimnya lewat MQTT, lalu tidur lagi; detailnya di Deep Sleep ESP32.
Error MQTT ESP32 yang umum dan solusinya
| Gejala atau pesan | Penyebab | Solusi |
|---|---|---|
| rc=-2 terus-menerus | IP atau port broker salah, broker tidak berjalan, atau Mosquitto dalam mode local-only | Cek IP, tambahkan listener 1883 ke konfigurasi, izinkan port 1883 di firewall |
| rc=5 | Nama pengguna atau kata sandi salah, atau upaya terhubung tanpa kredensial | Uji kata sandi dari komputermu dengan mosquitto_sub; buat ulang penggunanya kalau perlu |
| Terhubung, putus setelah beberapa detik, terus berulang | Dua perangkat memakai client ID yang sama; Mosquitto mencatat “Client esp32-salon already connected, closing old connection.” | Beri setiap perangkat ISTEMCI_ID yang unik |
| Pesan discovery tidak sampai, publish() mengembalikan false | Buffer PubSubClient secara bawaan 256 byte dan JSON-nya tidak muat | Panggil mqtt.setBufferSize(1024) di setup() |
| rc=-3 sering muncul | delay() yang panjang di dalam loop() menghentikan paket keep-alive, atau sinyal Wi-Fi lemah | Atur waktu dengan millis() dan dekatkan board ke router |
| Perintah tidak pernah sampai ke ESP32 | Nama topic berbeda huruf besar-kecil atau ejaannya, atau subscribe() tidak diulang setelah terhubung lagi | Cek topic dengan mosquitto_sub; taruh baris subscribe() di dalam fungsi koneksi |
| Relay menyala sendiri ketika mulai | Ada pesan retained lama yang tertinggal di topic perintah | Hapus dengan mosquitto_pub -r -n -t ev/salon/role/komut |
| Entity menampilkan “Unavailable” di Home Assistant | Topic availability berisi offline, atau online ditulis dengan ejaan berbeda | Pantau ev/salon/baglanti dan pastikan kode mem-publish online setelah terhubung |
| Karakter sampah alih-alih nilai | Payload tidak diakhiri \0 dan dibaca tanpa memakai length | Salin payload dalam perulangan sampai length |
| Perangkat ESPHome reboot setiap 15 menit | Dalam mode MQTT, blok api: masih ada tapi Home Assistant tidak pernah terhubung | Hapus blok api: atau tambahkan reboot_timeout: 0s |
Dengan sebuah broker, beberapa topic, dan PubSubClient, ESP32-mu sudah menjadi perangkat rumah pintar yang berbicara dengan bahasa yang sama seperti seisi rumah. Kamu bisa menambahkan sensor baru, ruangan lain, dan board berbeda seperti Pico W ke susunan yang sama, lalu mengelola semuanya dari satu dasbor Home Assistant. Di aplikasi BlueGrays kamu akan menemukan proyek seperti koneksi Wi-Fi ESP32, pengukuran suhu dan kelembapan DHT22, lampu pintar dengan PIR dan relay, kendali real-time dengan WebSocket, dan penyiraman tanaman pintar, langkah demi langkah dengan skema rangkaian dan kode.
Pertanyaan umum
MQTT dipakai untuk apa?
MQTT adalah protokol pesan ringan di mana perangkat mengirim dan menerima pesan lewat broker dengan memakai nama topic. Karena hemat bandwidth dan daya, MQTT ideal bagi perangkat kecil seperti ESP32 untuk mengirim data sensor dan menerima perintah. Home Assistant, Node-RED, dan sebagian besar sistem IoT industri memakai MQTT.
MQTT memakai port berapa?
MQTT tanpa enkripsi secara bawaan memakai port 1883, dan MQTT terenkripsi TLS memakai port 8883. Port WebSocket yang dipakai untuk koneksi browser tergantung broker-nya; di broker Mosquitto di Home Assistant, port-nya 1884. Di jaringan rumah, ESP32 biasanya terhubung ke 1883.
Apakah MQTT butuh koneksi internet?
Tidak. Kalau broker berjalan di Raspberry Pi atau di Home Assistant di rumah, lalu lintas antara ESP32 dan broker sepenuhnya tetap di jaringan lokalmu; sensor dan relay tetap bekerja meskipun internet mati. Kamu hanya butuh internet untuk mengakses sistem dari luar atau untuk memakai broker cloud.
Kenapa ESP32-ku tidak muncul di Home Assistant?
Penyebab yang paling umum adalah pesan discovery yang tidak muat di buffer 256 byte PubSubClient, topic config yang salah ketik, atau kesalahan tanda kutip di JSON. Dengarkan homeassistant/# dengan mosquitto_sub untuk mengecek apakah pesannya sampai ke broker, dan pastikan kode berisi baris mqtt.setBufferSize(1024). Integrasi MQTT di Home Assistant juga harus terhubung ke broker yang sama.
Sebaiknya pakai ESPHome atau MQTT dengan Arduino?
Kalau tujuanmu cepat punya perangkat rumah pintar yang berfungsi, ESPHome lebih sedikit usahanya: kamu menulis YAML, perangkat muncul sendiri di Home Assistant dan diperbarui lewat udara. Kalau kamu ingin mempelajari protokol MQTT, menulis logikamu sendiri, atau bekerja dengan sistem selain Home Assistant, Arduino dengan PubSubClient lebih fleksibel. Keduanya bisa hidup berdampingan dengan nyaman di rumah yang sama.
Apa bedanya QoS 0, 1, dan 2 di MQTT?
QoS 0 mengirim pesan sekali tanpa menunggu konfirmasi, QoS 1 mengirimnya ulang sampai dikonfirmasi tapi pesan bisa sampai dua kali, dan QoS 2 memakai jabat tangan empat langkah untuk menjamin pesan sampai tepat sekali. QoS 0 cukup untuk pembacaan sensor dan QoS 1 untuk perintah. PubSubClient hanya bisa publish dengan QoS 0 dan subscribe dengan QoS 0 atau 1.
Proyek untuk dibuat setelah membaca ini
Lihat semua proyek
LED Berkedip dengan ESP32
Mengajarkan penggunaan output GPIO dasar dengan ESP32. Kita membuat efek berkedip dengan menyalakan dan mematikan LED dari pin digital. Versi ESP32 dari proyek blink klasik di Arduino UNO; perintah blink dasar di lingkungan Arduino sama, tetapi susunan pin ESP32 dan level GPIO 3,3 V-nya berbeda dengan Arduino UNO.

Koneksi Wi-Fi STA ESP32 (dengan Layar LCD)
Di proyek ini, kita menyambungkan ESP32 ke jaringan Wi-Fi rumah dalam mode Station (STA) dengan cara yang aman dan tahan gangguan. Kita menyimpan SSID dan kata sandi di file secrets.h terpisah agar tidak bocor ke Git, menyiapkan mekanisme sambung ulang otomatis, dan menampilkan tingkat sinyal RSSI dan alamat IP di layar LCD I2C. LED bawaan bekerja sebagai indikator status. Ini adalah pengelola koneksi kelas produksi.

Suhu dan Kelembapan DHT22 ESP32 (dengan Layar LCD)
Proyek ini mengukur suhu dan kelembapan sekitar dengan sensor DHT22 dan menampilkan datanya secara real-time di LCD I2C 16x2. Data dibaca dari sensor dengan protokol satu kabel lewat library Adafruit DHT. Proyek ini menjadi dasar untuk stasiun cuaca IoT, otomasi rumah pintar, atau sistem pemantauan lingkungan di rumah kaca. Komunikasi dengan DHT22 dilakukan lewat pin GPIO 4 ESP32.

Lampu Pintar ESP32 (PIR + LDR + Relay + OLED)
Ubah lorong, kamar mandi, atau gudangmu menjadi lampu pintar dengan ESP32! Dengan sensor gerak PIR, sensor cahaya LDR, dan modul relay, kita membuat skenario klasik "lampu menyala ketika ada gerakan dalam gelap"; jika sudah terang, gerakan TIDAK menyalakan lampu, jadi energi hemat di siang hari. Lampu menyala 30 detik; jika gerakan berlanjut, timer diulang. OLED SSD1306 menampilkan status dengan font besar (NYALA / SIANG / MENUNGGU) dan hitung mundur.

Penghitung WebSocket ESP32 (2 Tombol + LCD + Web Real-Time)
Di proyek ini, dua tombol yang tersambung ke ESP32 (GPIO 5 menghitung naik, GPIO 4 menghitung turun) mengubah sebuah penghitung. Nilainya langsung diperbarui di LCD I2C 16x2 sekaligus, lewat dukungan WebSocket ESPAsyncWebServer, di setiap browser yang tersambung tanpa memuat ulang halaman. Alih-alih polling HTTP, dipakai satu koneksi yang tetap terbuka, dan ESP32 mengirim nilai baru ke semua orang dengan ws.textAll().

mDNS ESP32: Mengakses Perangkat lewat bluegrays-esp.local (dengan Layar LCD)
Di proyek ini, kita menambahkan layanan mDNS (Multicast DNS) ke ESP32, sehingga perangkat bisa diakses dengan nama host seperti bluegrays-esp.local, bukan alamat IP. Meskipun IP dari DHCP berubah, perangkat selalu bisa dijangkau dengan nama yang sama. Web server kecil di perangkat menerima perintah kendali LED dari browser lewat alamat http://bluegrays-esp.local/. Layar LCD I2C menampilkan nama host, alamat IP, dan status LED.

Sistem Alarm Gerakan ESP32 (PIR + Buzzer + LED + Telegram)
Sistem alarm keamanan pintar yang menyalakan buzzer dan LED ketika sensor PIR mendeteksi gerakan, sekaligus mengirim notifikasi instan ke pemilik lewat Telegram. Cooldown 30 detik membatasi seberapa sering alarm berulang; mekanisme ini tidak memvalidasi deteksi PIR atau menghilangkan pemicu palsu. Cocok untuk rumah, garasi, gudang, atau ruang kerja. Dengan ESP32-CAM bisa ditambahkan notifikasi berfoto; dengan ESP32 DevKit V1 klasik, notifikasinya berupa teks.
Artikel lainnya
Aplikasi BlueGrays
Rakit rangkaian ini langkah demi langkah di ponselmu
Skema pengkabelan, kode, dan daftar komponen dalam satu layar. 200+ proyek Arduino, ESP32, dan Pico siap dibuat.
Pindai dengan ponselmu
Arahkan kamera ke kode ini dan toko aplikasi di ponselmu akan terbuka.
atau buka toko aplikasi

