ESP32 MQTT Rehberi: Mosquitto, Home Assistant ve ESPHome
ESP32 MQTT rehberi: Mosquitto kurulumu, PubSubClient ile sensör yayınlama ve röle kontrolü, Home Assistant keşfi, ESPHome YAML örneği, QoS ve sık hatalar.
ESP32 MQTT ikilisi, evdeki sensörlerin ve rölelerin birbirleriyle ve Home Assistant gibi bir akıllı ev sistemiyle konuşmasının en yaygın yoludur. MQTT, küçük cihazlar için tasarlanmış hafif bir mesajlaşma protokolüdür: ESP32 ölçtüğü sıcaklığı "ev/salon/sicaklik" gibi bir konuya (topic) bırakır, o konuyu dinleyen her program değeri anında alır. Aynı yoldan, telefondaki Home Assistant uygulamasında bir düğmeye bastığında giden "ON" komutu saniyenin altında ESP32'ye ulaşır ve röleyi çeker. HTTP'deki gibi her istek için yeni bağlantı kurulmaz; tek bir açık bağlantı üzerinden, en az iki baytlık başlıklarla çalıştığı için hem hızlıdır hem de Wi-Fi'ı ve işlemciyi yormaz.
Bu rehberde sıfırdan çalışan bir akıllı ev düğümü kuracaksın. Önce MQTT'nin broker, topic, publish ve subscribe kavramlarını öğrenecek, ardından Home Assistant'ta ya da bir Raspberry Pi'de Mosquitto broker'ını kuracaksın. Sonra PubSubClient kütüphanesiyle ESP32'den DHT22 sıcaklık ve nem değerlerini yayınlayacak, röle komutlarını dinleyecek ve cihazın Home Assistant'ta kendiliğinden görünmesini sağlayan MQTT Discovery'yi ekleyeceksin. QoS ve retain ayarlarını, bağlantı koptuğunda cihazı "kullanılamıyor" gösteren son vasiyet (LWT) mesajını, hiç C++ yazmadan aynı işi yapan ESPHome alternatifini, ESP8266 ve Raspberry Pi Pico W farklarını ve en sık karşılaşılan hataları da tek tek ele alacağız.

