IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

ESP32C3 : sauvegarde de datas en mémoire


Sujet :

Arduino

  1. #1
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut ESP32C3 : sauvegarde de datas en mémoire
    Bonjour à tous

    Dans mon projet actuel , j'ai changé de support ESP8266 Wemos D1 => ESP32C3

    Préalablement avec ESP8266 je sauvegardais des datas ( SSID etc ..) sous cette forme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    struct
    {
        uint32_t crc32;    // 4 bytes
        uint8_t channel;   // 1 byte,   5 in total
        uint8_t ap_mac[6]; // 6 bytes, 11 in total
    } rtcData;
     
    // the CRC routine
    uint32_t calculateCRC32(const uint8_t *data, size_t length)
    {
        uint32_t crc = 0xffffffff;
        while (length--)
        {
            uint8_t c = *data++;
            for (uint32_t i = 0x80; i > 0; i >>= 1)
            {
                bool bit = crc & 0x80000000;
                if (c & i)
                {
                    bit = !bit;
                }
     
                crc <<= 1;
                if (bit)
                {
                    crc ^= 0x04c11db7;
                }
            }
        }
     
        return crc;
    }
    puis lors du setup

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     
     if (ESP.rtcUserMemoryRead(0, (uint32_t *)&rtcData, sizeof(rtcData)))
        {
            // Calculez le CRC de ce que nous venons de lire dans la mémoire du RTC, mais sautez les 4 premiers octets car c'est la somme de contrôle elle-même.
            uint32_t crc = calculateCRC32(((uint8_t *)&rtcData) + 4, sizeof(rtcData) - 4);
            if (crc == rtcData.crc32)
            {
                isRtcValid = true;
            }
        }

    'class EspClass' has no member named 'rtcUserMemoryRead'

    malheureusement j'ai une erreur liée je pense à la technologie propre du ESP32C3
    comment puis-je faire pour lire ces datas svp ?

    Merci mille fois

  2. #2
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    pour mettre quelque chose en mémoire RTC sur ESP32 il suffit de le dire au compilateur avec RTC_DATA_ATTR

    essayez un truc comme cela

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct MaStructure {
      uint32_t crc32;    // 4 bytes
      uint8_t channel;   // 1 byte,   5 in total
      uint8_t ap_mac[6]; // 6 bytes, 11 in total
    };
     
    RTC_DATA_ATTR MaStructure rtcData;
    et la variable rtcData devrait survivre au reboot après deep sleep par exemple

  3. #3
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    Merci Jay M

    je ne crois pas avoir vraiment tout saisi mais :
    voilà ce que j'ai compris

    1)lceci me permet de mettre mes trois variables en mémoire ( il est dit de mettre RTC_DATA_ATTR avant les variables à mettre en mémoire pourtant )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    RTC_DATA_ATTR MaStructure rtcData;

    2)je calcule le crc avec ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    uint32_t calculateCRC32(const uint8_t *data, size_t length)
    {
        uint32_t crc = 0xffffffff;
        while (length--)
        {
            uint8_t c = *data++;
            for (uint32_t i = 0x80; i > 0; i >>= 1)
            {
                bool bit = crc & 0x80000000;
                if (c & i)
                {
                    bit = !bit;
                }
     
                crc <<= 1;
                if (bit)
                {
                    crc ^= 0x04c11db7;
                }
            }
        }
     
        return crc;
    }
    3) je valide le RTCdata dans le setup :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    uint32_t crc = calculateCRC32(((uint8_t *)&rtcData) + 4, sizeof(rtcData) - 4);
            if (crc == rtcData.crc32)
            {
                isRtcValid = true;
            }
    Puis lorsque j'ai besoin une connexion rapide
    je regarde au reveil du µC si RTC est valide

    c'est çà ?

  4. #4
    Membre Expert Avatar de edgarjacobs
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2011
    Messages : 757
    Par défaut
    ----

  5. #5
    Membre Expert Avatar de edgarjacobs
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2011
    Messages : 757
    Par défaut
    struct
    {
    uint32_t crc32; // 4 bytes
    uint8_t channel; // 1 byte, 5 in total
    uint8_t ap_mac[6]; // 6 bytes, 11 in total
    } rtcData;
    Hé non. 12 au total, pour cause d'alignement (si la compilation se fait comme en C, ce que je pense):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #include <stdio.h>
     
    #define uint32_t	unsigned int
    #define uint8_t		unsigned char
     
    int main(void) {
    	struct {
    		uint32_t crc32;    // 4 bytes
    		uint8_t channel;   // 1 byte,   5 in total
    		uint8_t ap_mac[6]; // 6 bytes, 11 in total
    	} rtcData;
    	printf("%d\n", (int)sizeof(rtcData));
     
    	return(0);
    }
    Edit: pour avoir une taille de 11, il faut écrire struct __attribute__((packed)) {

  6. #6
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    Citation Envoyé par cobra38 Voir le message
    Puis lorsque j'ai besoin une connexion rapide
    je regarde au reveil du µC si RTC est valide

    c'est çà ?
    je ne sais pas trop ce que vous voulez faire mais voici un exemple avec la structure et un reboot après sleep automatique

    vous noterez que j'ai "packé" la structure et fait un alignement sur 1 seul octet pour que GCC ne mette pas de padding dans la structure (vous verrez à l'impression qu'elle fait bien 11 octets). J'ai mis le CRC à la fin, c'est souvent là où il est dans une structure.

    J'ai rajouté un compteur de boot qui vous montrera que l'ESP32 sait différencier le boot initial (après reset ou mise sous alimentation) et le reboot dû au timer et à chaque reboot sur timer j'augmente aussi la valeur du channel et je recalcule le CRC32 pour vous montrer qu'on peut mettre à jour la structure aussi et qu'elle est bien mémorisée.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    struct __attribute__((packed, aligned(1))) MaStructure {
      uint8_t channel;
      uint8_t ap_mac[6];
      uint32_t crc32;
    };
     
    RTC_DATA_ATTR MaStructure rtcData = {0, {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}, 0};
    RTC_DATA_ATTR uint32_t compteurDeReboot = 0;
     
    uint32_t calculateCRC32MPGE2(const uint8_t *data, size_t length) {
      uint32_t crc = 0xffffffff;
      while (length--) {
        uint8_t c = *data++;
        for (uint32_t i = 0x80; i > 0; i >>= 1) {
          bool bit = crc & 0x80000000;
          if (c & i) bit = !bit;
          crc <<= 1;
          if (bit) crc ^= 0x04c11db7;
        }
      }
      return crc;
    }
     
    void printByte(uint8_t b) {
      Serial.print("0x");
      if (b < 0x10) Serial.write('0');
      Serial.print(b, HEX);
    }
     
    void printStructure(MaStructure& s) {
      Serial.print("channel = "); Serial.println(s.channel);
      Serial.print("ap_mac[] = ");
      for (uint8_t i = 0; i < sizeof(s.ap_mac); i++) {
        printByte(s.ap_mac[i]);
        Serial.write(' ');
      }
      Serial.println();
      Serial.print("CRC32-MPEG2 = 0x"); Serial.println(s.crc32, HEX);
    }
     
     
    void setup() {
      delay(1000); // il sert surtout au premier boot pour qu'on le voit sur le moniteur série
      Serial.begin(115200);
      while (!Serial) yield();
      Serial.print("Taille de la structure = "); Serial.print(sizeof rtcData); Serial.println(" octets.");
     
      esp_reset_reason_t resetReason = esp_reset_reason();
      if (resetReason != ESP_RST_DEEPSLEEP) {
        Serial.println("Premier boot");
        compteurDeReboot = 0;
        rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
      } else {
        Serial.print("Reboot sur timer -> ");
        compteurDeReboot++;
        // on met à jour le channel par exemple pour montrer une modification de la structure
        rtcData.channel++;
        // il faut donc recalculer le CRC32
        rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
      }
     
     
      Serial.print("Boot #"); Serial.println(compteurDeReboot);
      printStructure(rtcData);
      Serial.flush();
     
      esp_sleep_enable_timer_wakeup(3000000ULL); // on programme un réveil pour dans 3s (en µs)
      esp_deep_sleep_start();
    }
     
    void loop() {}


    attention cependant avec RTC_DATA_ATTR et les structures (ou classes) si vous mettez un constructeur il sera appelé au reboot et donc vous perdrez les anciennes valeurs (contrairement aux valeurs par défaut qui ne sont mises qu'une fois) ==> donc pas de constructeur pour les variables avec l'attribut RTC_DATA_ATTR.

  7. #7
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    merci Jay M
    pardon pour le retour tardif

    Dans mon cas, je peux donc considérer que je n'ai pas besoin de boucle "Loop()"

    je teste uniquement dans le setup()
    l'ensemble des capteurs puis les affiche
    et au final j'envoie les liaisons MQTT par le Wifi
    puis je lance le deep_sleep() de 5mn
    étant donné que je n'ai pas de réveil externe

    c'est cela ?

  8. #8
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    effectivement si vous ne faites qu'une action à chaque réveil, pas besoin de loop, tout peut être mis dans le setup comme dans mon code d'exemple

  9. #9
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    merci Jay M

    je teste .....

    PS: pour que je comprennes bien
    je teste le contenu de rtcData.crc32
    car dans les 2 cas , je ne fait que le recalculer semble-t-il et mettre à jour ma structure

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    esp_reset_reason_t resetReason = esp_reset_reason();
      if (resetReason != ESP_RST_DEEPSLEEP) {
        Serial.println("Premier boot");
        compteurDeReboot = 0;
        rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
      } else {
        Serial.print("Reboot sur timer -> ");
        compteurDeReboot++;
        // on met à jour le channel par exemple pour montrer une modification de la structure
        rtcData.channel++;
        // il faut donc recalculer le CRC32
        rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
      }
    J'avoue que je n'ai pas bien saisi la notion de test du style que j'avais avant et qui me permettais de gagner du temps à la reconnexion
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    if (isRtcValid)
            {
                // The RTC data was good, make a quick connection
                D_timestamp();
                D_println("RTC OK, initier une connexion rapide");
                WiFi.begin(WLAN_SSID, WLAN_PASSWD, rtcData.channel, rtcData.ap_mac, true);
                isRegularWifi = false;
            }
            else
            {
                // Les données RTC n'étaient pas valides, il faut donc établir une connexion régulière.
                D_timestamp();
                D_println("RTC BAD, initier une connexion régulière");
                WiFi.begin(WLAN_SSID, WLAN_PASSWD);
                isRegularWifi = true;
            }

  10. #10
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    Pourquoi voulez vous tester le CRC des données sauvegardées ? Au cas où elles auraient été corrompues?

  11. #11
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    Pourquoi voulez vous tester le CRC des données sauvegardées ? Au cas où elles auraient été corrompues?
    Non juste pour me permettre de définir çà
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    isRtcValid = true;
    pour ensuite distinguer
    - soit une connexion WiFi rapide avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    WiFi.begin(WLAN_SSID, WLAN_PASSWD, rtcData.channel, rtcData.ap_mac, true);
    - soit une connexion standard avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     WiFi.begin(WLAN_SSID, WLAN_PASSWD);

    je mets ici le croquis complet qui intègre votre solution précédente, qui se compile mais encore non testé pour avis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
     
    /***************************************
              uPesy ESP32C3 Basic Low Power
              
                       ------------------
                       |                |
                       |----------------|
                       |                |
                       |                |
                       |----------------|
                       |                |
               RESET   |EN           OFF| POWER OFF
       SCL     GPIO4   |4              1| GPIO1      DC
      AM2301A  GPIO5   |5              2| GPIO2      RES   
       SDA     GPIO6   |6              3| GPIO3      BUSY
       CS      GPIO7   |7             10| GPIO10     DS18B20
               GPIO8   |8             20| GPIO20
               GPIO9   |9             21| GPIO21 
                       |VIN          3V3| 3V3    VCC
                       |5V           3V3| 3V3    VCC
                       |GND    |----| 17| GND
                       \-------|    |---/
                               |----| 
    *************************************/
     
    #include <WiFi.h>
    #include <Wire.h>
    #include <ArduinoOTA.h>
    #include <Arduino.h>
    #include <PubSubClient.h>
    #include "BitmapGraphics.h"
    #include <functional>
     
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include "config.h"
     
    #include "DHTesp.h"
    #include <MQTT.h>
     
    char server[] = "mqtt3.thingspeak.com";
     
    //  E-paper *********************************************
    #include <GxEPD2_BW.h>
    #include <GxEPD2_GFX.h>
    #include <Fonts/FreeMonoBold9pt7b.h>
    #include "FreeSerifBold30pt7b.h"
    // 1.54'' EPD Module
    GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(/*CS=7*/ 7, /*DC=*/ 1, /*RES=*/ 2, /*BUSY=*/3)); // GDEH0154D67 200x200, SSD1681
    //*******************************************************
     
    //*******************************************************
    #if DEBUG
    #define D_SerialBegin(...) Serial.begin(__VA_ARGS__)
    #define D_print(...) Serial.print(__VA_ARGS__)
    #define D_write(...) Serial.write(__VA_ARGS__)
    #define D_println(...) Serial.println(__VA_ARGS__)
    #define D_printf(...) Serial.printf(__VA_ARGS__)
    #define D_flush(...) Serial.flush(__VA_ARGS__)
    #define D_timestamp() Serial.printf("[%lu] ", millis())
    #else
    #define D_SerialBegin(bauds)
    #define D_print(...)
    #define D_write(...)
    #define D_println(...)
    #define D_printf(...)
    #define D_flush(...)
    #define D_timestamp()
    #endif
     
    #ifndef ESPTEMP_VERSION
    #define ESPTEMP_VERSION "v1.1" /**< The current version of the ESPtemp firmware*/
    #endif
     
    #ifndef SLEEPTIME
    #define SLEEPTIME 300e6 /**< Time in deepsleep */
    #endif
     
    #ifndef SLEEPTIME_EXTENDED
    #define SLEEPTIME_EXTENDED 21600e6 /**< Temps en sommeil profond si une erreur s'est produite en essayant de se connecter au wifi (pour éviter le drainage de la batterie).) */
    #endif
     
    #ifndef DEBUG
    #define DEBUG 0 /**< Régler à 1 pour déboguer en série */
    #endif
    //*******************************************************
     
    const byte oneWireBus = 10;  // DS18B20 pin used for Temperature sensor bus GIPO10
     
    float humidity;
    float temperature;
     
    char temp[10];
    char bat[10];
    float piscine;
     
    const gpio_num_t vbatPin = GPIO_NUM_0;
    float batteryVoltage;
    int8_t batteryPercentage;
    uint_fast16_t adcValue;
    char error[15];
     
    uint8_t wifiRetries = 0;
     
    bool isDS18B20ready = false;
    bool isDHTready = false;
    bool isADCReady = false;
    bool isWifiStarted = false;
    bool isWifiReady = false;
    bool isRegularWifi = false;
    bool isMQTTStarted = false;
    bool isMQTTReady = false;
    bool isRtcValid = false;
    bool isOTAEnabled = false;
     
    //*********** Init **************************
    WiFiClient  wifiClient;
    WiFiServer serverAP(80);
    PubSubClient pubSubclient(wifiClient);
    OneWire oneWire(oneWireBus);
    DallasTemperature sensors(&oneWire);
    DHTesp dht;
     
     
    //******************************************************** 
    struct __attribute__((packed, aligned(1))) MaStructure {
      uint8_t channel;
      uint8_t ap_mac[6];
      uint32_t crc32;
    };
     
    RTC_DATA_ATTR MaStructure rtcData = {0, {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}, 0};
    RTC_DATA_ATTR uint32_t compteurDeReboot = 0;
     
     
    //********************************************************  
    uint32_t calculateCRC32MPGE2(const uint8_t *data, size_t length) {
      uint32_t crc = 0xffffffff;
      while (length--) {
        uint8_t c = *data++;
        for (uint32_t i = 0x80; i > 0; i >>= 1) {
          bool bit = crc & 0x80000000;
          if (c & i) bit = !bit;
          crc <<= 1;
          if (bit) crc ^= 0x04c11db7;
        }
      }
      return crc;
    }
     
    //******************************************************** 
    void printByte(uint8_t b) {
      Serial.print("0x");
      if (b < 0x10) Serial.write('0');
      Serial.print(b, HEX);
    }
     
     
    //********************************************************  
    void printStructure(MaStructure& s) {
      Serial.print("channel = "); Serial.println(s.channel);
      Serial.print("ap_mac[] = ");
      for (uint8_t i = 0; i < sizeof(s.ap_mac); i++) {
        printByte(s.ap_mac[i]);
        Serial.write(' ');
      }
      Serial.println();
      Serial.print("CRC32-MPEG2 = 0x"); Serial.println(s.crc32, HEX);
    }
     
    unsigned long startMillis;
     
    //*****************************************
    // SETUP
    //****************************************
     
    void setup() {
     
      delay(1000); // il sert surtout au premier boot pour qu'on le voit sur le moniteur série
      D_SerialBegin(115200);
      while (!Serial) yield();
      Serial.print("Taille de la structure = "); Serial.print(sizeof rtcData); Serial.println(" octets.");
     
      Serial.println( "Start" );
      pinMode(0, INPUT); // Pin Entree VBAT
      pinMode(5, INPUT); // Pin Entree AM2301A
     
    	  /*    
    	   D_println();
    	   D_timestamp();
    	   D_printf("CpuFreqMHz: %u MHz\n", ESP.getCpuFreqMHz());
    	   D_timestamp();
    	   D_print("MAC Address: ");
    	   D_println(WiFi.macAddress()); 
    	  */
     
        //**** INIT Ecran E-paper**********
        display.init(115200,true,50,false);
        display.setRotation(3);
        display.setFullWindow();
        display.fillScreen(GxEPD_BLACK);
        display.drawBitmap(0, 0, gImage_gui, 200, 200, GxEPD_WHITE);
        while (display.nextPage()); 
        delay(500) ;     
     
        // *** DS18B20 Temperature sensor ****
        sensors.begin(); 
     
       // *** AM2301A Temperature sensor ****
        dht.setup(5, DHTesp::DHT22); // Connect DHT sensor to GPIO 5
     
        // Wait minimum sampling period
        startMillis = millis();
     
     
      esp_reset_reason_t resetReason = esp_reset_reason();
      if (resetReason != ESP_RST_DEEPSLEEP) {
        Serial.println("Premier boot");
        compteurDeReboot = 0;
        rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
      } else {
        Serial.print("Reboot sur timer -> ");
        compteurDeReboot++;
        // on met à jour le channel par exemple pour montrer une modification de la structure
        rtcData.channel++;
        // il faut donc recalculer le CRC32
        rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
        isRtcValid = true;
      }
     
     
     
      //---------------------------------------------
        // Step 0:
        // Read temperature from DS18B20
        //---------------------------------------------
     
        if (!isDS18B20ready)
        {  
           sensors.requestTemperatures(); 
           float raw_temp = sensors.getTempCByIndex(0);
           Serial.printf("Temperature = %8.4f°C\r\n", (float)raw_temp);
           snprintf(temp, sizeof temp, "%.1f",(float)raw_temp);
     
           updatePiscine();
          isDS18B20ready = true;
        }
     
        //---------------------------------------------
        // Step 1: Lecture de la température et de l'humidité à partir de l'AM2301A
        //---------------------------------------------
        if (!isDHTready)
        {
            humidity =  dht.getHumidity();       // Humidite Air  
            temperature = dht.getTemperature(); // temperature Air
            temperature = temperature -2; // facteur de correction(?)
     
            D_timestamp();
            D_println("AM2301A Reading ready");
            D_timestamp();
            D_printf("Temperature: %.1f, Humidity: %.1f ", temperature, humidity);
            D_println();
     
            isDHTready = true;
        }   
     
     
        //---------------------------------------------
        // Step 2: Demarrage Connection WIFI
        //---------------------------------------------
        if (!isWifiStarted)
        {
            D_timestamp();
            D_println("Démarrage du WiFi");
     
            // Désactivez la persistance du WiFi.  L'ESP8266 ne chargera pas et n'enregistrera pas inutilement les paramètres WiFi dans la mémoire flash..
            WiFi.persistent(false);
     
            // Affichez la connexion WiFi
            WiFi.mode(WIFI_STA);
            WiFi.config(ip, dns, gateway, subnet);
            //WiFi.hostname(MQTT_CLIENT);
     
            if (isRtcValid)
            {
                // Les données RTC étaient bonnes, établir une connexion rapide
                D_timestamp();
                D_println("RTC OK, initier une connexion rapide");
                WiFi.begin(WLAN_SSID, WLAN_PASSWD, rtcData.channel, rtcData.ap_mac, true);
                isRegularWifi = false;
            }
            else
            {
                // Les données RTC n'étaient pas valides, il faut donc établir une connexion régulière.
                D_timestamp();
                D_println("RTC BAD, initier une connexion régulière");
                WiFi.begin(WLAN_SSID, WLAN_PASSWD);
                isRegularWifi = true;
            }
     
            isWifiStarted = true;
        }
     
        //---------------------------------------------
        // Step 3: Lecture Batterie ADC GPIO0
        //---------------------------------------------
         if (!isADCReady)
        {
            adcValue = analogRead(vbatPin); //<============
            batteryVoltage = 2*(adcValue/4095.0)*3; // tension comprise netre 3.5v et 6.5v en entrée 
            batteryPercentage = ((batteryVoltage/6)*100); // 6V = 4 piles AA
     
            int tensionBrute =adcValue ;
            constexpr int seuilTensionBruteBasse = 2185; // 3.2V ==> calculé par (3.2V * 4096) / 6V
            if  (tensionBrute <= seuilTensionBruteBasse)
            {
                D_timestamp();
                D_println("Batterie faible. Sommeil profond.");
                D_printf("Battery Percentage: %i", batteryPercentage);
                esp_sleep_enable_timer_wakeup(60000000ULL); // on programme un réveil pour dans 60s (en µs)
            }
     
            D_timestamp();
            D_println("ADC Reading ready");
            D_printf("Vbat: %.1f",batteryVoltage);
            D_println();
     
            sprintf(bat, "%3d%s", batteryPercentage, "%");
            updateBattery() ;
            isADCReady = true;
        }
     
        //---------------------------------------------
        // Step 4: Si le WiFi est prêt : Initialiser le client MQTT
        //---------------------------------------------
        if (!isWifiReady)
        {
            if (WiFi.status() == WL_CONNECTED)
            {
                D_timestamp();
                D_print("WiFi connected (");
                D_print(WiFi.localIP());
                D_println(")");
                pubSubclient.setServer(server, 1883);
                isWifiReady = true;
     
                if (isOTAEnabled)
                {
                    D_timestamp();
                    D_println("Démarrage de l'OTA");
                    ArduinoOTA.setHostname(MQTT_CLIENT);
                    ArduinoOTA.begin();
                }
            }
            else if (((millis() - startMillis) > 5000) && (!isRegularWifi))
            {
                // Essayer une connexion régulière
                D_timestamp();
                D_println("Délai d'attente pour le WiFi, réessayer une connexion régulière");
                WiFi.disconnect();
                delay(5);
                WiFi.begin(WLAN_SSID, WLAN_PASSWD);
                isRtcValid = false;
                isRegularWifi = true;
            }
            else if ((millis() - startMillis) > 20000)
            {
                // Échec de la connexion Wifi, mise en veille prolongée
                WiFi.disconnect(true);
                D_timestamp();
                D_println("Échec de la connexion au réseau WiFi");
                D_flush(); // flush pour s'assurer que le texte est envoyé avant le reboot
                ESP.restart();
            }
        }   
     
          //---------------------------------------------
          // Step 5: Connexion au MQTT broker
          //---------------------------------------------
          else if (!isMQTTStarted)
          {
              if (!pubSubclient.connected())
              {
                  D_timestamp();
                  D_println("Connexion au courtier MQTT");
                  pubSubclient.connect(MQTT_CLIENT, MQTT_USER, MQTT_PASSWORD);
                  delay(10);
              }
              else
              {
                  D_timestamp();
                  D_println("MQTT connected");
                  //Serial.println( "Connected with Client ID:  " + String(MQTT_CLIENT) + " User "+ String(MQTT_USER) + " Pwd "+String(MQTT_PASSWORD) );
                  isMQTTStarted = true;
              }
          }
     
     
        //---------------------------------------------
        // Step 6: Si tous les relevés sont effectués et que le WiFi est prêt, transmettez les données MQTT.
        //---------------------------------------------
        if (isMQTTStarted && isWifiReady && isDHTready && !isMQTTReady  && isDS18B20ready)
        {
     
            D_timestamp();
            D_print("MQTT Publish: ");
            D_println(MQTT_TOPIC);
     
            pubSubclient.loop();
    	    	String topicString ="channels/" + String(MQTT_TOPIC) + "/publish";
    		    String dataString = String("field1=" + String(temperature) + "&field2=" + String(humidity) + "&field3=" + String(batteryPercentage) + "&field4=" + String(piscine));
            pubSubclient.publish(topicString.c_str(),dataString.c_str());
            delay(100);
     
            isMQTTReady = true;
        } 
     
      Serial.print("Boot #"); Serial.println(compteurDeReboot);
      printStructure(rtcData);
      Serial.flush();
     
      esp_sleep_enable_timer_wakeup(3000000ULL); // on programme un réveil pour dans 3s (en µs)
      esp_deep_sleep_start();
    }
     
     
    //**************************************
    //  LOOP
    //**************************************
    void loop() {}
     
     
    //*******************************************************
    void updateBattery() 
    {
      int16_t tbx, tPar;
      uint16_t tbw, tbh;
      display.setRotation(3);
      display.setFont(&FreeMonoBold9pt7b);
      display.setTextColor(GxEPD_BLACK);
      uint16_t x = 136;
      uint16_t y = 176;
      display.getTextBounds(bat, x, y, &tbx, &tPar, &tbw, &tbh);
     
      display.setPartialWindow(tbx, tPar, tbw, tbh);
      display.firstPage();
      do {
        //display.fillScreen(GxEPD_WHITE);
        display.setCursor(x, y);
        display.print(bat);
      } while (display.nextPage());
      delay(500);
     
    }
     
     
    //*******************************************************
    void updatePiscine() 
    {
      int16_t tbx, tPar;
      uint16_t tbw, tbh;
      display.setRotation(3);
      display.setFont(&FreeSerifBold30pt7b);
      display.setTextColor(GxEPD_BLACK);
      uint16_t x = 72;
      uint16_t y = 112;
      display.getTextBounds(temp, x, y, &tbx, &tPar, &tbw, &tbh);
     
      display.setPartialWindow(tbx, tPar, tbw, tbh);
      display.firstPage();
      do {
        display.fillScreen(GxEPD_WHITE);
        display.setCursor(x, y);
        display.print(temp);
      } while (display.nextPage());
       delay(500);
     
    }

  12. #12
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    ok. il ne faut pas mettre tout mon code car pour la démonstration je modifiais le Channel
    Souhaitez vous conserver les infos quand vous éteignez complètement le système ? (parce que la mémoire RTC a besoin d'être alimentée, ce n'est pas une EEPROM).

    Si vous voulez conserver les données même lors de l'extinction, vous pouvez utiliser la bibliothèque Preferences

    => un tuto en anglais
    https://randomnerdtutorials.com/esp3...y-preferences/

  13. #13
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    ok. il ne faut pas mettre tout mon code car pour la démonstration je modifiais le Channel
    oupss !! bien vu effectivement

    Souhaitez vous conserver les infos quand vous éteignez complètement le système ?
    Non, je ne pense pas j'avais compris que seul était maintenu RTC justement en sommeil profond
    Comme je devrais alimenter avec batteries le système, une coupure complète devrait rester exceptionnelle

    par contre, je ne pige pas la nature des datas dans la structure par ex :
    dois-je au préalable initialiser les données de la structure ?
    parce que le programme se bloque après le 1er démarrage et ne se relance pas
    Images attachées Images attachées  

  14. #14
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    peut-on prendre un pas de recul ?

    Si j'ai bien compris vous voulez pouvoir rentrer des informations concernant la connexion au réseau et avoir ces informations qui survivent au deep sleep mais pas à l'extinction de l'arduino. C'est ça ?

    si oui, comment sont acquises ces informations au boot ?

  15. #15
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    peut-on prendre un pas de recul ?
    pour ce projet , je suis inspiré de celui-ci
    https://github.com/ni-c/ESPtemp/tree/main/src

    l'auteur distinguait 2 méthodes pour se connecter au Wifi
    l'une rapide si le crc était correct et donc "isRTCvalid"
    l'autre plus lente si le crc n'était pas bon
    j'ai donc voulu reprendre le même principe à tort peut-être mais en pensant que je pouvais gagner du temps à la connexion
    entre temps j'ai du changer de support passant d'un ESP8266 à ESP32C3 d'où mais multiples échanges

    j'ai tout testé mais je me suis aperçu hier que l'ESP32 entrait en sommeil profond mais n'en sortait plus (voir image du post précédent)
    aujourd'hui il refuse de se connecter pour téléverser et maintenant après une mise à jour de la carte ESP32 v2.14 (Arduino 1.819)
    et pourtant j'ai déjà téléversé des centaines de fois le programme sans problème

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    Le croquis utilise 770816 octets (58%) de l'espace de stockage de programmes. Le maximum est de 1310720 octets.
    Les variables globales utilisent 45468 octets (13%) de mémoire dynamique, ce qui laisse 282212 octets pour les variables locales. Le maximum est de 327680 octets.
    esptool.py v4.5.1
    Serial port COM8
    Connecting...
     
    A serial exception error occurred: ClearCommError failed (PermissionError(13, 'Le p�riph�rique ne reconna�t pas la commande.', None, 22))
    Note: This error originates from pySerial. It is likely not a problem with esptool, but with the hardware connection or drivers.
    For troubleshooting steps visit: https://docs.espressif.com/projects/esptool/en/latest/troubleshooting.html
    le port série sélectionné For troubleshooting steps visit: https://docs.espressif.com/projects/esptool/en/latest/troubleshooting.html
     n'existe pas ou votre Arduino n'est pas connectée

    Je remets la dernière version utilisée qui se compile mais refuse de ce téléverser
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
     
    /***************************************
              uPesy ESP32C3 Basic Low Power
              
                       ------------------
                       |                |
                       |----------------|
                       |                |
                       |                |
                       |----------------|
                       |                |
               RESET   |EN           OFF| POWER OFF
       SCL     GPIO4   |4              1| GPIO1      DC
      AM2301A  GPIO5   |5              2| GPIO2      RES   
       SDA     GPIO6   |6              3| GPIO3      BUSY
       CS      GPIO7   |7             10| GPIO10     DS18B20
               GPIO8   |8             20| GPIO20
               GPIO9   |9             21| GPIO21 
                       |VIN          3V3| 3V3    VCC
                       |5V           3V3| 3V3    VCC
                       |GND    |----| 17| GND
                       \-------|    |---/
                               |----| 
    *************************************/
     
    #include <WiFi.h>
    #include <Wire.h>
    #include <ArduinoOTA.h>
    #include <Arduino.h>
    #include <PubSubClient.h>
    #include "BitmapGraphics.h"
    #include <functional>
     
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include "config.h"
     
    #include "DHTesp.h"
    #include <MQTT.h>
     
    char server[] = "mqtt3.thingspeak.com";
     
    //  E-paper *********************************************
    #include <GxEPD2_BW.h>
    #include <GxEPD2_GFX.h>
    #include <Fonts/FreeMonoBold9pt7b.h>
    #include "FreeSerifBold30pt7b.h"
    // 1.54'' EPD Module
    GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(/*CS=7*/ 7, /*DC=*/ 1, /*RES=*/ 2, /*BUSY=*/3)); // GDEH0154D67 200x200, SSD1681
    //*******************************************************
     
    //*******************************************************
    #if DEBUG
    #define D_SerialBegin(...) Serial.begin(__VA_ARGS__)
    #define D_print(...) Serial.print(__VA_ARGS__)
    #define D_write(...) Serial.write(__VA_ARGS__)
    #define D_println(...) Serial.println(__VA_ARGS__)
    #define D_printf(...) Serial.printf(__VA_ARGS__)
    #define D_flush(...) Serial.flush(__VA_ARGS__)
    #define D_timestamp() Serial.printf("[%lu] ", millis())
    #else
    #define D_SerialBegin(bauds)
    #define D_print(...)
    #define D_write(...)
    #define D_println(...)
    #define D_printf(...)
    #define D_flush(...)
    #define D_timestamp()
    #endif
     
    #define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
    #define TIME_TO_SLEEP  15        /* Time ESP32 will go to sleep (in seconds) */
     
    //#ifndef ESPTEMP_VERSION
    //#define ESPTEMP_VERSION "v1.1" //**< The current version of the ESPtemp firmware*/
    //#endif
     
    //#ifndef SLEEPTIME
    //#define SLEEPTIME 300e6 /**< Time in deepsleep */
    //#endif
     
    //#ifndef SLEEPTIME_EXTENDED
    //#define SLEEPTIME_EXTENDED 21600e6 /**< Temps en sommeil profond si une erreur s'est produite en essayant de se connecter au wifi (pour éviter le drainage de la batterie).) */
    //#endif
     
    #ifndef DEBUG
    #define DEBUG 0 /**< Régler à 1 pour déboguer en série */
    #endif
    //*******************************************************
     
    const byte oneWireBus = 10;  // DS18B20 pin used for Temperature sensor bus GIPO10
     
    float humidity;
    float temperature;
     
    char temp[10];
    char bat[10];
    float piscine;
     
    const gpio_num_t vbatPin = GPIO_NUM_0;
    float batteryVoltage;
    int8_t batteryPercentage;
    uint_fast16_t adcValue;
    char error[15];
     
    uint8_t wifiRetries = 0;
     
    bool isDS18B20ready = false;
    bool isDHTready = false;
    bool isADCReady = false;
    bool isWifiStarted = false;
    bool isWifiReady = false;
    bool isRegularWifi = false;
    bool isMQTTStarted = false;
    bool isMQTTReady = false;
    bool isRtcValid = false;
    bool isOTAEnabled = false;
     
    //*********** Init **************************
    WiFiClient  wifiClient;
    WiFiServer serverAP(80);
    PubSubClient pubSubclient(wifiClient);
    OneWire oneWire(oneWireBus);
    DallasTemperature sensors(&oneWire);
    DHTesp dht;
     
     
    //******************************************************** 
    struct __attribute__((packed, aligned(1))) MaStructure {
      uint8_t channel;
      uint8_t ap_mac[6];
      uint32_t crc32;
    };
     
    RTC_DATA_ATTR MaStructure rtcData = {0, {0x58, 0xCF, 0x79, 0x1A, 0x54, 0x14}, 0};
    RTC_DATA_ATTR uint32_t compteurDeReboot = 0;
     
     
    //********************************************************  
    uint32_t calculateCRC32MPGE2(const uint8_t *data, size_t length) {
      uint32_t crc = 0xffffffff;
      while (length--) {
        uint8_t c = *data++;
        for (uint32_t i = 0x80; i > 0; i >>= 1) {
          bool bit = crc & 0x80000000;
          if (c & i) bit = !bit;
          crc <<= 1;
          if (bit) crc ^= 0x04c11db7;
        }
      }
      return crc;
    }
     
    //******************************************************** 
    void printByte(uint8_t b) {
      Serial.print("0x");
      if (b < 0x10) Serial.write('0');
      Serial.print(b, HEX);
    }
     
     
    //********************************************************  
    void printStructure(MaStructure& s) {
      Serial.print("channel = "); Serial.println(s.channel);
      Serial.print("ap_mac[] = ");
      for (uint8_t i = 0; i < sizeof(s.ap_mac); i++) {
        printByte(s.ap_mac[i]);
        Serial.write(' ');
      }
      Serial.println();
      Serial.print("CRC32-MPEG2 = 0x"); Serial.println(s.crc32, HEX);
    }
     
    unsigned long startMillis;
     
    //*****************************************
    // SETUP
    //****************************************
     
    void setup()
    {
     
      delay(1000); // il sert surtout au premier boot pour qu'on le voit sur le moniteur série
      D_SerialBegin(115200);
      while (!Serial) yield();
      Serial.print("Taille de la structure = "); Serial.print(sizeof rtcData); Serial.println(" octets.");
     
      Serial.println( "Start" );
      pinMode(0, INPUT); // Pin Entree VBAT
      pinMode(5, INPUT); // Pin Entree AM2301A
     
     
    	D_println();
    	D_timestamp();
    	D_printf("CpuFreqMHz: %u MHz\n", ESP.getCpuFreqMHz());
    	D_timestamp();
    	D_print("MAC Address: ");
    	D_println(WiFi.macAddress()); 
     
     
        //**** INIT Ecran E-paper**********
        display.init(115200,true,50,false);
        display.setRotation(3);
        display.setFullWindow();
        display.fillScreen(GxEPD_BLACK);
        display.drawBitmap(0, 0, gImage_gui, 200, 200, GxEPD_WHITE);
        while (display.nextPage()); 
        delay(500) ;     
     
        // *** DS18B20 Temperature sensor ****
        sensors.begin(); 
     
        // *** AM2301A Temperature sensor ****
        dht.setup(5, DHTesp::DHT22); // Connect DHT sensor to GPIO 5
     
        // Wait minimum sampling period
        startMillis = millis();
     
     
         esp_reset_reason_t resetReason = esp_reset_reason();
    	  if (resetReason != ESP_RST_DEEPSLEEP) {
    		Serial.println("Premier boot");
    		compteurDeReboot = 0;
    		rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
    		isRtcValid = false;
    	  } else {
    		Serial.print("Reboot sur timer -> ");
    		compteurDeReboot++;
    		// il faut donc recalculer le CRC32
    		rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
    		isRtcValid = true;
    	  }
     
     
        //---------------------------------------------
        // Step 0:
        // Read temperature from DS18B20
        //---------------------------------------------
     
        if (!isDS18B20ready)
        {  
           sensors.requestTemperatures(); 
           float raw_temp = sensors.getTempCByIndex(0);
           piscine = sensors.getTempCByIndex(0);
           Serial.printf("Temperature = %8.4f°C\r\n", (float)raw_temp);
           snprintf(temp, sizeof temp, "%.1f",(float)raw_temp);
           updatePiscine();
           isDS18B20ready = true;
        }
     
        //---------------------------------------------
        // Step 1: Lecture de la température et de l'humidité à partir de l'AM2301A
        //---------------------------------------------
        if (!isDHTready)
        {
            humidity =  dht.getHumidity();       // Humidite Air  
            temperature = dht.getTemperature(); // temperature Air
            temperature = temperature -2; // facteur de correction(?)
            D_timestamp();
            D_println("AM2301A Reading ready");
            D_timestamp();
            D_printf("Temperature: %.1f, Humidity: %.1f ", temperature, humidity);
            D_println();
            isDHTready = true;
        }   
     
        //---------------------------------------------
        // Step 2: Demarrage Connection WIFI
        //---------------------------------------------
     
        D_timestamp();
        D_println("Démarrage du WiFi");
        // Désactivez la persistance du WiFi.  L'ESP8266 ne chargera pas et n'enregistrera pas inutilement les paramètres WiFi dans la mémoire flash..
        // WiFi.persistent(false);
     
        // Affichez la connexion WiFi
        WiFi.mode(WIFI_STA);
        WiFi.config(ip, dns, gateway, subnet);
        //WiFi.hostname(MQTT_CLIENT);
     
            if (isRtcValid)
            {
                // Les données RTC étaient bonnes, établir une connexion rapide
                D_timestamp();
                D_println("RTC OK, initier une connexion rapide");
                WiFi.begin(WLAN_SSID, WLAN_PASSWD, rtcData.channel, rtcData.ap_mac, true);
                isRegularWifi = false;
            }else {
                // Les données RTC n'étaient pas validées, il faut donc établir une connexion régulière.
                D_timestamp();
                D_println("RTC BAD, initier une connexion régulière");
                WiFi.begin(WLAN_SSID, WLAN_PASSWD);
                isRegularWifi = true;
            }
     
            isWifiStarted = true;
     
        //---------------------------------------------
        // Step 3: Lecture Batterie ADC GPIO0
        //---------------------------------------------
        if (!isADCReady)
        {
            adcValue = analogRead(vbatPin); //<============
            batteryVoltage = 2*(adcValue/4095.0)*3; // tension comprise netre 3.5v et 6.5v en entrée 
            batteryPercentage = ((batteryVoltage/6)*100); // 6V = 4 piles AA
     
            int tensionBrute =adcValue ;
            constexpr int seuilTensionBruteBasse = 2185; // 3.2V ==> calculé par (3.2V * 4096) / 6V
            if  (tensionBrute <= seuilTensionBruteBasse)
            {
                D_timestamp();
                D_println("Batterie faible. Sommeil profond.");
                D_printf("Battery Percentage: %i", batteryPercentage);
                //esp_sleep_enable_timer_wakeup(120000000ULL); // on programme un réveil pour dans 120s (en µs)
            }
     
            D_timestamp();
            D_println("ADC Reading ready");
            D_timestamp();
            D_printf("Vbat: %.1f",batteryVoltage);
            D_println();
     
            sprintf(bat, "%3d%s", batteryPercentage, "%");
            updateBattery() ;
            isADCReady = true;
        }
     
        //---------------------------------------------
        // Step 4: Si le WiFi est prêt : Initialiser le client MQTT
        //---------------------------------------------
     
        if (!isWifiReady)
        {
     
            if (WiFi.status() == WL_CONNECTED)
            {
                    D_timestamp();
                    D_print("WiFi connected (");
                    D_print(WiFi.localIP());
                    D_println(")");
                    pubSubclient.setServer(server, 1883);
                    isWifiReady = true;
     
            }else if (((millis() - startMillis) > 5000) && (!isRegularWifi)) {
     
                    // Essayer une connexion régulière
                    D_timestamp();
                    D_println("Délai d'attente pour le WiFi, réessayer une connexion régulière");
                    WiFi.disconnect();
                    delay(5);
                    WiFi.begin(WLAN_SSID, WLAN_PASSWD);
                    isRtcValid = false;
                    isRegularWifi = true;
     
             }else if ((millis() - startMillis) > 20000)  {
     
                 // Échec de la connexion Wifi, mise en veille prolongée
                 WiFi.disconnect(true);
                 D_timestamp();
                 D_println("Échec de la connexion au réseau WiFi");
                 D_flush(); // flush pour s'assurer que le texte est envoyé avant le reboot
                 ESP.restart();
              }
     
        }else if (!isMQTTStarted) {
            if (!pubSubclient.connected())
            {
                D_timestamp();
                D_println("Connecting to MQTT broker");
                pubSubclient.connect(MQTT_CLIENT, MQTT_USER, MQTT_PASSWORD);
                delay(10);
            } else {
                D_timestamp();
                D_println("MQTT connected");
                isMQTTStarted = true;
            }
        }
     
     
     
              pubSubclient.loop();
      	      String topicString ="channels/" + String(MQTT_TOPIC) + "/publish";
      		    String dataString = String("field1=" + String(temperature) + "&field2=" + String(humidity) + "&field3=" + String(batteryPercentage) + "&field4=" + String(piscine));
              pubSubclient.publish(topicString.c_str(),dataString.c_str());
              delay(100);
              isMQTTReady = true;
     
         if (isMQTTReady) 
         {  
              // Écriture des informations sur la connexion actuelle dans le RTC
              if (!isRtcValid)
              {
                    rtcData.channel = WiFi.channel();
                    memcpy(rtcData.ap_mac, WiFi.BSSID(), 6); // Copy 6 bytes of BSSID (AP's MAC address)
                    rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
                    //ESP.rtcUserMemoryWrite(0, (uint32_t *)&rtcData, sizeof(rtcData));
     
               }
     
                WiFi.disconnect(true);
                D_timestamp();
                D_println("C'est fait, je vais dormir");
                esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
                //esp_sleep_enable_timer_wakeup(15e6); // on programme un réveil pour dans 15s (en µs)
     
                //ESP.deepSleep(SLEEPTIME, WAKE_RF_DISABLED);
     
         } else if((millis() - startMillis) > 25000){
     
                WiFi.disconnect(true);
                D_timestamp();
                D_println("LONG TEMPS D'INTERRUPTION");
                //esp_sleep_enable_timer_wakeup(30000000ULL); // on programme un réveil pour dans 30s (en µs)
                //ESP.deepSleep(SLEEPTIME, WAKE_RF_DISABLED);
         }
     
     
      //Serial.print("Boot #"); Serial.println(compteurDeReboot);
      //printStructure(rtcData);
      Serial.flush();
     
      //esp_sleep_enable_timer_wakeup(15000000ULL); // on programme un réveil pour dans 15s (en µs)
      //esp_deep_sleep_start();
       esp_light_sleep_start();
     
     }
     
     
    //**************************************
    //  LOOP
    //**************************************
    void loop() {}
     
     
    //*******************************************************
    void updateBattery() 
    {
      int16_t tbx, tPar;
      uint16_t tbw, tbh;
      display.setRotation(3);
      display.setFont(&FreeMonoBold9pt7b);
      display.setTextColor(GxEPD_BLACK);
      uint16_t x = 136;
      uint16_t y = 176;
      display.getTextBounds(bat, x, y, &tbx, &tPar, &tbw, &tbh);
     
      display.setPartialWindow(tbx, tPar, tbw, tbh);
      display.firstPage();
      do {
        //display.fillScreen(GxEPD_WHITE);
        display.setCursor(x, y);
        display.print(bat);
      } while (display.nextPage());
      delay(500);
     
    }
     
     
    //*******************************************************
    void updatePiscine() 
    {
      int16_t tbx, tPar;
      uint16_t tbw, tbh;
      display.setRotation(3);
      display.setFont(&FreeSerifBold30pt7b);
      display.setTextColor(GxEPD_BLACK);
      uint16_t x = 72;
      uint16_t y = 112;
      display.getTextBounds(temp, x, y, &tbx, &tPar, &tbw, &tbh);
     
      display.setPartialWindow(tbx, tPar, tbw, tbh);
      display.firstPage();
      do {
        display.fillScreen(GxEPD_WHITE);
        display.setCursor(x, y);
        display.print(temp);
      } while (display.nextPage());
       delay(500);
    }

    Si j'ai bien compris vous voulez pouvoir rentrer des informations concernant la connexion au réseau et avoir ces informations qui survivent au deep sleep mais pas à l'extinction de l'arduino. C'est ça ?
    Oui , je pense que sauvegarder l'adresse mac pour permettre une connexion plus rapide semble être une bonne idée


    si oui, comment sont acquises ces informations au boot ?
    j'avoue ne pas comprendre votre question

    mais je suppose par ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    RTC_DATA_ATTR MaStructure rtcData = {0, {0x58, 0xCF, 0x79, 0x1A, 0x54, 0x14}, 0}; //j'ai rentré l'adresse mac du Wifi
    RTC_DATA_ATTR uint32_t compteurDeReboot = 0;

  16. #16
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    OK - je comprends mieux - quand la connexion au WiFi est réalisée (avec un mot de passe et SSDI connus et codés en dur - je pensais qu'ils feraient partie de ce que vous mettiez en RTC d'où ma question sur comment vous les obtenez, mais elle n'est pas fondée) l'auteur fait ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
                if (!isRtcValid)
                {
                    rtcData.channel = WiFi.channel();
                    memcpy(rtcData.ap_mac, WiFi.BSSID(), 6); // Copy 6 bytes of BSSID (AP's MAC address)
                    rtcData.crc32 = calculateCRC32(((uint8_t *)&rtcData) + 4, sizeof(rtcData) - 4);
                    ESP.rtcUserMemoryWrite(0, (uint32_t *)&rtcData, sizeof(rtcData));
                }
    il écrit donc en mémoire RTC le canal et l'adresse MAC ainsi qu'un CRC

    au réveil il lit ces données et si le CRC est correct, ça veut dire que la mémoire RTC contenait bien une information utilisable pour l'accès "accéléré" au WiFi


    Voici un exemple où cela est mis en oeuvre


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    #include <WiFi.h>
    const char*   WLAN_SSID = "XXX";
    const char*   WLAN_PASSWD = "XXX";
     
     
    struct __attribute__((packed, aligned(1))) WiFiRapide {
      uint8_t channel;
      uint8_t ap_mac[6];
      uint32_t crc32;
    };
     
    RTC_DATA_ATTR WiFiRapide rtcData = {0, {0, 0, 0, 0, 0, 0}, 0xDEADBEEF}; // on met n'importe quoi pour le premier boot
     
    uint32_t calculateCRC32MPGE2(const uint8_t *data, size_t length) {
      uint32_t crc = 0xffffffff;
      while (length--) {
        uint8_t c = *data++;
        for (uint32_t i = 0x80; i > 0; i >>= 1) {
          bool bit = crc & 0x80000000;
          if (c & i) bit = !bit;
          crc <<= 1;
          if (bit) crc ^= 0x04c11db7;
        }
      }
      return crc;
    }
     
    void printByte(uint8_t b) {
      Serial.print("0x");
      if (b < 0x10) Serial.write('0');
      Serial.print(b, HEX);
    }
     
    void printStructure(WiFiRapide& s) {
      Serial.print("channel = "); Serial.println(s.channel);
      Serial.print("ap_mac[] = ");
      for (uint8_t i = 0; i < sizeof(s.ap_mac); i++) {
        printByte(s.ap_mac[i]);
        Serial.write(' ');
      }
      Serial.println();
      Serial.print("CRC32-MPEG2 = 0x"); Serial.println(s.crc32, HEX);
    }
     
     
    void setup() {
      delay(1000); // juste pour voir la première connexion, à ne pas conserver
      Serial.begin(115200);
      while (!Serial) yield();
     
      esp_reset_reason_t resetReason = esp_reset_reason();
      if (resetReason != ESP_RST_DEEPSLEEP) {
        Serial.println("Premier boot");
      } else {
        Serial.println("Reboot sur timer");
      }
     
      // on vérifie si ce qu'on avait dans la mémoire était correct (ce ne sera pas le cas au boot)
      uint32_t crcAttendu = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
      bool isRtcValid = (rtcData.crc32 == crcAttendu);
     
      Serial.print("crcAttendu = 0x"); Serial.println(crcAttendu, HEX);
      Serial.print("crc en mémoire RTC = 0x"); Serial.println(rtcData.crc32, HEX);
     
      // Se connecter au Wi-Fi
      WiFi.mode(WIFI_STA);
      //  WiFi.config(ip, dns, gateway, subnet); // si vous n'avez pas une config en DHCP
     
      if (isRtcValid) {
        Serial.print("Connexion RAPIDE au Wi-Fi en cours...");
        WiFi.begin(WLAN_SSID, WLAN_PASSWD, rtcData.channel, rtcData.ap_mac, true);
      } else {
        Serial.print("Connexion LENTE au Wi-Fi en cours...");
        WiFi.begin(WLAN_SSID, WLAN_PASSWD);
      }
     
      while (WiFi.status() != WL_CONNECTED) {
        Serial.write('.');
        delay(500);
      }
     
      Serial.println(" => Connecté");
      Serial.print("adresse IP:");   Serial.println(WiFi.localIP());
     
      // si la mémoire RTC n'était pas valide, on la met à jour pour le prochain réveil
      if (!isRtcValid) {
        rtcData.channel = WiFi.channel();
        memcpy(rtcData.ap_mac, WiFi.BSSID(), 6); // les 6 octets de l'adresse mac
        // puis pn met à jour le CRC dans la structure
        rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
        Serial.println(" J'ai sauvegardé la config pour la prochaine fois en mémoire RTC. ");
        printStructure(rtcData);
      }
     
      Serial.flush();
     
      esp_sleep_enable_timer_wakeup(3000000ULL); // on programme un réveil pour dans 3s (en µs)
      esp_deep_sleep_start();
    }
     
    void loop() {}
    vous verrez qu'au premier boot les données ne sont pas bonnes (le crcAttendu n'est pas le même que celui en mémoire) et donc on fait une connexion wifi lente mais on mémorise les données et on calcule le bon CRC. Au reboot suivant sur timer, la mémoire est correcte (le crcAttendu est identique à celui en mémoire) et donc on utilise la connexion au WiFi rapide.

  17. #17
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    grand merci une fois encore Jay M

    Voici le croquis réactualisé avec votre prposition du post précédent

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
     
    /***************************************
              uPesy ESP32C3 Basic Low Power
              
                       ------------------
                       |                |
                       |----------------|
                       |                |
                       |                |
                       |----------------|
                       |                |
               RESET   |EN           OFF| POWER OFF
       SCL     GPIO4   |4              1| GPIO1      DC
      AM2301A  GPIO5   |5              2| GPIO2      RES   
       SDA     GPIO6   |6              3| GPIO3      BUSY
       CS      GPIO7   |7             10| GPIO10     DS18B20
               GPIO8   |8             20| GPIO20
               GPIO9   |9             21| GPIO21 
                       |VIN          3V3| 3V3    VCC
                       |5V           3V3| 3V3    VCC
                       |GND    |----| 17| GND
                       \-------|    |---/
                               |----| 
    *************************************/
     
    #include <WiFi.h>
    #include <Wire.h>
    #include <ArduinoOTA.h>
    #include <Arduino.h>
    #include <PubSubClient.h>
    #include "BitmapGraphics.h"
    #include <functional>
     
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include "config.h"
     
    #include "DHTesp.h"
    #include <MQTT.h>
     
    char server[] = "mqtt3.thingspeak.com";
     
    //  E-paper *********************************************
    #include <GxEPD2_BW.h>
    #include <GxEPD2_GFX.h>
    #include <Fonts/FreeMonoBold9pt7b.h>
    #include "FreeSerifBold30pt7b.h"
    // 1.54'' EPD Module
    GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(/*CS=7*/ 7, /*DC=*/ 1, /*RES=*/ 2, /*BUSY=*/3)); // GDEH0154D67 200x200, SSD1681
    //*******************************************************
     
    //*******************************************************
    #if DEBUG
    #define D_SerialBegin(...) Serial.begin(__VA_ARGS__)
    #define D_print(...) Serial.print(__VA_ARGS__)
    #define D_write(...) Serial.write(__VA_ARGS__)
    #define D_println(...) Serial.println(__VA_ARGS__)
    #define D_printf(...) Serial.printf(__VA_ARGS__)
    #define D_flush(...) Serial.flush(__VA_ARGS__)
    #define D_timestamp() Serial.printf("[%lu] ", millis())
    #else
    #define D_SerialBegin(bauds)
    #define D_print(...)
    #define D_write(...)
    #define D_println(...)
    #define D_printf(...)
    #define D_flush(...)
    #define D_timestamp()
    #endif
     
    #define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
    #define TIME_TO_SLEEP  15        /* Time ESP32 will go to sleep (in seconds) */
     
    //#ifndef ESPTEMP_VERSION
    //#define ESPTEMP_VERSION "v1.1" //**< The current version of the ESPtemp firmware*/
    //#endif
     
    #ifndef SLEEPTIME
      #define SLEEPTIME 15e6 /**< Time in deepsleep */
    #endif
     
    //#ifndef SLEEPTIME_EXTENDED
    //#define SLEEPTIME_EXTENDED 21600e6 /**< Temps en sommeil profond si une erreur s'est produite en essayant de se connecter au wifi (pour éviter le drainage de la batterie).) */
    //#endif
     
    #ifndef DEBUG
    #define DEBUG 0 /**< Régler à 1 pour déboguer en série */
    #endif
    //*******************************************************
     
    const byte oneWireBus = 10;  // DS18B20 pin used for Temperature sensor bus GIPO10
     
    float humidity;
    float temperature;
     
    char temp[10];
    char bat[10];
    float piscine;
     
    const gpio_num_t vbatPin = GPIO_NUM_0;
    float batteryVoltage;
    int8_t batteryPercentage;
    uint_fast16_t adcValue;
    char error[15];
     
    uint8_t wifiRetries = 0;
     
    bool isDS18B20ready = false;
    bool isDHTready = false;
    bool isADCReady = false;
    bool isWifiStarted = false;
    bool isWifiReady = false;
    bool isRegularWifi = false;
    bool isMQTTStarted = false;
    bool isMQTTReady = false;
    bool isRtcValid = false;
    bool isOTAEnabled = false;
     
    //*********** Init **************************
    WiFiClient  wifiClient;
    WiFiServer serverAP(80);
    PubSubClient pubSubclient(wifiClient);
    OneWire oneWire(oneWireBus);
    DallasTemperature sensors(&oneWire);
    DHTesp dht;
     
     
    //******************************************************** 
    struct __attribute__((packed, aligned(1))) WiFiRapide {
      uint8_t channel;
      uint8_t ap_mac[6];
      uint32_t crc32;
    };
     
    //RTC_DATA_ATTR MaStructure rtcData = {0, {0x58, 0xCF, 0x79, 0x1A, 0x54, 0x14}, 0};
    //RTC_DATA_ATTR uint32_t compteurDeReboot = 0;
    RTC_DATA_ATTR WiFiRapide rtcData = {0, {0, 0, 0, 0, 0, 0}, 0xDEADBEEF}; // on met n'importe quoi pour le premier boot
     
    uint32_t calculateCRC32MPGE2(const uint8_t *data, size_t length) {
      uint32_t crc = 0xffffffff;
      while (length--) {
        uint8_t c = *data++;
        for (uint32_t i = 0x80; i > 0; i >>= 1) {
          bool bit = crc & 0x80000000;
          if (c & i) bit = !bit;
          crc <<= 1;
          if (bit) crc ^= 0x04c11db7;
        }
      }
      return crc;
    }
     
    void printByte(uint8_t b) {
      Serial.print("0x");
      if (b < 0x10) Serial.write('0');
      Serial.print(b, HEX);
    }
     
    void printStructure(WiFiRapide& s) {
      Serial.print("channel = "); Serial.println(s.channel);
      Serial.print("ap_mac[] = ");
      for (uint8_t i = 0; i < sizeof(s.ap_mac); i++) {
        printByte(s.ap_mac[i]);
        Serial.write(' ');
      }
      Serial.println();
      Serial.print("CRC32-MPEG2 = 0x"); Serial.println(s.crc32, HEX);
    }
    unsigned long startMillis;
     
    //*****************************************
    // SETUP
    //****************************************
     
    void setup()
    {
     
      delay(1000); // il sert surtout au premier boot pour qu'on le voit sur le moniteur série
      D_SerialBegin(115200);
      while (!Serial) yield();
      Serial.print("Taille de la structure = "); Serial.print(sizeof rtcData); Serial.println(" octets.");
     
      esp_reset_reason_t resetReason = esp_reset_reason();
      if (resetReason != ESP_RST_DEEPSLEEP) {
        Serial.println("Premier boot");
      } else {
        Serial.println("Reboot sur timer");
      }
     
      // on vérifie si ce qu'on avait dans la mémoire était correct (ce ne sera pas le cas au boot)
      uint32_t crcAttendu = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
      bool isRtcValid = (rtcData.crc32 == crcAttendu);
     
      Serial.print("crcAttendu = 0x"); Serial.println(crcAttendu, HEX);
      Serial.print("crc en mémoire RTC = 0x"); Serial.println(rtcData.crc32, HEX);
     
     
     
      Serial.println( "Start" );
      pinMode(0, INPUT); // Pin Entree VBAT
      pinMode(5, INPUT); // Pin Entree AM2301A
     
     
    	D_println();
    	D_timestamp();
    	D_printf("CpuFreqMHz: %u MHz\n", ESP.getCpuFreqMHz());
    	D_timestamp();
    	D_print("MAC Address: ");
    	D_println(WiFi.macAddress()); 
     
     
        //**** INIT Ecran E-paper**********
        display.init(115200,true,50,false);
        display.setRotation(3);
        display.setFullWindow();
        display.fillScreen(GxEPD_BLACK);
        display.drawBitmap(0, 0, gImage_gui, 200, 200, GxEPD_WHITE);
        while (display.nextPage()); 
        delay(500) ;     
     
        // *** DS18B20 Temperature sensor ****
        sensors.begin(); 
     
        // *** AM2301A Temperature sensor ****
        dht.setup(5, DHTesp::DHT22); // Connect DHT sensor to GPIO 5
     
        // Wait minimum sampling period
        startMillis = millis();
     
        //---------------------------------------------
        // Step 0:
        // Read temperature from DS18B20
        //---------------------------------------------
     
        if (!isDS18B20ready)
        {  
           sensors.requestTemperatures(); 
           float raw_temp = sensors.getTempCByIndex(0);
           piscine = sensors.getTempCByIndex(0);
           Serial.printf("Temperature = %8.4f°C\r\n", (float)raw_temp);
           snprintf(temp, sizeof temp, "%.1f",(float)raw_temp);
           updatePiscine();
           isDS18B20ready = true;
        }
     
        //---------------------------------------------
        // Step 1: Lecture de la température et de l'humidité à partir de l'AM2301A
        //---------------------------------------------
        if (!isDHTready)
        {
            humidity =  dht.getHumidity();       // Humidite Air  
            temperature = dht.getTemperature(); // temperature Air
            temperature = temperature -2; // facteur de correction(?)
            D_timestamp();
            D_println("AM2301A Reading ready");
            D_timestamp();
            D_printf("Temperature: %.1f, Humidity: %.1f ", temperature, humidity);
            D_println();
            isDHTready = true;
        }   
     
        //---------------------------------------------
        // Step 2: Lecture Batterie ADC GPIO0
        //---------------------------------------------
        if (!isADCReady)
        {
            adcValue = analogRead(vbatPin); //<============
            batteryVoltage = 2*(adcValue/4095.0)*3; // tension comprise netre 3.5v et 6.5v en entrée 
            batteryPercentage = ((batteryVoltage/6)*100); // 6V = 4 piles AA
     
            int tensionBrute =adcValue ;
            constexpr int seuilTensionBruteBasse = 2185; // 3.2V ==> calculé par (3.2V * 4096) / 6V
            if  (tensionBrute <= seuilTensionBruteBasse)
            {
                D_timestamp();
                D_println("Batterie faible. Sommeil profond.");
                D_printf("Battery Percentage: %i", batteryPercentage);
                //esp_sleep_enable_timer_wakeup(120000000ULL); // on programme un réveil pour dans 120s (en µs)
            }
     
            D_timestamp();
            D_println("ADC Reading ready");
            D_timestamp();
            D_printf("Vbat: %.1f",batteryVoltage);
            D_println();
     
            sprintf(bat, "%3d%s", batteryPercentage, "%");
            updateBattery() ;
            isADCReady = true;
        }
     
     
     
        //---------------------------------------------
        // Step 3: Demarrage Connection WIFI
        //---------------------------------------------
     
    		D_timestamp();
    		D_println("Démarrage du WiFi");
     
     
    		// Se connecter au Wi-Fi
    		 WiFi.mode(WIFI_STA);
    		//  WiFi.config(ip, dns, gateway, subnet); // si vous n'avez pas une config en DHCP
     
    		if (isRtcValid) {
    			Serial.print("Connexion RAPIDE au Wi-Fi en cours...");
    			WiFi.begin(WLAN_SSID, WLAN_PASSWD, rtcData.channel, rtcData.ap_mac, true);
    		} else {
    			Serial.print("Connexion LENTE au Wi-Fi en cours...");
    			WiFi.begin(WLAN_SSID, WLAN_PASSWD);
    		}
     
    		isWifiStarted = true;
     
     
     
        //---------------------------------------------
        // Step 4: Si le WiFi est prêt : Initialiser le client MQTT
        //---------------------------------------------
     
        if (isWifiStarted)
        {
     
    		while (WiFi.status() != WL_CONNECTED) 
    		{
    		Serial.write('.');
    		delay(500);
            }
     
    		Serial.println(" => Connecté");
    		Serial.print("adresse IP:");   Serial.println(WiFi.localIP());
     
    		// si la mémoire RTC n'était pas valide, on la met à jour pour le prochain réveil
    		if (!isRtcValid) {
    			rtcData.channel = WiFi.channel();
    			memcpy(rtcData.ap_mac, WiFi.BSSID(), 6); // les 6 octets de l'adresse mac
    			// puis on met à jour le CRC dans la structure
    			rtcData.crc32 = calculateCRC32MPGE2((uint8_t*)&rtcData, sizeof rtcData - sizeof(uint32_t));
    			Serial.println(" J'ai sauvegardé la config pour la prochaine fois en mémoire RTC. ");
    			printStructure(rtcData);
    		}
     
    		Serial.flush();
     		esp_sleep_enable_timer_wakeup(SLEEPTIME); // on programme un réveil pour dans 15s (en µs)
    	}
     
      esp_deep_sleep_start();  
     
    }
     
     
    //**************************************
    //  LOOP
    //**************************************
    void loop() {}
     
     
    //*******************************************************
    void updateBattery() 
    {
      int16_t tbx, tPar;
      uint16_t tbw, tbh;
      display.setRotation(3);
      display.setFont(&FreeMonoBold9pt7b);
      display.setTextColor(GxEPD_BLACK);
      uint16_t x = 136;
      uint16_t y = 176;
      display.getTextBounds(bat, x, y, &tbx, &tPar, &tbw, &tbh);
     
      display.setPartialWindow(tbx, tPar, tbw, tbh);
      display.firstPage();
      do {
        //display.fillScreen(GxEPD_WHITE);
        display.setCursor(x, y);
        display.print(bat);
      } while (display.nextPage());
      delay(500);
     
    }
     
     
    //*******************************************************
    void updatePiscine() 
    {
      int16_t tbx, tPar;
      uint16_t tbw, tbh;
      display.setRotation(3);
      display.setFont(&FreeSerifBold30pt7b);
      display.setTextColor(GxEPD_BLACK);
      uint16_t x = 72;
      uint16_t y = 112;
      display.getTextBounds(temp, x, y, &tbx, &tPar, &tbw, &tbh);
     
      display.setPartialWindow(tbx, tPar, tbw, tbh);
      display.firstPage();
      do {
        display.fillScreen(GxEPD_WHITE);
        display.setCursor(x, y);
        display.print(temp);
      } while (display.nextPage());
       delay(500);
    }


    J'ai besoin de votre aide car si la compilation se passe sans problème par contre l'µC ne lui redemarre pas après les 15s de deep_sleep
    pourquoi ? Aurai-je oublier quelque chose ?

    ci_joint image 1er boot
    Images attachées Images attachées  

  18. #18
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    je ne sais pas trop (je n'ai pas de uPesy ESP32C3 pour tester)

    - pourquoi activer le WiFi alors qu'il n'est pas utilisé ?
    - pourquoi ne pas l'activer au début avant de faire toutes les mesures et mises à jour écran
    - pourquoi utiliser GPIO_NUM_0 et 0 - est-ce la même valeur ? qu'est-ce qui est connecté sur cette pin?
    - éviter de passer un nombre en notation scientifique (c'est un double) quand un unsigned long long est attendu. (faites esp_sleep_enable_timer_wakeup(15000000ull); par exemple)

    imprimez par acquis de conscience la valeur de SLEEPTIME


    est-ce que mon code de test fonctionnait ?

  19. #19
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    je ne sais pas trop (je n'ai pas de uPesy ESP32C3 pour tester)
    En fait , je pense que le problème vient du type ESP32C3 , la liaison USB est spéciale , je ne peux pas voir le réveil de l'µC comme un ESP32 par ex
    j'aurai un grand besoin de savoir comment je peux valider le reboot si je ne peux pas le suivre via la liaison USB

    - pourquoi activer le WiFi alors qu'il n'est pas utilisé ?
    où exactement ? pardon mais je n'ai pas compris la question

    pourquoi ne pas l'activer au début avant de faire toutes les mesures et mises à jour écran
    c'est juste mais un reste sans doute de l'auteur , mais çà permet par contre de ne pas bloquer la mise à jour de l'affichage en local en cas de perte de Wifi par ex
    le Wifi sert ici à la mise à jour MQTT

    pourquoi utiliser GPIO_NUM_0 et 0 - est-ce la même valeur ? qu'est-ce qui est connecté sur cette pin?
    sur uPesy ESP32C3 , le GPIO0 est utilisé pour Vbat avec un pont interne de 2Mohms tronquée à 2,5v max mais pas 3.3v
    donc je mets ici un bloc de 4 piles 1.5v

    - éviter de passer un nombre en notation scientifique (c'est un double) quand un unsigned long long est attendu. (faites esp_sleep_enable_timer_wakeup(15000000ull); par exemple)
    vous faites allusion à ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    #ifndef SLEEPTIME
      #define SLEEPTIME 15e6 /**< Time in deepsleep */
    #endif
    est-ce que mon code de test fonctionnait ?
    oui je pense car pour le vérifier (cf ci-dessus) , je suis obligé de relancer la liaison sérielle pour le vérifier
    mais j'ai bien eu 1er boot avec la liaison lente puis au second la liaison rapide

  20. #20
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    Citation Envoyé par cobra38 Voir le message
    sur uPesy ESP32C3 , le GPIO0 est utilisé pour Vbat avec un pont interne de 2Mohms tronquée à 2,5v max mais pas 3.3v
    donc je mets ici un bloc de 4 piles 1.5v
    J'ai regardé la doc de la carte et je ne suis pas sûr de votre formule - pourquoi le x3 ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     batteryVoltage = 2*(adcValue/4095.0)*3; // tension comprise netre 3.5v et 6.5v en entrée
    cette tension est fausse aussi si l'USB est branché apparement

    j'aurai un grand besoin de savoir comment je peux valider le reboot si je ne peux pas le suivre via la liaison USB
    effectivement la carte a des particularités. Si vous avez un adaptateur Série USB qui fonctionne en 3.3V vous pourriez le connecter sur les pins Rx et Tx et utiliser l'UART au lieu de l'USB ce qui vous permettrait aussi de ne pas brancher l'USB qui fausse la lecture de la tension de la batterie


    ----

    PS je faisais référence à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     		esp_sleep_enable_timer_wakeup(SLEEPTIME); // on programme un réveil pour dans 15s (en µs)
    avec SLEEPTIME défini par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #ifndef SLEEPTIME
      #define SLEEPTIME 15e6 /**< Time in deepsleep */
    #endif
    essayez en enlevant les #ifndef et mettez

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    const unsigned long long timeInDeepSleep = 15000000ull;  // Time in deepsleep
    ...
     
     
          sp_sleep_enable_timer_wakeup(timeInDeepSleep); // on programme un réveil pour dans 15s (en µs)
    il vaut mieux donner le max d'info au compilateur pour les types. Un #define n'est pas top pour cela

    si SLEEPTIME est défini ailleurs ce serait un souci aussi...


    -----------

    le Wifi sert ici à la mise à jour MQTT
    OK donc cette partie est manquante pour le moment

Discussions similaires

  1. Sauvegarde de data csv
    Par Invité dans le forum Général Python
    Réponses: 9
    Dernier message: 07/03/2019, 08h03
  2. sauvegarde des datas
    Par ludo1c2 dans le forum VMware
    Réponses: 2
    Dernier message: 05/12/2015, 09h59
  3. Réponses: 0
    Dernier message: 24/01/2014, 16h24
  4. Plus moyen de sauvegarder mes data dans tables
    Par melles dans le forum Bases de données
    Réponses: 6
    Dernier message: 02/10/2008, 16h39
  5. Sauvegarde des data d'une table
    Par yanis97 dans le forum Oracle
    Réponses: 4
    Dernier message: 03/07/2007, 08h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo