cartes qui ont : sommeil, deep sleep

Bonjour à tous,

Je réalise un projet qui utilise le deep sleep sur ESP32 wroom.

Mai la carte fonctionne mal elle ne dort que 48 à 60 minutes.
Il faudrait qu'elle 'dorme' 23 heures sur 24.

Client disconnected for : 120.00 minutes at ¬ 

2019-12-31  18:56:47
2019-12-31  19:48:34
2019-12-31  20:36:42
2019-12-31  21:32:13

Y a-til d'autres cartes qui ont cette caractéristique? Et qui fonctionnent?

JPDaviau

Bonjour

Montres ton code pour que l'on puisse voir comment tu as configuré la durée du sommeil, il me semble que le sommeil profond de l'ESP32 peut êtr plus long qu'une heure.

Des exemples -solutions trop avancées pour moi:

... coupé pcq trop long .......

#define Threshold 40 /* Greater the value, more the sensitivity */
#define DHTTYPE DHT11   // DHT 11
#define uS_TO_S_FACTOR 1000000UL //for sleep only
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
WiFiServer server(80);

RTC_DATA_ATTR unsigned long HOURS = 7200;  //en secondes
RTC_DATA_ATTR unsigned long delais = (120 * uS_TO_S_FACTOR ); //5 min
RTC_DATA_ATTR unsigned long timeDiff, timeDiff2;
int addDelays = 0;
RTC_DATA_ATTR uint8_t flag;

.......................  code coupé parce que trop long   ............................



