Bir ESP32 BME280 MQTT düğümü, tek bir küçük I2C çipiyle sıcaklık, nem ve barometrik basıncı ölçer ve bunları bir broker'a yayınlar. Bu eğitimde sensörü bağlayacak, düşük güçlü forced modda okuyacak, JSON'u broker.connectmq.com'a yayınlayacak ve yayın aralığını yeniden başlatmalardan sonra da kalıcı olan bir MQTT mesajıyla uzaktan değiştireceksiniz.
Neden BME280
Bosch BME280, DHT22'nin popüler bir üst basamağıdır. I2C ile haberleşir; bu yüzden kırılgan tek telli zamanlama yoktur, üç değerin hepsini milisaniyeler içinde okur ve basınç çıkışı hava eğilimlerini izlemenize veya rakımı tahmin etmenize olanak tanır. Ayrıca tek bir ölçüm alıp tekrar uykuya geçtiği, enerji tasarrufu sağlayan bir forced moda sahiptir; bu da kendi kendine ısınmayı azaltır.
Satın almadan önce bir uyarı: "BME280" etiketli birçok ucuz breakout kartında aslında nem sensörü olmayan bir BMP280 bulunur. İkisi aynı görünür. Aşağıdaki sketch çip kimliğini okur ve hangisine sahip olduğunuzu söyler.
Parçalar ve Kütüphaneler
- Bir ESP32 geliştirme kartı.
- Bir BME280 breakout kartı (3,3 V sürümü veya kart üzerinde regülatörü olan bir model).
- Dört jumper kablo.
- esp32 kart paketiyle Arduino IDE 2.x.
- Kütüphaneler: Adafruit BME280 Library, Adafruit Unified Sensor, Adafruit BusIO (bağımlılık olarak kurulur) ve PubSubClient.
Bağlantı
| BME280 pini | ESP32 pini (klasik) | Notlar |
|---|---|---|
| VIN veya VCC | 3V3 | Çıplak 3,3 V modüllerde 5 V kullanmayın |
| GND | GND | |
| SCL | GPIO 22 | Varsayılan I2C saat hattı |
| SDA | GPIO 21 | Varsayılan I2C veri hattı |
| SDO (varsa) | GND veya 3V3 | 0x76 veya 0x77 adresini seçer |
| CSB (varsa) | 3V3 | Çipi I2C modunda tutar |
ESP32-S3, C3 ve C6'da varsayılan I2C pinleri farklıdır. Sketch'te olduğu gibi Wire.begin(SDA, SCL) fonksiyonuna pinleri açıkça verin ve numaraları kartınıza göre ayarlayın.
Uzaktan Ayarlanabilir Aralıkla Topic Tasarımı
| Topic | Yön | Retained | Örnek payload |
|---|---|---|---|
connectmq/demo/bme5t8n/telemetry |
Cihaz yayınlar | Hayır | {"temperature":21.84,"humidity":46.2,"pressure":1013.6} |
connectmq/demo/bme5t8n/config/interval/set |
Siz yayınlarsınız | Evet | 30 |
connectmq/demo/bme5t8n/config/interval |
Cihaz yayınlar | Evet | 30 |
connectmq/demo/bme5t8n/status |
Cihaz yayınlar | Evet | online / offline |
Komut retained'dır; böylece siz gönderdiğinizde çevrimdışı olan bir cihaz da bir sonraki bağlantısında onu alır. Cihaz ardından gerçekte uyguladığı değeri ayrı bir retained topic'te bildirir. "İstenen" ve "bildirilen" değerleri farklı topic'lerde tutmak geri besleme döngülerini önler ve bir ayarın kabul edilip edilmediğini bir bakışta görmenizi sağlar. MQTT QoS seviyeleri rehberi, komut aboneliği için neden QoS 1 kullanıldığını açıklar.
ESP32 BME280 MQTT Sketch'i
#include <WiFi.h>
#include <Wire.h>
#include <PubSubClient.h>
#include <Preferences.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
const char* WIFI_SSID = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* PREFIX = "connectmq/demo/bme5t8n"; // kendi rastgele kimliğinizi kullanın
const int I2C_SDA = 21, I2C_SCL = 22;
const uint32_t MIN_INTERVAL_S = 5, MAX_INTERVAL_S = 3600;
Adafruit_BME280 bme;
WiFiClient net;
PubSubClient mqtt(net);
Preferences prefs;
String clientId;
String tTelemetry, tIntervalSet, tIntervalState, tStatus;
uint32_t intervalS = 60;
unsigned long lastPublish = 0;
bool hasHumidity = true;
void reportInterval() {
char buf[12];
snprintf(buf, sizeof(buf), "%lu", (unsigned long)intervalS);
mqtt.publish(tIntervalState.c_str(), buf, true);
}
void onMessage(char* topic, byte* payload, unsigned int len) {
if (tIntervalSet != topic) return;
char buf[12];
len = min(len, (unsigned int)sizeof(buf) - 1);
memcpy(buf, payload, len);
buf[len] = '\0';
long requested = atol(buf);
if (requested < (long)MIN_INTERVAL_S || requested > (long)MAX_INTERVAL_S) {
Serial.printf("Ignoring interval %s (allowed %lu-%lu)\n", buf,
(unsigned long)MIN_INTERVAL_S, (unsigned long)MAX_INTERVAL_S);
reportInterval(); // kullanılan değeri yeniden bildir
return;
}
if ((uint32_t)requested != intervalS) {
intervalS = requested;
prefs.putUInt("interval", intervalS);
Serial.printf("Interval set to %lu s\n", (unsigned long)intervalS);
}
reportInterval();
}
void connectWifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) delay(400);
Serial.printf("Wi-Fi OK, IP %s\n", WiFi.localIP().toString().c_str());
}
void connectMqtt() {
while (!mqtt.connected()) {
if (mqtt.connect(clientId.c_str(), tStatus.c_str(), 1, true, "offline")) {
mqtt.publish(tStatus.c_str(), "online", true);
mqtt.subscribe(tIntervalSet.c_str(), 1);
reportInterval();
Serial.println("MQTT connected");
} else {
Serial.printf("MQTT failed, state %d\n", mqtt.state());
delay(5000);
}
}
}
bool startSensor() {
Wire.begin(I2C_SDA, I2C_SCL);
if (!bme.begin(0x76, &Wire) && !bme.begin(0x77, &Wire)) return false;
uint8_t id = bme.sensorID();
hasHumidity = (id == 0x60);
Serial.printf("Sensor chip ID 0x%02X (%s)\n", id, hasHumidity ? "BME280" : "BMP280, no humidity");
// Forced mod: istek üzerine tek ölçüm, ardından uyku. Hava izleme için önerilir.
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // sıcaklık
Adafruit_BME280::SAMPLING_X1, // basınç
Adafruit_BME280::SAMPLING_X1, // nem
Adafruit_BME280::FILTER_OFF);
return true;
}
void setup() {
Serial.begin(115200);
prefs.begin("bme-node", false);
intervalS = prefs.getUInt("interval", 60);
if (!startSensor()) {
Serial.println("No BME280 found at 0x76 or 0x77. Check wiring.");
while (true) delay(1000);
}
clientId = "esp32-bme280-" + String((uint32_t)ESP.getEfuseMac(), HEX);
tTelemetry = String(PREFIX) + "/telemetry";
tIntervalSet = String(PREFIX) + "/config/interval/set";
tIntervalState = String(PREFIX) + "/config/interval";
tStatus = String(PREFIX) + "/status";
connectWifi();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(onMessage);
mqtt.setBufferSize(512);
connectMqtt();
lastPublish = millis() - intervalS * 1000UL; // hemen yayınla
}
void loop() {
if (WiFi.status() != WL_CONNECTED) connectWifi();
if (!mqtt.connected()) connectMqtt();
mqtt.loop();
if (millis() - lastPublish < intervalS * 1000UL) return;
lastPublish = millis();
if (!bme.takeForcedMeasurement()) {
Serial.println("Forced measurement failed");
return;
}
float t = bme.readTemperature(); // santigrat derece
float p = bme.readPressure() / 100.0f; // Pa -> hPa
float h = hasHumidity ? bme.readHumidity() : NAN;
char payload[200];
if (hasHumidity) {
snprintf(payload, sizeof(payload),
"{\"temperature\":%.2f,\"humidity\":%.1f,\"pressure\":%.1f,\"interval\":%lu}",
t, h, p, (unsigned long)intervalS);
} else {
snprintf(payload, sizeof(payload),
"{\"temperature\":%.2f,\"pressure\":%.1f,\"interval\":%lu}",
t, p, (unsigned long)intervalS);
}
mqtt.publish(tTelemetry.c_str(), payload);
Serial.println(payload);
}
ESP32 BME280 MQTT Ölçümlerini Test Etmek ve Aralığı Değiştirmek
Önekinizin altındaki her şeyi izleyin:
mosquitto_sub -h broker.connectmq.com -p 1883 -i bme-view-5t8n -t "connectmq/demo/bme5t8n/#" -v
Şimdi retained bir komutla aralığı 10 saniyeye değiştirin:
mosquitto_pub -h broker.connectmq.com -p 1883 -i bme-cmd-5t8n -q 1 -r \
-t "connectmq/demo/bme5t8n/config/interval/set" -m "10"
Kısa süre içinde config/interval 10 bildirir ve telemetri hızlanır. Kartı sıfırlayın: değeri flash'tan 10 olarak okur; flash silinmiş olsa bile retained komut bağlantı anında onu yeniden ayarlar. 2 gönderin; cihaz bunu reddeder ve mevcut değeri yeniden bildirir. Retained komutu daha sonra kaldırmak için aynı topic'e -r -n ile boş bir retained mesaj yayınlayın.
Broker'ın herkese açık alanı paylaşımlıdır; bu yüzden topic'inizi tahmin eden herkes komut topic'inize yayın yapabilir. Bu bir demo için kabul edilebilir, ancak production cihazlarının neden kimlik doğrulamalı kendi broker'larını kullanması gerektiğinin tam da nedenidir.
Ölçümleri Anlamak
- Basınç, istasyon seviyesinde hPa cinsinden bildirilir. Hava durumu servisleri deniz seviyesine indirgenmiş basıncı bildirir; bu yüzden yüksek rakımda sizin değeriniz daha düşük olur. Mutlak değerden çok eğilimler önemlidir: birkaç saat boyunca istikrarlı bir düşüş genellikle kötüleşen havanın habercisidir.
- Rakım,
bme.readAltitude(1013.25)ile tahmin edilebilir, ancak doğruluğu verdiğiniz deniz seviyesi basıncı kadardır ve hava durumuyla birlikte kayar. - Kendi kendine ısınma, düşük örnekleme hızlarında forced modda minimum düzeydedir. Oversampling ve kısa bekleme süresiyle normal modda ise çip ve yakındaki ESP32 ölçümü belirgin biçimde ısıtabilir.
Sorun Giderme
- "No BME280 found". Bir I2C tarayıcı sketch'i çalıştırın. Hiç cihaz bulunmaması bağlantı sorunu demektir; beklenmeyen bir adreste cihaz bulunması ise SDO pini ayarını gösterir.
- Nem her zaman 0 veya NaN. Elinizde bir BMP280 var. Çip kimliği çıktısı bunu doğrular.
- Basınç yaklaşık yüzde 10 sapmış. Pascal değerini 100'e bölmeyi unuttunuz veya deniz seviyesi basıncıyla karşılaştırıyorsunuz.
- Aralık komutu yok sayılıyor. Topic'in büyük-küçük harf dahil tam olarak eşleştiğini ve payload'ın düz bir sayı olduğunu kontrol edin.
- Kart Wi-Fi bağlantısı sırasında sıfırlanıyor. Zayıf bir USB beslemesi ESP32'de voltaj düşmesine yol açar. Daha iyi bir kablo veya güç kaynağı kullanın.
Production Kurulumu
Gerçek kurulumlar için app.connectmq.com adresinde bir broker oluşturun ve sketch'i ISRG Root X1 sertifikasıyla 8883 portunda WiFiClientSecure kullanacak şekilde değiştirip YOUR_CLIENT_ID, YOUR_USERNAME ve YOUR_PASSWORD ile bağlanın. Böylece yalnızca sizin kimlik bilgilerinize sahip istemciler aralık komutları gönderebilir. Wi-Fi kimlik bilgilerini kodda saklamak bir sonraki zayıf noktadır; WiFiManager kurulum rehberi bunları bunun yerine bir captive portal üzerinden nasıl gireceğinizi gösterir. Sensörleri karşılaştırıyorsanız ESP32 DHT22 eğitimi daha ucuz tek telli seçeneği ele alır.
Hava Verilerini Saklamak ve Grafiğe Dökmek
Broker mesajları iletir; bir veritabanı değildir. Hava geçmişi için her ölçümü kalıcı bir yere yazan bir subscriber'a ihtiyacınız vardır. Bu payload ile üç yaygın desen iyi çalışır:
- MQTT consumer girdisiyle Telegraf,
.../telemetrytopic'ine subscribe olur, JSON alanlarını ayrıştırır ve bunları Grafana grafiklerine hazır şekilde InfluxDB'ye yazar. - Node-RED, bir
mqtt indüğümüyle subscribe olur, mesajı yeniden şekillendirir ve düğümü bulunan herhangi bir veritabanına yazar; bildirim de göndermek istiyorsanız kullanışlıdır. - paho-mqtt kullanan küçük bir Python betiği satırları SQLite veya PostgreSQL'e ekler. Öğrenirken en şeffaf seçenektir.
Üçü de tıpkı ESP32 gibi kendi client ID'leriyle sıradan MQTT istemcileri olarak broker'a bağlanır. ConnectMQ portalında cihazlarınızla birlikte görünürler ve canlı topic gezgini, herhangi bir ayrıştırma kodu yazmadan önce JSON yapısını doğrulamanın hızlı bir yoludur. Cihaz her mesaja etkin interval değerini eklediği için grafikleriniz örnekleme hızının ne zaman değiştiğini de gösterebilir; bu da bir boşluğu kesinti olarak yanlış yorumlamayı önler.
ConnectMQ ile Başlayın
Bir hava düğümü, ancak verilerini toplayan broker kadar yararlıdır. ConnectMQ; TLS, retained mesajlar, MQTT 3.1.1 ve 5.0 ile canlı topic gezgini ve eşik uyarıları içeren bir portal sunan barındırılan bir MQTT broker hizmetidir; böylece basınç hızla düştüğünde bildirim alabilirsiniz. Ücretsiz Serverless plan kredi kartı gerektirmez. Kavramlarda yeniyseniz bir MQTT broker'ın ne yaptığını okuyun, ardından ESP32 IoT eğitimi serisinin tamamını keşfedin.
Sık Sorulan Sorular
BME280 ile BMP280 arasındaki fark nedir?
BME280 sıcaklık, nem ve basıncı ölçer; BMP280 ise yalnızca sıcaklık ve basıncı ölçer. Aynı fiziksel yerleşimi ve kütüphaneyi paylaşırlar; çip kimliği (0x60'a karşı 0x58) onları birbirinden ayırır.
Yayın aralığını neden MQTT üzerinden ayarlanabilir yapmalı?
Firmware'i yeniden yüklemeden, hata ayıklarken veya bir olay sırasında daha hızlı, geri kalan zamanda daha yavaş örnekleme yapmanızı sağlar. Değeri flash'ta saklamak ayarın yeniden başlatmalardan sonra korunmasını sağlar.
Aralık komutu retained olmalı mı?
Evet, ayarlar için olmalı. Retained bir komut, siz gönderdiğinizde çevrimdışı olsa bile cihaza ulaşır ve cihaz uygulanan değeri kendi retained topic'inde bildirir.
BME280 düğümünü pille çalıştırabilir miyim?
Evet. Ölçümler arasında deep sleep kullanın, sensörü forced modda tutun ve Wi-Fi'a yalnızca yayın yapmak için bağlanın. Enerji bütçesinde belirleyici olan Wi-Fi süresidir.



