Wetterstation mit CC1101 (über RadioLib) und ESP32-S3

Also, mein erster Versuch mit ELECHOUSE_CC1101_SRC_DRV hat zu einem Aufhängen ab der Initialisierung geführt. Ich habe es dann mit RadioLib versucht, mit dem Ergebnis, dass ich zwar irgendetwas senden kann, aber die Signale sehen in AirSpy komplett anders aus als die Signale, die die OOK (ASK) Wetterstationen senden.

Ich dachte, der CC1101 wäre der geeignetste Empfänger, da dieser auch in der RTL_433_ESP und dem BresserWeatherSensorReceiver genutzt wird. Warum wird beim BresserWeatherSensorReceiver 868.3 MHz genutzt und nicht 433.92 MHz?

Mit dem Ergebnis, dass dort Einstellungen vorgenommen werden, die bei mir geschützt sind, wenn ich es versuche. Ich habe auch einen FS1000A, der ebenfalls OOK (ASK) kann, aber eigentlich wollte ich es jetzt erst einmal mit einem CC1101 probieren, der von den technischen Daten her deutlich besser aussieht. Aber wie ich feststellen musste, ist er schwer zu nutzen. Ich bin mir nicht einmal sicher, ob er über ausreichend Empfindlichkeit verfügt. Deshalb habe ich ihn sogar schon an die Antenne meines SDR-Empfängers angeschlossen – ohne Erfolg.

Liegt es am ESP32 S3, an der Bibliothek oder stelle ich einfach alles falsch ein? Ich möchte nur meinen SDR-Stick durch einen energieeffizienten ESP32 S3 mit CC1101 austauschen. Aber irgendwie scheinen für den keine Bibliotheken zu existieren, die das können. Sollte man nicht eher so etwas wie einen direkten Modus nutzen, oder sind die Einstellungen einfach falsch, die ich vorgenommen habe, um so eine Wetterstation zu empfangen?

Einfaches Beispiel, angepasst für ESP32 S3:

/*
   RadioLib CC1101 Receive with Interrupts Example

   This example listens for FSK transmissions and tries to
   receive them. Once a packet is received, an interrupt is
   triggered.

   To successfully receive data, the following settings have to be the same
   on both transmitter and receiver:
    - carrier frequency
    - bit rate
    - frequency deviation
    - sync word

   For default module settings, see the wiki page
   https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101

   For full API reference, see the GitHub Pages
   https://jgromes.github.io/RadioLib/
*/

// include the library
#include <RadioLib.h>

// Definiere die Pins für den ESP32-S3
#define CC1101_CS_PIN 10    // Chip Select
#define CC1101_SCK_PIN 12   // Serial Clock
#define CC1101_MOSI_PIN 11  // Master Out Slave In
#define CC1101_MISO_PIN 13  // Master In Slave Out
#define CC1101_GDO0_PIN 38  // Definiere den GDO0 Pin (unverändert)
#define CC1101_GDO2_PIN 39  // Definiere den GDO2 Pin (unverändert)
#define CC1101_RST_PIN   -1 // Falls kein Reset-Pin verwendet wird
CC1101 radio = new Module(CC1101_CS_PIN, CC1101_GDO0_PIN, CC1101_RST_PIN, CC1101_GDO2_PIN, newSPI, SPISettings(2000000, MSBFIRST, SPI_MODE0));

// or using RadioShield
// https://github.com/jgromes/RadioShield
//CC1101 radio = RadioShield.ModuleA;

void setup() {
  Serial.begin(9600);

  newSPI.begin(CC1101_SCK_PIN, CC1101_MISO_PIN, CC1101_MOSI_PIN, CC1101_CS_PIN);

  // initialize CC1101 with default settings
  Serial.print(F("[CC1101] Initializing ... "));
  int state = radio.begin();
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

  // Konfiguriere das CC1101-Modul für eine einfache OOK-Wetterstation
  cc1101.setFrequency(433.92);  // Setze die Frequenz auf 433 MHz
  cc1101.setBitRate(17.24);     // Setze die Bitrate auf 17.24 kbps
  cc1101.setOutputPower(10);    // Setze die Sendeleistung auf 10 dBm
  cc1101.setSyncWord(0xAA, 0x2D); // Beispiel-Sync-Word, könnte angepasst werden müssen
  cc1101.disableSyncWordFiltering(false);
  cc1101.setCrcFiltering(false); // Deaktiviert die CRC-Prüfung für einfache Wetterstationen
  cc1101.setOOK(true);           // Setze die Modulation auf OOK (ASK)
  cc1101.setFrequencyDeviation(40); // Setze Frequenzabweichung auf 40 kHz
  cc1101.setRxBandwidth(270.0); // Setze Empfangsbandbreite auf 270 kHz

  // set the function that will be called
  // when new packet is received
  radio.setPacketReceivedAction(setFlag);

  // start listening for packets
  Serial.print(F("[CC1101] Starting to listen ... "));
  state = radio.startReceive();
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

  // if needed, 'listen' mode can be disabled by calling
  // any of the following methods:
  //
  // radio.standby()
  // radio.sleep()
  // radio.transmit();
  // radio.receive();
  // radio.readData();
}

