Horloge e-paper ESP32 & module RTC

Je rêvais d'une horloge numérique très lisible de loin en plein jour. La voici.

1 Description

Cette réalisation est basée sur une petite carte ESP32 TTGO-T5 sur laquelle un afficheur e-paper est implanté d'origine.
La base de temps est fournie par un module RTC DS1307 ayant sa propre pile de 3V (une classique 2032), sachant que l'horloge de la carte ESP32 est renommée pour ne pas être suffisamment précise pour garder l'heure. J'aurais aussi pu opter pour la solution qui consiste à câbler un quartz externe à la carte ESP32.
Il faut noter que la pile 2032 du module RTC n'alimente PAS la carte ESP32. Un connecteur pour accu LiPo est présent sur la carte.

2 Le schéma

La liaison se fait par le bus I2C (SDA - SLC).
Le fil qui relie le VCC du module RTC au +3V3 de la carte ESP est nécessaire pour la polarisation du bus I2C (par des résistances de pull-up présentes sur la carte) dont la connectique interne se fait avec des collecteurs ouverts et non des totem-pole, ce qui créerait plus que des conflits, des courts-jus !
Donc, bien que chaque carte possède sa propre alimentation, si vous omettez cette liaison ça ne marchera pas, le dialogue entre les carte ne se fera pas.

La LED (optionnelle) bat la mesure (1s), chose que l'on fait habituellement par clignotement des deux points entre les heures et les minutes, ce qui est tout à fait déconseillé dans le cas d'un afficheur e-paper. Non pas que la rapidité de rafraîchissement d'une si petite surface ne soit pas suffisante, il s'agit plutôt de ne pas abréger la durée de vie de l'afficheur (dit-on...)

3 Programme source en C++ : Horloge1.ino

