Horloge GPS client-serveur ESP32

Une horloge ESP32 serveur WiFi, pilotée par GPS, + horloge ESP32 client.
Cette réalisation nous permettra donc de nous familiariser avec :
- la programmation des microcontrôleurs ESP32.
- la connexion d'un module récepteur GPS NEO-6M à un ESP32.
- la création d'un réseau local WiFi autonome (ne nécessitant pas de box routeur internet).
- l'échange de données directement entre deux ESP32 par WiFi (requête et retour au format html).
- l'utilisation d'une mini carte ESP32 TTGO T-display (avec affichage intégré OLED couleur).

1 Le serveur de temps GPS

Le serveur dans son boîtier imprimé en 3D sur une Ender3 Pro.

- à droite le cordon d'alim 5V avec son adaptateur USB-C
- en haut le connecteur SMA pour la liaison à l'antenne GPS.

2 Le serveur vu de dos :

La carte ESP32 configurée en serveur WiFi 2.4GHz + le module GPS absorbent (et restituent en chaleur) environ 5V x 50mA = 0.25W, ce qui suffit à élever significativement la température dans cette très petite boite. D'où la grille pour l'aération. Il est extrêmement simple de dessiner une telle structure avec le logiciel libre FreeCad. Vous trouverez les sources au bas de la page.

3 Dans la boite :

Ici on voit surtout le module GPS.

La petite vis près du connecteur SMA sert à le fixer en rotation (avec une petite équerre en laiton, soudée).

4 Le carte ESP32 TTGO t-display

L"écran couleur LCD de 1.14" a une définition de 135 x 240 pixels. Çà peut paraître peu, mais compte tenu de la taille minuscule de l'afficheur, c'est tout à fait suffisant : on ne discerne pas les pixels à l’œil nu, et les images sont parfaitement nettes.

A noter toutefois une particularité étonnante : le connecteur USB est un modèle USB-C (qui se branche donc indifféremment dans les deux sens, mais qui nécessite un adaptateur pour pouvoir être connecté à un câble USB classique).

5 Schéma du serveur

C'est sans doute le schéma le plus simple que j'ai eu à dessiner !

Les pins GPIO37 et GPIO38 choisis pour la liaison série (RX-TX) sont définis dans le logiciel.

static const int RxPin = 38; // UART pin_in relié à GPS_Tx static const int TxPin = 37; // UART pin_out relié à GPS_Rx

On peut choisir autre chose, en fonction de la présence d'éventuels périphériques supplémentaires... Ce qui compte c'est que la sortie de l'un soit relié à l'entrée de l'autre, et vice-versa.

6 Le code source en C++ du serveur :

