Klimamessbox - Außenbereich mit Feinstaubmessung

  • NOCH nicht aktualisiert - Nur noch BME280, kein DHT22 mehr…
  • Die Bilder liegen noch nicht im WWW-Bereich und fehlen somit bei fehlender Anmeldung

Sensor Pin (GPIO) Anschluss Besonderheit
MH-Z19B GPIO12/14 D6 / D5 Spannungsteiler für D6; SoftwareSerial
SDS011 GPIO13/15 D7 / D8 Spannungsteiler für D7 darf NICHT eingebaut werden, der SDS sendet bereits mit 3,3V Logik; SoftwareSerial
BMP180 GPIO4/5 D2 / D1 I²C (fest: SDA=SDA, SCL=SCL)
LDR ADC0 A0 analog
DHT22 GPIO3 RX Nur nach Upload einstecken!

Di-mini-Platine

ACHTUNG: Für den SDS011 KEINEN Spannungsteiler verwenden, er sendet bereits mit 3,3 V Logik

Sensorplatine

TESTCODE KLIMABOX BME, MHZ und SDS

BME280

#include <Wire.h>
#include <Adafruit_BME280.h>

#define BME280_ADDRESS 0x76    // ggf. 0x77 testen
Adafruit_BME280 bme;

void setup() {
  Serial.begin(115200);
  delay(200);
  Serial.println("\nBME280 Test");

  Wire.begin(4, 5);            // SDA = GPIO4, SCL = GPIO5

  if (!bme.begin(BME280_ADDRESS)) {
    Serial.println("BME280 nicht gefunden, Adresse oder Verkabelung prüfen!");
    while (1) delay(100);
  }
  Serial.println("BME280 gefunden.");
}

void loop() {
  float t = bme.readTemperature();
  float h = bme.readHumidity();
  float p = bme.readPressure() / 100.0; // hPa

  Serial.print("Temp: "); Serial.print(t); Serial.println(" °C");
  Serial.print("Feuchte: "); Serial.print(h); Serial.println(" %");
  Serial.print("Druck: "); Serial.print(p); Serial.println(" hPa");
  Serial.println("----");
  delay(2000);
}
18:11:23.194 -> ----
18:11:25.191 -> Temp: 22.28 °C
18:11:25.191 -> Feuchte: 35.97 %
18:11:25.191 -> Druck: 1008.70 hPa
18:11:25.191 -> ----

MHZ-19B

#include <SoftwareSerial.h>

SoftwareSerial mhzSerial(12, 14);  // RX = GPIO12, TX = GPIO14
byte cmdReadCO2[] = {0xFF, 0x01, 0x86, 0, 0, 0, 0, 0, 0x79};

bool readMHZ19B(int &ppm, int &tempC) {
  while (mhzSerial.available()) mhzSerial.read();

  mhzSerial.write(cmdReadCO2, 9);

  uint8_t resp[9];
  int i = 0;
  uint32_t start = millis();
  while (millis() - start < 200) {
    if (mhzSerial.available()) {
      resp[i++] = mhzSerial.read();
      if (i == 9) break;
    }
  }
  if (i != 9) return false;
  if (resp[0] != 0xFF || resp[1] != 0x86) return false;

  uint8_t sum = 0;
  for (int k = 1; k < 8; k++) sum += resp[k];
  sum = 0xFF - sum + 1;
  if (sum != resp[8]) return false;

  ppm   = resp[2] * 256 + resp[3];
  tempC = resp[4] - 40;
  return true;
}

void setup() {
  Serial.begin(115200);
  delay(200);
  Serial.println("\nMH-Z19B Test");

  mhzSerial.begin(9600);
  Serial.println("Sensor heizt auf (ca. 3 Minuten)...");
}

void loop() {
  int ppm, t;
  if (readMHZ19B(ppm, t)) {
    Serial.print("CO2: ");
    Serial.print(ppm);
    Serial.print(" ppm, T-Sensor: ");
    Serial.print(t);
    Serial.println(" °C");
  } else {
    Serial.println("Fehler beim Lesen (noch am Aufwärmen?)");
  }
  delay(2000);
}
18:10:07.806 -> CO2: 674 ppm, T-Sensor: 24 °C
18:10:09.844 -> CO2: 675 ppm, T-Sensor: 24 °C

SDS011

#include <SoftwareSerial.h>

SoftwareSerial sdsSerial(13, 15);  // RX = GPIO13, TX = GPIO15

void setup() {
  Serial.begin(115200);
  delay(200);
  Serial.println("\nSDS011 Test");

  sdsSerial.begin(9600);
}

bool readSDS011(float &pm25, float &pm10) {
  uint8_t buf[10];
  int idx = 0;
  uint32_t start = millis();

  while (millis() - start < 2000) {
    if (sdsSerial.available()) {
      uint8_t b = sdsSerial.read();
      if (idx == 0 && b != 0xAA) continue;
      buf[idx++] = b;
      if (idx == 10) {
        if (buf[0] == 0xAA && buf[1] == 0xC0 && buf[9] == 0xAB) {
          pm25 = (buf[2] + 256 * buf[3]) / 10.0;
          pm10 = (buf[4] + 256 * buf[5]) / 10.0;
          return true;
        } else {
          idx = 0;
        }
      }
    }
  }
  return false;
}

void loop() {
  float pm25, pm10;
  if (readSDS011(pm25, pm10)) {
    Serial.print("PM2.5: ");
    Serial.print(pm25);
    Serial.print(" µg/m³, PM10: ");
    Serial.print(pm10);
    Serial.println(" µg/m³");
  } else {
    Serial.println("Kein gültiges SDS011 Paket empfangen.");
  }
  delay(2000);
}
18:29:09.513 -> PM2.5: 4.60 µg/m³, PM10: 8.10 µg/m³
18:29:11.513 -> PM2.5: 4.60 µg/m³, PM10: 8.00 µg/m³

