Outdoor Wetterstation mit Wemos D1 und Deep Sleep

Hallo,

derzeit bin ich dabei eine Outdoor Wettersensor mit BME280 und Aku Solar Betrieb zu bauen.

Aufgabe :
Ein Wemos D1 mit BME280 soll alle 30 Minuten aufwachen , allerdings zu festen Uhrzeiten ( volle Stunde / halbe Stunde) , seine Daten an einen Server senden und anschliessend wieder schlafen gehen.

Mit einer festen Zeitangabe für den Deepsleep hat das natürlich nicht geklappt, die Zeit ist ziemlich schnell weggelaufen. Also holt sich der Wemos die aktuelle Uhrzeit von der Fritzbox ( NTP) und berechnet nach getaner Arbeit seine neue Schlafzeit. Ist die kleiner als eine Minute dann wird der nächste Zyklus übersprungen. Da das Ganze mit Aku und einer Solarzelle läuft sollte natürlich nicht unnötig oft aufgeweckt werden. Die im Server gespeicherten Daten enthalten die Zeit des Servers wann Daten angekommen sind, damit ich das kontrollieren kann.

Zudem hab ich festgestellt das die berechnete Zeit gundsätzlich etwa 5% zu kurz ist deshalb gibt es eine Anpassung dazu.

Innerhab der Wohnung hat das ziemlich genau geklappt , schwankte schon mal um ein paar Sekunden. Seit das Ding draussen steht schwankt es um +-15s. Das ganze läuft jetzt seit einer Woche in der Testphase. Heute hat nun die Sonne drauf geschienen, die gemessene Temperatur war auch etwa 35 Grad. Dabei wurde dann der Wemos mehr als 1minute zu früh wieder wach, hat seine Arbeit gemacht und natürlich ist er nach etwas mehr als einer Minute erneut wieder wach geworden.

Zusammengefasst

bei 10-25 Grad scheint die Deep Sleep Zeit für 1800s innerhalb +-15s (1%) zu passen + die 5% Grund-Anpassung.
bei 35 Grad war die Sleepzeit etwa 90s zu kurz. -> 5%

ich schliesse daraus das die Frequenz Temperatur abhängig ist, macht ja auch Sinn. höhere Temperatur -> höhere Frequenz = Sleepzeit zu kürzer. Nun meiner Frage ist das im normlen Bereich ? oder habe ich ein extrem schlechtes Stück erwischt. :slight_smile: Zudem wird er womöglich im Winter dann in eine Winterschlaf verfallen und gar nicht mehr wach werden. :slight_smile: Damit wäre dann mein derzeitiges Konzept Banane.

Derzeit sehe ich als Lösung
Ich müsste also das Fenster grösser machen und 2-3 Minuten Abweichung zulassen.

kürzere Schalfzeiten, kontollieren ob die Zeit zum senden erreicht ist ... Würde ich aber wegen des Akus nur ungern machen. für ganze Hardware hab ich im Sleepmodus am Aku 0,5mA gemessen. Die gesamte Wachzeit beträgt etwa 6-7s . Das sollte also eigendllich auch im Winter ganz ohne Sonne für 6-8 Wochen, auch bei kaltem Aku, reichen. Muss ich halt dann mal sehen.

Hardware Wemos D1 , BME280
Stromversorgung Aku LIPO 18650 3,7V 2500mAh
Solarzelle 6V 100mA
Laderegler TP4056 mit Unterspannungsschutz
Step Up Wandler auf 5V
Akuspannung gemessen an A0 über zus.200KOhm (Messbereich 5,2V)

Gruß Heinz

hier noch der Sketch

/* Wetterdaten  mit ESP und BME 280
    Hardware Wemos D1 , BME280
    Stromversorgung Aku LIPO 18650 3,7V 2500mAh
    Solarzelle 6V 100mA
    Laderegler TP4056, Step Up Wandler auf 5V
    Akuspannung gemessen an A0 über zus.200KOhm (Messbereich 5,2V)
*/