MQTT nedir, nasıl çalışır?
MQTT (Message Queuing Telemetry Transport), yayınla-abone ol (publish/subscribe) modeliyle çalışır. Ortada broker adı verilen bir sunucu bulunur; ESP32, Home Assistant, telefonun ya da bilgisayarındaki bir program bu sunucuya istemci olarak bağlanır. İstemciler birbirini tanımaz, IP adreslerini bilmez: biri bir konuya mesaj yayınlar, broker bu mesajı o konuya abone olan herkese iletir. Bunu bir postane gibi düşünebilirsin: ESP32 mektubu "ev/salon/sicaklik" adresli kutuya atar, o kutuyu takip eden Home Assistant mektubu anında alır. Bağlantıyı her zaman istemci başlattığı için ESP32'nin sabit IP'ye ya da modemde açılmış bir porta ihtiyacı yoktur; tek bilmesi gereken broker'ın adresidir.
| Kavram | Ne işe yarar? | Örnek |
|---|---|---|
| Broker | Mesajları alan ve abonelere dağıtan sunucu | Mosquitto, Home Assistant'taki Mosquitto broker |
| İstemci (client) | Broker'a bağlanan her cihaz ya da program; benzersiz bir kimliği (client ID) olur | ESP32, Home Assistant, MQTT Explorer |
| Topic (konu) | Mesajın adresi; eğik çizgiyle ayrılmış seviyelerden oluşur | ev/salon/sicaklik |
| Publish (yayınla) | Bir konuya mesaj göndermek | "23.4" değerini ev/salon/sicaklik konusuna yollamak |
| Subscribe (abone ol) | Bir konudaki mesajları almak için kaydolmak | ESP32'nin ev/salon/role/komut konusunu dinlemesi |
| Payload (yük) | Mesajın içeriği; metin, sayı ya da JSON olabilir | ON, 23.4, {"sicaklik":23.4} |
| Retain | Broker'ın konudaki son mesajı saklayıp yeni abonelere hemen vermesi | Röle durumu: ON |
| LWT (son vasiyet) | İstemci habersizce koparsa broker'ın onun adına yayınladığı mesaj | ev/salon/baglanti: offline |
| QoS | Mesajın teslim garantisi seviyesi (0, 1 ya da 2) | Röle komutları için QoS 1 |
Neden MQTT? Web sunucusu, Blynk ve Telegram ile karşılaştırma
| Yöntem | Artısı | Eksisi | En uygun olduğu iş |
|---|---|---|---|
| MQTT + Home Assistant | Yerel ve hızlı, çift yönlü; yüzlerce cihaz tek panelde, otomasyon kurulabilir | Bir broker kurmak gerekir | Bütün evi tek merkezden yönetmek |
| ESP32 web sunucusu | Ek sunucu gerekmez, tarayıcıdan açılır | Her cihazın ayrı sayfası olur, cihazlar arası otomasyon yoktur | Tek cihazlık kontrol paneli |
| Blynk IoT | Hazır telefon paneli, internetten erişim | Buluta bağımlı, ücretsiz planda sınırlar var | Hızlı mobil prototip |
| Telegram botu | Ücretsiz anlık bildirim, port açmak gerekmez | Grafik ve panel yoktur | Alarm ve basit komutlar |
| ESP-NOW | Modem ve broker olmadan ESP'ler arasında haberleşme | Yalnız ESP kartları arasında, Home Assistant'a doğrudan ulaşmaz | Pille çalışan sensörden ağ geçidine veri taşımak |
Kısacası MQTT, cihaz sayısı arttıkça parlayan yöntemdir: yeni bir sensör eklediğinde mevcut kodların hiçbirine dokunmazsın, sadece yeni bir konu yayınlamaya başlarsın. Tek bir cihazı tarayıcıdan yönetmek istiyorsan ESP32 Async Web Server ve WebSocket, telefona bildirim istiyorsan ESP32 Telegram Bot, hazır bir mobil panel istiyorsan Blynk ESP32 rehberleri daha kısa yoldan sonuç verir. Modemin ulaşamadığı bir bahçe sensörü içinse ESP-NOW ile veriyi MQTT'ye bağlı bir ağ geçidi ESP32'ye taşımak iyi bir çözümdür.
MQTT topic yapısı ve joker karakterler
Topic'ler bir klasör yoluna benzer: "ev/salon/sicaklik" üç seviyeden oluşur ve büyük-küçük harfe duyarlıdır, yani "Ev/Salon" ile "ev/salon" iki ayrı konudur. Başa eğik çizgi koyma ("/ev/salon" boş bir ilk seviye üretir), boşluk ve Türkçe karakter kullanma; İngilizce harfler, rakamlar, tire ve alt çizgi yeterlidir. Abone olurken iki joker karakter kullanabilirsin: + tek bir seviyenin yerini tutar ("ev/+/sicaklik" bütün odaların sıcaklığını getirir), # ise kendisinden sonraki her şeyi kapsar ve yalnızca en sonda yazılır ("ev/#" evdeki bütün mesajları getirir). Jokerler yalnızca abone olurken geçerlidir; bir mesaj her zaman tam bir konuya yayınlanır. $ ile başlayan konular ($SYS gibi) broker'ın kendi istatistiklerine ayrılmıştır ve # aboneliğine dahil edilmez. Bu rehberdeki proje için şu düzeni kullanacağız:
| Topic | Yayınlayan | Dinleyen | Retain |
|---|---|---|---|
| ev/salon/sicaklik | ESP32 (30 saniyede bir) | Home Assistant | Evet |
| ev/salon/nem | ESP32 (30 saniyede bir) | Home Assistant | Evet |
| ev/salon/role/komut | Home Assistant, telefon, otomasyonlar | ESP32 | Hayır |
| ev/salon/role/durum | ESP32 (her değişimde) | Home Assistant | Evet |
| ev/salon/baglanti | ESP32 (online), broker (offline) | Home Assistant | Evet |
| homeassistant/status | Home Assistant (açılışta online) | ESP32 | Hayır |
MQTT broker kurulumu: Mosquitto
En yaygın ve ücretsiz MQTT broker'ı Eclipse Mosquitto'dur; bir Raspberry Pi'de bile saniyede yüzlerce mesajı rahatça taşır. Kurmanın üç kolay yolu var: Home Assistant OS kullanıyorsan resmi Mosquitto broker uygulaması, ayrı bir Raspberry Pi ya da Linux bilgisayar kullanıyorsan apt paketi, Windows'ta ise Mosquitto'nun kurulum dosyası. Hangisini seçersen seç, broker şifresiz MQTT için 1883, TLS ile şifrelenmiş MQTT için 8883 portunu kullanır ve ESP32 ile aynı ev ağında olması yeterlidir. Home Assistant'ta kurulum şöyle:
- Home Assistant'ta Ayarlar > Uygulamalar bölümünü aç (eski sürümlerde bu bölümün adı Eklentiler / Add-ons'tur), Uygulama yükle düğmesine bas ve listeden Mosquitto broker'ı seç.
- Yükle düğmesine bas; kurulum bitince Başlat'a bas ve açılışta başlatma seçeneğini açık bırak.
- ESP32 için ayrı bir kullanıcı aç: Ayarlar > Kişiler > Kullanıcılar bölümünden "esp32" adında bir kullanıcı ve güçlü bir şifre oluştur. Bu sekmeyi göremiyorsan profil sayfanda Gelişmiş modu aç. "homeassistant" ve "addons" adları broker için ayrılmıştır, bunları kullanma.
- Ayarlar > Cihazlar ve hizmetler sayfasında MQTT entegrasyonu genellikle "Bulundu" olarak kendiliğinden çıkar; Yapılandır'a basıp onayla. Çıkmazsa Entegrasyon ekle düğmesiyle MQTT'yi arat ve Mosquitto'yu otomatik yapılandırma seçeneğini kullan.
- ESP32 kodunda broker adresi olarak Home Assistant'ın IP adresini (örneğin 192.168.1.10), port olarak 1883'ü ve az önce açtığın kullanıcıyı yazacaksın.
Raspberry Pi ya da Ubuntu gibi bir Linux makinede kurulum birkaç komuttur. sudo apt install mosquitto mosquitto-clients ile broker'ı ve test araçlarını kur. sudo mosquitto_passwd -c /etc/mosquitto/passwd esp32 komutuyla "esp32" kullanıcısını oluştur ve şifreyi iki kez gir; -c parametresi dosyayı sıfırdan yaratır, bu yüzden ikinci kullanıcıyı eklerken -c yazma, yoksa önceki kullanıcılar silinir. Sonra /etc/mosquitto/conf.d/ klasöründe yerel.conf adında bir dosya oluşturup aşağıdaki üç satırı yaz ve sudo systemctl restart mosquitto ile servisi yeniden başlat. Windows'ta aynı satırları Mosquitto'nun kurulum klasöründeki mosquitto.conf dosyasına ekleyip Mosquitto Broker servisini yeniden başlatman yeterlidir.
| Satır | Anlamı |
|---|---|
| listener 1883 | Bütün ağ arayüzlerinde 1883 portunu dinler; bu satır olmadan Mosquitto 2.x yalnızca aynı bilgisayardan gelen bağlantıları kabul eder |
| allow_anonymous false | Kullanıcı adı ve şifresi olmayan bağlantıları reddeder; 2.x sürümlerinde zaten varsayılandır ama açıkça yazmak iyi bir alışkanlıktır |
| password_file /etc/mosquitto/passwd | mosquitto_passwd ile oluşturduğun şifre dosyasını kullanır; şifreler dosyada özetlenmiş (hash) olarak saklanır |
ESP32'ye geçmeden önce broker'ı bilgisayarından test et; sorunun kodda mı broker'da mı olduğunu baştan ayırmak sana çok zaman kazandırır. Bir terminalde mosquitto_sub -h 192.168.1.10 -u esp32 -P sifren -t "ev/#" -v komutuyla evdeki bütün konuları dinlemeye başla. İkinci bir terminalde mosquitto_pub -h 192.168.1.10 -u esp32 -P sifren -t ev/salon/test -m merhaba yaz. İlk terminalde "ev/salon/test merhaba" satırı görünüyorsa broker çalışıyor ve şifre doğru demektir. -v parametresi her mesajın önüne konusunu yazar, -r parametresi ise mesajı retain olarak gönderir.
Gerekli malzemeler ve bağlantı şeması
Proje için bir ESP32 geliştirme kartı, bir DHT22 sıcaklık ve nem sensörü, 3,3 V ile tetiklenebilen bir röle modülü, breadboard ve jumper kablolar yeterli. DHT22, DHT11'e göre daha hassastır: sıcaklığı ±0,5 °C, nemi yaklaşık ±%2–5 doğrulukla ölçer ve -40 ile 80 °C arasında çalışır; sensör ailesini DHT11 Sıcaklık ve Nem Sensörü yazısında ayrıntılı anlattık. Elinde DHT11 varsa koddaki DHT22 yazan yeri DHT11 yapman yeterli. İlk bağlantı testi için yalnızca ESP32 ve bir USB kablosu yeter; sensörü ve röleyi sonra ekleyebilirsin.



