ESP 8266 D1 Deepsleep aufwecken fällt aus

Hallo,
ich brauch noch mal einen Tipp von Euch.
ich habe draußen einen D1 mit einem BME280 mit Aku und einer Solarzelle. Der sendet alle halbe Stunde seine Messwerte mittels TCP an einen ESP32. Da werden die Daten ausgewertet und mittels Chart angezeigt. Das Ganze läuft jetzt seit fast drei Jahren zuverlässig. Nun habe ich festgestellt das seit etwa 2 Wochen 5-6 mal ( Tendenz steigend) innerhalb von 24 Stunden jeweils ein Messwert fehlt. Entweder zur vollen Stunde oder zur halben. Da ich zunächst eine kalte Lötstelle vermutet habe , ist alles auf Streifenraster ohne Schutzlack , habe ich das Teil ausgebaut und nachgelötet , sah alles besser aus als ich gedacht hatte nach zwei Wintern. Das Teil hängt im Trockenen an der Hauswand. War aber anscheinend nicht der Fall, der Fehler ist immer noch da. :sleepy:
Normalerweise kommen die Messwerte um hh.28.55 und hh.58:55 etwa rein. Dabei ist das jeweils die aktuelle Zeit vom ESP32. Ich hab das extra eine Minute nach vorne geholt, damit der ESP die aktuellen Daten jeweils zur vollen Stunde sicher hat.

Im Fehlerfall fehlt dann allerdings eine Messung, dafür ist die nächste aber ein paar Minuten später. Das sieht also etwa so aus.

Hier fehlt z.B die Messung um 8:28 und dafür ist die Messung die eigentlich um 8:58 sein sollte erst um 9:07 gekommen. Die nächste 9:28 war dann wieder in der Reihe. 9:58 fehlt wieder dafür dann 10:36.
Zudem habe ich festgestellt das die Zeiten mit der Ereignisliste in der Fritzbox identisch sind und im Fehlerfall auch keine Anmeldung in der Fritzbox erfolgt. Ich galube jetzt nicht mehr das es am Sketch liegt. Da im Fehlerfall die Zeit zwischen zwei Messungen allerdings dann etwa 67-68 min (etwa maxzeit) ist denke ich ehr daran das die RTC für den Deep-Sleep dann nicht mehr richtig läuft und es sich somit ehr um ein Hardware Problem des D1 handelt.
Kann es sein das der Speicher an der Stelle an der die Sleepzeit abgelegt wird Möhre wird. ?
Ich hab jetzt keinen D1 mehr hier, sonst würde ich das probieren.
Haltet Ihr meine Vermutung für möglich ?
Heinz
hier der Sketch

