===== 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 {{:info:arduino:esp8266-wemos-d1-mini-pinout-gpio-pin-2.png?300|}}{{:info:platinen:sds011-dust-sensor-pinout-diagram.jpg?300|}} ^ 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 {{:info:platinen:platine-klimamessbox-d1-mini.png?300|}} {{:info:platinen:platine-klimamessbox-d1-mini-2d-unten.png?200|}} {{:info:platinen:platine-klimamessbox-d1-mini-2d-oben.png?200|}} {{:info:platinen:platine-klimamessbox-d1-mini-3d-unten.png?200|}} {{:info:platinen:platine-klimamessbox-d1-mini-3d-oben.png?200|}} ==== Sensorplatine ==== {{:info:platinen:platine-klimamessbox-sensoren.png?300|}} {{:info:platinen:platine-klimamessbox-sensoren-2d-unten.png?200|}} {{:info:platinen:platine-klimamessbox-sensoren-2d-oben.png?200|}} {{:info:platinen:platine-klimamessbox-sensoren-3d-unten.png?200|}} {{:info:platinen:platine-klimamessbox-sensoren-3d-oben.png?200|}} ===== TESTCODE KLIMABOX BME, MHZ und SDS===== ==== BME280 ==== #include #include #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 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 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 #include #include // 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³