| Bağlantı | 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 |
| Röle VCC | VIN (5V) | VIN (5V) | VBUS (5V) |
| Röle IN | GPIO 26 | D1 (GPIO 5) | GP14 |
| Röle GND | GND | GND | GND |
Arduino IDE'de PubSubClient kurulumu
- Arduino IDE'de ESP32 kart paketi kurulu değilse önce onu kur; adımlar ESP32 Nedir? yazısında.
- Araçlar > Kütüphaneleri Yönet menüsünü aç, arama kutusuna PubSubClient yaz ve yazarı Nick O'Leary olan kütüphaneyi kur. Bu rehberdeki kodlar 2.8 sürümüyle derlendi.
- Aynı pencerede DHT sensor library ara ve Adafruit'in kütüphanesini kur; bağımlılıkları sorduğunda Install all seçerek Adafruit Unified Sensor'ı da kur.
- Kütüphane kurarken sorun yaşarsan Arduino Kütüphane Ekleme rehberine göz at.
İlk test: ESP32'yi MQTT broker'a bağlamak
Sensörlere geçmeden önce Wi-Fi, broker adresi ve şifrenin doğru olduğunu en basit kodla doğrulayalım. Aşağıdaki kod broker'a bağlanır, "test/esp32/durum" konusuna "merhaba" yayınlar ve "test/esp32/komut" konusuna gelen her mesajı Seri Monitör'e yazar. Wi-Fi adını, şifreni, broker IP'sini ve MQTT kullanıcısını kendi bilgilerinle değiştir, kodu yükle ve Seri Monitör'ü 115200 baud hızında aç:
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}Seri Monitör'de "baglandi" yazısını gördükten sonra bilgisayarındaki terminalden mosquitto_pub -h 192.168.1.10 -u esp32 -P sifren -t test/esp32/komut -m selam gönder; birkaç milisaniye içinde Seri Monitör'de "Mesaj [test/esp32/komut] selam" satırı belirir. Bağlantı başarısız olursa kod mqtt.state() ile bir hata kodu yazar ve 5 saniye sonra yeniden dener. Bu kodlar sorunun nerede olduğunu doğrudan söyler:
| rc | PubSubClient adı | Anlamı ve çözümü |
|---|---|---|
| -4 | MQTT_CONNECTION_TIMEOUT | Broker zamanında yanıt vermedi; ağ zayıf ya da broker aşırı yüklü |
| -3 | MQTT_CONNECTION_LOST | Kurulu bağlantı koptu; çoğunlukla loop() uzun süre çağrılmadığı ya da Wi-Fi gittiği için |
| -2 | MQTT_CONNECT_FAILED | TCP bağlantısı hiç kurulamadı: IP ya da port yanlış, broker kapalı, Mosquitto yalnız yerel modda ya da güvenlik duvarı 1883'ü engelliyor |
| -1 | MQTT_DISCONNECTED | Bağlantı düzgün şekilde kapatıldı (disconnect çağrıldı) ya da henüz hiç bağlanılmadı |
| 2 | MQTT_CONNECT_BAD_CLIENT_ID | İstemci kimliği reddedildi; boş ya da geçersiz bir client ID kullanılmış |
| 4 | MQTT_CONNECT_BAD_CREDENTIALS | Kullanıcı adı ya da şifre hatalı (bazı broker'lar bu kodu döndürür) |
| 5 | MQTT_CONNECT_UNAUTHORIZED | Yetki yok; Mosquitto hem yanlış şifrede hem de şifresiz bağlanmaya çalışıldığında bu kodu döndürür |
ESP32 ile sensör verisi yayınlama ve röle komutu dinleme
Şimdi asıl projeyi kuruyoruz. Aşağıdaki kod 30 saniyede bir DHT22'yi okuyup sıcaklığı ve nemi retain bayrağıyla yayınlar, "ev/salon/role/komut" konusuna gelen ON, OFF ve TOGGLE komutlarıyla röleyi yönetir ve rölenin yeni durumunu "ev/salon/role/durum" konusuna bildirir. Bağlanırken broker'a bir son vasiyet bırakır, Home Assistant'a kendini MQTT Discovery ile tanıtır ve bağlantı koptuğunda loop()'u kilitlemeden 5 saniyede bir yeniden bağlanmayı dener. Kodun başındaki #if defined(ESP8266) bloğu sayesinde aynı kod hiçbir değişiklik yapmadan NodeMCU'da da derlenir.
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}| Satır | Görevi |
|---|---|
| mqtt.connect(ISTEMCI_ID, ..., T_BAGLANTI, 1, true, "offline") | Bağlanırken son vasiyeti de bildirir: ESP32 habersizce koparsa broker ev/salon/baglanti konusuna kalıcı olarak "offline" yazar |
| mqtt.publish(T_BAGLANTI, "online", true) | Bağlanır bağlanmaz durumu "online" yapar; Home Assistant cihazı yeniden kullanılabilir gösterir |
| mqtt.subscribe(T_KOMUT, 1) | Röle komutlarını QoS 1 ile dinler; PubSubClient abonelikte yalnızca QoS 0 ve 1'i destekler |
| mqtt.setBufferSize(1024) | Paket tamponunu varsayılan 256 bayttan büyütür; en büyük keşif paketi yaklaşık 355 bayttır |
| mqtt.loop() | Gelen mesajları okur ve keep-alive (PINGREQ) paketlerini gönderir; her loop turunda çağrılmalıdır |
| ROLE_AKTIF_LOW | Çoğu röle modülü LOW sinyalle çeker; modülün HIGH ile çekiyorsa false yap |
| OLCUM_ARALIGI | Ölçüm sıklığı; DHT22 en fazla 2 saniyede bir okunabilir, oda sıcaklığı için 30–60 saniye idealdir |
Koddaki birkaç ayrıntı bilerek seçildi. mesajGeldi() fonksiyonu konu ve payload'ı ilk iş olarak String'e kopyalar, çünkü PubSubClient gelen ve giden mesajlar için tek bir tampon kullanır: geri çağırma içinde publish() yaptığın anda topic ve payload işaretçilerinin gösterdiği veri silinir. Payload'ın sonunda C dizilerindeki gibi \0 karakteri de yoktur; bu yüzden length değeri kadar karakter okuyoruz. Ölçümlerde ve röle durumunda retain kullanıyoruz ki Home Assistant yeniden başladığında son değeri 30 saniye beklemeden görsün. Zamanlama da millis() ile yapılıyor: loop() içinde uzun bir delay() olsaydı keep-alive paketleri gecikir, broker bağlantıyı düşürürdü. Bu tekniği Arduino millis() ve delay() Farkı yazısında ayrıntılı anlattık.
Home Assistant'ta görünüm: MQTT Discovery
Home Assistant, homeassistant/ önekiyle başlayan konuları sürekli dinler. Bir cihaz homeassistant/[tür]/[düğüm]/[nesne]/config biçimindeki bir konuya JSON yapılandırması yayınladığında Home Assistant o varlığı kendiliğinden oluşturur; buna MQTT Discovery denir. Bizim kodumuz üç mesaj gönderir: iki sensör (sıcaklık ve nem) için homeassistant/sensor/esp32-salon/... ve röle için homeassistant/switch/esp32-salon/role/config. Mesajlar retain'li olduğu için Home Assistant yeniden başladığında bile kaybolmaz. Ayrıca kod homeassistant/status konusuna abonedir: Home Assistant açıldığında buraya "online" yazar ve ESP32 tanıtımı yeniler. Home Assistant'ın belgeleri, çok sayıda cihaz varsa bu yeniden tanıtımın küçük rastgele bir gecikmeyle yapılmasını önerir.
| JSON alanı | Anlamı | Bizim değerimiz |
|---|---|---|
| name | Varlığın görünen adı; başına cihaz adı eklenir | Sıcaklık (Salon ESP32 Sıcaklık olarak görünür) |
| unique_id | Varlığın değişmeyen kimliği; olmazsa varlığın adı ve odası arayüzden düzenlenemez | esp32-salon_sicaklik |
| state_topic | Değerin okunacağı konu | ev/salon/sicaklik |
| command_topic | Anahtar (switch) komutlarının gönderileceği konu | ev/salon/role/komut |
| device_class | Simgeyi, birim seçeneklerini ve grafik türünü belirler | temperature, humidity |
| unit_of_measurement | Ölçü birimi | °C ve % |
| state_class | measurement değeri uzun dönem istatistik ve grafik tutulmasını sağlar | measurement |
| availability_topic | online/offline durumunun okunacağı konu; varsayılan yükler online ve offline'dır | ev/salon/baglanti |
| device | Varlıkları tek bir cihaz kartında toplar | identifiers, name, model |
Kodu yükledikten birkaç saniye sonra Ayarlar > Cihazlar ve hizmetler > MQTT sayfasında "Salon ESP32" adlı bir cihaz belirir. Cihaz kartında sıcaklık ve nem sensörleri ile bir röle anahtarı bulunur; sıcaklığa tıkladığında geçmiş grafiği açılır, anahtara bastığında röle çeker. Bu varlıkları panoya (dashboard) ekleyebilir, sesli asistanlara açabilir ya da otomasyonlarda kullanabilirsin: örneğin "salon sıcaklığı 27 °C'yi geçerse vantilatörün bağlı olduğu röleyi aç, 25 °C'nin altına inince kapat" kuralı birkaç tıklamayla kurulur. ESP32'nin fişini çektiğinde en geç 22 saniye kadar sonra varlıklar "Kullanılamıyor" durumuna geçer; bu, son vasiyet mesajının çalıştığını gösterir. Discovery kullanmak istemezsen aynı varlıkları configuration.yaml dosyasında mqtt: başlığı altına sensor ve switch olarak elle de tanımlayabilirsin.
QoS ve retain: hangisi ne zaman kullanılır?
QoS (Quality of Service), bir mesajın karşı tarafa ulaştığından ne kadar emin olmak istediğini belirler. Önemli bir ayrıntı: QoS iki ayrı yolda ayrı ayrı uygulanır. Yayınlayan ile broker arasında yayınlayanın seçtiği QoS, broker ile abone arasında ise aboneliğin QoS'u geçerlidir; abonenin aldığı mesajın garantisi bu ikisinden düşük olanıdır. PubSubClient yayınlarda yalnızca QoS 0'ı, aboneliklerde QoS 0 ve 1'i destekler. Ev içi Wi-Fi'da QoS 0 ile kaybolan mesaj çok nadirdir; yine de komutlar için aboneliği QoS 1 yapmak ucuz bir sigortadır.
| QoS | Garanti | Nasıl çalışır? | Ne zaman kullanılır? |
|---|---|---|---|
| 0 | En fazla bir kez | Mesaj tek sefer gönderilir, onay beklenmez; bağlantı o an koparsa kaybolabilir | Sık gelen sensör ölçümleri |
| 1 | En az bir kez | Alıcı PUBACK ile onaylar, onay gelmezse mesaj yeniden gönderilir; aynı mesaj iki kez gelebilir | Röle komutları, alarmlar |
| 2 | Tam olarak bir kez | PUBREC, PUBREL ve PUBCOMP ile dört adımlı el sıkışma; en yavaş seviye | Tekrarın zararlı olduğu sayaç gibi işler; PubSubClient desteklemez |
Retain bayrağı ise teslimle değil hafızayla ilgilidir: broker her konunun yalnızca son retain'li mesajını saklar ve o konuya yeni abone olan herkese hemen gönderir. Sensör değerleri, röle durumu ve çevrimiçi bilgisi gibi "şu anki durum" mesajları için idealdir; komutlar ve tek seferlik olaylar için ise tehlikelidir. Son vasiyet (LWT) bunun tamamlayıcısıdır: broker, istemciden keep-alive süresinin 1,5 katı boyunca hiçbir paket gelmezse bağlantının koptuğuna karar verir ve vasiyet mesajını yayınlar. PubSubClient'ın varsayılan keep-alive süresi 15 saniyedir, yani fişi çekilen bir ESP32 en geç yaklaşık 22 saniye sonra "offline" görünür. Bu süreyi mqtt.setKeepAlive(30) gibi bir satırla değiştirebilirsin, ama uzattıkça kopmayı daha geç fark edersin.
ESPHome ile kodsuz alternatif
ESPHome, YAML dosyasıyla tarif ettiğin cihazı ESP32 için hazır bir yazılıma dönüştüren ücretsiz bir araçtır; tek satır C++ yazmazsın. Home Assistant'ta Ayarlar > Uygulamalar bölümünden ESPHome Device Builder'ı kur, arayüzünü aç ve Yeni cihaz sihirbazıyla bir yapılandırma oluştur. İlk yükleme bir kez USB kablosuyla yapılır: Chrome ya da Edge tarayıcısı kartı doğrudan programlayabilir, olmazsa sihirbazın indirdiği dosyayı ESPHome Web sayfasıyla yükleyebilirsin. Sonraki bütün güncellemeler Wi-Fi üzerinden kablosuz (OTA) gider. Aşağıdaki yapılandırma, yukarıdaki Arduino projesinin aynısıdır: GPIO 4'teki DHT22'yi 30 saniyede bir okur ve GPIO 26'daki aktif LOW röleyi bir anahtar olarak sunar. Wi-Fi ve şifre bilgileri !secret ile ayrı secrets.yaml dosyasından okunur:
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_sifresiDikkat etmen gereken bir fark var: ESPHome varsayılan olarak MQTT değil, kendi şifreli native API'sini kullanır. Home Assistant cihazı ağda kendiliğinden bulur ve broker'a hiç ihtiyaç duymaz. MQTT'yi ancak Node-RED gibi başka sistemlerin de aynı veriyi okumasını istiyorsan ya da Home Assistant kullanmıyorsan seçmelisin. Bunun için dosyanın sonundaki mqtt: satırlarını aç ve api: bloğunu sil; silmezsen cihaz 15 dakika boyunca native API'ye kimse bağlanmadığında kendini yeniden başlatır (bu süre reboot_timeout ayarıdır). MQTT modunda ESPHome, Home Assistant keşif mesajlarını ve salon-sensor/status konusundaki online/offline mesajlarını kendisi gönderir; yani bizim Arduino kodunda elle yaptığımız her şeyi otomatik yapar.
| Özellik | PubSubClient (Arduino kodu) | ESPHome (YAML) |
|---|---|---|
| Kod yazma | Her şeyi C++ ile sen yazarsın | Yalnızca YAML; yazılım otomatik derlenir |
| Home Assistant'a ekleme | Keşif JSON'larını sen gönderirsin | Kendiliğinden bulunur |
| Esneklik | Sınırsız; her kütüphane ve mantık kullanılabilir | Hazır bileşenlerle sınırlı ama yüzlerce sensör destekli; gerekirse lambda ile C++ eklenir |
| Kablosuz güncelleme | ArduinoOTA'yı koda sen eklersin | Hazır gelir |
| Broker gereksinimi | Gerekli | Native API ile gerekmez |
| Öğrenme değeri | MQTT protokolünü ve programlamayı öğretir | Hızlı sonuç verir, arka planı gizler |
ESP8266 ve Raspberry Pi Pico W ile MQTT
Yukarıdaki tam kod ESP8266 NodeMCU ve Wemos D1 Mini kartlarında olduğu gibi çalışır: Araçlar > Kart menüsünden NodeMCU 1.0 seçtiğinde #if defined(ESP8266) bloğu WiFi.h yerine ESP8266WiFi.h dosyasını ve D2, D1 pinlerini kendiliğinden seçer. Raspberry Pi Pico W tarafında ise MicroPython'un umqtt.simple modülünü kullanırız. Bu modül Pico W'nun MicroPython yazılımında hazır gelmez; Thonny'de Araçlar > Paketleri Yönet menüsünden umqtt.simple aratarak ya da Wi-Fi'ya bağlıyken komut satırında import mip; mip.install("umqtt.simple") yazarak kurabilirsin. DHT22 için gereken dht modülü ise yazılımla birlikte gelir. Aşağıdaki kod mutfağa koyduğun bir Pico W'nun aynı ölçüm ve röle işini yapmasını sağlar. Kod kısa kalsın diye keşif mesajlarını eklemedik; Pico W'yu Home Assistant'ta görmek için ESP32 kodundaki keşif JSON'larını ev/mutfak konularıyla yayınlayabilir ya da varlıkları configuration.yaml dosyasında mqtt: başlığı altında elle tanımlayabilirsin. Dosyayı main.py adıyla kaydedersen kart her açıldığında çalışır:
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)ESP32 MQTT proje fikirleri
- Oda oda sıcaklık haritası: Her odaya bir ESP32 ile DHT22 ya da BME280 koy, ev/+/sicaklik aboneliğiyle bütün evi tek grafikte izle.
- Akıllı lamba ve priz: Röleyi Home Assistant otomasyonuna bağla; gün batımında yakıp gece yarısı söndür.
- Kapı ve pencere sensörü: Bir reed röle ile kapı açılınca MQTT'ye mesaj gönder, evde kimse yokken telefona bildirim al.
- Hareketle yanan koridor ışığı: PIR sensörü hareketi yayınlasın, ışığı Home Assistant otomasyonu yaksın.
- Bitki sulama istasyonu: Toprak nem sensörü değerini yayınla, nem düşünce pompayı MQTT komutuyla çalıştır.
- Enerji izleme: ACS712 akım sensörü ile bir cihazın çektiği akımı ölç ve günlük tüketimi grafikle.
- Pille çalışan sensör: Ölçüm yapıp MQTT'ye gönderen, sonra uykuya dalan bir düğüm kur; ayrıntılar ESP32 Deep Sleep yazısında.
ESP32 MQTT sık hataları ve çözümleri
| Belirti ya da mesaj | Sebep | Çözüm |
|---|---|---|
| Sürekli rc=-2 | Broker IP'si ya da portu yanlış, broker kapalı ya da Mosquitto yalnız yerel modda | IP'yi kontrol et, yapılandırmaya listener 1883 ekle, güvenlik duvarında 1883 portuna izin ver |
| rc=5 | Kullanıcı adı ya da şifre yanlış, ya da şifresiz bağlanılmaya çalışılıyor | Şifreyi mosquitto_sub ile bilgisayardan dene; gerekirse kullanıcıyı yeniden oluştur |
| Bağlanıyor, birkaç saniyede kopuyor, döngü sürüyor | İki cihaz aynı client ID'yi kullanıyor; Mosquitto günlüğe "Client esp32-salon already connected, closing old connection." yazar | Her cihaza benzersiz bir ISTEMCI_ID ver |
| Keşif mesajları gitmiyor, publish() false döndürüyor | PubSubClient tamponu varsayılan 256 bayt, JSON sığmıyor | setup() içinde mqtt.setBufferSize(1024) çağır |
| Sık sık rc=-3 | loop() içinde uzun delay() var, keep-alive gönderilemiyor ya da Wi-Fi sinyali zayıf | Zamanlamayı millis() ile yap, kartı modeme yaklaştır |
| Komutlar ESP32'ye ulaşmıyor | Konu adında harf farkı var ya da subscribe() yeniden bağlanınca tekrarlanmıyor | Konuyu mosquitto_sub ile doğrula; subscribe() satırlarını bağlanma fonksiyonunun içine koy |
| Röle açılışta kendiliğinden açılıyor | Komut konusunda retain'li eski bir mesaj duruyor | mosquitto_pub -r -n -t ev/salon/role/komut ile retain mesajını sil |
| Home Assistant'ta varlıklar "Kullanılamıyor" | availability konusunda offline var ya da online yazımı farklı | ev/salon/baglanti konusunu dinle; kodun bağlanınca online yayınladığından emin ol |
| Değer yerine anlamsız karakterler | Payload \0 ile bitmez, length kullanılmadan okunmuş | Payload'ı length kadar döngüyle kopyala |
| ESPHome cihazı 15 dakikada bir yeniden başlıyor | MQTT modunda api: bloğu duruyor ama Home Assistant bağlanmıyor | api: bloğunu sil ya da reboot_timeout: 0s ekle |
Bir broker, birkaç konu ve PubSubClient ile ESP32'n artık evin geri kalanıyla aynı dili konuşan bir akıllı ev cihazına dönüştü. Aynı yapıya yeni sensörler, başka odalar ve Pico W gibi farklı kartlar ekleyebilir, hepsini Home Assistant'tan tek panelde yönetebilirsin. BlueGrays uygulamasında ESP32 Wi-Fi bağlantısı, DHT22 ile sıcaklık ve nem ölçümü, PIR ve röleli akıllı aydınlatma, WebSocket ile gerçek zamanlı kontrol ve akıllı bitki sulama gibi projeleri devre şemaları ve kodlarıyla adım adım bulabilirsin.
Sıkça sorulan sorular
MQTT nedir, ne işe yarar?
MQTT, cihazların bir broker üzerinden konu (topic) adlarıyla mesaj alıp verdiği hafif bir mesajlaşma protokolüdür. Az bant genişliği ve az enerji harcadığı için ESP32 gibi küçük cihazların sensör verisini göndermesi ve komut alması için idealdir. Home Assistant, Node-RED ve endüstriyel IoT sistemlerinin çoğu MQTT konuşur.
MQTT hangi portu kullanır?
Şifresiz MQTT varsayılan olarak 1883, TLS ile şifrelenmiş MQTT ise 8883 portunu kullanır. Tarayıcıdan bağlanmak için kullanılan WebSocket portu broker'a göre değişir; Home Assistant'taki Mosquitto broker'da bu port 1884'tür. ESP32 ev ağında genellikle 1883'e bağlanır.
MQTT için internet gerekir mi?
Hayır. Broker evdeki bir Raspberry Pi'de ya da Home Assistant'ta çalışıyorsa ESP32 ile broker arasındaki trafik tamamen yerel ağda kalır; internet kesilse bile sensörler ve röleler çalışmaya devam eder. İnternet yalnızca evin dışından erişmek ya da bulut tabanlı bir broker kullanmak istediğinde gerekir.
ESP32 neden Home Assistant'ta görünmüyor?
En sık sebepler keşif mesajının 256 baytlık PubSubClient tamponuna sığmaması, config konusunun yanlış yazılması ya da JSON'da bir tırnak hatasıdır. mosquitto_sub ile homeassistant/# konusunu dinleyerek mesajın broker'a gelip gelmediğini kontrol et ve kodda mqtt.setBufferSize(1024) satırının bulunduğundan emin ol. Home Assistant'taki MQTT entegrasyonunun aynı broker'a bağlı olması da gerekir.
ESPHome mu, Arduino ile MQTT mi kullanmalıyım?
Amacın çalışan bir akıllı ev cihazını hızlıca kurmaksa ESPHome daha az uğraştırır: YAML yazarsın, cihaz Home Assistant'ta kendiliğinden belirir ve kablosuz güncellenir. MQTT protokolünü öğrenmek, kendi mantığını yazmak ya da Home Assistant dışındaki sistemlerle çalışmak istiyorsan Arduino ve PubSubClient daha esnektir. İkisi aynı evde sorunsuz bir arada kullanılabilir.
MQTT QoS 0, 1 ve 2 arasındaki fark nedir?
QoS 0 mesajı bir kez gönderir ve onay beklemez, QoS 1 onay gelene kadar tekrar gönderir ama mesaj iki kez ulaşabilir, QoS 2 ise dört adımlı el sıkışmayla mesajın tam olarak bir kez ulaşmasını garanti eder. Sensör ölçümleri için QoS 0, komutlar için QoS 1 yeterlidir. PubSubClient yalnızca QoS 0 ile yayın yapabilir ve QoS 0 ya da 1 ile abone olabilir.
Bu yazıdan sonra yapabileceğin projeler
Tüm projeleri gör
ESP32 ile LED Yakma
ESP32 ile temel GPIO çıkışı kullanımını öğretir. Bir LED'i dijital pinden açıp kapatarak yanıp sönme efekti elde ederiz. Arduino UNO'daki klasik blink projesinin ESP32 versiyonu; Arduino ortamındaki temel blink komutları aynıdır, ancak ESP32'nin pin yerleşimi ve 3,3 V GPIO seviyeleri Arduino UNO'dan farklıdır.