CODE SOURCE en C++
  1.  
  2. /**
  3. Horloge1
  4.  
  5. pour 02- LILYGO TTGO T5 + 2.13" E-Paper Screen (250 x 122 px)
  6. OK compilé avec type de carte = "ESP32 Dev Module"
  7. **/
  8.  
  9.  
  10. #define version1 "4.1"
  11.  
  12.  
  13. #include <stdint.h>
  14.  
  15. String recp_time = "12345678";
  16. String recp_date = "87654321";
  17.  
  18.  
  19. #include <GxEPD.h> // note: cette lib inclue la lib "Adafruit_GFX.h" dans laquelle se trouvent les fonctions de base
  20. #include "SPI.h"
  21. #include <Wire.h>
  22. #include "uRTCLib.h"
  23. #include "DHT.h"
  24.  
  25. #include <WiFi.h>
  26. #include <HTTPClient.h>
  27.  
  28. const char* ssid = "TPGPS_123";
  29. const char* password = "abcd1234";
  30.  
  31. const char* srvName_heure = "http://192.168.4.1/heure";
  32. const char* srvName_date = "http://192.168.4.1/date";
  33.  
  34. uRTCLib rtc(0x68);
  35.  
  36.  
  37. //! There are three versions of the 2.13 screen
  38. //#include <GxGDE0213B1/GxGDE0213B1.h> // 2.13" b/w
  39. //#include <GxGDEH0213B72/GxGDEH0213B72.h> // 2.13" b/w new panel
  40. #include <GxGDEH0213B73/GxGDEH0213B73.h> // 2.13" b/w newer panel
  41.  
  42. #include "chiffres/60_75/chiffres60_75.c"
  43.  
  44. // FreeFonts from Adafruit_GFX
  45. #include <Fonts/FreeMonoBold9pt7b.h>
  46. #include <Fonts/FreeMonoBold12pt7b.h>
  47. #include <Fonts/FreeMonoBold18pt7b.h>
  48. #include <Fonts/FreeMonoBold24pt7b.h>
  49.  
  50.  
  51. #include <GxIO/GxIO_SPI/GxIO_SPI.h>
  52. #include <GxIO/GxIO.h>
  53.  
  54. #define SPI_MOSI 23
  55. #define SPI_MISO -1
  56. #define SPI_CLK 18
  57.  
  58. #define ELINK_SS 5
  59. #define ELINK_BUSY 4
  60. #define ELINK_RESET 16
  61. #define ELINK_DC 17
  62.  
  63. #define SDCARD_SS 13
  64. #define SDCARD_CLK 14
  65. #define SDCARD_MOSI 15
  66. #define SDCARD_MISO 2
  67.  
  68. #define DHTTYPE DHT11 // DHT 11
  69. //#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
  70. //#define DHTTYPE DHT21 // DHT 21 (AM2301)
  71. #define DHTPIN 19 // Digital pin connected to the DHT sensor
  72.  
  73.  
  74. //#define bouton1 39
  75. //#define led1 12 //const int led1 = 12;
  76.  
  77. const int led1 = 12;
  78. const int bouton1 = 39;
  79.  
  80. bool led1_etat = LOW;
  81. bool bouton1_etat; // état bouton1
  82.  
  83. const uint32_t partial_update_period_s = 1;
  84. const uint32_t full_update_period_s = 6 * 60 * 60;
  85.  
  86.  
  87. uint32_t start_time;
  88. uint32_t next_time;
  89. uint32_t previous_time;
  90. uint32_t previous_full_update;
  91.  
  92. uint32_t memoM1 = 0;
  93. uint32_t memoM2 = 0;
  94. uint32_t currentMillis=0;
  95. const uint32_t tempo1 = 2000; // 2000 ms = 2s
  96.  
  97. #define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
  98. #define TIME_TO_SLEEP 2 /* Time ESP32 will go to sleep (secondes) */
  99.  
  100. uint8_t annee;
  101. uint8_t mois;
  102. uint8_t jour;
  103. uint8_t jour_de_la_semaine;
  104. uint8_t heure=0;
  105. uint8_t minute=0;
  106. uint8_t memo_minute=0;
  107. uint8_t seconde=0;
  108.  
  109. uint8_t annee_in=0;
  110. uint8_t mois_in=0;
  111. uint8_t jour_in=0;
  112. uint8_t heures_in=0;
  113. uint8_t minutes_in=0;
  114. uint8_t secondes_in=0;
  115.  
  116.  
  117. uint8_t W_chiffres = 60;
  118. uint8_t H_chiffres = 75;
  119.  
  120. uint16_t box1_x = 0;
  121. uint16_t box1_y = 0;
  122. uint16_t box1_w = 249;
  123. uint16_t box1_h = 110;
  124.  
  125. uint16_t box2_x = 0;
  126. uint16_t box2_y = 121-20;
  127. uint16_t box2_w = 175;
  128. uint16_t box2_h = 20;
  129.  
  130.  
  131.  
  132. GxIO_Class io(SPI, ELINK_SS, ELINK_DC, ELINK_RESET);
  133. GxEPD_Class display(io, ELINK_RESET, ELINK_BUSY);
  134.  
  135. SPIClass sdSPI(VSPI);
  136.  
  137. const char *skuNum = "SKU:H239";
  138. int startX = 40, startY = 10;
  139.  
  140. DHT dht(DHTPIN, DHTTYPE);
  141.  
  142. uint8_t WiFi_status=0;
  143.  
  144.  
  145. static void smartdelay(unsigned long ms)
  146. {
  147. unsigned long start = millis();
  148. while (millis() - start < ms) {;}
  149. }
  150.  
  151.  
  152.  
  153. int connection_WiFi()
  154. {
  155. //Serial.println("Cnx Client WiFi");
  156. WiFi.persistent(false);
  157. WiFi.begin(ssid, password);
  158. delay(2000);
  159.  
  160. uint8_t n=0;
  161. while(WiFi.status() != WL_CONNECTED)
  162. {
  163. delay(500);
  164. n++;
  165. display.setTextColor(GxEPD_BLACK);
  166. display.setFont(&FreeMonoBold9pt7b);
  167. display.setTextSize(1);
  168. display.setCursor(0, display.height() -2);
  169. display.print(".");
  170. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  171. if (n>10) {return 1;}
  172. // ECRAN_1.print(".");
  173. //Serial.print(".");
  174. }
  175.  
  176. //Serial.println("");
  177. //Serial.print("Connected to WiFi - IP Address : ");
  178. //Serial.println(WiFi.localIP());
  179. //Serial.println("\n");
  180. return 0;
  181. }
  182.  
  183.  
  184. void httpGetTime()
  185. {
  186. //Serial.println("envoi req Heure");
  187.  
  188. HTTPClient http1;
  189.  
  190. http1.begin(srvName_heure);
  191.  
  192. int httpResponseCode = http1.GET();
  193.  
  194. if (httpResponseCode>0)
  195. {
  196. recp_time = http1.getString();
  197. }
  198. http1.end();
  199. }
  200.  
  201.  
  202. void httpGetDate()
  203. {
  204. //Serial.println("envoi req Date");
  205.  
  206. HTTPClient http2;
  207.  
  208. http2.begin(srvName_date);
  209.  
  210. int httpResponseCode = http2.GET();
  211.  
  212. if (httpResponseCode>0)
  213. {
  214. recp_date = http2.getString();
  215. }
  216. http2.end();
  217. }
  218.  
  219.  
  220. void ajuste_time()
  221. {
  222. //Serial.println("ajuste_time");
  223. //Serial.println( recp_time);
  224. if(recp_time.length() == 8)
  225. {
  226. WiFi_status =1;
  227.  
  228. //String data_in = "11:40:30"
  229.  
  230. heures_in =(recp_time.substring(0,2)).toInt();
  231. //Serial.print(heures_in); //Serial.print(":");
  232.  
  233. minutes_in =(recp_time.substring(3,5)).toInt();
  234. //Serial.print(minutes_in); //Serial.print(":");
  235.  
  236. secondes_in =(recp_time.substring(6,8)).toInt();
  237. //Serial.println(secondes_in);
  238. //secondes_in++; // pour compenser le temps de traitement
  239.  
  240. if ((heures_in==0) && (minutes_in==0)) { return; }
  241.  
  242. if (heure != heures_in) {heure = heures_in;}
  243. if (minute != minutes_in) {minute = minutes_in;}
  244. if (seconde != secondes_in) {seconde = secondes_in;}
  245. }
  246. else
  247. {
  248. //Serial.println("y a qq chose qui cloche !");
  249. WiFi_status=0;
  250. }
  251.  
  252. }
  253.  
  254.  
  255. void ajuste_date()
  256. {
  257. //Serial.println("ici7");
  258. if(recp_date.length() == 8)
  259. {
  260. WiFi_status =1;
  261. //Serial.println("ajuste_date");
  262. //Serial.println( recp_date);
  263. // String data_in = "01:02:21"
  264.  
  265. jour_in =(recp_date.substring(0,2)).toInt();
  266. //Serial.println(jour_in);
  267.  
  268. mois_in =(recp_date.substring(3,5)).toInt();
  269. //Serial.println(mois_in);
  270.  
  271. annee_in =(recp_date.substring(6,8)).toInt();
  272. //Serial.println(annee_in);
  273.  
  274. if (jour != jour_in) {jour = jour_in;}
  275. if (mois != mois_in) {mois = mois_in;}
  276. if (annee != annee_in) {annee = annee_in;}
  277. }
  278. else {WiFi_status=0;}
  279. }
  280.  
  281.  
  282.  
  283. void set_time_par_wifi()
  284. {
  285.  
  286. display.setTextColor(GxEPD_BLACK);
  287. display.setFont(&FreeMonoBold9pt7b);
  288. display.setTextSize(1);
  289.  
  290. display.fillRect(box2_x, box2_y, box2_w, box2_h, GxEPD_WHITE);
  291. display.print("Cnx Wifi");
  292.  
  293. //display.drawRect(box2_x, box2_y, box2_w, box2_h, GxEPD_BLACK); // pour test visuel de la position et taille de la box
  294. //display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  295.  
  296. int w1=connection_WiFi();
  297. if (w1==0)
  298. {
  299.  
  300. if(WiFi.status()== WL_CONNECTED )
  301. {
  302. //display.print("OK !");
  303.  
  304. delay(500);
  305.  
  306. display.fillRect(box2_x, box2_y, box2_w, box2_h, GxEPD_WHITE);
  307. display.setCursor(0, display.height() -2);
  308. display.print("Rx DATE...");
  309. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  310.  
  311. httpGetDate();
  312. ajuste_date();
  313.  
  314. display.print(recp_date);
  315. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  316. delay(2000);
  317. }
  318. }
  319. else
  320. {
  321. display.fillRect(box2_x, box2_y, box2_w, box2_h, GxEPD_WHITE);
  322. display.setCursor(0, display.height() -2);
  323. display.print("No WIfI");
  324. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  325. smartdelay(1000);
  326. display.fillRect(box2_x, box2_y, box2_w, box2_h, GxEPD_WHITE);
  327. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  328. return ;
  329.  
  330. }
  331.  
  332. //---------------------------------------------------------------------
  333.  
  334. int w2=connection_WiFi();
  335. if (w2==0)
  336. {
  337. if(WiFi.status()== WL_CONNECTED )
  338. {
  339. //display.print("OK !");
  340.  
  341. delay(500);
  342.  
  343. display.fillRect(box2_x, box2_y, box2_w, box2_h, GxEPD_WHITE);
  344. display.setCursor(box2_x+5, box2_y+20);
  345. display.print("Rx TIME...");
  346. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  347.  
  348. httpGetTime();
  349. ajuste_time();
  350.  
  351. display.print(recp_time);
  352. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  353. delay(2000); // pour éviter collision accès wifi
  354.  
  355. }
  356. }
  357.  
  358. delay(1000);
  359. incremente_heure(6); // pour compenser les delais de traitement
  360.  
  361. // paramétrage du module RTC DS1307
  362. //Serial.println("parametrage du module RTC DS1307");
  363. rtc.set(seconde, minute, heure, jour_de_la_semaine, jour, mois, annee);
  364.  
  365. delay(500);
  366.  
  367. /*
  368. display.fillRect(box2_x, box2_y, box2_w, box2_h, GxEPD_WHITE);
  369. for(int8_t n =0; n<4; n++)
  370. {
  371. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  372. }
  373. */
  374.  
  375. display.fillRect(box2_x, box2_y, box2_w, box2_h, GxEPD_WHITE);
  376. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  377.  
  378. delay(100);
  379. //display.update(); //full pour éviter de garder des moirages
  380. //Serial.println("deconnexion WiFi");
  381. WiFi.disconnect();
  382.  
  383. }
  384.  
  385.  
  386.  
  387. void Set_Time()
  388. {
  389. // appelée par appui sur le bouton (en bord de carte) après avoir correctement paramétré ces données.
  390.  
  391. uint8_t second = 3;
  392. uint8_t minute = 39;
  393. uint8_t hour = 5;
  394. uint8_t dayOfWeek = 4; // toutefois le jour de la semaine sera recalculé plus bas, en temps réel
  395. uint8_t dayOfMonth = 20;
  396. uint8_t month = 1;
  397. uint8_t year = 21; // 2021
  398.  
  399. // ensuite je re-commente la ligne ci-dessous pour éviter de reprogrammer l'heure en appuyant sur le bouton par inadvertance...
  400. // rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
  401. }
  402.  
  403.  
  404.  
  405. void incremente_heure(uint8_t nb_s)
  406. {
  407. for (uint8_t n=0; n<nb_s; n++)
  408. {
  409. if (seconde < 59) {seconde+=1;}
  410. else
  411. {
  412. seconde=0;
  413. if (minute < 59) {minute+=1;}
  414. else
  415. {
  416. minute=0;
  417. if (heure < 23) {heure+=1;}
  418. else
  419. heure=0;
  420. }
  421. }
  422. }
  423. }
  424.  
  425.  
  426.  
  427. void setup()
  428. {
  429. esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  430.  
  431. delay (1000);
  432. pinMode(bouton1, INPUT);
  433. pinMode(led1, OUTPUT);
  434.  
  435. //Serial.begin(115200);
  436. //Serial.println("//Serial OK");
  437.  
  438. #ifdef ARDUINO_ARCH_ESP8266
  439. URTCLIB_WIRE.begin(0, 2); // D3 and D4 on ESP8266
  440. #else
  441. URTCLIB_WIRE.begin();
  442. #endif
  443.  
  444. start_time = next_time = previous_time = previous_full_update = millis();
  445.  
  446. display.init();
  447.  
  448. display.setRotation(1);
  449. //display.fillScreen(GxEPD_WHITE);
  450. display.setTextColor(GxEPD_BLACK);
  451. display.setFont(&FreeMonoBold12pt7b);
  452. display.setCursor(0, 0);
  453.  
  454. //esp_sleep_enable_ext0_wakeup((gpio_num_t)BUTTON_PIN, LOW);
  455.  
  456. display.fillScreen(GxEPD_WHITE);
  457. //display.eraseDisplay();
  458.  
  459. display.update();
  460.  
  461. dht.begin();
  462.  
  463. start_time = next_time = previous_time = previous_full_update = millis();
  464.  
  465. Lit_RTC();
  466. affichages();
  467. //set_time_par_wifi();
  468. //delay(1000);
  469. //affichages();
  470. }
  471.  
  472.  
  473.  
  474. void print_big_chiffre(uint8_t nb, uint16_t x0 ,uint16_t y0) //avec bitmaps perso
  475. {
  476. uint16_t w0=60;
  477. uint16_t h0=75;
  478.  
  479. switch (nb)
  480. {
  481. case 0: {display.drawBitmap(chiffre0, x0, y0, w0, h0, GxEPD_BLACK); } break;
  482. case 1: {display.drawBitmap(chiffre1, x0, y0, w0, h0, GxEPD_BLACK); } break;
  483. case 2: {display.drawBitmap(chiffre2, x0, y0, w0, h0, GxEPD_BLACK); } break;
  484. case 3: {display.drawBitmap(chiffre3, x0, y0, w0, h0, GxEPD_BLACK); } break;
  485. case 4: {display.drawBitmap(chiffre4, x0, y0, w0, h0, GxEPD_BLACK); } break;
  486. case 5: {display.drawBitmap(chiffre5, x0, y0, w0, h0, GxEPD_BLACK); } break;
  487. case 6: {display.drawBitmap(chiffre6, x0, y0, w0, h0, GxEPD_BLACK); } break;
  488. case 7: {display.drawBitmap(chiffre7, x0, y0, w0, h0, GxEPD_BLACK); } break;
  489. case 8: {display.drawBitmap(chiffre8, x0, y0, w0, h0, GxEPD_BLACK); } break;
  490. case 9: {display.drawBitmap(chiffre9, x0, y0, w0, h0, GxEPD_BLACK); } break;
  491. }
  492. }
  493.  
  494.  
  495.  
  496. void affiche_heure()
  497. {
  498. display.fillRect(box1_x, box1_y, box1_w, box1_h, GxEPD_WHITE);
  499. //display.setCursor(box1_x, cursor_y);
  500.  
  501. uint8_t x0 = box1_x;
  502. uint8_t y0 = 5;
  503.  
  504. uint8_t heures_unites;
  505. uint8_t heures_dizaines;
  506. heures_unites = heure %10;
  507. heures_dizaines = heure /10;
  508. print_big_chiffre(heures_dizaines, x0, y0);
  509. print_big_chiffre(heures_unites, x0+56, y0);
  510.  
  511. x0+=133;
  512.  
  513. uint8_t minutes_unites ;
  514. uint8_t minutes_dizaines;
  515. minutes_unites = minute %10;
  516. minutes_dizaines = minute /10;
  517. print_big_chiffre(minutes_dizaines, x0, y0);
  518. print_big_chiffre(minutes_unites, x0+56, y0);
  519.  
  520. display.setCursor(106, 70);
  521. display.setTextSize(3);
  522. display.println(":");
  523.  
  524.  
  525. display.updateWindow(box1_x, box1_y, box1_w, box1_h, true);
  526. }
  527.  
  528.  
  529.  
  530. void calcul_jour_de_la_semaine()
  531. {
  532. // d'après l'Algorithme de Mike Keith
  533. uint16_t d, m, y, z, jds;
  534.  
  535. d=jour;
  536. m=mois;
  537. y=annee;
  538.  
  539. if (m>=3)
  540. {
  541. jds = ( ((23*m)/9) + d + 4 + y + (y/4) - (y/100) + (y/400) - 2 ) % 7;
  542. }
  543. else
  544. {
  545. z = y-1;
  546. jds = ( ((23*m)/9) + d + 4 + y + (z/4) - (z/100) + (z/400) ) % 7;
  547. }
  548. jour_de_la_semaine = jds;
  549. }
  550.  
  551.  
  552.  
  553. uint8_t decToBcd( int val )
  554. {
  555. return (uint8_t) ((val / 10 * 16) + (val % 10));
  556. }
  557.  
  558.  
  559.  
  560. String conv_time(uint8_t t)
  561. {
  562. String r;
  563. r=String(t);
  564. if (t<10) {r="0"+r;}
  565. return r;
  566. }
  567.  
  568.  
  569. void affiche_date()
  570. {
  571.  
  572. display.fillRect(box2_x, box2_y, box2_w, box2_h, GxEPD_WHITE);
  573.  
  574. String date;
  575.  
  576. calcul_jour_de_la_semaine();
  577.  
  578.  
  579. switch (jour_de_la_semaine)
  580. {
  581. case 0: { date+="DIM ";} break;
  582. case 1: { date+="LUN ";} break;
  583. case 2: { date+="MAR ";} break;
  584. case 3: { date+="MER ";} break;
  585. case 4: { date+="JEU ";} break;;
  586. case 5: { date+="VEN ";} break;
  587. case 6: { date+="SAM ";} break;
  588. }
  589.  
  590. date += String(conv_time(jour))+" ";
  591.  
  592. switch (mois)
  593. {
  594. case 1: {date+="JAN"; } break;
  595. case 2: {date+="FEV"; } break;
  596. case 3: {date+="MARS";} break;
  597. case 4: {date+="AVR"; } break;
  598. case 5: {date+="MAI"; } break;
  599. case 6: {date+="JUIN";} break;
  600. case 7: {date+="JUIL";} break;
  601. case 8: {date+="AOUT";} break;
  602. case 9: {date+="SEPT";} break;
  603. case 10: {date+="OCT"; } break;
  604. case 11: {date+="NOV"; } break;
  605. case 12: {date+="DEC"; } break;
  606. }
  607. date += " 20"+String(annee);
  608. //date;
  609.  
  610. uint16_t x0=290, y0=75;
  611.  
  612. display.setTextColor(GxEPD_BLACK);
  613. display.setFont(&FreeMonoBold9pt7b);
  614. display.setTextSize(1);
  615. display.setCursor(0, display.height() -2);
  616. display.print(date);
  617.  
  618. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true);
  619.  
  620. currentMillis = millis();
  621. if (currentMillis > 2000) memoM1= currentMillis - 2000; // pour afficher +rapidement au départ
  622.  
  623. }
  624.  
  625.  
  626.  
  627. void affiche_temperature(double T)
  628. {
  629. uint16_t y0 = 122; // position verticale du bord supérieur de la box
  630. uint16_t dy = 34; // dimension verticale de la box
  631. uint16_t box2_x = 180; // position horizontale du bord gauche de la box
  632. uint16_t box2_y = y0-dy;
  633. uint16_t box2_w = 65; // largeur de la box
  634. uint16_t box2_h = dy;
  635.  
  636. display.fillRect(box2_x, box2_y, box2_w, box2_h, GxEPD_WHITE); // efface la surface de la box (en RAM de l'afficheur)
  637.  
  638. display.setTextColor(GxEPD_BLACK);
  639. display.setFont(&FreeMonoBold12pt7b);
  640. display.setTextSize(1,2);
  641. display.setCursor(box2_x, y0-4);
  642.  
  643. display.print(T,1);
  644.  
  645. display.setFont(&FreeMonoBold9pt7b);
  646. display.setTextSize(1);
  647. display.setCursor(box2_x +30, display.height() -20);
  648. display.print("o"); // le signe 'degré' (° Celsius en l'occurence) , absent de la police de caractères
  649.  
  650. // display.drawRect(box2_x, box2_y, box2_w, box2_h, GxEPD_BLACK); // pour test visuel de la position et taille de la box
  651.  
  652. display.updateWindow(box2_x, box2_y, box2_w, box2_h, true); // affichage physique sur l'e-paper
  653.  
  654. }
  655.  
  656.  
  657.  
  658. void affichages()
  659. {
  660. affiche_heure();
  661. affiche_date();
  662.  
  663. float H1 = dht.readHumidity();
  664. double T1 = dht.readTemperature(); // °C par defaut
  665. //Serial.print(F("Temperature: ")); ////Serial.println(T1);
  666. affiche_temperature(T1);
  667.  
  668. }
  669.  
  670.  
  671.  
  672. void Lit_RTC()
  673. {
  674. rtc.refresh();
  675.  
  676. annee=rtc.year();
  677. mois=rtc.month();
  678. jour=rtc.day();
  679. jour_de_la_semaine=rtc.dayOfWeek();
  680. heure = rtc.hour();
  681.  
  682. memo_minute = minute;
  683. minute = rtc.minute();
  684.  
  685. seconde = rtc.second();
  686. }
  687.  
  688.  
  689.  
  690. void loop()
  691. {
  692. bouton1_etat = digitalRead(bouton1);
  693. if (bouton1_etat == 0)
  694. {
  695. Set_Time();
  696.  
  697. for(int n=0; n<20; n++)
  698. {
  699. digitalWrite(led1, HIGH);
  700. delay(20);
  701. digitalWrite(led1, LOW);
  702. delay(20);
  703. }
  704. }
  705.  
  706. currentMillis = millis();
  707.  
  708. if(currentMillis - memoM1 >= tempo1)
  709. {
  710. memoM1 = currentMillis;
  711. // B = digitalRead(BUTTON_PIN);
  712.  
  713. digitalWrite(led1, HIGH); // allume la led (ajoutée) (pour un bref petit flash) -> test visuel du fonctionnement
  714.  
  715. Lit_RTC();
  716.  
  717. digitalWrite(led1, LOW); // éteint la led ajoutée
  718.  
  719. if(minute != memo_minute)
  720. {
  721. affichages();
  722. }
  723. }
  724. esp_light_sleep_start();
  725. }
  726.  
  727.  
  728.  
  729.  