CODE SOURCE en C++
  1. /***********
  2.   GPS_Time & SERVEUR WiFi local (ip=192.168.4.1/)
  3.   pour ESP32 (TTGO T-Display, avec petit ecran LCD couleur IPS ST7789V 1.14 Inch 135x240 px)
  4.   + module NEO-6M
  5.  
  6. il faut choisir (décommenter) la ligne suivante, dans le fichier /libraries/TFT_eSPI/User_Setup_Select.h :
  7.   #include <User_Setups/Setup25_TTGO_T_Display.h> // Setup file for ESP32 and TTGO T-Display ST7789V SPI bus TFT
  8.  
  9.   voir l'exemple "Colour_Test"
  10.  
  11. ************/
  12.  
  13. #define Version "1.1"
  14.  
  15. #include <SoftwareSerial.h>
  16. #include <TinyGPS.h> // include TinyGPS++ library
  17. #include <TFT_eSPI.h>
  18. #include <TimeLib.h> // include Arduino time library
  19. #include <WiFi.h>
  20.  
  21. // #include <WebServer.h>
  22. #include "ESPAsyncWebServer.h"
  23.  
  24.  
  25. const char* ssid = "TPHGS_26";
  26. const char* password = "hd2y8sd5f";
  27.  
  28.  
  29. // WebServer server(80);
  30. AsyncWebServer server(80); // Create AsyncWebServer object on port 80
  31.  
  32.  
  33. static const int RxPin = 38; // UART pin_in relié à GPS_Tx
  34. static const int TxPin = 37; // UART pin_out relié à GPS_Rx
  35.  
  36. TinyGPS GPS;
  37. TFT_eSPI ECRAN_1 = TFT_eSPI();
  38. SoftwareSerial ss(RxPin, TxPin);
  39.  
  40.  
  41. unsigned long age_GPS;
  42. unsigned long date_GPS;
  43. unsigned long heure_GPS;
  44.  
  45.  
  46. uint16_t annee;
  47. uint8_t mois;
  48. uint8_t jour;
  49. uint8_t heures=0;
  50. uint8_t minutes=0;
  51. uint8_t secondes=0;
  52. uint8_t jour_de_la_semaine;
  53.  
  54. uint16_t compte1=0;
  55.  
  56.  
  57. String annee_txt;
  58. String mois_txt;
  59. String jour_txt;
  60. String date_txt;
  61. String date_txt_compacte;
  62.  
  63. String heures_txt;
  64. String minutes_txt;
  65. String secondes_txt;
  66.  
  67.  
  68. char heure_array[9]; // 23:56:02 + zero terminal
  69. char date_array[17]; // Sam 30 Janv 2021 + zero terminal
  70.  
  71. void setup()
  72. {
  73. Serial.begin(115200);
  74. ss.begin(9600);
  75.  
  76. Serial.println("\n");
  77.  
  78.  
  79. ECRAN_1.init();
  80. ECRAN_1.setRotation(1);
  81. ECRAN_1.fillScreen(TFT_BLACK);
  82. ECRAN_1.setCursor(0, 0, 2); // Set "cursor" at top left corner of display (0,0) and select font 4
  83. ECRAN_1.setTextColor(TFT_WHITE, TFT_BLACK);
  84. ECRAN_1.println("Horloge GPS + serveur WiFi");
  85. delay(500);
  86. ECRAN_1.setCursor(0, 20, 4);
  87. ECRAN_1.setTextColor(TFT_YELLOW, TFT_BLACK);
  88. ECRAN_1.println("Connexion...");
  89.  
  90. WiFi.persistent(false);
  91.  
  92. WiFi.softAP(ssid, password); // ok, ça marche, crée un réseau. mode privé
  93.  
  94. IPAddress IP = WiFi.softAPIP();
  95. Serial.print("AP IP address: "); Serial.println(IP);
  96.  
  97. Serial.println(WiFi.status());
  98. // while (WiFi.status() != WL_CONNECTED) // <------ ne marche pas ! toujours = 255
  99. // while (WiFi.localIP().toString() == "0.0.0.0") // <------ ne marche pas non plus !!
  100. {
  101. Serial.print("...");
  102. delay(200);
  103. }
  104.  
  105.  
  106.  
  107. //= heures_txt +":" + minutes_txt +":" + secondes_txt;
  108. server.on("/heure", HTTP_GET, [](AsyncWebServerRequest *request)
  109. {
  110. request->send_P(200, "text/plain", heure_array);
  111. });
  112.  
  113.  
  114. server.on("/date", HTTP_GET, [](AsyncWebServerRequest *request)
  115. {
  116. request->send_P(200, "text/plain", date_array);
  117. });
  118.  
  119.  
  120.  
  121. server.begin();
  122.  
  123. Serial.println("Serveur web actif!");
  124.  
  125. ECRAN_1.setTextColor(TFT_GREEN, TFT_BLACK);
  126. ECRAN_1.println("Serveur web actif !");
  127.  
  128. smartdelay(2000);
  129. ECRAN_1.fillScreen(TFT_BLACK);
  130.  
  131. ECRAN_1.setCursor(200, 0, 2); // Set "cursor" at top left corner of display (0,0) and select font 4
  132. ECRAN_1.setTextColor(TFT_BLUE, TFT_BLACK);
  133. ECRAN_1.println("GPS");
  134.  
  135. delay(1000);
  136. GPS.get_datetime(&date_GPS, &heure_GPS, &age_GPS);
  137. decode_time(date_GPS, heure_GPS);
  138. affiche_date();
  139. }
  140.  
  141.  
  142.  
  143. static void smartdelay(unsigned long ms)
  144. {
  145. unsigned long start = millis();
  146. do
  147. {
  148. while (ss.available()) { GPS.encode(ss.read()); }
  149. }
  150. while (millis() - start < ms);
  151. }
  152.  
  153.  
  154. void decode_time(int32_t date_GPS, int32_t time_GPS)
  155. {
  156. annee = date_GPS % 100;
  157. mois = (date_GPS / 100) % 100;
  158. jour = date_GPS / 10000;
  159. heures = time_GPS / 1000000;
  160.  
  161. heures +=1; //l'hiver +=1 ; l'été -> += 2
  162.  
  163. minutes = (time_GPS / 10000) % 100;
  164. secondes = (time_GPS / 100) % 100;
  165.  
  166. annee_txt="";
  167. if (annee<10) {annee_txt="0";}
  168. annee_txt += (String) annee;
  169.  
  170. mois_txt="";
  171. if (mois<10) {mois_txt="0";}
  172. mois_txt += (String) mois;
  173.  
  174. jour_txt="";
  175. if (jour<10) {jour_txt="0";}
  176. jour_txt += (String) jour;
  177.  
  178. heures_txt="";
  179. if (heures<10) {heures_txt="0";}
  180. heures_txt += (String) heures;
  181.  
  182. minutes_txt="";
  183. if (minutes<10) {minutes_txt="0";}
  184. minutes_txt += (String) minutes;
  185.  
  186. secondes_txt="";
  187. if (secondes<10) {secondes_txt="0";}
  188. secondes_txt += (String) secondes;
  189. }
  190.  
  191.  
  192. void calcul_jour_de_la_semaine()
  193. {
  194. // d'après l'Algorithme de Mike Keith
  195. uint16_t d, m, y, z, jds;
  196.  
  197. d=jour;
  198. m=mois;
  199. y=annee;
  200.  
  201. if (m>=3)
  202. {
  203. jds = ( ((23*m)/9) + d + 4 + y + (y/4) - (y/100) + (y/400) - 2 ) % 7;
  204. }
  205. else
  206. {
  207. z = y-1;
  208. jds = ( ((23*m)/9) + d + 4 + y + (z/4) - (z/100) + (z/400) ) % 7;
  209. }
  210. jour_de_la_semaine = jds;
  211. }
  212.  
  213.  
  214. String conv_time(uint8_t t)
  215. {
  216. String r;
  217. r=String(t);
  218. if (t<10) {r="0"+r;}
  219. return r;
  220. }
  221.  
  222.  
  223.  
  224. void affiche_date()
  225. {
  226. uint16_t box2_x = 0;
  227. uint16_t box2_y = 121-20;
  228. uint16_t box2_w = 175;
  229. uint16_t box2_h = 20;
  230.  
  231. date_txt="";
  232.  
  233. calcul_jour_de_la_semaine();
  234.  
  235.  
  236. switch (jour_de_la_semaine)
  237. {
  238. case 0: { date_txt+="Dim ";} break;
  239. case 1: { date_txt+="Lun ";} break;
  240. case 2: { date_txt+="Mar ";} break;
  241. case 3: { date_txt+="Mer ";} break;
  242. case 4: { date_txt+="Jeu ";} break;;
  243. case 5: { date_txt+="Ven ";} break;
  244. case 6: { date_txt+="Sam ";} break;
  245. }
  246.  
  247. date_txt += String(conv_time(jour))+" ";
  248.  
  249. switch (mois)
  250. {
  251. case 1: {date_txt+="Janv "; } break;
  252. case 2: {date_txt+="Fev "; } break;
  253. case 3: {date_txt+="Mars "; } break;
  254. case 4: {date_txt+="Avr "; } break;
  255. case 5: {date_txt+="Mai "; } break;
  256. case 6: {date_txt+="Juin "; } break;
  257. case 7: {date_txt+="Juil "; } break;
  258. case 8: {date_txt+="Aout "; } break;
  259. case 9: {date_txt+="Sept "; } break;
  260. case 10: {date_txt+="Oct "; } break;
  261. case 11: {date_txt+="Nov "; } break;
  262. case 12: {date_txt+="Dec "; } break;
  263. }
  264.  
  265. date_txt + "20"; // ce sera le bug de l'an 3000 ;)
  266. date_txt += annee_txt;
  267.  
  268. ECRAN_1.setCursor(0, 100, 4);
  269. ECRAN_1.setTextColor(TFT_CYAN, TFT_BLACK);
  270. ECRAN_1.print(date_txt);
  271.  
  272. }
  273.  
  274.  
  275.  
  276. void affiche_heure()
  277. {
  278. ECRAN_1.setCursor(20, 30, 6);
  279. ECRAN_1.setTextColor(TFT_YELLOW, TFT_BLACK);
  280. ECRAN_1.print(heures);
  281. ECRAN_1.print(":");
  282. if(minutes<10){ECRAN_1.print(0);}
  283. ECRAN_1.print(minutes);
  284.  
  285. ECRAN_1.print(" ");
  286. ECRAN_1.setTextColor(TFT_DARKGREY, TFT_BLACK);
  287. if(secondes<10){ECRAN_1.print(0);}
  288. ECRAN_1.print(secondes);
  289. }
  290.  
  291.  
  292. void loop()
  293. {
  294.  
  295. Serial.println(compte1);
  296. // date as ddmmyy, time as hhmmsscc, and age in milliseconds
  297. // void get_datetime(unsigned long *date, unsigned long *time, unsigned long *age = 0);
  298.  
  299. GPS.get_datetime(&date_GPS, &heure_GPS, &age_GPS);
  300. decode_time(date_GPS, heure_GPS);
  301.  
  302. Serial.print("date_GPS: "); Serial.println(date_GPS);
  303. Serial.print("heure_GPS: "); Serial.println(heure_GPS);
  304.  
  305. Serial.print("annee= "); Serial.println(annee);
  306. Serial.print("mois= "); Serial.println(mois);
  307. Serial.print("jour= "); Serial.println(jour);
  308.  
  309. Serial.print("heures= "); Serial.println(heures);
  310. Serial.print("minutes= "); Serial.println(minutes);
  311. Serial.print("secondes= "); Serial.println(secondes);
  312.  
  313. Serial.print("heures_txt= "); Serial.println(heures_txt);
  314. Serial.print("minutes_txt= "); Serial.println(minutes_txt);
  315. Serial.print("secondes_txt= "); Serial.println(secondes_txt);
  316.  
  317.  
  318. heure_array[0]=heures_txt[0];
  319. heure_array[1]=heures_txt[1];
  320. heure_array[2]=':';
  321. heure_array[3]=minutes_txt[0];
  322. heure_array[4]=minutes_txt[1];
  323. heure_array[5]=':';
  324. heure_array[6]=secondes_txt[0];
  325. heure_array[7]=secondes_txt[1];
  326. heure_array[8]=0; // zéro terminal -> string
  327.  
  328. // 31:01:21 pour "31 Janv 2021"
  329.  
  330. date_array[0]=jour_txt[0];
  331. date_array[1]=jour_txt[1];
  332. date_array[2]=':';
  333. date_array[3]=mois_txt[0];
  334. date_array[4]=mois_txt[1];
  335. date_array[5]=':';
  336. date_array[6]=annee_txt[0];
  337. date_array[7]=annee_txt[1];
  338. date_array[8]=0; // zéro terminal -> string
  339.  
  340.  
  341. Serial.println();
  342.  
  343. Serial.print("GPS.satellites: "); Serial.println(GPS.satellites());
  344. Serial.println(" ");
  345.  
  346. Serial.println();
  347.  
  348. affiche_heure();
  349. affiche_date();
  350.  
  351. smartdelay(1000);
  352. compte1++;
  353.  
  354. }
  355.  