ESP32 Wi-Fi STA Bağlantısı (LCD Ekranlı)
Bu projede ESP32'yi Station (STA) modunda evdeki Wi-Fi ağına güvenli ve hata toleranslı şekilde bağlıyoruz. SSID/şifreyi secrets.h dosyasına ayırarak Git'e sızmasını önlüyor, otomatik yeniden bağlanma mekanizması kuruyor, RSSI sinyal seviyesini ve IP adresini I2C LCD ekranda gösteriyoruz. Dahili LED durum göstergesi olarak çalışır. Üretim seviyesi bir bağlantı yöneticisidir.

ESP32 DHT22 Sıcaklık ve Nem (LCD Ekranlı)
DHT22 sensörü ile ortam sıcaklığını ve nem oranını ölçüp 16x2 I2C LCD ekranda gerçek zamanlı olarak gösteren bir projedir. Adafruit DHT kütüphanesi kullanılarak tek kablo (one-wire) protokolü ile sensörden veri okunur. Bu proje, IoT hava istasyonu, akıllı ev otomasyonu veya seralarda ortam takip sistemlerinin temelini oluşturur. ESP32'nin GPIO 4 pini üzerinden DHT22 ile haberleşme sağlanır.

ESP32 Akıllı Aydınlatma (PIR + LDR + Röle + OLED)
ESP32, PIR hareket sensörü, LDR ışık sensörü ve röle modülü ile evinin koridorunu, tuvaletini veya kilerini akıllı aydınlatmaya dönüştürüyoruz. Klasik "karanlıkta hareket algılanınca ışık yansın" senaryosunu inşa ediyoruz — ortam aydınlıksa hareket olsa bile ışık yanmaz, böylece gündüz gereksiz yere yanmaz ve enerji tasarrufu sağlanır. Işık 30 saniye yanık kalır; hareket devam ederse timer otomatik sıfırlanır ve süre uzar. SSD1306 OLED ekranda büyük fontlarla durum (AÇIK / GÜNDÜZ / BEKLE), geri