Ce code est à compiler avec l'EDI Arduino en ayant pris soin de le configurer pour "Type de carte" = "ESP32 Dev Module"
Il faut bien entendu avoir chargé les plugings ESP avec le "Gestionnaire de modules".
Pour plus de détails, je vous renvoie vers mon article précédent :

4 Mise à l'heure du module RTC 1307

Il suffit d'appuyer sur le bouton de la carte (celui le plus proche du bord de la carte). En ayant au préalable paramétré correctement la fonction : "void Set_Time()"

void Set_Time() //appelée par appui sur le bouton tout à droite (après avoir correctement paramétré ces données)
{
// rappel format: RTCLib::set(second, minute, hour, dayOfWeek, dayOfMonth, month, year)
   rtc.set(3, 20, 15, 7, 16, 1, 21); // Only used once, then disabled
}


L'appel de cette fonction se fait en début de la boucle "Loop"

5 Que diriez vous d'un petit boitier ?

Vous avez une imprimante 3D ? Alors je vous ai créé ce petit boitier sur mesure en PLA blanc.

Le câble noir est branché sur le connecteur USB de la carte et ne sert ici qu'à l'alimentation électrique en 5V. Mais on peut tout à fait alimenter cette carte par un autre moyen, batterie par exemple (attention à la tension toutefois).

6 qui tient dans la main

Ben oui, ces cartes ESP32 sont toutes-petites.

7 Voyons ce qu'il y a dans la boite :

le module RTC fixé sur une petite plaque de séparation

8 positionneurs de la carte ESP

Cette plaque est elle même fixée sur deux éléments servant à positionner la carte ESP32 et son afficheur e-paper précisément derrière la fenêtre.

9 L'ensemble des éléments

On voit ici l'arrière de la carte ESP32, son afficheur est situé sur l'autre face.

Vous trouverez plus bas sur cette page tous les fichiers source 3D servant à fabriquer (et/ou modifier) ce boîtier :
- fichier source pour le dessin avec le logiciel libre et gratuit Freecad
- fichier .stl pour le programme Cura
- fichier .gcode pour l'imprimante 3D "Ender 3"

10 Capteur de température

9 Fev 2021 :
Ajout d'un capteur de température DHT11 relié à l'entrée GPIO 19 de l'ESP32. J'ai complété le programme en conséquence.

Il y a lieu de placer ce capteur en dehors du boîtier principal afin d'éviter de mesurer une température faussé par la chaleur dégagée par la carte ESP32 (plusieurs °C en plus).

11 Mode basse consommation

14 fev 2021 :
J'ai programmé le mode "esp_light_sleep" qui se déclenche à intervalles réguliers, le réveil se faisant par un timer prévu à cet effet :