7 La seconde horloge : Client WiFi

Même carte ESP32 TTGO T-display dans un boîtier moins profond puisque cette fois il n'y a pas de module GPS.

8 La carte ESP dans le boitier

Le boîtier mesure 55x30mm pour une profondeur de 16mm. Voir le dessin 3D pour le logiciel FreeCad au bas de l'article.

9 Vue d'ensemble des éléments :

Il faut préciser que le câble USB n'est absolument pas nécessaire, aucune donnée n'est transmise de cette façon, et on peut tout à fait alimenter la carte par un petit connecteur prévu pour cela (au dos de la carte).

10 Le code source en C++ du Client WiFi :

CODE SOURCE en C++
  1. /***********
  2.   GPS_Time & CLIENT WiFi local (ip=192.168.4.1/)
  3.   pour ESP32 (TTGO T-Display, avec petit ecran LCD couleur IPS ST7789V 1.14 Inch 135x240 px)
  4.   + module NEO-6M
  5.  
  6. il faut choisir (décommenter) la ligne suivante, dans le fichier /libraries/TFT_eSPI/User_Setup_Select.h :
  7.   #include <User_Setups/Setup25_TTGO_T_Display.h> // Setup file for ESP32 and TTGO T-Display ST7789V SPI bus TFT
  8.  
  9.   voir l'exemple "Colour_Test"
  10.  
  11. ************/
  12.  
  13.  
  14. #include <SoftwareSerial.h>
  15. #include <TFT_eSPI.h>
  16. #include <TimeLib.h> // include Arduino time library
  17.  
  18. #include <WiFi.h>
  19. #include <HTTPClient.h>
  20.  
  21.  
  22. const char* ssid = "ici_nom_du_serveur";
  23. const char* password = "mot_de passe_12345";
  24.  
  25. //IP address with URL path
  26. const char* srvName_heure = "http://192.168.4.1/heure";
  27. const char* srvName_date = "http://192.168.4.1/date";
  28.  
  29. TFT_eSPI ECRAN_1 = TFT_eSPI();
  30.  
  31. String recp_time = "{}";
  32. String recp_date = "{}";
  33.  
  34.  
  35. uint8_t WiFi_status=0;
  36.  
  37. uint32_t memoMillis = 0;
  38. uint32_t currentMillis;
  39. const uint32_t tempo = 2000;
  40.  
  41.  
  42. uint16_t annee;
  43. uint8_t mois;
  44. uint8_t jour;
  45.  
  46. uint8_t annee_in=0;
  47. uint8_t mois_in=0;
  48. uint8_t jour_in=0;
  49.  
  50. uint8_t heures=0;
  51. uint8_t minutes=0;
  52. uint8_t secondes=0;
  53. uint8_t jour_de_la_semaine;
  54.  
  55. uint8_t heures_in=0;
  56. uint8_t minutes_in=0;
  57. uint8_t secondes_in=0;
  58.  
  59. uint16_t compte1=0;
  60. uint16_t compte2=0;
  61.  
  62. String annee_txt;
  63. String mois_txt;
  64. String jour_txt;
  65. String date_txt;
  66.  
  67. String heures_txt;
  68. String minutes_txt;
  69. String secondes_txt;
  70.  
  71.  
  72.  
  73. void setup()
  74. {
  75. Serial.begin(115200);
  76. delay(2000);
  77. Serial.println("ESP CLIENT WiFi");
  78. Serial.println("Setup");
  79.  
  80. ECRAN_1.init();
  81. ECRAN_1.setRotation(1);
  82. ECRAN_1.fillScreen(TFT_BLACK);
  83. ECRAN_1.setCursor(0, 0, 2); // Set "cursor" at top left corner of display (0,0) and select font 4
  84. ECRAN_1.setTextColor(TFT_WHITE, TFT_BLACK);
  85. ECRAN_1.println("Horloge Client WiFi");
  86.  
  87. delay(500);
  88.  
  89. ECRAN_1.setCursor(0, 20, 4);
  90. ECRAN_1.setTextColor(TFT_YELLOW, TFT_BLACK);
  91. ECRAN_1.print("Connexion :");
  92.  
  93. WiFi.persistent(false);
  94. WiFi.begin(ssid, password);
  95. delay(2000);
  96.  
  97.  
  98.  
  99. Serial.println("Connecting");
  100.  
  101. ECRAN_1.setTextColor(TFT_BLUE, TFT_BLACK);
  102. //ECRAN_1.setTextFont(1);
  103. ECRAN_1.setCursor(0, 40, 1);
  104. while(WiFi.status() != WL_CONNECTED)
  105. {
  106. delay(500);
  107. ECRAN_1.print(".");
  108. Serial.print(".");
  109. }
  110.  
  111. Serial.println("");
  112. Serial.print("Connected to WiFi - IP Address : ");
  113. Serial.println(WiFi.localIP());
  114. Serial.println("\n");
  115.  
  116. ECRAN_1.setTextColor(TFT_GREEN, TFT_BLACK);
  117. ECRAN_1.println(" ");
  118. ECRAN_1.println("OK");
  119. smartdelay(500);
  120. ECRAN_1.fillScreen(TFT_BLACK);
  121.  
  122. ECRAN_1.setCursor(130, 0, 2); // Set "cursor" at top left corner of display (0,0) and select font 4
  123. ECRAN_1.setTextColor(TFT_BLUE, TFT_BLACK);
  124. ECRAN_1.println("Client WiFi");
  125.  
  126. delay(500);
  127.  
  128. affiche_date();
  129. }
  130.  
  131.  
  132. void httpGetTime()
  133. {
  134. Serial.println("envoi req Heure");
  135.  
  136. HTTPClient http1;
  137.  
  138. http1.begin(srvName_heure);
  139.  
  140. int httpResponseCode = http1.GET();
  141.  
  142. if (httpResponseCode>0)
  143. {
  144. recp_time = http1.getString();
  145. }
  146. http1.end();
  147. }
  148.  
  149.  
  150. void httpGetDate()
  151. {
  152. Serial.println("envoi req Date");
  153.  
  154. HTTPClient http2;
  155.  
  156. http2.begin(srvName_date);
  157.  
  158. int httpResponseCode = http2.GET();
  159.  
  160. if (httpResponseCode>0)
  161. {
  162. recp_date = http2.getString();
  163. }
  164. http2.end();
  165. }
  166.  
  167.  
  168. static void smartdelay(unsigned long ms)
  169. {
  170. unsigned long start = millis();
  171. while (millis() - start < ms) {;}
  172. }
  173.  
  174.  
  175.  
  176. void ajuste_time()
  177. {
  178.  
  179. if(recp_time.length() == 8)
  180. {
  181. WiFi_status =1;
  182. Serial.println("ajuste_time");
  183. Serial.println( recp_time);
  184. // String data_in = "11:40:30"
  185.  
  186.  
  187. heures_in =(recp_time.substring(0,2)).toInt();
  188. Serial.println(heures_in);
  189.  
  190. minutes_in =(recp_time.substring(3,5)).toInt();
  191. Serial.println(minutes_in);
  192.  
  193. secondes_in =(recp_time.substring(6,8)).toInt();
  194. Serial.println(secondes_in);
  195. //secondes_in++; // pour compenser le temps de traitement
  196.  
  197. if (heures != heures_in) {heures = heures_in;}
  198. if (minutes != minutes_in) {minutes = minutes_in;}
  199. if (secondes != secondes_in) {secondes = secondes_in;}
  200. }
  201. else {WiFi_status=0;}
  202.  
  203. }
  204.  
  205.  
  206. void ajuste_date()
  207. {
  208. Serial.println("ici7");
  209. if(recp_date.length() == 8)
  210. {
  211. WiFi_status =1;
  212. Serial.println("ajuste_date");
  213. Serial.println( recp_date);
  214. // String data_in = "01:02:21"
  215.  
  216. jour_in =(recp_date.substring(0,2)).toInt();
  217. Serial.println(jour_in);
  218.  
  219. mois_in =(recp_date.substring(3,5)).toInt();
  220. Serial.println(mois_in);
  221.  
  222. annee_in =(recp_date.substring(6,8)).toInt();
  223. Serial.println(annee_in);
  224.  
  225.  
  226. if (jour != jour_in) {jour = jour_in;}
  227. if (mois != mois_in) {mois = mois_in;}
  228. if (annee != annee_in) {annee = annee_in;}
  229. }
  230. else {WiFi_status=0;}
  231.  
  232. }
  233.  
  234.  
  235. void calcul_jour_de_la_semaine()
  236. {
  237. // d'après l'Algorithme de Mike Keith
  238. uint16_t d, m, y, z, jds;
  239.  
  240. d=jour;
  241. m=mois;
  242. y=annee;
  243.  
  244. if (m>=3)
  245. {
  246. jds = ( ((23*m)/9) + d + 4 + y + (y/4) - (y/100) + (y/400) - 2 ) % 7;
  247. }
  248. else
  249. {
  250. z = y-1;
  251. jds = ( ((23*m)/9) + d + 4 + y + (z/4) - (z/100) + (z/400) ) % 7;
  252. }
  253. jour_de_la_semaine = jds;
  254. }
  255.  
  256.  
  257. String conv_time(uint8_t t)
  258. {
  259. String r;
  260. r=String(t);
  261. if (t<10) {r="0"+r;}
  262. return r;
  263. }
  264.  
  265.  
  266.  
  267. void affiche_date()
  268. {
  269. date_txt="";
  270.  
  271. calcul_jour_de_la_semaine();
  272.  
  273. switch (jour_de_la_semaine)
  274. {
  275. case 0: { date_txt+="Dim ";} break;
  276. case 1: { date_txt+="Lun ";} break;
  277. case 2: { date_txt+="Mar ";} break;
  278. case 3: { date_txt+="Mer ";} break;
  279. case 4: { date_txt+="Jeu ";} break;;
  280. case 5: { date_txt+="Ven ";} break;
  281. case 6: { date_txt+="Sam ";} break;
  282. }
  283.  
  284. date_txt += String(conv_time(jour))+" ";
  285.  
  286. switch (mois)
  287. {
  288. case 1: {date_txt+="Janv "; } break;
  289. case 2: {date_txt+="Fev "; } break;
  290. case 3: {date_txt+="Mars "; } break;
  291. case 4: {date_txt+="Avr "; } break;
  292. case 5: {date_txt+="Mai "; } break;
  293. case 6: {date_txt+="Juin "; } break;
  294. case 7: {date_txt+="Juil "; } break;
  295. case 8: {date_txt+="Aout "; } break;
  296. case 9: {date_txt+="Sept "; } break;
  297. case 10: {date_txt+="Oct "; } break;
  298. case 11: {date_txt+="Nov "; } break;
  299. case 12: {date_txt+="Dec "; } break;
  300. }
  301.  
  302. if (annee_in >0) // pour éviter d'afficher une date fantaisiste au départ
  303. {
  304. uint16_t annee_in2 = annee_in + 2000;
  305. annee_txt = (String)annee_in2;
  306. Serial.print("annee_txt="); Serial.println(annee_txt);
  307.  
  308.  
  309. date_txt += annee_txt;
  310.  
  311. ECRAN_1.setCursor(0, 100, 4);
  312. ECRAN_1.setTextColor(TFT_CYAN, TFT_BLACK);
  313. ECRAN_1.print(date_txt);
  314. }
  315.  
  316. }
  317.  
  318.  
  319.  
  320. void affiche_heure()
  321. {
  322. ECRAN_1.setCursor(20, 30, 6);
  323. ECRAN_1.setTextColor(TFT_YELLOW, TFT_BLACK);
  324.  
  325. if(heures<10){ECRAN_1.print(0);}
  326. ECRAN_1.print(heures);
  327. ECRAN_1.print(":");
  328. if(minutes<10){ECRAN_1.print(0);}
  329. ECRAN_1.print(minutes);
  330.  
  331. ECRAN_1.print(" ");
  332. ECRAN_1.setTextColor(TFT_DARKGREY, TFT_BLACK);
  333. if(secondes<10){ECRAN_1.print(0);}
  334. ECRAN_1.print(secondes);
  335.  
  336. if(WiFi_status == 1) {ECRAN_1.fillCircle(233, 5, 5,TFT_GREEN );} else {ECRAN_1.fillCircle(233, 5, 5,TFT_RED );}
  337. }
  338.  
  339.  
  340.  
  341. void incremente_heure(uint8_t nb_s)
  342. {
  343. for (uint8_t n=0; n<nb_s; n++)
  344. {
  345. if (secondes < 59) {secondes+=1;}
  346. else
  347. {
  348. secondes=0;
  349. if (minutes < 59) {minutes+=1;}
  350. else
  351. {
  352. minutes=0;
  353. if (heures < 23) {heures+=1;}
  354. else
  355. heures=0;
  356. }
  357. }
  358. }
  359. }
  360.  
  361.  
  362.  
  363. void loop()
  364. {
  365. compte1++;
  366. Serial.println(compte1);
  367.  
  368. if ((compte1 % 10)==0) // toutes les 10s
  369. {
  370. compte2++;
  371. if (compte2 < 3) // sauf les multiples de 30s (les deux requettes ne doivent pas se collisionner dans le temps)
  372. {
  373. recp_time = "{}";
  374. if(WiFi.status()== WL_CONNECTED )
  375. {
  376. httpGetTime();
  377. ajuste_time();
  378. Serial.println("------");
  379. }
  380. else { Serial.println("WiFi Disconnected"); }
  381. }
  382. if (compte2 >= 3) // toutes les 3x10=30s
  383. {
  384. compte2=0;
  385. recp_date = "{}";
  386. if(WiFi.status()== WL_CONNECTED )
  387. {
  388. httpGetDate();
  389. ajuste_date();
  390. Serial.println("------");
  391. }
  392. else { Serial.println("WiFi Disconnected"); }
  393. }
  394.  
  395. }
  396.  
  397. incremente_heure(1); // 1s
  398. smartdelay(1000);
  399.  
  400. affiche_heure();
  401.  
  402. affiche_date();
  403.  
  404.  
  405. }
  406.  


