/* * Blink * Turns on an LED on for one second, * then off for one second, repeatedly. */ #include #include #include #include #include #include #include #include #include #include "bitmaps/Bitmaps128x250.h" #include #include #include "Adafruit_BME280.h" #include "Adafruit_BME680.h" #include "Adafruit_VEML6075.h" #define ARDUINO_SAMD_VARIANT_COMPLIANCE #include "SdsDustSensor.h" #include "network/XD0OTA.h" #include "network/XD0MQTT.h" #include "icons.h" extern "C" { uint8_t temprature_sens_read(); } static const char* TAG = "MAIN"; WiFiMulti wifiMulti; GxEPD2_BW display(GxEPD2_213_B72(/*CS=SS*/ TFT_CS, /*DC=*/ TFT_DC, /*RST=*/ TFT_RST, /*BUSY=*/ -1)); // GDEH0213B72 Adafruit_BME280 bme280; // I2C (also available: hardware SPI Adafruit_BME680 bme680; // I2C (also available: hardware SPI //HardwareSerial Serial2(2); SdsDustSensor sds(Serial2); Adafruit_VEML6075 uv = Adafruit_VEML6075(); XD0OTA ota("esp32-weatherstation"); XD0MQTT mqtt; struct __attribute__((packed)) { float temperature = 0.0; // °C float humidity = 0.0; // %H float pressure = 0.0; // Pa uint32_t voc = 0; // Ohm float pm10 = 0.0; // µg/m³ float pm25 = 0.0; // µg/m³ float uvi = 0.0; float uva = 0.0; float uvb = 0.0; } sensor_readings; uint32_t lastDisplayUpdate = 0; bool bme280_active = false; bool bme680_active = false; bool uv_active = false; bool sds_active = false; void helloWorld() { const char HelloWorld[] = "IchbinsBens!"; //Serial.println("helloWorld"); display.setRotation(1); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); int16_t tbx, tby; uint16_t tbw, tbh; display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); // center bounding box by transposition of origin: uint16_t x = ((display.width() - tbw) / 2) - tbx; uint16_t y = ((display.height() - tbh) / 2) - tby; display.setFullWindow(); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setCursor(x, y); display.print(HelloWorld); display.setCursor(5, display.height()-5); display.setFont(&Org_01); display.print(FW_VERSION); } while (display.nextPage()); //Serial.println("helloWorld done"); } void displayIcoPartial(const uint8_t bitmap[], uint16_t x, uint16_t y, uint16_t w, uint16_t h) { display.setPartialWindow(x, y, w, h); display.firstPage(); do { display.drawInvertedBitmap(x, y, bitmap, w, h, GxEPD_BLACK); } while (display.nextPage()); } void getTime(char* ptr, size_t maxsize, const char* format) { time_t now; struct tm timeinfo; time(&now); // update 'now' variable with current time setenv("TZ", "CET-1CEST,M3.5.0/2,M10.5.0/3", 1); tzset(); localtime_r(&now, &timeinfo); strftime(ptr, maxsize, format, &timeinfo); } void getSensorMeasurements() { if (bme280_active) { bme280.takeForcedMeasurement(); sensor_readings.temperature = bme280.readTemperature(); sensor_readings.humidity = bme280.readHumidity(); sensor_readings.pressure = bme280.readPressure(); } if (bme680_active) { if (bme680.performReading()) { sensor_readings.temperature = bme680.temperature; sensor_readings.humidity = bme680.humidity; sensor_readings.pressure = bme680.pressure; sensor_readings.voc = bme680.gas_resistance; } else { Serial.println("Failed to perform reading :("); } } if (uv_active) { sensor_readings.uvi = uv.readUVI(); sensor_readings.uva = uv.readUVA(); sensor_readings.uvb = uv.readUVB(); } if (sds_active) { PmResult pm = sds.readPm(); if (pm.isOk()) { sensor_readings.pm10 = pm.pm10; sensor_readings.pm25 = pm.pm25; } } } void printValues() { if (bme280_active || bme680_active) { #define SEALEVELPRESSURE_HPA (1013.25) Serial.print("Temperature = "); Serial.print(sensor_readings.temperature); Serial.println(" *C"); Serial.print("Pressure = "); Serial.print(sensor_readings.pressure / 100.0F); Serial.println(" hPa"); Serial.print("Humidity = "); Serial.print(sensor_readings.humidity); Serial.println(" %"); } if (bme680_active) { Serial.print("VOC = "); Serial.print(sensor_readings.voc / 1000.0F); Serial.println(" hPa"); } Serial.println(); if (uv_active) { Serial.print("UV Index reading: "); Serial.println(sensor_readings.uvi); Serial.print("Raw UVA reading: "); Serial.println(sensor_readings.uva); Serial.print("Raw UVB reading: "); Serial.println(sensor_readings.uvb); Serial.println(); } if (sds_active) { Serial.print("PM2.5 = "); Serial.print(sensor_readings.pm25); Serial.print(", PM10 = "); Serial.println(sensor_readings.pm10); } } void sendValues() { /* send values MQTT */ if (bme280_active || bme680_active) { String topic_temperature = String("thomas/sensor/") + ota.getMAC() + String("/temperature"); String topic_humidity = String("thomas/sensor/") + ota.getMAC() + String("/humidity"); String topic_pressure = String("thomas/sensor/") + ota.getMAC() + String("/pressure"); mqtt.publish(topic_temperature.c_str(), sensor_readings.temperature, "%.2f"); mqtt.publish(topic_humidity.c_str(), sensor_readings.humidity, "%.2f"); mqtt.publish(topic_pressure.c_str(), sensor_readings.pressure / 100.0F, "%.2f"); } if (bme680_active) { String topic_voc = String("thomas/sensor/") + ota.getMAC() + String("/voc"); mqtt.publish(topic_voc.c_str(), sensor_readings.voc / 1000.0F, "%.2f"); } if (!bme280_active && !bme680_active) { String topic_temperature = String("thomas/sensor/") + ota.getMAC() + String("/temperature"); float esp32_temperature = (temprature_sens_read() - 32) / 1.8; char temperature[8]; sprintf(temperature, "%.2f", esp32_temperature-29.40); mqtt.publish(topic_temperature.c_str(), temperature, strlen(temperature)); } if (uv_active) { String topic_uvi = String("thomas/sensor/") + ota.getMAC() + String("/uvi"); String topic_uva = String("thomas/sensor/") + ota.getMAC() + String("/uva"); String topic_uvb = String("thomas/sensor/") + ota.getMAC() + String("/uvb"); mqtt.publish(topic_uvi.c_str(), sensor_readings.uvi, "%.2f"); mqtt.publish(topic_uva.c_str(), sensor_readings.uva, "%.2f"); mqtt.publish(topic_uvb.c_str(), sensor_readings.uvb, "%.2f"); } if (sds_active) { String topic_pm10 = String("thomas/sensor/") + ota.getMAC() + String("/pm10"); String topic_pm25 = String("thomas/sensor/") + ota.getMAC() + String("/pm25"); mqtt.publish(topic_pm10.c_str(), sensor_readings.pm10, "%.2f"); mqtt.publish(topic_pm25.c_str(), sensor_readings.pm25, "%.2f"); } } /** * \brief Setup function * * is run once on startup */ void setup() { Serial.begin(115200); delay(10); ESP_LOGD(TAG, "setup hardware and sensors"); // initialize LED digital pin as an output. pinMode(LED_BUILTIN, OUTPUT); // initialize e-paper display SPI.begin(18, 19, 23, TFT_CS); display.init(); #define BME_SDA 21 #define BME_SCL 22 Wire.begin(BME_SDA, BME_SCL); if (bme280.begin()) { bme280_active = true; } else { ESP_LOGE(TAG, "Could not find a valid BME280 sensor, check wiring!"); } if (bme680.begin()) { bme680_active = true; // Set up oversampling and filter initialization bme680.setTemperatureOversampling(BME680_OS_8X); bme680.setHumidityOversampling(BME680_OS_2X); bme680.setPressureOversampling(BME680_OS_4X); bme680.setIIRFilterSize(BME680_FILTER_SIZE_3); bme680.setGasHeater(320, 150); // 320*C for 150 ms } else { ESP_LOGE(TAG, "Could not find a valid BME680 sensor, check wiring!"); } if (uv.begin()) { uv_active = true; uv.setIntegrationTime(VEML6075_100MS); // Set the integration constant uv.setHighDynamic(true); // Set the high dynamic mode uv.setForcedMode(false); // Set the calibration coefficients uv.setCoefficients(2.22, 1.33, // UVA_A and UVA_B coefficients 2.95, 1.74, // UVB_C and UVB_D coefficients 0.001461, 0.002591); // UVA and UVB responses } else { Serial.println("Failed to communicate with VEML6075 sensor, check wiring?"); } sds.begin(); FirmwareVersionResult sds_fw = sds.queryFirmwareVersion(); if (sds_fw.isOk()) { sds_active = true; sds.setActiveReportingMode(); // ensures sensor is in 'active' reporting mode sds.setCustomWorkingPeriod(5); // sensor sends data every 3 minutes } else { Serial.println("Failed to communicate with SDS011 sensor, check wiring?"); } display.clearScreen(); display.refresh(); ESP_LOGD(TAG, "displaying welcome screen"); helloWorld(); display.powerOff(); ESP_LOGD(TAG, "connecting to WiFi"); WiFi.setHostname("esp32-weatherstation"); wifiMulti.addAP(WIFI_SSID, WIFI_PASSWD); wifiMulti.addAP(WIFI_SSID2, WIFI_PASSWD2); wifiMulti.addAP(WIFI_SSID3, WIFI_PASSWD3); for (int tries=0; wifiMulti.run() != WL_CONNECTED && tries < 10; tries++) { Serial.print("."); delay(500); } if(wifiMulti.run() == WL_CONNECTED) { Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); displayIcoPartial(ico_wifi16, display.width()-20, 0, ico_wifi16_width, ico_wifi16_height); } ESP_LOGD(TAG, "trying to fetch over-the-air update"); if (WiFi.status() == WL_CONNECTED) { ota.update(); } ESP_LOGD(TAG, "connecting to MQTT"); mqtt.begin(); ESP_LOGD(TAG, "setup done"); } /** * \brief Arduino main loop */ void loop() { ESP_LOGD(TAG, "loop()"); /* Do an e-paper display refresh every 2 minutes */ if (millis() - lastDisplayUpdate >= 1*60*1000) { lastDisplayUpdate = millis(); getSensorMeasurements(); display.setFullWindow(); display.setRotation(1); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setTextColor(GxEPD_BLACK); display.setTextWrap(false); display.setCursor(0, 11); display.setFont(&FreeSans9pt7b); display.println("ESP32-Wetterstation"); display.drawFastHLine(0, 14, display.width(), GxEPD_BLACK); //display.setFont(NULL); display.setCursor(0, 32); if (bme280_active || bme680_active) { display.print("Temperatur: "); display.print(sensor_readings.temperature); display.println(" *C"); display.print("Luftfeuchte: "); display.print(sensor_readings.humidity); display.println(" %"); display.print("Luftdruck:"); display.print(sensor_readings.pressure / 100.0F); display.println(" hPa"); } if (bme680_active) { display.print("Gas: "); display.print(sensor_readings.voc / 1000.0); display.println(" KOhms"); } if (!bme280_active && !bme680_active) { display.print("Temperatur: "); float esp32_temperature = (temprature_sens_read() - 32) / 1.8; display.println(esp32_temperature-29.40); display.println("kein BME Sensor"); } char timeStr[9]; getTime(timeStr, sizeof(timeStr), "%H:%M:%S"); display.setCursor(5, display.height()-5); display.setFont(&Org_01); display.print("Zeit: "); display.println(timeStr); } while (display.nextPage()); display.powerOff(); printValues(); sendValues(); } if(wifiMulti.run() != WL_CONNECTED) { Serial.println("WiFi not connected!"); delay(1000); } delay(2000); }