// flag to indicate that a packet was received
volatile bool receivedFlag = false;

// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
//            and MUST NOT have any arguments!
#if defined(ESP8266) || defined(ESP32)
  ICACHE_RAM_ATTR
#endif
void setFlag(void) {
  // we got a packet, set the flag
  receivedFlag = true;
}

void loop() {
  // check if the flag is set
  if(receivedFlag) {
    // reset flag
    receivedFlag = false;

    // you can read received data as an Arduino String
    String str;
    int state = radio.readData(str);

    // you can also read received data as byte array
    /*
      byte byteArr[8];
      int numBytes = radio.getPacketLength();
      int state = radio.readData(byteArr, numBytes);
    */

    if (state == RADIOLIB_ERR_NONE) {
      // packet was successfully received
      Serial.println(F("[CC1101] Received packet!"));

      // print data of the packet
      Serial.print(F("[CC1101] Data:\t\t"));
      Serial.println(str);

      // print RSSI (Received Signal Strength Indicator)
      // of the last received packet
      Serial.print(F("[CC1101] RSSI:\t\t"));
      Serial.print(radio.getRSSI());
      Serial.println(F(" dBm"));

      // print LQI (Link Quality Indicator)
      // of the last received packet, lower is better
      Serial.print(F("[CC1101] LQI:\t\t"));
      Serial.println(radio.getLQI());

    } else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
      // packet was received, but is malformed
      Serial.println(F("CRC error!"));

    } else {
      // some other error occurred
      Serial.print(F("failed, code "));
      Serial.println(state);

    }

    // put module back to listen mode
    radio.startReceive();
  }

}

ChatGPT hat versucht die SPIwriteRegister hinzufügen, das führt aber zu Fehlern bei der Ausführung 21455][E][esp32-hal-gpio.c:190] __digitalRead(): IO 39 is not set as GPIO

#include <SPI.h>
#include <RadioLib.h>

// Definiere die Pins für den ESP32-S3
#define CC1101_CS_PIN 10    // Chip Select
#define CC1101_SCK_PIN 12   // Serial Clock
#define CC1101_MOSI_PIN 11  // Master Out Slave In
#define CC1101_MISO_PIN 13  // Master In Slave Out
#define CC1101_GDO0_PIN 38  // Definiere den GDO0 Pin
#define CC1101_GDO2_PIN 39  // Definiere den GDO2 Pin
#define CC1101_RST_PIN   -1 // Falls kein Reset-Pin verwendet wird

SPIClass newSPI(HSPI);

// Erstellen einer benutzerdefinierten Klasse, die von CC1101 erbt
class CustomCC1101 : public CC1101 {
public:
  using CC1101::CC1101;
  using CC1101::SPIwriteRegister;
  using CC1101::SPIsendCommand;
};

// Initialisiere das benutzerdefinierte CC1101-Modul
CustomCC1101 cc1101 = new Module(CC1101_CS_PIN, CC1101_GDO0_PIN, CC1101_RST_PIN, CC1101_GDO2_PIN, newSPI, SPISettings(2000000, MSBFIRST, SPI_MODE0));

