LOG DES TEMPÉRATURES AVEC UN ESP32
Public: Développeurs C++ et web - PHP/HTML5/CSS3/JavascriptDate publication: 28 aout 2024 - mise à jour 15 septembre 2025
DESCRIPTION
Un ESP32C3 Super Mini avec deux capteurs de tempéature DS18B20 pour intérieur/extérieur relève les températures une fois par heure, stocke les valeurs dans sa mémoire RTC, et se rendort profondément en consommant 10μA (RTC Timer+RTC memory). Comme je ne veux pas que le Wifi soit activé 24/7, le Wifi de la Box est configuré pour être actif chaque jour seulement entre 23h et 00h. C'est à ce moment-là que l'ESP peut et doit envoyer ses 24 mesures prises ce jour-là. L'ESP consomme moins d'électricité, car il ne se connecte qu'une fois par jour au Wifi (conso 600mA) pour envoyer les données au serveur. Finalement une page PHP transforme le CSV choisi en un graphique avec Javascript Voir ce que ça donne.
BRANCHEMENTS ESP32 ET DS18B20
CAPTEUR DE TEMPÉRATURE DS18B20
| Tension de fonctionnement | 3-5.5V |
| Consommation | 1mA en mode actif et 750nA en mode standby |
| Plage de température | -10°C à +85°C |
| Précision température | ± 0.5° |
| Résistance | 4.7 KΩ |
| Prix | 1.24€ avec câble 1 mètre, 0.32€ sans câble |

L'ESP32C3 Super mini fait 24mm de longueur.
Une batterie 12V alimentée par panneau photovoltaïque, et un abaisseur 5V alimentent l'ESP via le câble USB-C.
L'ESP embarque un régulateur de tension qui convertit le 5V en 3.3V pour alimenter le processeur (le C3 n'a qu'un seul CPU - avec l'ULP Ultra Low Processor) et les capteurs DS18B20.
Au lieu d'utiliser la LED bleue interne de l'ESP, il y a une LED externe (avec une résistance) car l'ESP est caché dans un cadre mural et on ne voir pas sa LED bleue. Selon sa fréquence de clignotement de la LED déportée, elle indique quand il tente de se connecter au Wifi et quand il envoie les données.
Aussi le script PHP m'envoie un email pour indiquer l'heure exacte de l'envoi... Il envoie vers 23h27:30s (malgré l'ajout de 8 secondes par heure dans le code ci-dessous): le Timer RTC a toujours du retard (à cause des variations de température!) donc après l'envoi il dort en fonction du timestamp envoyé par le script PHP.


Attention aux soudures entre GND et 3.3V: si les fils se touchent l'ESP et l'alimentation crament.
Content que ça n'ait pas cramé, j'ai fait une photo. Vraiment super ce nouveau fer à souder à 3.79€ frais de port inclus!

Lors de l'envoi des données à 23h30, comme la LED clignotait indéfiniment et que l'ESP est à plusieurs mètres de la Box,
j'en ai déduit que l'ESP n'arrivait pas à se connecter au Wifi parce que cet ESP n'a pas d'antenne convaincante par rapport à celle de l'ESP-WROOM-32D.
J'ai donc soudé une extension en cuivre pour augmenter le signal... Maintenant il se connecte plus vite que l'EP-WROOM-32D!

... Mais en fait c'était le filtrage MAC de la Box qui l'empêchait de se connecter pour envoyer les données.
Ensuite j'ai soudé un deuxième ESP32-C3, cette fois avec un DS18B20 sans câble pour le capteur intérieur. Sans antenne. Avec une LED blanche. Le reste est identique.