ESP32 WebSocket Sayaç (2 Buton + LCD + Web Realtime)
Bu projede ESP32'ye bağlı iki butonla (GPIO 5 artırır, GPIO 4 azaltır) bir sayaç değiştirilir. Değer hem 16x2 I2C LCD'de hem de ESPAsyncWebServer'ın WebSocket desteğiyle bağlı tüm tarayıcılarda anında güncellenir; sayfayı yenilemek gerekmez. HTTP polling yerine tek bir kalıcı bağlantı kullanılır ve ESP32 yeni değeri ws.textAll() ile herkese gönderir.

ESP32 mDNS: bluegrays-esp.local ile Cihaza Erişim (LCD Ekranlı)
Bu projede ESP32'ye mDNS (Multicast DNS) servisi ekleyerek IP adresi yerine bluegrays-esp.local gibi okunabilir bir host adıyla erişim sağlıyoruz. DHCP'nin verdiği IP değişse bile cihaza her zaman aynı isimle ulaşabilirsiniz. Üzerinde küçük bir web server da çalıştırarak tarayıcıdan http://bluegrays-esp.local/ adresiyle LED kontrolü gönderiyoruz. I2C LCD ekranda hostname, IP ve LED durumu hem Türkçe hem İngilizce gösterilir. iOS, macOS ve Linux mDNS'i doğal olarak destekler; Windows'ta Bonjo

ESP32 Hareket Alarm Sistemi (PIR + Buzzer + LED + Telegram)
PIR sensörü hareket algıladığında buzzer ve LED'i aktif eden, aynı anda Telegram üzerinden sahibine anlık bildirim gönderen akıllı bir güvenlik alarm sistemidir. Tekrarlayan alarmların sıklığını sınırlamak için 30 saniyelik cooldown (bekleme süresi) mekanizması vardır; bu mekanizma PIR sensörünün yanlış algılamalarını doğrulamaz veya ortadan kaldırmaz. Ev güvenliği, garaj izleme, depo veya çalışma odası gibi alanlarda kullanılabilir. Telegram entegrasyonu sayesinde nerede olursanız olun anında h
Diğer yazılar
BlueGrays uygulaması
Bu devreyi telefonunda adım adım kur
Devre şeması, kod ve parça listesi tek ekranda. 200'den fazla Arduino, ESP32 ve Pico projesi seni bekliyor.
Telefonunla tara
Kamerayı koda tut; telefonunun uygulama mağazası açılır.
ya da mağazada aç