void loop() {
  
  if (flag == 1) {
    Serial.println("_410 Time gone before restarted : ");
    Serial.print("now       ");
    Serial.println(myMinutesTime());
    Serial.print("previous -");
    Serial.println(timeDiff);
    Serial.println("=========");
    Serial.print("timeDiff  ");
    timeDiff2 = ((myMinutesTime() - timeDiff));///60000.0
    Serial.print(timeDiff2);
    Serial.println(" minutes");
    Serial.println();
    Serial.print("addDelays/60000.0 : ");
    Serial.println((2*addDelays));
    flag = 0;
  }
  Serial.println();
  Serial.println("_420- Before if (client)  bootCount : " + (String)(++bootCount));
  Serial.println();

  // listen for incoming clients
  WiFiClient client = server.available();
  if (client ) {
    //========&& ((bootCount % 2) == 0)
    Serial.println("_431 - if (client");
    memset(linebuf, 0, sizeof(linebuf));
    charcount = 0;
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        //Serial.write(c);
        //read char by char HTTP request
        linebuf[charcount] = c;
        if (charcount < sizeof(linebuf) - 1) charcount++;
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        //================================================================
        if (c == '\n' && currentLineIsBlank) {
          // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
          float h = dht.readHumidity();
          // Read temperature as Celsius (the default)
          float t = dht.readTemperature();
          double dew = dewPoint(t, h);
          // Read temperature as Fahrenheit (isFahrenheit = true)
          float f = dht.readTemperature(true);
          // Check if any reads failed and exit early (to try again).
          if (isnan(h) || isnan(t) || isnan(f)) {
            Serial.println("Failed to read from DHT sensor!");
            strcpy(celsiusTemp, "Failed");
            strcpy(fahrenheitTemp, "Failed");
            strcpy(humidityTemp, "Failed");
          }
          else
          {
            // Computes temperature values in Celsius + Fahrenheit and Humidity
            hic = dht.computeHeatIndex(t, h, false);
            dtostrf(hic, 6, 2, celsiusTemp);
            float hif = dht.computeHeatIndex(f, h);
            dtostrf(hif, 6, 2, fahrenheitTemp);
            dtostrf(h, 6, 2, humidityTemp);
            val = analogRead(pinToRead);
            delay(2000);addDelays += 2000;
            Serial.print("_376 val = : ");
            Serial.println(val);
            //val = ((val + 2496.24) / 38.7692);
            val = map(val, 3150, 1938, 0, 100); //2019 4100,2438, 2465 1704ay use an exponential function
            aNewLine += myDate();
            aNewLine += " : " + (String)val + "%  Soil Moisture  Temperature: " ;
            aNewLine += (String)t + " °C  Humidity: " + (String)h;
            aNewLine += "%   Heat index: " + (String)hic + " °C   Dew " + (String)dew + "%\n" ;

          }
          Serial.println(aNewLine);
          // apPend(aNewLine);
          long un = myMinutesTime();//returns  minutes
          Serial.print("_495-un: ");
          Serial.println(un); 
          long two = timeDiffData(un);//returns  minutes diff
          Serial.print(" minutes diff: ");
          Serial.println(two); 
          Serial.print("_494-function(function)minutes diff:  "); 
          Serial.println(timeDiffData(myMinutesTime())); 
          Serial.print(" aNewLine  : "); 
          Serial.println(aNewLine);
          const char *result = aNewLine.c_str();
          appendFile(SPIFFS, "/gardenTemp.txt", result);
          for (int stat = decCnt; stat >= 0; stat--)
          {
            if (datArray[stat] != 0)
            {
              Serial.println(datArray[stat]);
            }
            //Serial.println(datArray[stat]);
          }
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          //client.println("Content-Type: image/gif");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println();
          client.println("<!DOCTYPE HTML><html lang=\"fr\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
          client.println("<meta http-equiv=\"refresh\" content=\"30\"></head>");
          client.println("<body style=\"color:#f3d6e1;\"><div style=\"font-size: 3.5rem;color:green;\"><p style=\"text-align:center;\">Météo</p>");
          if (atoi(celsiusTemp) >= 25) {
            client.println("<div style=\"color: #930000;\"><p style=\"text-align:center;\">");
          }
          else if (atoi(celsiusTemp) < 25 && atoi(celsiusTemp) >= 5) {
            client.println("<div style=\"color: #006601;\"><p style=\"text-align:center;\">");
          }
          else if (atoi(celsiusTemp) < 5) {
            client.println("<div style=\"color: #009191;\">");
          }
          client.println("<p style=\"text-align:center;font-size:14pt;\">");
          client.println(myDate());
          client.println("</p><p></p><p style=\"text-align:center;\">");
          client.print(celsiusTemp);
          client.print("&deg;C&nbsp;&nbsp;&nbsp;&nbsp;");
          client.print(fahrenheitTemp);
          client.println(" &deg;F</p><p style=\"text-align:center;\">");
          client.print(humidityTemp);
          client.print("&nbsp;%H&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
          client.print(dew);
          client.println("&nbsp;&nbsp;&deg; Rosé</p><p style=\"text-align:center;\">");
          client.print(hic);
          client.print("&nbsp;&deg;Ressenti&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
          client.print(val);
          client.print("&nbsp;%Soil Moisture</p><p style=\"text-align:center;font-size:12pt;\">");

          for (int stat = decCnt; stat >= 0; stat--) {
            if (datArray[stat] != 0) {
              client.print(datArray[stat] + "
");
            }
          }
          client.print("</p></div>");

          client.print("</body></html>");

          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
          memset(linebuf, 0, sizeof(linebuf));
          charcount = 0;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(20000);
    addDelays += 20000;
    Serial.println("====== 20 000 done =====");
    // close the connection:
    client.stop();
  }//if client && ((bootCount%2) == 0)============
  //  Serial.flush();
  delay(50000);
  addDelays += 50000;
  Serial.println("====== 100 000 done =====");
  Serial.println("_573- Before (_deep_sleep_) bootCount: " + (String)bootCount);
  if ((bootCount % 2) == 0) {
    delayMicroseconds(delais);
    Serial.print("Client disconnected for : ");
    Serial.print((HOURS / 60.0));
    Serial.println(" minutes at ¬ ");
    Serial.print(myDate());
    Serial.println();
    Serial.println();
    timeDiff = myMinutesTime();
    flag = 1;
    gotoSleep();
  }
}

    void gotoSleep(){
    esp_deep_sleep_enable_timer_wakeup(HOURS * uS_TO_S_FACTOR);
    esp_deep_sleep_start(); // esp_light_sleep_start(); //
    //esp_sleep_enable_timer_wakeup(HOURS * uS_TO_S_FACTOR);
      }

autre solution, 'soft', un peu bâtarde, inspirée de ce qui se fait avec les AVR :
réveil toutes les heures, incrémentation d'un compteur sauvegardé en RTCRAM, rendormissement immédiat si la 24e heure n'est pas atteinte

Remarque : il me semble avoir lu des choses contradictoires (32bits vs 64 bits) concernant le nombre maximal de µS du sommeil profond mais je n'ai jamais tenté de dépasser l'heure n'ayant pas encore rencontré le besoin

A niveau de l'IDF Espressif la doc montre un format uint64_t pour le temps de sommeil maximal exprimé en µs
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/sleep_modes.html
idf max deepsleep.png

Espérons que la surcouche Arduino ne vienne pas gâter la sauce... :wink:

idf max deepsleep.png

Il y a aussi

void esp_deep_sleep(uint64_t time_in_us)

qui lance le sommeil pour la durée spécifiée.

Au passage 2^64 microsecondes ça fait pas loin de 600 000 ans, donc il y a de la marge...

Comment je peux vérifier le return?

String ret = esp_sleep_enable_timer_wakeup(HOURS * uS_TO_S_FACTOR);

Serial.println(ret); ?

ou

dois-je déclarer dans ma fonction :

esp_err_t esp_sleep_enable_timer_wakeup(HOURS * uS_TO_S_FACTOR);

ou

esp_err_t ret = esp_sleep_enable_timer_wakeup(HOURS * uS_TO_S_FACTOR);
Serial.println(ret); ?

Essaites tout simplement avec la fonction signalée par lesept qui ne renvoie pas de valeur (la fonction que l'ai indiqué n'est peut être pas accessible par l'IDE Arduino)

 esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  esp_deep_sleep_start();

pour mettre en sommeil avec réveil a bout du temps fixé içi par exemple par TIME_TO_SLEEP en secondes
Juste pour tester la possibilité de réveil au bout d'environ 24h

De mon côté je viens de lancer l'exemple TimerWakeUP du groupe d'exemples ESP32/DeepSleep avec la valeur 7200 pour TIME_TO_SLEEP...... RdV dans 2h !
Réveil au bout de 2h constaté içi :
sommeil 2h.png

sommeil 2h.png

Le reveil de l'ESP32 au bout de 2h est donc OK

Nouveau test lançé pour 10h de sommeil...... RdV demain !

//***** parametres deepSleep **********************
#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  36000  // 36000 secondes , soit 10 heures

al1fch:
Le reveil de l'ESP32 au bout de 2h est donc OK

Nouveau test lançé pour 12h de sommeil...... RdV demain !

//***** parametres deepSleep **********************

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  43200  // 43200 secondes , soit 12 heures

:grin:

Bonsoir al1
test pour test

j'aurais mis une valeur > 65536 plutôt que 43200 , du genre 70000 : "on est pas/plus à 5 minutes prés " 8)

Bonsoir Artouste
j'avais un bug dans mon dernier test.......il a déjà été relancé sur 10h (36000 secondes).....si positif le prochain sera sur 24h !!

Je viens de me rendre compte que les exemples récents utilisent la fonction

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

alors que mes codes passés en étaient restés à cette fonction:

esp_deep_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

J'ai l'impression que la première prend un uint64_t en paramètre quand la seconde , dépréciée, prend un uint32_t.

D'ou l'intérêt de partir des exemples actuels (à défaut de doc de référence actualisée) et non des tutoriels .....qui copient des tutoriels ... basés sur des données obsolètes. :wink:

(il manque une notion de date de péremption pour nombre de tutoriels ou du moins l'indication des versions d'IDE et de 'core' utilisés !!)

J'attends les preuves pour conclure !!

Bonjour

Réveil de l'ESP32 au bout de 10h : test concluant (durée exacte sur mon module : 9h53)
Nouveau test lançé sur 24h
à demain matin !

Pour info le code est celui de l'exemple TimerWakeUP + un envoi de donnée vers ThinkSpeak à chaque réveil
IDE Arduino 1.8.10 et un Core ESP32/Arduino v 1.0.4

Bonjour

Mon ESP32 s'est reveillé ce matin environ 24h après la mise en sommeil.(20' d'avance)

(erreur 1,5% sur la durée, dans la tolérance de 5% pour l'horloge RC à 150kHz utilisée par défaut pendant le deep-sleep)

--> L'ESP32 est donc capable de réaliser ton objectif, Jean24816

Grand Merci.
Je peux développer mon code un peu plus. Je fais des tests avec ce code pas bête:

Ajuste le temps de sommeil pour les problèmes de wifi et pour les périodes de jour ou de nuit.

Heureusement que le jardin ne se réveille qu'au printemps. :O)

/*
   https://forum.arduino.cc/index.php?topic=626840.0
   I want to set a deep sleep period for the board more that 1h.
   I have wrote the code and it compiles fine. My problem is that
   when I execute and use sleep period greater than the value of
   long signed int (in micro seconds) it doen't work..
   The reason of micro seconds is that the definition of the
   wake up timer must be done in micro seconds.
   When I set a timer less than long signed int
   ( <2.147.483.647 micro seconds) it works fine.
   Also I tried to use the uint64_t data type but
   it doesn't work either.
*/

#include <WiFi.h>
#include <NTPClient.h> //For NTP Server
#include <WiFiUdp.h> //For NTP Server
#include "esp_deep_sleep.h"


#define uS_TO_S_FACTOR 1000000ULL  // Conversion factor for micro seconds to seconds for deep sleep usage
RTC_DATA_ATTR int TIME_TO_SLEEP_WiFi = 10;    // Time to sleep in case of unavailable WiFi (This is the first sleep)
#define TIME_TO_SLEEP_MAX 80ULL      // MAX Time to sleep in case of repeatable unsuccessfull connection attempts
#define TIME_TO_SLEEP_CASE1 3600ULL // Time to sleep (3600s = 1h) in if the time is 06:00 - 20:00 
#define TIME_TO_SLEEP_CASE2 18000ULL //2.5h Time to sleep (9000s = 2.5h) if time isn't 06:00 - 20:00 
#define DAY_PERIOD_START 60000  // 06:00 in the morning
#define DAY_PERIOD_END 200000  // 20:00 in the morning
RTC_DATA_ATTR int bootCount = 0;
const char* ssid     = "23JANVIER-2012_Network_1";
const char* password = "cvq1-3bhy-afp6";
//http://189.143.0.107/
//24:6F:28:17:F9:50

long timezone = -5;
uint8_t daysavetime = 1;
struct tm tmstruct;
unsigned long currentMillis;
const unsigned long period = 10000; //set the period that esp32 will try to connect with WIFI in ms

// Variables to save date and time
String formattedDate;
String timeStamp;

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);

void print_wakeup_reason() {
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch (wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}


void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  ++bootCount;
  /*------------------------------------------------------------------------------------------------------*/
  while (WiFi.status() != WL_CONNECTED) {

    currentMillis = millis(); //Assign the ms have been passed since ESP32 code start running
    Serial.println("Boot number: " + String(bootCount));

    //Print the wakeup reason for ESP32
    print_wakeup_reason();

    if (currentMillis > period) {
      WiFi.disconnect();
      esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP_WiFi * uS_TO_S_FACTOR);
      Serial.println("Going to sleep now for " + String(TIME_TO_SLEEP_WiFi) + " Seconds" + " Due to WiFi unavailability");
      esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
      Serial.println("Configured all RTC Peripherals to be powered down in sleep");
      Serial.println("Sleep for ..................." + String(TIME_TO_SLEEP_WiFi));

      while (TIME_TO_SLEEP_WiFi < TIME_TO_SLEEP_MAX) { // While the sleep time is less than the predefined limit keep double the sleep time. When the sleep time exceeds the limit then keep a constant sleep time equal to the limit.
        TIME_TO_SLEEP_WiFi = TIME_TO_SLEEP_WiFi * 2; // Double the sleep time
        esp_deep_sleep_start();
      }

      TIME_TO_SLEEP_WiFi = TIME_TO_SLEEP_MAX;            // Set the sleep time equal to the limit
      esp_deep_sleep_start();
    }

    Serial.println("Connecting to WiFi..");
    delay(1000);

  }
  /*-----------------------------------------------------------------------------------------------------*/
  Serial.print("Connected to ");
  Serial.print(ssid);
  Serial.println(" network");
  Serial.println(WiFi.macAddress());
  Serial.println(WiFi.RSSI());
  TIME_TO_SLEEP_WiFi = 10;
  /*-----------------------------------------------------------------------------------------------------*/
  timeClient.begin(); // Initialize a NTPClient to get time
  // Set offset time in seconds to adjust for your timezone, for example:
  timeClient.setTimeOffset(-18000); //Cyprus Time Zone GMT -5 = -18000
  /*-----------------------------------------------------------------------------------------------------*/
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
  Serial.println("Configured all RTC Peripherals to be powered down in sleep");
  Serial.println("NTP Client initialized");
  delay(100);
}

void loop() {

  while (!timeClient.update()) {
    timeClient.forceUpdate();
  }
  // The formattedDate comes with the following format:
  // 2018-05-28T16:00:13Z
  formattedDate = timeClient.getFormattedDate();
  Serial.print("Date: ");
  Serial.println(formattedDate);

  Serial.print("The time is: ");
  String timeE = formattedDate.substring(formattedDate.indexOf("T") + 1, formattedDate.length() - 1);
  Serial.println(timeE);

  // Extract tha time part into clear integer
  int splitT = formattedDate.indexOf("T"); // The output is the number 10 , splitT=10 (Start counting from 0)
  String timeStamp1 = formattedDate.substring(splitT + 1, splitT + 3 ); // splitT+1 = 11, formattedDate.length()-1 = 19  --> 16:00:13Z
  String timeStamp2 = formattedDate.substring(splitT + 4, splitT + 6 );
  String timeStamp3 = formattedDate.substring(splitT + 7, splitT + 9 );
  timeStamp = timeStamp1 + timeStamp2 + timeStamp3;
  int result = timeStamp.toInt();
  Serial.println("_138-int result = timeStamp.toInt(); ");
  Serial.println(result);

  // Check the time in order to adjust the time to sleep period
  if (result >= DAY_PERIOD_START && result <= DAY_PERIOD_END) {
     esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP_CASE1 * uS_TO_S_FACTOR);
     esp_deep_sleep_start();
    } else {
  Serial.println("Going to sleep for 2.5h");
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP_CASE2 * uS_TO_S_FACTOR);
  esp_deep_sleep_start();
  }

}

JPD

Normalement, quand on met l'ESP32 en deep sleep, il se réveille et relance le setup (il y a peut-être des options pour reprendre l'exécution au point où il l'a laissée, mais je ne sais pas si ça existe pour le deep sleep). Du coup, toutes les instructions sont mises dans le setup, et la loop reste vide puisqu'on vise une consommation minimale.

Donc, tu peux déplacer le contenu de la loop à la fin du setup. Ca ne changera pas grand chose, mais ça sera plus propre...

Le reveil du deep-sleep est exclusivement un redémarrage, un 'redémarrage à chaud' : une petite RAM reste alimentée pendant le sommeil et on retrouve son contenu au réveil.
Dans mes applications de ce type le préfère laisser loop() vide pour mettre en évidence le fonctionnement.

lesept:
Normalement, quand on met l'ESP32 en deep sleep, il se réveille et relance le setup (il y a peut-être des options pour reprendre l'exécution au point où il l'a laissée, mais je ne sais pas si ça existe pour le deep sleep). Du coup, toutes les instructions sont mises dans le setup, et la loop reste vide puisqu'on vise une consommation minimale.

Donc, tu peux déplacer le contenu de la loop à la fin du setup. Ca ne changera pas grand chose, mais ça sera plus propre...

Le placer dans un while ou simplement le copier-coller (avec les ajustements qui s'imposent)?

Juste les déplacer, sans rien changer.