esp_sleep_enable_timer_wakeup()

ce qui réduit drastiquement la consommation électrique de la carte, et laisse envisager de replacer le capteur de température à l'intérieur du boitier et d'alimenter le tout par batterie LiPo miniature. Toutefois je ne confirme pas ce dernier point avant de l'avoir expérimenté...

12 Mise à l'heure par Wifi

12 avril 2021 :
Au lancement du programme (c'est à dire lors du branchement de l'alimentation), l'horloge cherche à se connecter à un serveur WiFi afin de récupérer l'heure exacte et de programmer le module RTC en conséquence. Pas n'importe quel serveur WiFi. Le serveur en question est celui décrit dans cet article :

C'est un ESP32 qui ne comprend pas de module RTC mais reçoit l'heure par GPS. Il faut juste choisir les identifiants et mots de passe, (ceux que vous voulez) identiques pour le serveur et le client. Si le serveur en question n'est pas reçu, (pas en fonction ou hors de portée WiFi), l'horloge démarre normalement sur son module RTC. Ce qui signifie que l'on est pas obligé de laisser tourner le serveur GPS H24. Toutefois lorsqu'on désire resynchroniser précisément l'horloge, il y a lieu de démarrer au préalable le serveur, et surtout d'attendre sa propre synchronisation par GPS sous peine de récupérer une heure inexacte (1:00 l'hiver ou 2:00 l'été) et de programmer le module RTC avec... (m'enfin, rien de grave, mais c'est pas top !)

Et si vous êtes allergique au WiFI, aux serveurs, au GPS, ou simplement si vous ne comptez pas réaliser ledit serveur, j'ai conservé une fonction de mise à l'heure manuelle (dont j'ai déjà parlé plus haut) dans le programme :

void Set_Time() {.....}

Voir le code source pour plus de détails.

13 Documents

14 -

Liens...

10316