void setup() {
  Serial.begin(115200);
  Serial.println("Start Setup");

  newSPI.begin(CC1101_SCK_PIN, CC1101_MISO_PIN, CC1101_MOSI_PIN, CC1101_CS_PIN);

  int state = cc1101.begin();
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println("CC1101 initialized successfully.");
  } else {
    Serial.print("CC1101 initialization failed, code ");
    Serial.println(state);
    while (true);
  }

  // Konfiguriere das CC1101-Modul für eine einfache OOK-Wetterstation
  cc1101.setFrequency(433.92);  // Setze die Frequenz auf 433 MHz
  cc1101.setBitRate(17.24);     // Setze die Bitrate auf 17.24 kbps
  cc1101.setOutputPower(10);    // Setze die Sendeleistung auf 10 dBm
  cc1101.setSyncWord(0xAA, 0x2D); // Beispiel-Sync-Word, könnte angepasst werden müssen
  cc1101.disableSyncWordFiltering(false);
  cc1101.setCrcFiltering(false); // Deaktiviert die CRC-Prüfung für einfache Wetterstationen
  cc1101.setOOK(true);           // Setze die Modulation auf OOK (ASK)

  // Setze spezifische Registerwerte, falls notwendig
  cc1101.SPIwriteRegister(RADIOLIB_CC1101_REG_PKTLEN, 0);

  cc1101.SPIwriteRegister(RADIOLIB_CC1101_REG_AGCCTRL2, 0xc7);

  cc1101.SPIwriteRegister(RADIOLIB_CC1101_REG_MDMCFG3, 0x93); // Data rate

  cc1101.SPIwriteRegister(RADIOLIB_CC1101_REG_MDMCFG4, 0x07); // Bandwidth

  cc1101.setFrequencyDeviation(40); // Setze Frequenzabweichung auf 40 kHz
  cc1101.setRxBandwidth(270.0); // Setze Empfangsbandbreite auf 270 kHz
}

void loop() {
  // Daten, die gesendet werden sollen
  uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
  int state = cc1101.transmit(data, sizeof(data));

  // Überprüfe, ob das Senden erfolgreich war
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println("Data sent successfully.");
  } else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
    Serial.println("Transmit timeout!");
  } else {
    Serial.print("Send failed, code ");
    Serial.println(state);
  }

  // Empfange Daten
  uint8_t byteArr[64];
  cc1101.startReceive();
  state = cc1101.receive(byteArr, sizeof(byteArr));

  // Überprüfe, ob der Empfang erfolgreich war
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println("Data received!");
    Serial.print("Data: ");
    for (int i = 0; i < sizeof(byteArr); i++) {
      Serial.print(byteArr[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
  } else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
    Serial.println("CRC error!");
  } else if (state == RADIOLIB_ERR_RX_TIMEOUT) {
    Serial.println("Receive timeout!");
  } else {
    Serial.print("Receive failed, code ");
    Serial.println(state);
  }

  delay(2000); // Warte 2 Sekunden, bevor du erneut sendest
}

Das kann man ganz leicht beantworten. Da gibt es weniger Störungen, weil weniger genutzt und geringere Reichweite mit den erhältlichen Modulen.
Warum testest du dein Projekt nicht mit einem üblichen 433,92 MHz Empfänger ?
Ein RXB6 oder RXB8 wären dafür am besten geeignet. Wenn das funktioniert, kannst du immer noch auf einen CC1101 umsteigen.

Und ja, der ist deutlich schwieriger was die Einstellungen betrifft. Leider habe ich damit noch zu wenig gemacht, daher kann ich diesbezüglich keine Tipps geben.

1 Like

Warum testest du dein Projekt nicht mit einem üblichen 433,92 MHz Empfänger ?

Ich habe diesen Empfänger im Projekt RTL_433_ESP auf GitHub gesehen und dachte, er wäre geeigneter, weshalb ich ihn bestellt habe. Später stellte sich jedoch heraus, dass das Projekt offenbar feste SPI-Ports benötigt und nicht ohne Anpassungen für alle ESPs geeignet ist. Daher habe ich weiter gesucht und bin auf die Bibliothek BresserWeatherSensorReceiver gestoßen, die ebenfalls den Empfang von Wetterstationen mit diesem Empfänger ermöglichen soll.

Leider hatte ich wieder das gleiche Problem: Als Beispiel wird kein ESP32-S3 gezeigt. Mich hat nur gewundert, warum eine Bibliothek für 433 MHz Wetterstationen standardmäßig 868 MHz im Code verwendet. Die Antwort auf GitHub war, dass dies eine Anpassung für 868 MHz Stationen ist.

Ein RXB6 oder RXB8 wären dafür am besten geeignet. Wenn das funktioniert, kannst du immer noch auf einen CC1101 umsteigen.

Vielleicht kann ich damit etwas empfangen, da dieser auch ASK unterstützt. Falls ich es schaffe, eine Station zu empfangen, werde ich es berichten. :smiley: Ich wollte keinen BME280 auf den Balkon hängen, weil dieser anscheinend Probleme mit Gehäusen hat. Also dachte ich, die Stationen der Nachbarn könnte man gleich mitverwenden. Man hätte sogar einen AP hinzufügen können, über den sie die Daten mit zeitlichem Verlauf einsehen könnten. :smiley:

Mal sehen, ob ich eine Lösung finde.

SPI benötigen und sollten damit auf den meisten ESPs auch laufen. Zumindest die, die auch SPI zur Verfügung stellen.

Das kann man schon machen, die dürfen nur nicht nass werden.
In einem passenden Gehäuse ist das schon machbar. Allerdings warum ?
Muss du die Luftfeuchtigkeit auch draußen messen ?

Ist doch unterschied je nach Wetterlage

Schau mall hier
kann man auch anders bauen.
Ich habe ein paar nachgebaut funktionieren 1A bis 10m

1 Like

SPI benötigen und sollten damit auf den meisten ESPs auch laufen. Zumindest die, die auch SPI zur Verfügung stellen.

Die haben das fertige Projekt direkt zum Flashen bereitgestellt, also ohne Anpassungen für meine GPIO-Pins wird es wohl nicht laufen. Aber ja, möglich wäre es.

Das kann man schon machen, die dürfen nur nicht nass werden.
In einem passenden Gehäuse ist das schon machbar. Allerdings warum ?
Muss du die Luftfeuchtigkeit auch draußen messen ?

Ich habe in einem anderen Post in einem Forum gelesen, dass die Temperatur falsch ist, wenn die Sensoren im Gehäuse sind, weil sich das Gehäuse aufheizt. Also müsste ich sie in einer überdachten Ecke anbringen. Ich meine, es ist auch nützlich zu wissen, wie hoch die Luftfeuchtigkeit draußen ist. Dann weiß man, ob das Lüften gerade eine gute oder schlechte Idee ist.

Ich habe die Nachricht davor gelöscht, weil ich dachte, sie wurde nicht gesendet, also die war nur doppelt.

Dafür gibt es doch im Haus Fenster. :wink:
Da muss ich das nicht in Prozent wissen.

Für die Temperatur nehme ich eh immer einen DS18B20.

1 Like

Naja, da kann man sich doch sicher auf den normalen Menschenverstand verlassen.
Wir lüften immer. Fenster für ein paar Minuten komplett öffnen, es darf nur nicht reinregnen. :wink:
Die Anzeige im Zimmer kann man ja dabei beobachten. Wenn die stark ansteigt, Fenster wieder zu.

So wie immer jeder darf seine, eigene Meinung haben.
Ich bin auch für das meine Wetterstation mir anzeigt Luftdruck, Feuchtigkeit und Temperatur, und das einigermaßen korrekt.

Ist natürlich richtig und ok.
Für mich ist daher die Luftfeuchtigkeit im Raum wichtig.

Wichtig ist halt auch immer, wie die Luftfeuchtigkeit draußen ist, und der Taupunkt ist ebenfalls entscheidend. Ansonsten hast du später das Problem, dass die Luftfeuchtigkeit bei dir über die 60%-Marke steigt, und dann kann es ganz schnell schimmeln. Für den Taupunkt könnt ihr eine Formel nutzen. :wink:

Was ist für Arduino schon über 10J alt :wink:

Nur wen man zu wenig Lüftet :joy:

Klar, wenn man sich nur auf die Geräte verlässt.

Jedoch ist da die Luftfeuchtigkeit im Raum und die Temperatur im Raum wichtig.
Zumindest für mich.
Und wie @fony schreibt, lüften ist wichtig.

Wichtig ist auch, wann man lüftet. Gerade im Sommer ist die Luftfeuchtigkeit oft hoch, weil warme Luft mehr Feuchtigkeit speichern kann. Daher ist es sinnvoll, morgens oder abends zu lüften, wenn es draußen kühler ist. Im Winter hast du jedoch auch Vorteile: Lüftest du stoßweise, wird die warme Luft mit der hohen Luftfeuchtigkeit nach draußen getragen und durch trockenere Außenluft ersetzt. Meine Gegend hat jetzt nicht so viele Probleme mit der Luftfeuchtigkeit, aber für einen Bekannten von mir ist das ziemlich wichtig. Bei ihm ist die Luft draußen nicht selten extrem feucht.