/* Wetterdaten  mit ESP und BME 280
    Hardware Wemos D1 , BME280
    Stromversorgung Aku 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 = "xxx";
const char* password = "yyyy";

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

const char*host = "192.168.178.21";   //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 uint32_t messcycle = 1800UL;   // Messzyklus sekunden
uint32_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,
  BME280I2C::I2CAddr_0x77 // I2C address. I2C specific.
);
BME280I2C bme(settings);

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

  Serial.begin(74880);
  //Serial.setDebugOutput(true);
  Serial.println("start wire");
  // I2C Bus starten an pin D1=SCL u pin D2=SDA
  Wire.begin();
  //delay(200);
  conectWIFI();   // einloggen

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

  Serial.println(F("Waiting for time "));
  while (!time(nullptr)) {
    Serial.print(".");
    delay(500);
  }
  delay(1000); // warten auf NTP Zeit
  byte count = 0;
  while (!bme.begin()) {
    delay(100);
    Serial.println(F(" Kann BME 280 Sensor nicht finden"));
    // Wenn keine Verbindung möglich beenden
    count++;
    if (count == 10) {
      readtime();
      //sendTCP();
      calcnext();
      ESP_sleep(messcycle);
    }
  }
}
//-------------- Loop ----------------
void loop() {

  // 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(sleeptime);  // ESP in sleepmodus
  // }

}

//================= funktions ======================
void conectWIFI() {
  byte maxzeit = 0;
  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(".");
    maxzeit++; // max Zeit
    if (maxzeit > 30) ESP_sleep(messcycle);
  }
  Serial.print(F(" connected \nlocale 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(1000);
    return;
  }
  Serial.println(F("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(F("closing connection"));
  delay(100);
  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("Time is %02u-%02u-%4u  ", day, month, year);
  Serial.printf("%02u:%02u:%02u \n", hour, minute, second);

}

//----------------- ESP sleep
void ESP_sleep(uint32_t sl) {
  delay(300);// noch warten sonst fehlen Telegramme
  // anpassung der esp Frequenz +5%
  sl = sl + sl * 5UL / 100UL;
  Serial.printf("Korr. Sleepwert %u Laufzeit war %lums\n", sl, millis());
  WiFi.disconnect(true);
  delay(1);
  WiFi.mode(WIFI_OFF);
  WiFi.forceSleepBegin ();
  delay(1);
  ESP.deepSleep(sl * 1000000, WAKE_NO_RFCAL);
  delay(1);
}
//----------------- Nexte weckzeit berechnen
// nächstes Wecken soll bei minuten 28 u 58 sein
// wenn nächste sleepzeit < 5 min dann ausfallen lassen
void calcnext() {
  uint32_t actsec = 0;

  if (year < 2000) {  // Datum war falsch
    sleeptime = messcycle -  millis() / 1000UL;
  }
  else {
    actsec = minute * 60UL + second;
    actsec = actsec + 60UL; // messung um 1 minuten vorlegen
    sleeptime = messcycle - actsec % messcycle;
    sleeptime = sleeptime - millis() / 1000UL;  // Laufzeit abziehen

    if (sleeptime < 300UL) {    // wenn < 5 min dann ausfallen lassen.
      sleeptime = messcycle + sleeptime;
    }
    Serial.printf("akt.Sekunde %u Messcycle %us Sleeptime %us \n", actsec, messcycle, sleeptime);
  }
}

Verbindung D0 <-> Reset noch ordentlich vorhanden? D0 Zieht ja nach dem Sleep kurzzeitig Reset runter. Hängt noch mehr an Reset?

Etwas über eine Stunde klingt nach maximal Sleep Zeit.

Hallo,
ja das war auch mein erster Ansatz , deshalb hab ich ja nochmal alles nachgelötete was in Frage kommen könnte, auch die pins am D1. Ich kann mir eigentlich nicht mehr vorstellen das es daran liegen könnte.
ich glaube ich werde mal welche bestellen und einen tauschen.
Heinz

Hallo,
ich muss nochmal auf das Thema kommen, es lag nicht an der Hardware D1 getauscht Problem immer noch vorhanden. Jetzt bin ich im Sketch über die Berechnung der sleepzeit gestolpert und vermute da einen Überlauf der dazu führt das letztlich die maximale sleepzeit des ESP zum tragen kommt und nicht das was da eigentlich drin sein sollte. Allerdings habe ich mit der Kontrollausgabe auf dem Monitor bisher keine falschen Werte festgestellt.
Dabei geht es um den Abschnitt:

    actsec = minute * 60UL + second;
    actsec = actsec + 60UL; // messung um 1 minuten vorlegen
    sleeptime = messcycle - actsec % messcycle;
    sleeptime = sleeptime - millis() / 1000UL;  // Laufzeit abziehen

actsec, sleepzeit, messcycle sind als uint32_t definiert, minute, second als byte.
modulo erwartet eigentlich int Werte.
Insofern könnte da was in die Hose gehen. Macht es Sinn das zu ändern und auf int zu wechseln. allerdings ist es ein ESP der arbeite ja auch bei int mit 32 bit, insofern kann da ja eigentlich nicht irgendwas aus einem Register aus dem H-Word falsch übernommen worden sein, oder wie seht Ihr das?

Heinz

Das glaub ich nicht. Allerdings habe ich auch calcnext() nicht verstanden.
Das wäre meine Rechnung (ungetestet):

void calcnext()
{
  if (minute >= 28 && minute <= 56)  // einfache Rechnung
  {
    // Nächster Weckpunkt 57
    sleeptime = ((57 - minute) * 60UL) + 60UL - sekunden;
  }
  else                               // Minutenüberlauf berücksichtigen
  {
    // Nächster Weckpunkt 27
    //             bin zu spät aufgewacht?   Oder nicht
    minute < 27 ?  sleeptime = 27 - minute : 60UL - minute + 27;
    sleeptime *= 60UL;
    sleeptime += 60UL - sekunden;
  }
  if (sleeptime < 300) sleeptime += messcycle;
  Serial.printf("akt.Sekunde %u Messcycle %us Sleeptime %us \n", actsec, messcycle, sleeptime);
  sleeptime *= 1000UL; // umrechnen in millisekunden
}

Danach würde ich zum Zeitpunkt des Schlafen gehens die Zeit zwischen readtime() und "jetzt" noch abziehen , und gut ist.

Im setup() machst Du sowohl im connectWIFI() als auch im bme.begin()

das könnte der Hinweis sein, für den verspäteten nächsten Messzyklus, da Du ja die Laufzeit bis dahin nicht mitnimmst.

Und dann erklär mal, was

wozu das. Ist das eine empirische Fehlerbehandlung? :wink:

Hallo,
@my_xy_projekt danke für Deine Antwort, ja ich bin ein bisschen am verzweifeln. Ich fang mal hinten an.

sl = sl + sl * 5UL / 100UL;

ist schon ziemlich lange drin, ich hatte festgestellt das die Zeit nicht stimmt und eigentlich immer 5% zu klein war, also habe ich den intergalaktischen Faktor eingefügt.

das zweimalige aufrufen der ESP_sleep (messcycle) ist vor einem Jahr etwa reingekommen. Hintergrund ist der, das für den Fall das keine Wlan Verbindung zu Stande kommt das Ding erst mal wieder pennen geht. Es gab mal einen Stromausfall bei uns der fast 10 Stunden bestand. Anschließend war der Aku von dem Modul halb leer weil der Sleep nicht kam und das Ding stundenlang versucht hat eine Verbindung aufzubauen. Bei der Gelegenheit habe ich dann gleiches für den Fall eingebaut das der Sensor nicht gefunden wird, bzw die NTP nciht gekommen oder falsch ist.
Eine kompletter Zyklus dauert etwa 5s , wenn ich also die Laufzeit für den Fall nicht berücksichtige wird er höchstens 5-10s zu lange schlafen gehen denke ich.

Deine Function schaue ich mir mal an und probiere das mal.
Gruß Heinz

Das sollte aufgelöst werden können.
Die Funktion ist blind geschrieben.
Da stimmen die Zeiten nicht ganz, weil ich die sekunden ja noch mit aufaddiere. und an Stelle von second hab ich sekunden drin stehen.
Das müsste richtiger sein:

void calcnext()
{
  if (minute >= 28 && minute <= 57)  // einfache Rechnung
  {
    // Nächster Weckpunkt 58
    sleeptime = ((57 - minute) * 60UL) + 60UL - second; // von jetzt bis 57 + sekunden
  }
  else                               // Minutenüberlauf berücksichtigen
  {
    // Nächster Weckpunkt 28
    //             bin zu spät aufgewacht?   Oder nicht
    minute < 27 ?  sleeptime = 27 - minute : sleeptime = 60UL - minute + 27;
    sleeptime *= 60UL;
    sleeptime += 60UL - second;
  }
  if (sleeptime < 300) sleeptime += messcycle;
  //Serial.printf("akt.Sekunde %u Messcycle %us Sleeptime %us \n", actsec, messcycle, sleeptime);
  sleeptime *= 1000UL; // umrechnen in millisekunden
}

Ich hab kein ESP und die BMP-Lib hab ich auch nicht gesucht , dann hät ichs wenigstens versucht zu kompilieren...

Dann würden 90 sekunden fehlen?

Hallo,
sieht so aus als hätte ich es gefunden. Es lauft jetzt seit 4 Tagen fehlerfrei.

Ich habe alle Berechnungen der Sleepzeit auf integer umgestellt und den ESP Aufruf geändert . irgendwo habe ich was gefunden das der Sleepwert im ESP ein 64 bit wert ist. der Aufruf sieht jetzt so aus.
ESP.deepSleep(sl * 1000000ULL, WAKE_NO_RFCAL);

wobei Sl ein int ist.

Gruß Heinz

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.