|
|
|
/*
|
|
|
|
* Blink
|
|
|
|
* Turns on an LED on for one second,
|
|
|
|
* then off for one second, repeatedly.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <Arduino.h>
|
|
|
|
#include <WiFi.h>
|
|
|
|
#include <WiFiMulti.h>
|
|
|
|
|
|
|
|
#include <Wire.h>
|
|
|
|
#include <SPI.h>
|
|
|
|
|
|
|
|
#include <GxEPD2_BW.h>
|
|
|
|
#include <Fonts/FreeMonoBold9pt7b.h>
|
|
|
|
#include <Fonts/FreeSans9pt7b.h>
|
|
|
|
#include <Fonts/Org_01.h>
|
|
|
|
#include "bitmaps/Bitmaps128x250.h"
|
|
|
|
#include <Adafruit_GFX.h>
|
|
|
|
|
|
|
|
#include <Adafruit_Sensor.h>
|
|
|
|
#include "Adafruit_BME280.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<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display(GxEPD2_213_B72(/*CS=SS*/ TFT_CS, /*DC=*/ TFT_DC, /*RST=*/ TFT_RST, /*BUSY=*/ -1)); // GDEH0213B72
|
|
|
|
Adafruit_BME280 bme; // I2C (also available: hardware SPI
|
|
|
|
//HardwareSerial Serial2(2);
|
|
|
|
SdsDustSensor sds(Serial2);
|
|
|
|
Adafruit_VEML6075 uv = Adafruit_VEML6075();
|
|
|
|
|
|
|
|
XD0OTA ota("esp32-weatherstation");
|
|
|
|
XD0MQTT mqtt;
|
|
|
|
|
|
|
|
uint32_t lastDisplayUpdate = 0;
|
|
|
|
bool bme_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 printValues() {
|
|
|
|
if (bme_active) {
|
|
|
|
#define SEALEVELPRESSURE_HPA (1013.25)
|
|
|
|
Serial.print("Temperature = ");
|
|
|
|
Serial.print(bme.readTemperature());
|
|
|
|
Serial.println(" *C");
|
|
|
|
|
|
|
|
Serial.print("Pressure = ");
|
|
|
|
|
|
|
|
Serial.print(bme.readPressure() / 100.0F);
|
|
|
|
Serial.println(" hPa");
|
|
|
|
|
|
|
|
Serial.print("Approx. Altitude = ");
|
|
|
|
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
|
|
|
|
Serial.println(" m");
|
|
|
|
|
|
|
|
Serial.print("Humidity = ");
|
|
|
|
Serial.print(bme.readHumidity());
|
|
|
|
Serial.println(" %");
|
|
|
|
|
|
|
|
Serial.println();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uv_active) {
|
|
|
|
Serial.print("UV Index reading: "); Serial.println(uv.readUVI());
|
|
|
|
Serial.print("Raw UVA reading: "); Serial.println(uv.readUVA());
|
|
|
|
Serial.print("Raw UVB reading: "); Serial.println(uv.readUVB());
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
if (sds_active) {
|
|
|
|
PmResult pm = sds.readPm();
|
|
|
|
if (pm.isOk()) {
|
|
|
|
Serial.print("PM2.5 = ");
|
|
|
|
Serial.print(pm.pm25);
|
|
|
|
Serial.print(", PM10 = ");
|
|
|
|
Serial.println(pm.pm10);
|
|
|
|
|
|
|
|
// if you want to just print the measured values, you can use toString() method as well
|
|
|
|
Serial.println(pm.toString());
|
|
|
|
} else {
|
|
|
|
Serial.print("Could not read values from sensor, reason: ");
|
|
|
|
Serial.println(pm.statusToString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendValues() {
|
|
|
|
/* send values MQTT */
|
|
|
|
if (bme_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");
|
|
|
|
char temperature[8]; sprintf(temperature, "%.2f", bme.readTemperature());
|
|
|
|
char humidity[7]; sprintf(humidity, "%.2f", bme.readHumidity());
|
|
|
|
char pressure[8]; sprintf(pressure, "%.2f", bme.readPressure() / 100.0F);
|
|
|
|
mqtt.publish(topic_temperature.c_str(), temperature, strlen(temperature));
|
|
|
|
mqtt.publish(topic_humidity.c_str(), humidity, strlen(humidity));
|
|
|
|
mqtt.publish(topic_pressure.c_str(), pressure, strlen(pressure));
|
|
|
|
} else {
|
|
|
|
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");
|
|
|
|
char uvi[10]; sprintf(uvi, "%.2f", uv.readUVI());
|
|
|
|
char uva[10]; sprintf(uva, "%.2f", uv.readUVA());
|
|
|
|
char uvb[10]; sprintf(uvb, "%.2f", uv.readUVB());
|
|
|
|
mqtt.publish(topic_uvi.c_str(), uvi, strlen(uvi));
|
|
|
|
mqtt.publish(topic_uva.c_str(), uva, strlen(uva));
|
|
|
|
mqtt.publish(topic_uvb.c_str(), uvb, strlen(uvb));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sds_active) {
|
|
|
|
PmResult pm = sds.readPm();
|
|
|
|
if (pm.isOk()) {
|
|
|
|
String topic_pm10 = String("thomas/sensor/") + ota.getMAC() + String("/pm10");
|
|
|
|
char pm10[10]; sprintf(pm10, "%.2f", pm.pm10);
|
|
|
|
String topic_pm25 = String("thomas/sensor/") + ota.getMAC() + String("/pm25");
|
|
|
|
char pm25[10]; sprintf(pm25, "%.2f", pm.pm25);
|
|
|
|
mqtt.publish(topic_pm10.c_str(), pm10, strlen(pm10));
|
|
|
|
mqtt.publish(topic_pm25.c_str(), pm25, strlen(pm25));
|
|
|
|
|
|
|
|
// if you want to just print the measured values, you can use toString() method as well
|
|
|
|
Serial.println(pm.toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \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 (bme.begin()) {
|
|
|
|
bme_active = true;
|
|
|
|
} else {
|
|
|
|
ESP_LOGE(TAG, "Could not find a valid BME280 sensor, check wiring!");
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
// Set up oversampling and filter initialization
|
|
|
|
bme.setTemperatureOversampling(BME680_OS_8X);
|
|
|
|
bme.setHumidityOversampling(BME680_OS_2X);
|
|
|
|
bme.setPressureOversampling(BME680_OS_4X);
|
|
|
|
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
|
|
|
|
bme.setGasHeater(320, 150); // 320*C for 150 ms
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (uv.begin()) {
|
|
|
|
uv_active = true;
|
|
|
|
} 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();
|
|
|
|
display.setFullWindow();
|
|
|
|
display.setRotation(1);
|
|
|
|
display.firstPage();
|
|
|
|
do
|
|
|
|
{
|
|
|
|
display.fillScreen(GxEPD_WHITE);
|
|
|
|
display.setTextColor(GxEPD_BLACK);
|
|
|
|
display.setFont(&FreeSans9pt7b);
|
|
|
|
display.setTextWrap(false);
|
|
|
|
display.setCursor(0, 11);
|
|
|
|
display.println("ESP32-Wetterstation");
|
|
|
|
display.drawFastHLine(0, 14, display.width(), GxEPD_BLACK);
|
|
|
|
display.setCursor(0, 32);
|
|
|
|
if (bme_active) {
|
|
|
|
display.print("Temperatur: ");
|
|
|
|
display.print(bme.readTemperature());
|
|
|
|
display.println(" *C");
|
|
|
|
display.print("Luftfeuchte: ");
|
|
|
|
display.print(bme.readHumidity());
|
|
|
|
display.println(" %");
|
|
|
|
display.print("Luftdruck:");
|
|
|
|
display.print(bme.readPressure() / 100.0F);
|
|
|
|
display.println(" hPa");
|
|
|
|
} else {
|
|
|
|
display.print("Temperatur: ");
|
|
|
|
float esp32_temperature = (temprature_sens_read() - 32) / 1.8;
|
|
|
|
display.println(esp32_temperature-29.40);
|
|
|
|
display.println("kein BME280");
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|