Ich habe ein Skript umgeschrieben. Daten vom Sensor cachen und an meinen Server senden fehlt noch. Dazu ist ein Fix fürs WiFi drin, weil das ESP32 Dev Kit v1 aus China ein seltsames Problem mit dem WiFi hat. Dieses benutze ich jetzt für diesen Sensor. Aber es ist vielleicht eine nette Vorlage für andere.

/*********
  Rui Santos
  Complete project details at http://randomnerdtutorials.com  
*********/

// Load Wi-Fi library
#include <WiFi.h>
#include <NetworkClient.h>
#include <ESPmDNS.h>
#include <DNSServer.h>

#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>

// Uncomment the following lines if you're using SPI
/*#include <SPI.h>
#define BME_SCK 18
#define BME_MISO 19
#define BME_MOSI 23
#define BME_CS 5*/

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI

// Replace with your network credentials
const char* ssid = "";
const char* password = "";

// Access Point credentials
const char* ap_ssid = "HdB Wetterstation Receiver";
const char* ap_password = "";

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

// Timing variables for updating the display
unsigned long lastDisplayUpdate = 0;
const unsigned long displayUpdateInterval = 1000; // 1 second

// Timing variables for HTTP client
unsigned long currentTime = millis();
unsigned long previousTime = 0; 
const long timeoutTime = 2000;

const int led = 2;
#define SDA_2 33
#define SCL_2 32

/* Uncomment to initialize the I2C address, uncomment only one, If you get a totally blank screen try the other*/
#define i2c_Address 0x3c //initialize with the I2C addr 0x3C Typically eBay OLED's
//#define i2c_Address 0x3d //initialize with the I2C addr 0x3D Typically Adafruit OLED's

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1   // QT-PY / XIAO

Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1, OLED_RESET);

// Variables for display power control
#define BOOT_BUTTON_PIN 0  // GPIO0 is the Boot button pin
//#define DISPLAY_POWER_PIN 2  // GPIO2 to control the display power

bool displayOn = true;
// DNS-Server auf Port 53
DNSServer dnsServer;

// Startzeitpunkt
unsigned long startTime;
const unsigned long interval = 5 * 60 * 1000; // 5 Minuten in Millisekunden

void setup() {
  pinMode(BOOT_BUTTON_PIN, INPUT);
  //pinMode(DISPLAY_POWER_PIN, OUTPUT);
  //digitalWrite(DISPLAY_POWER_PIN, HIGH);  // Turn on the display

  Serial.begin(115200);
  bool status;

  // Default settings
  Wire.begin();
  Wire1.begin(SDA_2, SCL_2);

  if (!bme.begin(0x76, &Wire)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  // Initialize the display
  delay(250); // Wait for the OLED to power up
  display.begin(i2c_Address, true); // Address 0x3C default
 
  display.display();
  delay(2000);

  // Clear the buffer
  display.clearDisplay();

  // Draw a single pixel
  display.drawPixel(10, 10, SH110X_WHITE);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_AP_STA);  // Enable AP-STA mode

  // Fix WiFi Bug
  WiFi.setDualAntennaConfig(-1, -1, WIFI_RX_ANT0, WIFI_TX_ANT0);
  
  // Start the access point
  Serial.print("Setting AP (Access Point)…");
  WiFi.softAP(ap_ssid, ap_password);

  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);
  
  // Connect to Wi-Fi network with SSID and password
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  // DNS-Server konfigurieren
  dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
  dnsServer.start(53, "*", WiFi.softAPIP());
  if (MDNS.begin("esp32")) {
    Serial.println("MDNS responder started");
  }

  server.begin();
  startTime = millis();
}

// Funktion zur Berechnung des Taupunkts
double berechneTaupunkt(double temperatur, double relativeFeuchtigkeit) {
  const double a = 17.27;
  const double b = 237.7;
  double alpha = ((a * temperatur) / (b + temperatur)) + log(relativeFeuchtigkeit / 100.0);
  double taupunkt = (b * alpha) / (a - alpha);
  return taupunkt;
}