11 Documents :

Includes : fichiers boitier 3D : :

12 Client avec Ecran TFT 3,5

Afin d'améliorer l’esthétique de l'horloge cliente, j'en ai crée une basée sur un ESP32 classique connecté à un afficheur TFT couleur 3,5". Le schéma, la circuiterie et donc le circuit imprimé sont identiques à ceux utilisé pour le "Primary Flight Display" et autre "Navigation Display" décrits sur ce site (avec les boutons en moins).

13 L'horloge 3,5

14 Schéma de l'horloge cliente GPS 3,5

Comme dit précédemment, il faut juste supprimer les Switches qui sont absents de cette réalisation. Il n'y a donc que deux composants: la platine ESP32 et l'afficheur 3,5" 480x320px.

Cette horloge étant un client Wifi, elle ne fonctionne que si le serveur décrit plus haut est en marche.

15 Le code source de l'horloge 3,5

CODE SOURCE en C++
  1. /*
  2. Horloge_TFT ()
  3.  
  4. pour ESP32 Wroom + afficheur 3.5" TFT 480x320
  5.  
  6. par Silicium628
  7.  
  8. */
  9.  
  10.  
  11. /*=====================================================================================================
  12. CONCERNANT L'AFFICHAGE TFT: connexion:
  13.  
  14. (Pensez à configurer le fichier User_Setup.h de la bibliothèque ~/Arduino/libraries/TFT_eSPI/ )
  15.  
  16. les lignes qui suivent ne sont q'un commentaire pour vous indiquer la config à utiliser
  17. placée ici, elle ne sont pas fonctionnelles
  18. Il FAUT modifier le fichier User_Setup.h installé par le système Arduino dans ~/Arduino/libraries/TFT_eSPI/
  19.  
  20. // ESP32 pins used for the parallel interface TFT
  21. #define TFT_CS 27 // Chip select control pin
  22. #define TFT_DC 14 // Data Command control pin - must use a pin in the range 0-31
  23. #define TFT_RST 26 // Reset pin
  24.  
  25. #define TFT_WR 12 // Write strobe control pin - must use a pin in the range 0-31
  26. #define TFT_RD 13
  27.  
  28. #define TFT_D0 16 // Must use pins in the range 0-31 for the data bus
  29. #define TFT_D1 4 // so a single register write sets/clears all bits
  30. #define TFT_D2 2 // 23
  31. #define TFT_D3 22
  32. #define TFT_D4 21
  33. #define TFT_D5 15 // 19
  34. #define TFT_D6 25 // 18
  35. #define TFT_D7 17
  36. =====================================================================================================*/
  37.  
  38.  
  39. String version="2.1";
  40.  
  41. uint8_t fond_blanc = 0;
  42.  
  43.  
  44. #include <stdint.h>
  45. #include <TFT_eSPI.h> // Hardware-specific library
  46. #include "Free_Fonts.h"
  47.  
  48. #include "FS.h"
  49. #include "SD.h"
  50.  
  51. TFT_eSPI TFT480 = TFT_eSPI(); // Configurer le fichier User_Setup.h de la bibliothèque TFT480_eSPI au préalable
  52.  
  53. #include <WiFi.h>
  54. #include <HTTPClient.h>
  55.  
  56. const char* ssid = "TPGPS_34";
  57. const char* password = "94r6tkJ31";
  58.  
  59. //IP address with URL path
  60. const char* srvName_heure = "http://192.168.4.1/heure";
  61. const char* srvName_date = "http://192.168.4.1/date";
  62.  
  63. String recp_time = "{}";
  64. String recp_date = "{}";
  65.  
  66. uint8_t WiFi_status=0;
  67.  
  68. uint32_t memoMillis = 0;
  69. uint32_t currentMillis;
  70. const uint32_t tempo = 2000;
  71.  
  72.  
  73. uint16_t annee;
  74. uint8_t mois;
  75. uint8_t jour;
  76.  
  77. uint8_t annee_in=0;
  78. uint8_t mois_in=0;
  79. uint8_t jour_in=0;
  80.  
  81. uint8_t heures=0;
  82. uint8_t memo_heures;
  83. uint8_t minutes=0;
  84. uint8_t memo_minutes=0;
  85. uint8_t secondes=0;
  86. uint8_t jour_de_la_semaine;
  87.  
  88. uint8_t heures_in=0;
  89. uint8_t minutes_in=0;
  90. uint8_t secondes_in=0;
  91.  
  92. uint16_t compte1=0;
  93. uint16_t compte2=0;
  94.  
  95. String annee_txt;
  96. String mois_txt;
  97. String jour_txt;
  98. String date_txt;
  99.  
  100. uint8_t SDcardOk=0;
  101.  
  102. uint8_t num_image;
  103.  
  104.  
  105. //uRTCLib rtc(0x68); // MODULE HORLOGE TEMPS REEL; 0x68 = adresse sur le bus I2C
  106.  
  107.  
  108. //const int led2 = 12;
  109. //bool led2_etat = LOW;
  110.  
  111. /*
  112. const int GPIO_bouton0 = 13; // Bouton interne
  113. bool bouton0_etat;
  114. bool memo_bouton0_etat;
  115.  
  116. const int GPIO_bouton1 = 14; // bouton externe
  117. bool bouton1_etat;
  118. bool memo_bouton1_etat;
  119.  
  120. const int GPIO_bouton2 = 27; // bouton externe
  121. bool bouton2_etat;
  122. bool memo_bouton2_etat;
  123. */
  124.  
  125. uint32_t memoM1 = 0;
  126. uint32_t memoM2 = 0;
  127. const uint32_t tempo1 = 2000; // 2000 ms = 2s
  128. const uint32_t tempo2 = 300*1000; // 300s = 5mn
  129.  
  130. uint8_t stop_affichage =0;
  131.  
  132.  
  133. // #define TIME_TO_SLEEP 1000 /* Time ESP32 will go to sleep (en ms) */
  134. // uint8_t sleep_enable = 1;
  135.  
  136.  
  137. #define NOIR 0x0000
  138. #define MARRON 0x9240
  139. #define ROUGE 0xF800
  140. #define ROSE 0xFBDD
  141. #define ORANGE 0xFBC0
  142. #define JAUNE 0xFFE0
  143. #define JAUNE_PALE 0xF7F4
  144. #define VERT 0x07E0
  145. #define VERT_FONCE 0x02E2
  146. #define OLIVE 0x05A3
  147. #define CYAN 0x07FF
  148. #define BLEU_CLAIR 0x455F
  149. #define AZUR 0x1BF9
  150. #define BLEU 0x001F
  151. #define MAGENTA 0xF81F
  152. #define VIOLET1 0x781A
  153. #define VIOLET2 0xECBE
  154. #define GRIS_TRES_CLAIR 0xDEFB
  155. #define GRIS_CLAIR 0xA534
  156. #define GRIS 0x8410
  157. #define GRIS_FONCE 0x5ACB
  158. #define GRIS_TRES_FONCE 0x2124
  159. #define BLANC 0xFFFF
  160.  
  161. //int startX = 40, startY = 10;
  162.  
  163.  
  164. uint16_t couleur_txt = BLANC;
  165. uint16_t couleur_fond = GRIS_TRES_FONCE;
  166. uint16_t couleur_fond_txt = VERT_FONCE;
  167.  
  168.  
  169. uint32_t bmp_offset = 0;
  170.  
  171.  
  172. static void smartdelay(unsigned long ms)
  173. {
  174. unsigned long start = millis();
  175. while (millis() - start < ms) {;}
  176. }
  177.  
  178.  
  179. void init_SDcard()
  180. {
  181. String s1;
  182.  
  183. TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
  184. TFT480.setTextColor(BLANC, NOIR);
  185. TFT480.setFreeFont(FF1);
  186.  
  187. uint16_t y=0;
  188.  
  189. TFT480.drawString("ND - Navigation Display", 0, y);
  190. y+=20;
  191.  
  192. s1="version " + version;
  193. TFT480.drawString(s1, 0, y);
  194.  
  195. y+=40;
  196. TFT480.setTextColor(VERT, NOIR);
  197. TFT480.drawString("Init SDcard", 0, y);
  198. y+=20;
  199.  
  200. if(!SD.begin())
  201. {
  202. TFT480.drawString("Card Mount Failed", 0, y);
  203. delay (2000);
  204. TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
  205. return;
  206. }
  207.  
  208.  
  209. uint8_t cardType = SD.cardType();
  210.  
  211. if(cardType == CARD_NONE)
  212. {
  213. TFT480.drawString("No SDcard", 0, y);
  214. delay (2000);
  215. TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
  216. return;
  217. }
  218.  
  219. SDcardOk=1;
  220.  
  221. TFT480.drawString("SDcard Type: ", 0, y);
  222. if(cardType == CARD_SD) {TFT480.drawString("SDSC", 150, y);}
  223. else if(cardType == CARD_SDHC) {TFT480.drawString("SDHC", 150, y);}
  224.  
  225. y+=20;
  226.  
  227. uint32_t cardSize = SD.cardSize() / (1024 * 1024);
  228. s1=(String)cardSize + " GB";
  229. TFT480.drawString("SDcard size: ", 0, y);
  230. TFT480.drawString(s1, 150, y);
  231.  
  232. // listDir(SD, "/", 0);
  233.  
  234. //Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
  235. //Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
  236.  
  237. delay (1000);
  238. TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
  239. }
  240.  
  241.  
  242.  
  243. void httpGetTime()
  244. {
  245. Serial.println("envoi req Heure");
  246.  
  247. HTTPClient http1;
  248.  
  249. http1.begin(srvName_heure);
  250.  
  251. int httpResponseCode = http1.GET();
  252.  
  253. if (httpResponseCode>0)
  254. {
  255. recp_time = http1.getString();
  256. }
  257. http1.end();
  258. }
  259.  
  260.  
  261. void httpGetDate()
  262. {
  263. Serial.println("envoi req Date");
  264.  
  265. HTTPClient http2;
  266.  
  267. http2.begin(srvName_date);
  268.  
  269. int httpResponseCode = http2.GET();
  270.  
  271. if (httpResponseCode>0)
  272. {
  273. recp_date = http2.getString();
  274. }
  275. http2.end();
  276. }
  277.  
  278.  
  279. void ajuste_time()
  280. {
  281. if(recp_time.length() == 8)
  282. {
  283. WiFi_status =1;
  284. Serial.println("ajuste_time");
  285. Serial.println( recp_time);
  286. // String data_in = "11:40:30"
  287.  
  288.  
  289. heures_in =(recp_time.substring(0,2)).toInt();
  290. Serial.println(heures_in);
  291.  
  292. minutes_in =(recp_time.substring(3,5)).toInt();
  293. Serial.println(minutes_in);
  294.  
  295. secondes_in =(recp_time.substring(6,8)).toInt();
  296. Serial.println(secondes_in);
  297. //secondes_in++; // pour compenser le temps de traitement
  298.  
  299. if (heures != heures_in) {heures = heures_in;}
  300. if (minutes != minutes_in) {minutes = minutes_in;}
  301. if (secondes != secondes_in) {secondes = secondes_in;}
  302. }
  303. else {WiFi_status=0;}
  304.  
  305. }
  306.  
  307.  
  308. void ajuste_date()
  309. {
  310. if(recp_date.length() == 8)
  311. {
  312. WiFi_status =1;
  313. Serial.println("ajuste_date");
  314. Serial.println( recp_date);
  315. // String data_in = "01:02:21"
  316.  
  317. jour_in =(recp_date.substring(0,2)).toInt();
  318. Serial.println(jour_in);
  319.  
  320. mois_in =(recp_date.substring(3,5)).toInt();
  321. Serial.println(mois_in);
  322.  
  323. annee_in =(recp_date.substring(6,8)).toInt();
  324. Serial.println(annee_in);
  325.  
  326.  
  327. if (jour != jour_in) {jour = jour_in;}
  328. if (mois != mois_in) {mois = mois_in;}
  329. if (annee != annee_in) {annee = annee_in;}
  330. }
  331. else {WiFi_status=0;}
  332.  
  333. }
  334.  
  335. void calcul_jour_de_la_semaine()
  336. {
  337. // d'après l'Algorithme de Mike Keith
  338. uint16_t d, m, y, z, jds;
  339.  
  340. d=jour;
  341. m=mois;
  342. y=annee;
  343.  
  344. if (m>=3)
  345. {
  346. jds = ( ((23*m)/9) + d + 4 + y + (y/4) - (y/100) + (y/400) - 2 ) % 7;
  347. }
  348. else
  349. {
  350. z = y-1;
  351. jds = ( ((23*m)/9) + d + 4 + y + (z/4) - (z/100) + (z/400) ) % 7;
  352. }
  353. jour_de_la_semaine = jds;
  354. }
  355.  
  356. String conv_time(uint8_t t)
  357. {
  358. String r;
  359. r=String(t);
  360. if (t<10) {r="0"+r;}
  361. return r;
  362. }
  363.  
  364.  
  365.  
  366. void affiche_date()
  367. {
  368. date_txt="";
  369.  
  370. calcul_jour_de_la_semaine();
  371.  
  372. switch (jour_de_la_semaine)
  373. {
  374. case 0: { date_txt+="Dim ";} break;
  375. case 1: { date_txt+="Lun ";} break;
  376. case 2: { date_txt+="Mar ";} break;
  377. case 3: { date_txt+="Mer ";} break;
  378. case 4: { date_txt+="Jeu ";} break;;
  379. case 5: { date_txt+="Ven ";} break;
  380. case 6: { date_txt+="Sam ";} break;
  381. }
  382.  
  383. date_txt += String(conv_time(jour))+" ";
  384.  
  385. switch (mois)
  386. {
  387. case 1: {date_txt+="Janv "; } break;
  388. case 2: {date_txt+="Fev "; } break;
  389. case 3: {date_txt+="Mars "; } break;
  390. case 4: {date_txt+="Avr "; } break;
  391. case 5: {date_txt+="Mai "; } break;
  392. case 6: {date_txt+="Juin "; } break;
  393. case 7: {date_txt+="Juil "; } break;
  394. case 8: {date_txt+="Aout "; } break;
  395. case 9: {date_txt+="Sept "; } break;
  396. case 10: {date_txt+="Oct "; } break;
  397. case 11: {date_txt+="Nov "; } break;
  398. case 12: {date_txt+="Dec "; } break;
  399. }
  400.  
  401. if (annee_in >0) // pour éviter d'afficher une date fantaisiste au départ
  402. {
  403. uint16_t annee_in2 = annee_in + 2000;
  404. annee_txt = (String)annee_in2;
  405. Serial.print("annee_txt="); Serial.println(annee_txt);
  406.  
  407. date_txt += annee_txt;
  408.  
  409. TFT480.setTextColor(JAUNE, NOIR);
  410. TFT480.setFreeFont(FF6);
  411. TFT480.setTextSize(1);
  412.  
  413. TFT480.drawString(date_txt,0,300);
  414. }
  415.  
  416. }
  417.  
  418.  
  419.  
  420. void affiche_heure()
  421. {
  422. String s1;
  423.  
  424. if (memo_minutes != minutes)
  425. {
  426. memo_minutes = minutes;
  427.  
  428. //TFT480.fillRect(0, 50, 479, 125, couleur_fond_txt);
  429. num_image = random(1, 23);
  430. affi_img(0, 0, num_image);
  431.  
  432. s1="";
  433. if(heures<10){s1+="0";}
  434. s1 += String(heures);
  435. s1 += ":";
  436. if(minutes<10){s1+="0";}
  437. s1 += String(minutes);
  438.  
  439. TFT480.setTextColor(couleur_txt, couleur_fond_txt);
  440.  
  441.  
  442. //TFT480.setFreeFont(FF24);
  443. TFT480.setFreeFont(FF8);
  444. TFT480.setTextSize(3);
  445.  
  446. TFT480.setTextColor(NOIR);
  447. TFT480.drawString(s1, 20+5, 50+5);
  448. TFT480.setTextColor(couleur_txt);
  449. TFT480.drawString(s1, 20, 50);
  450.  
  451. affiche_date();
  452. }
  453.  
  454. TFT480.setTextColor(couleur_txt, couleur_fond_txt);
  455.  
  456. TFT480.setFreeFont(FF7);
  457. TFT480.setTextSize(1);
  458. s1="";
  459. if(secondes<10){s1+="0";}
  460. s1 += String(secondes);
  461.  
  462. TFT480.fillRect(400, 200, 40, 24, couleur_fond_txt);
  463. TFT480.drawString(s1, 400, 200);
  464.  
  465. if(WiFi_status == 1) { TFT480.fillCircle(470, 5, 5,TFT_GREEN );} else { TFT480.fillCircle(470, 5, 5,TFT_RED );}
  466.  
  467. }
  468.  
  469.  
  470. uint8_t decToBcd( int val )
  471. {
  472. return (uint8_t) ((val / 10 * 16) + (val % 10));
  473. }
  474.  
  475.  
  476. uint16_t bmp_width;
  477. uint16_t bmp_heigh;
  478.  
  479.  
  480. uint16_t Color_To_565(uint8_t r, uint8_t g, uint8_t b)
  481. {
  482. return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
  483. }
  484.  
  485.  
  486. void RGB565_to_888(uint16_t color565, uint8_t *R, uint8_t *G, uint8_t *B)
  487. {
  488. *R=(color565 & 0xFFFFF800) >> 8;
  489. *G=(color565 & 0x7E0) >> 3;
  490. *B=(color565 & 0x1F) << 3 ;
  491. }
  492.  
  493.  
  494.  
  495.  
  496. uint16_t read_16(File fp)
  497. {
  498. uint8_t low;
  499. uint16_t high;
  500. low = fp.read();
  501. high = fp.read();
  502. return (high<<8)|low;
  503. }
  504.  
  505.  
  506.  
  507. uint32_t read_32(File fp)
  508. {
  509. uint16_t low;
  510. uint32_t high;
  511. low = read_16(fp);
  512. high = read_16(fp);
  513. return (high<<8)|low;
  514. }
  515.  
  516.  
  517.  
  518. void write_16(uint16_t v16, File fp)
  519. {
  520. uint8_t low, high;
  521.  
  522. low = v16 & 0xFF;
  523. high= v16 >>8;
  524.  
  525. fp.write(low);
  526. fp.write(high);
  527. }
  528.  
  529.  
  530. void write_32(uint32_t v32, File fp)
  531. {
  532. uint16_t low, high;
  533.  
  534. low = v32 & 0xFFFF;
  535. high= v32 >>16;
  536.  
  537. write_16(low, fp);
  538. write_16(high, fp);
  539. }
  540.  
  541.  
  542.  
  543.  
  544. bool teste_bmp_header(File fp)
  545. {
  546. if(read_16(fp) != 0x4D42) { return false; } // (2 bytes) The header field used to identify the BMP
  547. read_32(fp); // (4 bytes) get bmp size (nombre total d'octets)
  548. read_32(fp); // (4 bytes) get creator information
  549. bmp_offset = read_32(fp); // (4 bytes) get offset information
  550. read_32(fp);//get DIB information
  551.  
  552. // ici on a lu 16 octets
  553. bmp_width = read_32(fp); //(4 bytes) get width and heigh information
  554. bmp_heigh = read_32(fp); //(4 bytes)
  555.  
  556. // ici on a lu 24 octets
  557. //if(read_16(fp)!= 1) {return false;}
  558. read_16(fp);
  559. //if(read_32(fp)!= 0) {return false;}
  560. return true;
  561. }
  562.  
  563.  
  564. uint8_t LumCtr(uint8_t vi, float lum, float ctr)
  565. {
  566. float v2;
  567. uint8_t result;
  568. v2 = ((float)vi - lum) * ctr;
  569. if (v2<0) {v2=0;}
  570. if (v2>255) {v2=255;}
  571. result = (uint8_t) v2;
  572. return result;
  573. }
  574.  
  575.  
  576. void draw_bmp(uint16_t x0, uint16_t y0, File* fp)
  577. {
  578.  
  579. //sram = freeRam(); Serial.print("03-freeRam="); Serial.println(sram);
  580. uint16_t i,j,k,p,m=0;
  581. uint16_t y1;
  582. uint8_t bmp_data[2*3]={0};
  583. uint16_t bmp_color[2];
  584. uint8_t rot =1;
  585.  
  586. fp->seek(bmp_offset);
  587. for(i=0; i<bmp_heigh; i++)
  588. {
  589. for(j=0; j<(bmp_width/2); j++)
  590. {
  591. m=0;
  592. fp->read(bmp_data,2*3);
  593. for(k=0; k<2; k++)
  594. {
  595. bmp_color[k]= Color_To_565(bmp_data[m+2], bmp_data[m+1], bmp_data[m+0]);
  596. m+=3;
  597. }
  598. for(p=0; p<2; p++)
  599. {
  600. if (rot==0)
  601. {
  602. y1=y0;
  603. TFT480.drawPixel(x0+i, y0+j*2+p, bmp_color[p]);
  604. }
  605. if (rot==1)
  606. {
  607. //y1=160-y0;
  608. y1=y0;
  609. TFT480.drawPixel(x0+j*2+p,320-(y1+i), bmp_color[p]);
  610. }
  611. }
  612. }
  613. }
  614. }
  615.  
  616.  
  617. void affi_img(uint16_t x0, uint16_t y0, uint8_t num)
  618. {
  619.  
  620. File bmp_file;
  621. TFT480.setFreeFont(FF1);
  622. TFT480.setTextColor(ORANGE, NOIR);
  623. String numtxt = String(num);
  624. String filename;
  625. filename ="/bmp/";
  626. filename += numtxt;
  627. filename += ".bmp";
  628.  
  629. //bmp_file = SD.open("/bmp/1.bmp");
  630. bmp_file = SD.open(filename);
  631. if(!bmp_file)
  632. {
  633. //efface_carte(x0,y0);
  634. bmp_file.close();
  635. Serial.println("ici1");
  636. return;
  637. }
  638. if(!teste_bmp_header(bmp_file))
  639. {
  640. bmp_file.close();
  641. Serial.println("ici2");
  642. return;
  643. }
  644.  
  645. Serial.println("ici3");
  646.  
  647. draw_bmp(x0, y0, &bmp_file);
  648.  
  649. bmp_file.close();
  650. // delay(1000);
  651.  
  652. }
  653.  
  654.  
  655.  
  656.  
  657.  
  658. void setup()
  659. {
  660. //esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000);
  661. //esp_sleep_enable_ext0_wakeup((gpio_num_t)BUTTON_PIN, LOW);
  662.  
  663. Serial.begin(19200);
  664.  
  665. num_image = random(1, 23);
  666.  
  667. init_SDcard();
  668.  
  669. Serial.println("display.init()");
  670.  
  671. TFT480.init();
  672. TFT480.setRotation(3); // 0..3 à voir, suivant disposition de l'afficheur et sa disposition
  673.  
  674. TFT480.fillScreen(NOIR);
  675.  
  676. TFT480.setTextColor(BLANC, NOIR);
  677.  
  678. TFT480.setFreeFont(FF1);
  679. uint16_t y=0;
  680. TFT480.drawString("Horloge TFT", 0, y);
  681. y+=20;
  682. String s1="version " + version;
  683. TFT480.drawString(s1, 0, y);
  684. y+=20;
  685. TFT480.setTextColor(BLEU, NOIR);
  686. TFT480.drawString("Heure GPS", 0, y);
  687. y+=20;
  688. TFT480.setTextColor(JAUNE, NOIR);
  689. TFT480.drawString("Client WiFi", 0, y);
  690. y+=40;
  691.  
  692.  
  693. /*
  694. TFT480.setFreeFont(FF24);
  695. TFT480.setTextSize(4);
  696. uint16_t y=0;
  697. TFT480.drawString("12:34", 0, y);
  698. */
  699. delay (2000);
  700.  
  701. if(fond_blanc == 1) {TFT480.fillScreen(BLANC);} else {TFT480.fillScreen(NOIR);}
  702. TFT480.setCursor(0, 20, 4);
  703. TFT480.setTextColor(TFT_YELLOW, TFT_BLACK);
  704. TFT480.print("Connexion au serveur GPS WiFi:");
  705.  
  706. WiFi.persistent(false);
  707. WiFi.begin(ssid, password);
  708.  
  709. delay(1000);
  710.  
  711. Serial.println("Connecting");
  712.  
  713. TFT480.setTextColor(TFT_BLUE, TFT_BLACK);
  714. //TFT480.setTextFont(1);
  715. TFT480.setCursor(0, 40, 1);
  716. while(WiFi.status() != WL_CONNECTED)
  717. {
  718. delay(500);
  719. TFT480.print(".");
  720. Serial.print(".");
  721. }
  722.  
  723. Serial.println("");
  724. Serial.print("Connected to WiFi - IP Address : ");
  725. Serial.println(WiFi.localIP());
  726. Serial.println("\n");
  727.  
  728. TFT480.setTextColor(TFT_GREEN, TFT_BLACK);
  729. TFT480.println(" ");
  730. TFT480.println("OK");
  731. smartdelay(500);
  732. TFT480.fillScreen(NOIR);
  733.  
  734. TFT480.setCursor(130, 0, 2); // Set "cursor" at top left corner of display (0,0) and select font 4
  735. TFT480.setTextColor(TFT_BLUE, TFT_BLACK);
  736. TFT480.println("Client WiFi");
  737.  
  738. delay(500);
  739.  
  740. TFT480.fillScreen(couleur_fond);
  741.  
  742.  
  743. TFT480.setTextColor(CYAN, couleur_fond);
  744. TFT480.setFreeFont(FF5);
  745. TFT480.setTextSize(1);
  746.  
  747. TFT480.drawString("GPS Time",0,0);
  748.  
  749. affi_img(0, 0, num_image);
  750.  
  751. //affiche_date();
  752.  
  753. compte1=8;
  754.  
  755.  
  756. }
  757.  
  758.  
  759. void incremente_heure(uint8_t nb_s)
  760. {
  761. for (uint8_t n=0; n<nb_s; n++)
  762. {
  763. if (secondes < 59) {secondes+=1;}
  764. else
  765. {
  766. secondes=0;
  767. if (minutes < 59) {minutes+=1;}
  768. else
  769. {
  770. minutes=0;
  771. if (heures < 23) {heures+=1;}
  772. else
  773. heures=0;
  774. }
  775. }
  776. }
  777. }
  778.  
  779.  
  780. void loop()
  781. {
  782. compte1++;
  783. Serial.println(compte1);
  784.  
  785. if ((compte1 % 10)==0) // toutes les 10s
  786. {
  787. compte2++;
  788. if (compte2 < 3) // sauf les multiples de 30s (les deux requettes ne doivent pas se collisionner dans le temps)
  789. {
  790. recp_time = "{}";
  791. if(WiFi.status()== WL_CONNECTED )
  792. {
  793. httpGetTime();
  794. ajuste_time();
  795. Serial.println("------");
  796. }
  797. else { Serial.println("WiFi Disconnected"); }
  798. }
  799. if (compte2 >= 3) // toutes les 3x10=30s
  800. {
  801. compte2=0;
  802. recp_date = "{}";
  803. if(WiFi.status()== WL_CONNECTED )
  804. {
  805. httpGetDate();
  806. ajuste_date();
  807. Serial.println("------");
  808. }
  809. else { Serial.println("WiFi Disconnected"); }
  810. }
  811.  
  812. }
  813.  
  814. incremente_heure(1); // 1s
  815. smartdelay(1000);
  816.  
  817. affiche_heure();
  818.  
  819. }
  820.  
  821.  
  822.  


16 Documents

Voici le code source complet ainsi que les images de fond d'écran à placer dans un dossier nommé "bmp" lui-même placé à la racine de la SDcard connectée directement au dos de l'afficheur. L'image affichée change aléatoirement toutes les minutes. Vous pouvez utiliser vos propres images, elles doivent être au format bpm 480x320px.

17 -

Liens...

COMMENTAIRES


1777