Alle drei Sensoren

#include <Wire.h>
#include <Adafruit_BME280.h>
#include <SoftwareSerial.h>

// BME280 an I2C: SDA = GPIO4 (D2), SCL = GPIO5 (D1)
#define BME280_ADDRESS 0x76
Adafruit_BME280 bme;

// MH-Z19B an GPIO12/14
SoftwareSerial mhzSerial(12, 14);  // RX = 12, TX = 14
byte cmdReadCO2[] = {0xFF, 0x01, 0x86, 0, 0, 0, 0, 0, 0x79};

// SDS011 an GPIO13/15
SoftwareSerial sdsSerial(13, 15);  // RX = 13, TX = 15

byte sds011_sleep[]  = {0xAA, 0xB4, 0x06, 0x01, 0x00,
                        0x00, 0x00, 0x00, 0x00, 0x00,
                        0x00, 0x00, 0x00, 0x00,
                        0xFF, 0xFF, 0x05, 0xAB};
byte sds011_wakeup[] = {0xAA, 0xB4, 0x06, 0x01, 0x01,
                        0x00, 0x00, 0x00, 0x00, 0x00,
                        0x00, 0x00, 0x00, 0x00,
                        0xFF, 0xFF, 0x06, 0xAB};

// ---- Hilfsfunktionen ----

bool readMHZ19B(int &ppm, int &tempC) {
  while (mhzSerial.available()) mhzSerial.read();
  mhzSerial.write(cmdReadCO2, 9);

  uint8_t resp[9];
  int i = 0;
  uint32_t start = millis();
  while (millis() - start < 200) {
    if (mhzSerial.available()) {
      resp[i++] = mhzSerial.read();
      if (i == 9) break;
    }
  }
  if (i != 9) return false;
  if (resp[0] != 0xFF || resp[1] != 0x86) return false;

  uint8_t sum = 0;
  for (int k = 1; k < 8; k++) sum += resp[k];
  sum = 0xFF - sum + 1;
  if (sum != resp[8]) return false;

  ppm   = resp[2] * 256 + resp[3];
  tempC = resp[4] - 40;
  return true;
}

bool readSDS011(float &pm25, float &pm10) {
  uint8_t buf[10];
  int idx = 0;
  uint32_t start = millis();

  while (millis() - start < 2000) {
    if (sdsSerial.available()) {
      uint8_t b = sdsSerial.read();
      if (idx == 0 && b != 0xAA) continue;
      buf[idx++] = b;
      if (idx == 10) {
        if (buf[0] == 0xAA && buf[1] == 0xC0 && buf[9] == 0xAB) {
          pm25 = (buf[2] + 256 * buf[3]) / 10.0;
          pm10 = (buf[4] + 256 * buf[5]) / 10.0;
          return true;
        } else {
          idx = 0;
        }
      }
    }
  }
  return false;
}

void setSDS011Sleep(bool sleep) {
  if (sleep) {
    sdsSerial.write(sds011_sleep, sizeof(sds011_sleep));
  } else {
    sdsSerial.write(sds011_wakeup, sizeof(sds011_wakeup));
  }
  delay(100);
}

// ---- Setup & Loop ----

void setup() {
  Serial.begin(115200);
  delay(200);
  Serial.println("\nGesamttest: BME280 + MH-Z19B + SDS011");

  // BME280
  Wire.begin(4, 5);  // SDA, SCL
  if (!bme.begin(BME280_ADDRESS)) {
    Serial.println("BME280 nicht gefunden!");
    while (1) delay(100);
  }
  Serial.println("BME280 OK.");

  // MH-Z19B
  mhzSerial.begin(9600);
  Serial.println("MH-Z19B UART gestartet (9600 Baud).");

  // SDS011
  sdsSerial.begin(9600);
  setSDS011Sleep(false);
  Serial.println("SDS011 aufgeweckt, Lüfter sollte laufen.");
}

void loop() {
  Serial.println("\n--- neuer Messzyklus ---");

  // BME280
  bme.takeForcedMeasurement();
  float t = bme.readTemperature();
  float h = bme.readHumidity();
  float p = bme.readPressure() / 100.0;

  Serial.print("BME280: ");
  Serial.print(t); Serial.print(" °C, ");
  Serial.print(h); Serial.print(" %, ");
  Serial.print(p); Serial.println(" hPa");

  // MH-Z19B
  int ppm, tco2;
  if (readMHZ19B(ppm, tco2)) {
    Serial.print("MH-Z19B: ");
    Serial.print(ppm); Serial.print(" ppm, ");
    Serial.print(tco2); Serial.println(" °C (Sensorsensor)");
  } else {
    Serial.println("MH-Z19B: kein gültiges Paket.");
  }

  // SDS011
  float pm25, pm10;
  if (readSDS011(pm25, pm10)) {
    Serial.print("SDS011: PM2.5=");
    Serial.print(pm25);
    Serial.print(" µg/m³, PM10=");
    Serial.print(pm10);
    Serial.println(" µg/m³");
  } else {
    Serial.println("SDS011: kein gültiges Paket.");
  }

  delay(10000);
}
18:33:44.196 -> --- neuer Messzyklus ---
18:33:44.196 -> BME280: 21.54 °C, 37.46 %, 1008.72 hPa
18:33:44.259 -> MH-Z19B: 673 ppm, 22 °C (Sensorsensor)
18:33:44.259 -> SDS011: PM2.5=4.20 µg/m³, PM10=7.20 µg/m³
QR-Code
QR-Code www-messdatenerfassung-sas:platinenschaltung-aussenbox (erstellt für aktuelle Seite)