Algorithme ESP32
Au démarrage/reboot/Reset, Comme la Box/Wifi est probablement éteinte, l'ESP se connecte à un Access Point Android pour obtenir le timestamp d'un script PHP <?php echo time(); ?> pour faire settimeofday(). Et calcule combien de secondes dormir jusqu'à la 30e minute suivante Au réveil par Timer, il prend les mesures des deux capteurs et les place avec jour et heure dans le tableau de structures typedef struct{ float inte;// 4 octets float exte;// 4 octets char jour; // 1 octet char heure;// 1 octet } mesure; // 24 mesures prendront donc (4+4+1+1)*24 = 240 octets en mémoire. Si heure = 23, transforme le tableau de structures en CSV, Spec CSV: temp int,temp ext,jour,heure\n "12.55,11.33,12,0\n12.55,11.33,12,1\n12.55,11.33,12\2\n..." se connecte au Wifi de la Box et envoie le CSV au serveur qui regarde quelle année on est, quel mois pour ajouter les données dans le CSV du mois concerné ex. 2025-08.csv Et se rendort jusqu'à l'heure suivante
Le changement d'heure est pris en compte
Ils nous gonflent gentiment tous les 6 mois, pour pas grand chose sinon bouleverser notre horloge biologique. L'ESP regarde la dernière heure de mesure: mesures[nbmesures-1].heure. Normalement c'est heure actuelle - 1. Mais en cas de changement d'heure c'est à 3h il est 2h → si heure d'avant == heure → ne rien faire à 2h il est 3h → si heure d'avant = heure-2 → dupliquer temp 1h → 2h 26 octobre nb heure 1 0h30 2 1h30 3 2h30 à 3 heures, il est 2 heures - 2h30 ESP regarde si heure == heure d'avant. ici 2 = 2 donc ne rien faire 4 3h30 5 4h30 6 5h30 7 6h30 8 7h30 9 8h30 10 9h30 11 10h30 12 11h30 13 12h30 14 13h30 15 14h30 16 15h30 17 16h30 18 17h30 19 18h29 20 19h29 21 20h28 22 21h27 23 22h27 24 23h30 Envoi. L'ESP a pris 24 mesures donc ok 28 mars 1 0h30 2 1h30 à 2 heures, il est 3 heures - 2h30 3 3h30 La mesure 2h30 n'existe pas. L'ESP regarde si heure-2 == heure d'avant. ici 3-2=1 donc duplique temp 01h→02h 4 4h30 5 5h30 6 6h30 7 7h30 8 8h30 9 9h30 10 10h30 11 11h30 12 12h30 13 13h30 14 14h30 15 15h30 16 16h30 17 17h30 18 18h29 19 19h29 20 20h28 21 21h27 22 22h27 23 23h30 Envoi. L'ESP a pris 23 mesures, mais a dupliqué 1h30 vers 2h30 donc 24 mesures ok
CODE ESP32
#include <OneWire.h> #include <DallasTemperature.h> #include <WiFi.h> #include <HTTPClient.h> /*=============================================================*/ // LED: GPIO1 A1 // CAPTEURS: GPIO2 A2 /*=============================================================*/ typedef struct{ float inte;// 4 octets float exte;// 4 octets int8_t jour; // 1 octet int8_t heure;// 1 octet } mesure; //(4+4+1+1)*24 = 240 octets en mémoire. La RTC fait 8K. Pourrait stocker (8X1024)/240 = 34 jours max RTC_DATA_ATTR mesure mesures[24]; RTC_DATA_ATTR int8_t nbmesures = 0; const char* PHPscript = "https://apps.masta.fr/temperature2/script.php"; /*=============================================================*/ void setheure(String timestamp){ setenv("TZ","CET-1CEST,M3.5.0,M10.5.0/3",1); tzset(); struct timeval tv; tv.tv_sec = uint64_t(atoi(timestamp.c_str())); tv.tv_usec = 0; settimeofday(&tv, NULL); } /*=============================================================*/ void set_timestamp() { WiFi.begin("AndroidAP31CF", "mdp"); while (WiFi.status() != WL_CONNECTED){ digitalWrite(A1,HIGH);delay(200); digitalWrite(A1,LOW); delay(200); } HTTPClient http; http.begin(PHPscript); int httpCode = http.GET(); if (httpCode==200) setheure(http.getString()); http.end(); WiFi.disconnect(true); //plus besoin de Wifi WiFi.mode(WIFI_OFF); // deep sleep l'éteint non? } /*=============================================================*/ struct tm* get_timestamp() { struct timeval tv; struct timezone tz; setenv("TZ","CET-1CEST,M3.5.0,M10.5.0/3",1); tzset(); gettimeofday(&tv,&tz); struct tm* now = localtime(&tv.tv_sec); return now; } /*=============================================================*/ void prise_mesures(int jour, int8_t heure) { digitalWrite(A1,HIGH); // il y a eu changement d'heure? if(nbmesures == 2){ // si heure == heure précédente alors il y a eu changement d'heure: à 3h il est 2h if(heure == mesures[nbmesures-1].heure){ nbmesures++; return; } // si heure-2 == heure précédente alors changement d'heure: à 2h il est 3h else if(heure-2 == mesures[nbmesures-1].heure){ nbmesures++; mesures[nbmesures].inte = mesures[nbmesures-1].inte;// duplique mesure de 1h sur 2h mesures[nbmesures].exte = mesures[nbmesures-1].exte; } } OneWire oneWire(A2); DallasTemperature sensors(&oneWire); sensors.begin(); // parfois -127° ou 85°! Malgré la résistance indiquée dans la doc // La solution c'est de reprendre une température tant qu'elle est en dehors de la normale int nbtentatives = 0; do{ // parfois la lumière reste bleue et reset forcé, donc passe en force après 10 tentatives nbtentatives++; if(nbtentatives==10){ if(nbmesures>0) mesures[nbmesures].inte = mesures[nbmesures-1].inte; break; } sensors.requestTemperaturesByIndex(0); mesures[nbmesures].inte = sensors.getTempCByIndex(0); } while(mesures[nbmesures].inte < -125.0 || mesures[nbmesures].inte > 80.0); nbtentatives = 0; do{ nbtentatives++; if(nbtentatives==10){ if(nbmesures>0) mesures[nbmesures].exte = mesures[nbmesures-1].exte; break; } sensors.requestTemperaturesByIndex(1); mesures[nbmesures].exte = sensors.getTempCByIndex(1); } while(mesures[nbmesures].exte < -125.0 || mesures[nbmesures].exte > 80.0); mesures[nbmesures].jour = jour; mesures[nbmesures].heure = heure; nbmesures++; } /*=============================================================*/ // "data=-12.55,-11.33,24,10\n-12.55,-11.33,24,11\n...\n" 20 octets x 24 mesures = 5+480+1 octets void envoi_donnees_au_serveur() { char data[486] = "data="; for (int8_t n=0; n<24; n++){ char ligne[21]; sprintf(ligne, "%.2f,%.2f,%d,%d\n", mesures[n].inte, mesures[n].exte, mesures[n].jour, mesures[n].heure); strcat(data, ligne); } WiFi.begin("box_ssid","mdp"); while (WiFi.status() != WL_CONNECTED){ digitalWrite(A1,HIGH);delay(200); digitalWrite(A1,LOW); delay(200); } digitalWrite(A1,HIGH); // allume la LED HTTPClient http; http.begin(PHPscript); http.addHeader("Content-Type", "application/x-www-form-urlencoded"); int httpCode = http.POST(data); if(httpCode==200) setheure(http.getString()); http.end(); nbmesures = 0; // Reset compteur on recommence à 0h30 } /*=============================================================*/ void setup() { pinMode(A1, OUTPUT); struct tm* now; //================================================================= if(esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TIMER){ now = get_timestamp(); // quelle heure est-il, quel jour? prise_mesures(now->tm_mday, now->tm_hour); if(now->tm_hour==23){ // À 23h et quelques envoie les données en POST envoi_donnees_au_serveur(); now = get_timestamp(); } } //================================================================= // RESET: demande le timestamp à un script PHP pour faire settimeofday() else{ set_timestamp(); now = get_timestamp(); // quelle heure est-il? Quel jour? nbmesures = (now->tm_min<30) ? now->tm_hour : now->tm_hour + 1; // met les heures d'avant manquées à 0 for(int n=0; n<nbmesures; n++){ mesures[n].inte = 0; mesures[n].exte = 0; mesures[n].jour = now->tm_mday; mesures[n].heure = n; } } //================================================================= int sececoulees = now->tm_min*60 + now->tm_sec;// nombre de secondes écoulées depuis le début de l'heure? uint64_t dormirs = 3600+1800-sececoulees + 8; esp_sleep_enable_timer_wakeup(dormirs * 1000000ULL); esp_deep_sleep_start(); } void loop() {}
COMPILATION/TÉLÉVERSEMENT POUR ESP32C3-Super mini dans Arduino IDE
Installer les librairies OneWire, DallasTemperature, HTTPClient Menu Fichier/Préférences Ajouter (en séparant par un point virgule s'il y en a plusieurs) https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json Menu Outils/Cartes sélectionner ESP32C3 Dev Module ou XIAO_ESP32C3 Menu Outils/Port choisir /dev/tty/ACM0 (ESP32 Famlily Device) Si /dev/tty/ACM0 n'apparaît plus, brancher l'ESP en USB, presser Boot puis reset, relacher reset puis Boot et regarder dans le menu Outils/Port. Si ça ne marche pas, le débrancher, appuyer sur Boot, le brancher et relacher le bouton Boot. Regarder dans le menu Outils/Port. Menu Outils/Upload speed: 460800 * Ne pas oublier d'obtenir l'adresse MAC de l'ESP et la rentrer dans la Box, sinon il ne pourra pas se connecter au Wifi car elle filtre les adresse MAC. Quand on téléverse un programme, Arduino IDE indique l'adresse MAC. * Dans Arduino IDE choisir carte XIAO_ESP32C3 pour faire du Serial.print() et activer menu Outils/USB CDC on boot
SCRIPT PHP D'AJOUT DE DONNÉES
<?php if(isset($_POST['data']) && $_POST['data']!=''){ $an = date('Y'); $mois = date('m'); // 01 à 12 mois avec zéro initial file_put_contents("data/$an-$mois.csv", $_POST['data'], FILE_APPEND); } echo time(); ?>
UN FICHIER CSV exemple 2024-05.csv
Spec: température intérieure, température extérieure, jour, heure23.00,14.94,1,21 22.94,13.69,1,22 24.37,13.19,1,23 23.50,13.06,2,0 23.19,12.75,2,1 23.19,12.37,2,2 22.87,11.00,2,3
PAGE WEB PHP QUI TRANSFORME LE CSV EN GRAPHIQUE
<!doctype html> <html> <head> <meta charset="utf-8"/> <?php $jstab = ''; $nb = 0; // nombre de valeurs $maxint = 0.000; $minint = 50.000; $tempint = 0.00; $moyint = 0; $maxext = 0.000; $minext = 50.000; $tempext = 0.00; $moyext = 0; $j = date('d'); $m = date('n'); // mois sans zéro initial 1 à 12 $mois=''; $y = date('Y'); $lesmois = ['','Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Aout','Septembre','Octobre','Novembre','Décembre']; $choix=''; $voirunjour = $voirunmois = $voiruneannee = 0; // il veut voir un jour en particulier if(isset($_GET['jour']) && $_GET['jour']!= 'tous'){ //echo 'voir un jour '; $j = $_GET['jour']; $m = ($_GET['mois']!='tous') ? intval($_GET['mois'])+1 : $m; $mois = $lesmois[$m]; if($m<10) $m = '0'.$m; $y = $_GET['annee']; getdata("$y-$m.csv", $mois, $j); $choix = "$j $mois $y"; $voirunjour = 1; } // il veut voir un mois en particulier: ouvre ce CSV else if(isset($_GET['mois']) && $_GET['mois']!= 'tous'){ //echo 'voir un mois '; $m = $_GET['mois']+1; $mois = $lesmois[$m]; if($m<10) $m = '0'.$m; $y = $_GET['annee']; getdata("$y-$m.csv", $mois, ''); $choix = "$mois $y"; $voirunmois = 1; } // il veut voir toute une année, ouvre plusieurs CSV else if(isset($_GET['annee'])){ //echo 'voir une année '; $y = $_GET['annee']; $csv=''; for($n=1; $n<13; $n++){ $mois = $lesmois[$n]; if($n<10) $n = '0'.$n; $csv .= "$y-$n.csv"; //echo "$csv "; getdata("$y-$n.csv", $mois, ''); } $choix = $y; $voiruneannee = 1; } else{ // il ne précise ni jour ni mois: par défaut sort le mois en cours //echo 'voir le mois en cours '; $mois = $lesmois[$m]; if($m<10) $m = '0'.$m; $csv = "$y-$m.csv"; getdata($csv,$mois,''); $choix = "$mois $y"; $voirunmois = 1; } $moyint = sprintf("%.2f", $moyint ($nb+1)); $moyext = sprintf("%.2f", $moyext ($nb+1)); $nbjoursdanscemois = cal_days_in_month(CAL_GREGORIAN, $m, $y); // ouvre un CSV et retourne un objet contenant le nombre de valeurs, et les données du tableau JS function getdata($csv, $mois, $jour=''){ if(!file_exists("data/$csv")) return; //echo "$csv "; global $jstab, $nb, $j, $maxint, $minint, $tempint, $moyint, $maxext, $minext, $tempext, $moyext; $lignes = explode("\n", file_get_contents("data/$csv")); $localnb = count($lignes)-1; //$nb += $localnb; for($n=0; $n<$localnb; $n++){ $t = explode(',',$lignes[$n]); if($jour && $t[2]!= $jour) continue; $nb++; $int = floatval($t[0]); if($maxint < $int) $maxint = $int; if($minint >= $int) $minint = $int; $tempint = $int; $moyint += $int; $ext = floatval($t[1]); if($maxext < $ext) $maxext = $ext; if($minext >= $ext) $minext = $ext; $tempext = $ext; $moyext += $ext; $dernierjour = $t[2]; $derniereheure = $t[3]; $dernieredate = "{$t[2]} $mois à {$t[3]}h30"; $jstab .= "\t[$int,$ext,'$dernieredate'],\n"; } } ?> <title>Températures <?php echo $mois.' '.$y;?></title> <style> body{background-color:#2e3436;color:gold;} input,select{ font-size:25px; border-radius:5px; background-color:#2e3436; color:white; } div#gauche{ margin-left:75px; font-family:arial; font-weight:bold; /*animation: fondu 4s;*/ } /*@keyframes fondu {0% {opacity: 0;}100% {opacity: 1;}}*/ span#titre{color:white;font-size:38px;} div#divdate{position:absolute;} span#heure{font-size:22px;color:#fff;} span#tempint{color:gold;font-size:38px;} span#tempext{color:orange;font-size:38px;} table#temps{font-size:14px;color:gray;} table#temps td{text-align:right;border-bottom:1px solid silver;} canvas { margin:2px 0px; border:1px solid silver; cursor:none; } div#barreVerticale{ width:0px; border-right:1px dashed silver; height:400px; position:absolute; cursor:none; } span.label{position:absolute; text-align:right; color:#888;} a.lien{ float:right; margin-right:10px; color:white;} </style> </head> <body> <div id="gauche"> <table border="1" style="border-collapse:collapse;float:right"> <tr><th></th> <th>intérieur</th> <th>extérieur</th></tr> <tr style="background-color:#8D6564"><td>Max</td> <td id="maxint"></td> <td id="maxext"></td></tr> <tr><td>Moy</td> <td id="moyint"></td> <td id="moyext"></td></tr> <tr style="background-color:#0288D1"><td>Min</td> <td id="minint"></td> <td id="minext"></td></tr> <tr><td colspan="3" id="nbmesures"></td></tr> </table> <a href="https://programming.masta.fr/ESP32/projets/Log%20temp%C3%A9ratures/2capteurs.html" target="_blank" class="lien">Page de développement</a><br> <a href="moyennes.php" class="lien">Moyennes mensuelles</a> <form name="frm" action="index.php"> <select name="jour"><option value="tous">tous les jours</option></select> <select name="mois"><option value="tous">tous les mois</option></select> <select name="annee"></select> <input type="submit" value="voir"> </form> <input type="checkbox" onclick="tracer()" id="chkint" checked>intérieures <input type="checkbox" onclick="tracer()" id="chkext" checked><span style="color:orange;">extérieures</span> <br> <script> sel = document.frm.jour; for(n=1; n< <?php echo ($m!='tous')?$nbjoursdanscemois+1:32;?>; n++) addOption(sel, n, n); sel.selectedIndex = <?php echo (!isset($_GET['jour']) || $_GET['jour']=='tous') ? 0 : $j;?>; sel = document.frm.mois; const lesmois=['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Aout','Septembre','Octobre','Novembre','Décembre']; for(n=0; n<12; n++) addOption(sel, n, lesmois[n]); sel.selectedIndex = <?php echo ($_GET['mois']=='tous') ? 0 : $m;?>; sel = document.frm.annee; for(n=2024; n<=<?php echo $y;?>; n++) addOption(sel, n, n); sel.selectedIndex = <?php echo $y;?> - 2024; function addOption(sel, val, txt){ const opt = document.createElement('option'); opt.value = val; opt.innerHTML = txt; sel.appendChild(opt); } </script> <span id="titre">Températures Marseille <?php echo $choix;?></span><br><br><br><br><br> <div id="divdate"> <span id="heure"></span><br> <span id="tempint"></span> <span id="tempext"></span> </div> <div id="divgraphique" style="width:80%;margin-bottom:20px;"> <span id="moinsdix" class="label">-10°</span> <span id="zero" class="label">0°</span> <span id="dix" class="label">10°</span> <span id="vingt" class="label">20°</span> <span id="trente" class="label">30°</span> <span id="quarante" class="label">40°</span> <div id="barreVerticale"></div> <canvas id="graphe" width="" height="400" style="margin-left:20px:">texte</canvas> <div style="clear:both"></div> </div> </div> <script> const canvas = document.getElementById("graphe"); canvas.style.marginLeft="30px"; const w = canvas.width = document.getElementById("divgraphique").offsetWidth - 30; const h = canvas.height; const ctx = canvas.getContext('2d'); const rect = canvas.getBoundingClientRect(); const barreVerticale = document.getElementById('barreVerticale'); barreVerticale.style.left = rect.left+rect.width-1+'px'; barreVerticale.style.top = rect.top+'px'; const divdate = document.getElementById('divdate'); const spanHeure = document.getElementById('heure'); const spantempint = document.getElementById('tempint'); const spantempext = document.getElementById('tempext'); document.getElementById("maxint").textContent = '<?php echo $maxint;?>°'; document.getElementById("moyint").textContent = '<?php echo $moyint;?>°'; document.getElementById("minint").textContent = '<?php echo $minint;?>°'; document.getElementById("maxext").textContent = '<?php echo $maxext;?>°'; document.getElementById("moyext").textContent = '<?php echo $moyext;?>°'; document.getElementById("minext").textContent = '<?php echo $minext;?>°'; const t = [ <?php echo $jstab; ?> ]; document.getElementById("nbmesures").textContent = t.length+' mesures'; const nbpixelsparjour = w (t.length-1); function tracer(){ ctx.clearRect(0, 0, w, h); const chkint = document.getElementById("chkint").checked; const chkext = document.getElementById("chkext").checked; //const chkheu = document.frm.heure.checked; /*----------------------------------------------------------------------------*/ // Trace les lignes horizontales const palier = rect.height/5; // les températures vont de -10 à 40° soit 5 paliers let y = 0; y = 1*palier; ligne(ctx, 0,y, w,y, "red" ,1); y = 2*palier; ligne(ctx, 0,y, w,y, "#5f5" ,1); y = 3*palier; ligne(ctx, 0,y, w,y, "#55f" ,1); y = 4*palier; ligne(ctx, 0,y, w,y, "white",1); /*----------------------------------------------------------------------------*/ // Labels document.getElementById('quarante').style.top = rect.top+'px'; y = rect.top + palier -8; document.getElementById('trente').style.top = y+'px'; y = rect.top + 2*palier -8;document.getElementById('vingt').style.top = y+'px'; y = rect.top + 3*palier -8;document.getElementById('dix').style.top = y+'px'; y = rect.top + 4*palier -8;document.getElementById('zero').style.top = y+'px'; y = rect.top + 5*palier -8;document.getElementById('moinsdix').style.top = y+'px'; y = parseInt(rect.top) - 40; //spantemperature.style.top = y+'px'; /*----------------------------------------------------------------------------*/ function ligne(ctx, x,y, a,b, color, epaisseur=2){ ctx.beginPath(); ctx.moveTo(x,y); ctx.lineTo(a,b); ctx.lineWidth = epaisseur; ctx.strokeStyle = color; ctx.stroke(); } /*----------------------------------------------------------------------------*/ // Le centre des coordonnées est le coin supérieur gauche du Canvas. // Les coordonnées maximales sont h et w respectivement en hauteur et en largeur //ctx.clearRect(0, 0, w,h); let jour = '' let ax = 0; let ayint = Math.round(((40-t[0][0]) *320) 40); let ayext = Math.round(((40-t[0][1]) *320) 40); let heu = ''; let moi = ''; for(n in t){ const x = Math.round(n * nbpixelsparjour); //[22.06, 11, '1 Mai à 11h30'], const tab = t[n][2].split(' '); <?php // si voir un jour, trace une ligne verticale à chaque changement d'heure if($voirunjour) echo ' if(heu != tab[3]){ heu = tab[3]; ligne(ctx, x,0, x,h, "#555",1); ctx.font = "20px serif"; ctx.fillStyle = "#ffffff"; ctx.fillText(heu, x+10, h-6); }'; // si voir un mois, trace une ligne verticale à chaque changement de jour else if($voirunmois) echo ' if(jour != tab[0]){ jour = tab[0]; ligne(ctx, x,0, x,h, "#555",1); ctx.font = "20px serif"; ctx.fillStyle = "#ffffff"; ctx.fillText(jour, x+10, h-6); }'; // si voir une année, trace une ligne verticale à chaque changement de mois else if($voiruneannee) echo ' if(moi != tab[1]){ moi = tab[1]; ligne(ctx, x,0, x,h, "#555",1); ctx.font = "20px serif"; ctx.fillStyle = "#ffffff"; ctx.fillText(moi+" "+'.$y.', x+10, h-6); }'; ?> // Pas simple de rentrer une température qui oscille entre -10° et +40° sur une hauteur de 400 pixels, // sachant que 0° est à 320px du bord haut // 40-x // 40° 0 → 0px // 30° 10 → 80px // 20° 20 → 160px // 10° 30 → 240px // 0° 40 → 320px //-10° 50 → 400px // x° 40-x→ ? // c'est tout simplement un produit en croix: px X 40 = (40-x)*320 donc px = ((40-x)*320)/40 if(chkint){ const yint = Math.round(((40-t[n][0]) *320) / 40); // intérieur ligne(ctx, ax,ayint, x,yint, "gold",1); ayint = yint; } if(chkext){ const yext = Math.round(((40-t[n][1]) *320) / 40); //extérieur ligne(ctx, ax,ayext, x,yext, "orange",1); ayext = yext; } ax = x; } spanHeure.textContent=t[t.length-1][2]; spantempint.textContent='int:'+t[t.length-1][0]+'°'; spantempext.textContent='ext:'+t[t.length-1][1]+'°'; ax = rect.left + (t.length-1) * nbpixelsparjour; barreVerticale.style.left = ax+'px'; divdate.style.left = ax-100+'px'; divdate.style.top = rect.top-70+'px'; } /*----------------------------------------------------------------------------*/ canvas.addEventListener('mousemove', function(evt) { const mousePosX = evt.clientX - rect.left; const n = Math.floor(mousePosX nbpixelsparjour); if(t[n]){ spanHeure.textContent=t[n][2]; spantempint.textContent='int:'+t[n][0]+'°'; spantempext.textContent='ext:'+t[n][1]+'°'; const x = rect.left + mousePosX; barreVerticale.style.left = x+'px'; divdate.style.left = x-100+'px'; divdate.style.top = rect.top-70+'px'; } }, false); tracer() </script> </body> </html>
Voir ce que ça donne
Bilan des températures annuelles
En 2024 l'été a été normal: période de canicule normale (c'est Marseille, pas Dunkerque) du 15 juillet au 15 aout.
En septembre, gros coup de froid. Chute spectaculaire des températures. Pas de plage ni été indien en 2024!
Hiver normal, avec de fortes chutes de neige dans les Alpes, qui ont généreusement rempli les nappes phréatiques au printemps.
Été 2025: période de canicule précoce fin juin, puis deux gros coups de froid (18° la nuit en été ce sont les températures de Lille et Moscou, mais pas Marseille): c'est bien une preuve du réchauffement de ma couille gauche dont les médias parlent si souvent pour justifier des lois indignes comme l'interdiction des voitures, comme si les vieilles de 92 ans à Marseille mourraient jeunes à 30 ans à cause la qualité de l'air.
En juillet mon arbre ficus a perdu les deux tiers de ses feuilles, pensant que l'automne était revenu.
On constate que la température moyenne du mois d'aout 2025 est inférieure (de 2°) à celle d'aout 2024, ce qui confirme que les médias sont de cupides malfrats qui nous prennent pour des lapins de six semaines. Plus ils racontent de conneries, moins on les écoute, et plus il faut les subventionner avec de l'argent public...
Ils peuvent raconter ce qu'ils veulent: l'ESP lui n'est pas payé pour mentir.
C'est la clavicule il fait trop chaud, c'est à cause du réchauffement pneumatique.