#include <ESP8266WiFi.h>

#include <time.h>
#include <BME280I2C.h>
#include <Wire.h>

const char* ssid = "xxxx";
const char* password = "xxxx";

IPAddress staticIP(192, 168, 178, 10);  // eigene PI
IPAddress gateway(192, 168, 178, 1);  // Fritzbox Heimnetz
IPAddress subnet(255, 255, 255, 0);

const char*host = "192.168.178.10";   //server IP
//uint16_t localPort = 4211;
uint16_t hostPort = 4210;             // Host Port


float temp, hum, pres, Vcc;
unsigned long altzeit;
int devAdress = 1;
int year;
byte month, day, hour, minute, second;
const uint16_t messcycle = 1800;   // Messzyklus sekunden
uint16_t sleeptime = 0;     // ESP deep Sleep Zeit

//ADC_MODE(ADC_VCC);

// BME settings
BME280I2C::Settings settings(
  BME280::OSR_X1,
  BME280::OSR_X1,
  BME280::OSR_X1,
  BME280::Mode_Forced,
  BME280::StandbyTime_1000ms,
  BME280::Filter_Off,
  BME280::SpiEnable_False,
  0x77 // I2C address. I2C specific.
);
BME280I2C bme(settings);

//---------------- Setup--------------
void setup() {

  Serial.begin(115200);
  Serial.println("wire");
  // I2C Bus starten an pin D1=SCL u pin D2=SDA
  Wire.begin();
  delay(200);
  while (!bme.begin()) {
    Serial.println(F(" Kann BME 280 Sensor nicht finden"));
    // Wenn keine Verbindung möglich beenden
    calcnext();
    ESP_sleep();
  }

  conectWIFI();   // einloggen

  configTime(0, 0, "192.168.178.1"); // locale Fritzbox
  setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);  // locale Zeit einstellen mit Sommerzeit

  Serial.print("Waiting for time ");
  while (!time(nullptr)) {
    Serial.print(".");
    delay(1000);
  }
  delay(1000); // warten auf NTP Zeit
}
//-------------- Loop ----------------
void loop() {

  if (WiFi.status() != WL_CONNECTED) {
    conectWIFI();
    delay(1000);
  }
  // if (millis() - altzeit >= sleeptime * 1000UL) {
  altzeit = millis();
  readtime();   // aktuelle Zeit lesen
  messen();     // Messdaten holen
  sendTCP();    // daten an Server senden

  calcnext();   // nexte Weckzeit berechnen
  ESP_sleep();  // ESP in sleepmodus
  // }

}

//================= funktions ======================
void conectWIFI() {

  WiFi.persistent(false);   // daten nicht in EEprom
  WiFi.mode(WIFI_STA);
  Serial.printf("Connecting to %s ", ssid);

  WiFi.config(staticIP, gateway, subnet);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connected");
  Serial.print("local IP:");
  Serial.println(WiFi.localIP());


}
// ---------- messen -------------------------
void messen() {

  BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
  BME280::PresUnit presUnit(BME280::PresUnit_hPa);

  bme.read(pres, temp, hum, tempUnit, presUnit);


  // umrechnen auf Meereshöhe Luftruck wird immer auf Meereshöhe bezogen
  // vereinfachte Rechnung 12.2mbar /100m mehr
  // Wohnort liegt ca. auf 150m

  pres = pres + 12.2 * 150 / 100;
  temp = temp - 2.2;  // Temp anpassen
  Vcc =  analogRead(A0) / 1024.0 * 5.20;// zus. 200KOhm Messbereich jetzt 5,2V
}

// -------------- send TCP -------------------------
void sendTCP() {
  Serial.printf("connecting to %s %d \n", host, hostPort);
  WiFiClient client;
  if (!client.connect(host, hostPort)) {
    Serial.println("connection failed");
    delay(5000);
    return;
  }
  Serial.println("sending data to server");
  Serial.printf("%4d;%4.2f;%4.2f;%4.2f;%4.2f\n", devAdress, temp, hum, pres, Vcc);
  client.printf("%4d;%4.2f;%4.2f;%4.2f;%4.2f", devAdress, temp, hum, pres, Vcc);
  Serial.println("closing connection");
  client.stop();
}

// ------------------Datum und zeit auslesen
void readtime() {
  time_t now = time(nullptr);
  struct tm*timeinfo;
  time(&now);
  timeinfo = localtime(&now);
  year = 1900 + timeinfo->tm_year;
  month = 1 + timeinfo->tm_mon;
  day = timeinfo->tm_mday;
  hour = timeinfo->tm_hour;
  minute = timeinfo->tm_min;
  second = timeinfo->tm_sec;
  // Serial.printf("%02u-%02u-%4u\n", day, month, year);
  Serial.printf("%02u:%02u:%02u \n", hour, minute, second);

  if (year < 2000) {  // das war nix Zeit fasch
    ESP.restart();
  }
}

//----------------- ESP sleep
void ESP_sleep() {
  delay(500);// noch warten sonst fehlen Telegramme
  // anpassung der esp Frequenz +5%
  sleeptime = sleeptime + sleeptime * 5 / 100;
  Serial.printf("gehe schlafen für %u s Laufzeit war %lu ms\n", sleeptime, millis());
  WiFi.disconnect(true);
  delay(1);
  WiFi.mode(WIFI_OFF);
  WiFi.forceSleepBegin ();
  delay(1);
  ESP.deepSleep(sleeptime * 1000000, WAKE_NO_RFCAL);
  delay(1);
}
//----------------- Nexte weckzeit berechnen
void calcnext() {
  uint16_t actsec = 0;
  actsec = minute * 60 + second;
  sleeptime = messcycle - actsec % messcycle;
  // sleeptime = sleeptime - millis() / 1000;  // Laufzeit abziehen

  if (sleeptime < 60) {
    sleeptime = messcycle + sleeptime;
  }
  Serial.printf("akt.Sekunde %u Messcycle %u Sleeptime %u \n", actsec, messcycle, sleeptime);
}

Hallo Heinz,

Deine Annahme mit dem Verhältnis Temperatur zu Frequenz ist richtig. Eine Lösung wäre eine RTC wie zum Beispiel die DS3232 zu verwenden. Diese hat eine Temperatur Stabilisierung drin und kann dir den Mikrocontroller zu bestimmten Zeiten aufwecken. So hast du auch immer eine ziemlich genaue Uhrzeit die sogar alle paar Monate mal mit der NTP syncronisiert werden könnte. Hab das zwar selbst noch nicht getestet aber mich mal eingelesen.

http://www.killerhippy.de/archives/2015/04/den-arduino-schlafen-schicken-und-von-der-realtimeclock-wieder-aufwecken.html?show_id=30#bk_30

Eine Sache noch zu dem BME280:
Die angezeigte Temperatur ist die intere Temperatur zum errechnen der Luftfeuchte. Heißt sie weicht leicht von der Umgebung ab. Bei mir sind es fast 3°C die zuviel angezeigt werden. Wenn du in Google "BME280 Temperatur" eingibst bekommst du schon einiges Vorgeschlagen mit "zu hoch", "Genauigkeit", Kalibrierung",...

Gruß
Frank

Hallo
Danke für Rückmeldung, so genau muss das ja nicht , wenn die Messung in einem Zeitfenster von 3-4 Minuten ankommt reicht das ja. Mir ging es ehr darum ob meine Ergebnisse im üblichen Rahmen liegen, oder ob mein D1 ehr Schrott ist.

Hab mich jetzt dazu entschieden das wenn die Zeit zum nächsten Wecken <5 min ist , der Zyklus übersprungen wird.

Ja die Temperatur ist bei den beiden BME 280 die ich habe 2-3 Grad zu hoch. Es handelt sich aber um einen Offset also kein echtes Problem .

Heinz

Achso ok, dachte nur weil du das so genau analysiert hattest :wink:

So ist es, nur ist es vielen unbekannt...

Gruß

Frank