void loop() {
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // Print a message out in the serial port
    String currentLine = "";                // Make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) {  // Loop while the client's connected
      currentTime = millis();
      if (client.available()) {             // If there's bytes to read from the client,
        char c = client.read();             // Read a byte, then
        Serial.write(c);                    // Print it out the serial monitor
        header += c;
        if (c == '\n') {                    // If the byte is a newline character
          // If the current line is blank, you got two newline characters in a row.
          // That's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // And a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
            
            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the table 
            client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial;}");
            client.println("table { border-collapse: collapse; width:35%; margin-left:auto; margin-right:auto; }");
            client.println("th { padding: 12px; background-color: #0043af; color: white; }");
            client.println("tr { border: 1px solid #ddd; padding: 12px; }");
            client.println("tr:hover { background-color: #bcbcbc; }");
            client.println("td { border: none; padding: 12px; }");
            client.println(".sensor { color:white; font-weight: bold; background-color: #bcbcbc; padding: 1px; }");
            
            // Web Page Heading
            client.println("</style></head><body><h1>ESP32 with BME280</h1>");
            client.println("<table><tr><th>MEASUREMENT</th><th>VALUE</th></tr>");
            client.println("<tr><td>Temp. Celsius</td><td><span class=\"sensor\">");
            client.println(bme.readTemperature());
            client.println(" *C</span></td></tr>");  
            client.println("<tr><td>Temp. Fahrenheit</td><td><span class=\"sensor\">");
            client.println(1.8 * bme.readTemperature() + 32);
            client.println(" *F</span></td></tr>");       
            client.println("<tr><td>Pressure</td><td><span class=\"sensor\">");
            client.println(bme.readPressure() / 100.0F);
            client.println(" hPa</span></td></tr>");
            client.println("<tr><td>Approx. Altitude</td><td><span class=\"sensor\">");
            client.println(bme.readAltitude(SEALEVELPRESSURE_HPA));
            client.println(" m</span></td></tr>"); 
            client.println("<tr><td>Humidity</td><td><span class=\"sensor\">");
            client.println(bme.readHumidity());
            client.println(" %</span></td></tr>");
            client.println("<tr><td>Dew Point</td><td><span class=\"sensor\">");
            client.println(berechneTaupunkt(bme.readTemperature(), bme.readHumidity()));
            client.println(" *C</span></td></tr>"); 
            client.println("</body></html>");
            
            // The HTTP response ends with another blank line
            client.println();
            // Break out of the while loop
            break;
          } else { // If you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // If you got anything else but a carriage return character,
          currentLine += c;      // Add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println(""); 
  }

  // Handle display update
  if (millis() - lastDisplayUpdate >= displayUpdateInterval) {
    lastDisplayUpdate = millis();
    updateDisplay();
  }

  // Handle Boot button press
  if (digitalRead(BOOT_BUTTON_PIN) == LOW) {  // If the Boot button is pressed
    delay(50);  // Debounce
    if (digitalRead(BOOT_BUTTON_PIN) == LOW) {
      displayOn = !displayOn;  // Toggle the display state
      //digitalWrite(DISPLAY_POWER_PIN, displayOn ? HIGH : LOW);
      if (displayOn) {
        startTime = millis();
        updateDisplay();  // Show the display if it is turned on
      } else {
        display.clearDisplay();  // Clear the display content if it is turned off
        display.display();  // Show the display if it is turned on
      }

      delay(500);  // Short delay to avoid accidental multiple triggers
    }
  }
}

void updateDisplay() {
  if (!displayOn) return;  // Do not update the display if it is off

  if (millis() - startTime >= interval) {
    display.clearDisplay();  // Clear the display content if it is turned off
    display.display();  // Show the display if it is turned on
    displayOn = !displayOn;
    return;
  }

  display.clearDisplay();
  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SH110X_WHITE); // Draw white text
  display.setCursor(0,0);     // Start at top-left corner
  display.println("ESP32 with BME280");
  display.print("Temp: ");
  display.print(bme.readTemperature());
  display.println(" *C");
  display.print("Humidity: ");
  display.print(bme.readHumidity());
  display.println(" %");
  display.print("Pressure: ");
  display.print(bme.readPressure() / 100.0F);
  display.println(" hPa");
  display.print("Altitude: ");
  display.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
  display.println(" m");
  display.print("Dew Point: ");
  display.print(berechneTaupunkt(bme.readTemperature(), bme.readHumidity()));
  display.println(" *C");
  display.display();
}

Genau so ist das, und dazu brauch ich def. keine Messgeräte.
Wir wohnen seit ca. 40 Jahren in unserem Haus, welches damals neu gebaut wurde und wir kennen keinen Schimmel im Haus.

Manche versuchen halt gesunden Menschenverstand durch Technik zu ersetzen.
Den Grund weiß ich nicht. Wenn ich raten soll: Mangel an Erstem oder einfach Spaß am Basteln? Hoffentlich 2. Variante.

Gruß Tommy

1 Like

Das sehe ich genau so und hatte es in meinem Post #11 auch schon angemerkt.