Ethernet Shield takılı bir Arduino Uno veya Mega, bir sensörü ya da röleyi MQTT'ye bağlamanın hâlâ en güvenilir yollarından biridir: kopan Wi-Fi yok, radyo paraziti yok; bir pano içinde ya da bodrumda sorunsuz çalışan kablolu bir bağlantı var. Standart yığın, WIZnet çipi için Ethernet kütüphanesi ile MQTT için PubSubClient'tır.
Bu eğitim bir W5100 veya W5500 shield'ı broker'a bağlıyor, bir sensör değeri yayınlıyor ve komut kabul ediyor; çekilen kablolara ve broker yeniden başlatmalarına dayanan bir yeniden bağlanma döngüsüyle. Ardından her şeyi tarayıcıdan uçtan uca doğruluyorsunuz.
Donanım ve kütüphaneler
| Parça | Notlar |
|---|---|
| Arduino Uno R3 veya Mega 2560 | Uno: 2 KB RAM, Mega: 8 KB RAM |
| Ethernet Shield W5100 veya Ethernet Shield 2 (W5500) | SPI ile konuşur, chip select 10 numaralı pinde |
| DHCP'li bir router'a ağ kablosu | Ya da LAN'ınızda statik bir IP |
Library Manager'dan iki kütüphane kurun: Ethernet (Arduino'nun; W5100, W5200 ve W5500'ü destekler) ve PubSubClient (Nick O'Leary'nin). Çoğu shield'da chip select'i 4 numaralı pin olan bir microSD yuvası da bulunur; kart kullanmıyorsanız SPI hattını bozmaması için pin 4'ü HIGH yapın.
Sketch'in tamamı
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
// Ağınızdaki her kart için benzersiz bir MAC kullanın
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x10, 0x01 };
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* CLIENT_ID = "arduino-eth-0001";
const char* MQTT_USER = "username";
const char* MQTT_PASS = "password";
const char* T_STATUS = "testmqtt/arduino-eth/0001/status";
const char* T_TEMP = "testmqtt/arduino-eth/0001/temp";
const char* T_CMD = "testmqtt/arduino-eth/0001/cmd/led";
EthernetClient ethClient;
PubSubClient mqtt(ethClient);
unsigned long lastReconnect = 0;
unsigned long lastPublish = 0;
void onMessage(char* topic, byte* payload, unsigned int length) {
Serial.print(F("<- "));
Serial.print(topic);
Serial.print(F(" = "));
Serial.write(payload, length);
Serial.println();
if (strcmp(topic, T_CMD) == 0 && length > 0) {
digitalWrite(LED_BUILTIN, payload[0] == '1' ? HIGH : LOW);
}
}
bool connectMqtt() {
Serial.print(F("MQTT connecting... "));
// id, user, pass, willTopic, willQos, willRetain, willMessage
if (mqtt.connect(CLIENT_ID, MQTT_USER, MQTT_PASS, T_STATUS, 1, true, "offline")) {
Serial.println(F("connected"));
mqtt.publish(T_STATUS, "online", true);
mqtt.subscribe(T_CMD, 1);
return true;
}
Serial.print(F("failed, rc="));
Serial.println(mqtt.state());
return false;
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(4, OUTPUT);
digitalWrite(4, HIGH); // SD kartı devre dışı bırak
Serial.begin(9600);
Ethernet.init(10); // W5100/W5500 chip select
Serial.println(F("DHCP..."));
if (Ethernet.begin(mac) == 0) {
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println(F("No Ethernet shield found"));
} else {
Serial.println(F("DHCP failed - check the cable or use a static IP"));
}
while (true) delay(1000);
}
Serial.print(F("IP: "));
Serial.println(Ethernet.localIP());
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(onMessage);
mqtt.setKeepAlive(30);
}
void loop() {
if (!mqtt.connected()) {
unsigned long now = millis();
if (now - lastReconnect > 5000) { // bloklamadan 5 sn'de bir tekrar dene
lastReconnect = now;
connectMqtt();
}
} else {
mqtt.loop();
}
if (mqtt.connected() && millis() - lastPublish > 10000) {
lastPublish = millis();
char buf[8];
int raw = analogRead(A0);
itoa(raw, buf, 10);
mqtt.publish(T_TEMP, buf);
}
Ethernet.maintain(); // DHCP kirasını yenile
}Bu sketch'teki bazı tercihler göründüğünden daha önemlidir:
F("...")string'leri sabit metni RAM yerine flash'ta tutar. Uno'da bir düzine debug string'i aksi hâlde belleğin dörtte birini yiyebilir.- Yeniden bağlanma bloklamaz.
loop()denemeler arasında çalışmaya devam eder; böylece broker erişilemezken yerel mantık (butonlar, röleler, watchdog) donmaz. mqtt.loop()sık çalışmalıdır. Gelen paketleri okur ve keep alive PINGREQ'ini gönderir. Kodunuzdaki uzun birdelay(), broker'ın bağlantıyı 1,5 × keep alive sonra kesmesine yol açar.- Bir Last Will ve retained bir
onlineher dashboard'a güvenilir bir çevrimiçi/çevrimdışı göstergesi verir. Bkz. MQTT Last Will.
DHCP yerine statik IP
Endüstriyel ağlarda çoğu zaman DHCP yoktur. Adresi, DNS sunucusunu, gateway'i ve alt ağ maskesini açıkça verin; DNS olmadan broker.connectmq.com hostname'i çözümlenemez:
IPAddress ip(192, 168, 1, 50);
IPAddress dns(192, 168, 1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
Ethernet.begin(mac, ip, dns, gateway, subnet);DNS yoksa mqtt.setServer() bir IPAddress de kabul eder; ancak bu durumda broker IP'sinin değişmesi tüm cihazları bozar. Ağ izin verdiği sürece hostname tercih edin.
Uçtan uca test
- Seri Monitörü 9600 baud ile açın. Bir IP adresi, ardından
MQTT connecting... connectedgörmelisiniz. - Online MQTT istemcisini açın, güvenli WebSocket ile
broker.connectmq.comadresine bağlanın (port 8084, path/mqtt) vetestmqtt/arduino-eth/0001/#topic'ine subscribe olun. - Retained
status = onlinehemen gelir, ardından her on saniyede birtempdeğeri. testmqtt/arduino-eth/0001/cmd/ledtopic'ine1yayınlayın. Karttaki LED yanar ve Seri Monitör mesajı yazdırır. Söndürmek için0yayınlayın.- Ağ kablosunu çekin. Yaklaşık 45 saniye sonra broker will mesajını gönderir ve durum
offlineolur. Kabloyu geri takın: sketch birkaç saniye içinde yeniden bağlanır ve tekraronlineyayınlar.
Arduino'yu online istemcide izleyin
Terminalden test etmeyi tercih ederseniz mosquitto_pub ve mosquitto_sub aynı işi görür: mosquitto_sub -h broker.connectmq.com -t 'testmqtt/arduino-eth/#' -v.
mqtt.state() değerini okuma
connect() başarısız olduğunda state() nedenini söyler. PubSubClient'ın tanımladığı kodlar şunlardır:
| Kod | Sabit | Anlamı |
|---|---|---|
| -4 | MQTT_CONNECTION_TIMEOUT | Keep alive süresi içinde yanıt yok |
| -3 | MQTT_CONNECTION_LOST | Ağ bağlantısı koptu |
| -2 | MQTT_CONNECT_FAILED | TCP bağlantısı başarısız (DNS, IP, port, firewall) |
| -1 | MQTT_DISCONNECTED | Düzgün şekilde bağlantı kesildi |
| 1 | MQTT_CONNECT_BAD_PROTOCOL | Broker protokol sürümünü reddetti |
| 2 | MQTT_CONNECT_BAD_CLIENT_ID | Client ID reddedildi |
| 3 | MQTT_CONNECT_UNAVAILABLE | Broker kullanılamıyor |
| 4 | MQTT_CONNECT_BAD_CREDENTIALS | Kullanıcı adı veya şifre yanlış |
| 5 | MQTT_CONNECT_UNAUTHORIZED | Yetkisiz |
failed, rc=-2 açık ara en yaygın olanıdır: shield broker'a TCP üzerinden hiç ulaşamamıştır. Ethernet.localIP() değerinin 0.0.0.0 olmadığını, DNS sunucusunun erişilebilir olduğunu ve giden 1883 portuna izin verildiğini kontrol edin. PubSubClient sorun giderme rehberi her kodu ayrıntılı ele alıyor.
Bellek ve paket boyutu sınırları
PubSubClient gelen ve giden paketler için tek bir buffer ayırır. Varsayılan boyutu 256 bayttır ve buna sabit başlık, topic ve payload dahildir. Buffer'dan büyük bir paket alınırken sessizce atılır, gönderirken de publish() false döndürür.
mqtt.setBufferSize(512); // setup() içinde, connect() öncesinde bir kez çağırınUno'da buffer'ı makul, topic'leri kısa tutun. Bir paketin tam boyutunu paket boyutu hesaplayıcı ile bulabilirsiniz. Mega'da 1–2 KB buffer'lar gerçekçidir. Büyük bir payload hâlâ başarısız oluyorsa paket çok büyük rehberi broker tarafındaki sınırları da anlatıyor.
Hesaba katmanız gereken diğer sınırlar:
- Yalnızca QoS 0 publish. PubSubClient QoS 0 ile publish eder, QoS 0 veya 1 ile subscribe olur. Teslimat önemliyse retained bir durum topic'i veya uygulama seviyesinde bir onay kullanın.
- Yalnızca MQTT 3.1.1. Reason code ve MQTT 5 property'leri yok.
- Socket sayısı. W5100'de 4, W5500'de 8 socket vardır. DHCP ve DNS kısa süreliğine birini kullanır; aynı zamanda web sunucusu da çalıştıran bir sketch'te socket'ler tükenebilir.
Uno'nun ötesine ne zaman geçmeli
Uno + Ethernet kombinasyonu basit, kablolu, yerel cihazlar için mükemmeldir. TLS, daha büyük JSON payload'ları veya MQTT 5 özellikleri gerekiyorsa aynı PubSubClient kodu W5500'lü bir ESP32'ye ya da Wi-Fi kartlarına neredeyse hiç değişmeden taşınır: bkz. Arduino ve MQTT ile ESP32. AVR üzerinde QoS 1 ile publish etmek istiyorsanız arduino-mqtt kütüphanesine göz atmaya değer.
MQTT'deki kablolu bir Arduino büyük ölçüde disiplin meselesidir: benzersiz MAC ve client ID'ler, F() string'leri, bloklamayan bir yeniden bağlanma ve asla takılmayan bir döngü. Seri log'un connected demesini sağlayın, publish'i, komutları ve Last Will'i online istemciden kanıtlayın; kart yıllarca dokunulmadan çalışacaktır.
Sıkça sorulan sorular
Arduino Uno TLS üzerinden MQTT kullanabilir mi?
Pratikte hayır. ATmega328P'de 2 KB RAM var; bu bir TLS handshake için çok az ve W5100/W5500 çipleri TLS'i kendileri yapmaz. Güvenilir bir ağda şifresiz MQTT kullanın, TLS ile ileten yerel bir gateway koyun ya da ESP32 veya daha fazla belleği olan bir karta geçin.
PubSubClient neden uzun mesajlarımı almıyor?
PubSubClient, buffer'ından büyük her paketi atar; varsayılan buffer topic ve başlıklar dahil 256 bayttır. setBufferSize() ile daha büyük bir değer verin; ancak Uno'da her baytın 2 KB RAM'den gittiğini unutmayın.
PubSubClient QoS 1 ile publish yapabilir mi?
Hayır. PubSubClient yalnızca QoS 0 ile publish eder ve MQTT 3.1.1'i destekler. QoS 0 veya 1 ile subscribe olabilir. QoS 1 publish gerekiyorsa uygulama seviyesinde bir onay ekleyin veya başka bir kütüphane kullanın.

