« ESP32 Horloge à LED » : différence entre les versions
m (V 0.0.1) |
mAucun résumé des modifications |
||
Ligne 11 : | Ligne 11 : | ||
== Montage et branchements == | == Montage et branchements == | ||
On se base sur la page déjà écrite pour brancher une carte "breakout" [[ESP32 | On se base sur la page déjà écrite pour brancher une carte "breakout" [[ESP32 DEVKITV2|ESP32]] V2 et un module à base de [[ESP32 Matrice de led|MAX7219]]. | ||
[[Fichier:ESP32+LEDMATRIX.png|sans_cadre| | [[Fichier:ESP32+LEDMATRIX.png|sans_cadre|320x320px]] | ||
{| class="wikitable" | {| class="wikitable" | ||
|[[Fichier:Attention.png|gauche|57x57px|sans_cadre]]ATTENTION: Je refais ma remarque faite dans la page correspondante. Alimenter les 256 LEDs consomme pas mal (256x20 mA) > 5 A! L'alim USB branchée sur le port USB ne peut pas suivre. Branché sur le port USB A de mon laptop... ça a du mal, en revanche avec un câble µUSB - USBC branché sur le "dock" ca marche bien. | |[[Fichier:Attention.png|gauche|57x57px|sans_cadre]]ATTENTION: Je refais ma remarque faite dans la page correspondante. Alimenter les 256 LEDs consomme pas mal (256x20 mA) > 5 A! L'alim USB branchée sur le port USB ne peut pas suivre. Branché sur le port USB A de mon laptop... ça a du mal, en revanche avec un câble µUSB - USBC branché sur le "dock" ca marche bien. |
Version du 29 novembre 2023 à 18:29
Présentation
On se propose de réaliser une Horloge à LED.
Les besoins sont :
- Récupérer l'heure (avec une connectivité Internet c'est facile) en NTP sur pool.ntp.org par exemple.
- Afficher l'heure sur une matrice de LED basée sur un MAX7219.
- Il faut aussi se localiser car un serveur NTP donne l'heure TU (avant on disait GMT) il nous faut connaitre la "time zone" (le fuseau horaire) et l'état DST (Heure d'été / heure d'Hiver). Des API existent pour cela, Abstract API en est une.
- Comme cette API est implémentée en HTTPS il faudra également utilise la librairie https.
- Toujours à cause de l'API Abstract il faudra savoir gérer du JSON
Montage et branchements
On se base sur la page déjà écrite pour brancher une carte "breakout" ESP32 V2 et un module à base de MAX7219.
ATTENTION: Je refais ma remarque faite dans la page correspondante. Alimenter les 256 LEDs consomme pas mal (256x20 mA) > 5 A! L'alim USB branchée sur le port USB ne peut pas suivre. Branché sur le port USB A de mon laptop... ça a du mal, en revanche avec un câble µUSB - USBC branché sur le "dock" ca marche bien. |
ATTENTION: Avec la carte ESP32_DEVKITV2 les branchements sont un peu diffréent. Bien se reporter au "pinout" de la carte disponible sur la page ci-dessus. Le GND n'est plus disponible en bas à gauche a côté du 5V mais quelques pines au dessus. Même chose pour GPIO19 qui elle est un cran plus bas en raison d'un GND qui apparait entre GPIO19 et GPIO21 |
Code
Code de test
On teste le montage avec le code suivant.
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4 // 4 blocks
#define CS_PIN 21
// create an instance of the MD_Parola class
MD_Parola ledMatrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
void setup() {
// Initialize the breakout buildin led
pinMode(2,OUTPUT);
digitalWrite(2,HIGH);
ledMatrix.begin(); // initialize the LED Matrix
ledMatrix.setIntensity(0); // set the brightness of the LED matrix display (from 0 to 15)
ledMatrix.displayClear(); // clear LED matrix display
}
void loop() {
ledMatrix.setTextAlignment(PA_CENTER);
ledMatrix.print("12:30"); // display text
Résultat:
Ca marche on a une horloge à l'heure… deux fois par jours.
Mise à l'heure
En se connectant à un serveur NTP on pourrait afficher l'heure UT.
#include <WiFi.h>
#include <WiFiMulti.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include "SSIDs.h"
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4 // 4 blocks
#define CS_PIN 21
// create an instance of the MD_Parola class
MD_Parola ledMatrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Time update
void setClock() {
configTime(0, 0, "pool.ntp.org");
Serial.println("Waiting for NTP time sync: ");
time_t nowSecs = time(nullptr);
while (nowSecs < 8 * 3600 * 2) {
delay(500);
Serial.print(F("."));
yield();
nowSecs = time(nullptr);
}
Serial.println();
struct tm timeinfo;
gmtime_r(&nowSecs, &timeinfo);
Serial.print("Current time: ");
Serial.println(asctime(&timeinfo));
}
// Manage Wifi
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
// Initialize the breakout buildin led
pinMode(2,OUTPUT);
digitalWrite(2,HIGH);
ledMatrix.begin(); // initialize the LED Matrix
ledMatrix.setIntensity(0); // set the brightness of the LED matrix display (from 0 to 15)
ledMatrix.displayClear(); // clear LED matrix display
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(PRIMARY_SSID);
#ifdef SECONDARY_SSID
WiFiMulti.addAP(SECONDARY_SSID);
#endif
// wait for WiFi connection
Serial.println("Serach WIFI");
ledMatrix.setTextAlignment(PA_CENTER);
ledMatrix.print("WiFi");
Serial.print("Waiting for WiFi to connect...");
while ((WiFiMulti.run() != WL_CONNECTED)) {
delay (100);
}
ledMatrix.setTextAlignment(PA_CENTER);
ledMatrix.print(WiFi.SSID());
delay (1000);
Serial.println(" connected");
ledMatrix.setTextAlignment(PA_CENTER);
ledMatrix.print("Time");
setClock();
}
void loop() {
struct tm timeinfo;
time_t nows = time(nullptr);
gmtime_r(&nows, &timeinfo);
Serial.print(asctime(&timeinfo));
int h = timeinfo.tm_hour;
int m = timeinfo.tm_min;
char timeBuffer[6];
sprintf(timeBuffer,"%d:%02d", h, m);
ledMatrix.setTextAlignment(PA_CENTER);
ledMatrix.print(timeBuffer); // display time
unsigned long old=m;
// Wait for next minute
while (old==m) {
nows = time(nullptr);
gmtime_r(&nows, &timeinfo);
m = timeinfo.tm_min;
}
}
Le fichier "SSID.h" contient une ou deux macros définissant le SSID primaire et celui de backup.
#define PRIMARY_SSID "MABOXP", "lsqkdjlqksjdlqskjdlksq"
#define SECONDARY_SSID "MABOXS", "pozaidlsqkjdlzajdlqksj"
Dans l'ordre l'afficheur nous indique
La connexion wifi s'établit.
Une fois celle-ci établie, comme on utilise WiFiMulti on affiche le SSID qui a été choisit.
Puis on affiche :
Et puis enfin l'heure (mise a jour toutes les secondes)
On y crois mais ATTENTION c'est l'heure TU (GMT). L'heure à Greenwich en hivers! |
Gestion des "time zones"
On va utiliser l'API Abstract qui, à partir de notre IP publique va nous donner notre position, notre timezone etc.
L'URL de base de cette API est : https://ipgeolocation.abstractapi.com/v1/
Pour avoir son certificat on suit la procédure décrite dans la page l'API Abstract. A l'heure ou j'écris ces lignes c'est : Amazon Root CA 1 et elle est valable jusqu'au : January 16, 2038... on a du temps. En revanche le certificat de ipgeolocation.abstractapi.com expire le mercredi 22 mai 2024. Rien n'assure qu'après cette date le nouveau certificat de renouvellement sera toujours signé par Amazon!
Quand on développe un objet connecté on doit, de préférence, utiliser une URL dont on maitrise le certificat. Surtout prendre garde à ce que le serveur gérant le FW Update ne soit pas derrière un certificat que l'on ne maitrise pas.
Le certificat CA de Amazon est le suivant:
-----BEGIN CERTIFICATE-----
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
rqXRfboQnoZsG4q5WTP468SQvvG5
-----END CERTIFICATE-----
On en fait une chaine de caractère et on la mets dans le fichier CA-certificat.h
const char* rootCACertificate = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n" \
"ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" \
"b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n" \
"MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n" \
"b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n" \
"ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n" \
"9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n" \
"IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n" \
"VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n" \
"93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n" \
"jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" \
"AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n" \
"A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n" \
"U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n" \
"N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n" \
"o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n" \
"5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n" \
"rqXRfboQnoZsG4q5WTP468SQvvG5\n" \
"-----END CERTIFICATE-----\n";
On inclus ce fichier en tête de notre programme. On crée également un fichier Abstract.h qui contient l'API_KEY qui nous identifie associé à l'URL:
#define ABSTRACT_URL "https://ipgeolocation.abstractapi.com/v1/?api_key=xxxxxx&fields=timezone"
On ajoute en tête de programme :
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include "Abstract.h"
Pour inclure les librairies http client et ssl (TLS) Et on ajoute une fonction getAbstractApiInfo():
String getAbstractApiInfo(){
WiFiClientSecure *client = new WiFiClientSecure;
if(client) {
client -> setCACert(rootCACertificate);
{
HTTPClient https;
Serial.print("[HTTPS] begin...\n");
if (https.begin(*client, ABSTRACT_URL)) { // Defined in Abstract.h
Serial.print("[HTTPS] GET...\n");
// start connection and send HTTP header
int httpCode = https.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = https.getString();
return payload;
}
} else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
}
https.end();
} else {
Serial.printf("[HTTPS] Unable to connect\n");
}
}
}
return ("ERROR");
}
Qui nous renvoie une chaine :
{"timezone":{"name":"Europe/Paris","abbreviation":"CET","gmt_offset":1,"current_time":"20:55:32","is_dst":false}}
Qui est du JSON :
{
"timezone": {
"name": "Europe/Paris",
"abbreviation": "CET",
"gmt_offset": 1,
"current_time": "20:55:32",
"is_dst": false
}
}
Il nous faut alors utiliser la librairie standard JSON écrite pour les utilisateurs Arduino et qui est très légère : #include <Arduino_JSON.h>
Elle est compatible ESP32 et prendra donc peu de place.
On ajoute :
#include <Arduino_JSON.h>
Et on ajoute à la fin de setup():
ledMatrix.setTextAlignment(PA_CENTER);
ledMatrix.print("Geoloc");
String loc=getAbstractApiInfo();
JSONVar myObject = JSON.parse(loc);
// JSON.typeof(jsonVar) can be used to get the type of the variable
if (JSON.typeof(myObject) == "undefined") {
Serial.println("Parsing input failed!");
return; // exit form setup reboot
}
int hShift;
if (myObject.hasOwnProperty("timezone")) {
hShift=(int)myObject["timezone"]["gmt_offset"];
}
int sShift=hShift*3600;
String timeZone="TU";
if (sShift>=0)
timeZone+="+";
timeZone+=String(hShift);
ledMatrix.print(timeZone);
delay (5000);
timeShift=sShift;
Les deux premières lignes ne sont là que pour afficher:
Pendant les requêtes de géolocalisation.
Ensuite on appelle l'API "Abstract" pour connaitre la time-zone de l'IP publique de l'ESP32.
On "parse" ce code JSON pour en retirer te GMT Offset (en heures). On le traduit en secondes car certaines parties du monde n'ont pas un décalage horaire en heures entières.
- En Inde c'est UTC+5:30 (5.5)
- En Australie centrale (Alice Spring, Adelaide...) c'est 9H1/2 en hiver et 10h en été (oui ils sont compliqués les Australiens).
- Le Népal est a 5:45 ou 5 3/4 ou 5.75....
Donc faut gérer.
Ensuite on fait une jolie "string" avec TU + ou - le dévalage.
Et on l'affiche :
On aurait la place de faire un GMT+1 ou un UTC+1 mais en cas de +5.75 ... faut prévoir. (même là le 5 de 75 va passer par dessus bord… tampi pour les Népalais j'ai pas un afficheur assez grand)
Remarque :On pourrait afficher des messages plus longs en ajoutant un ou deux digits à la suite. Moi je n'ai trouvé que des cartes toutes faites de 4 digits mais elles semblent "sécables". Il suffit de les relier entres elles avec les 5 fils et de déclarer : #define MAX_DEVICES 6 au début. Peut être au Népal les boutiques de makers vendent des breakout de 6 digits! |
Ensuite l'afficheur indique l'heure où que vous soyez (pourvu que qu'un WIFI wifi ayant un SSID et un password indiqué dans "SSIDs.h" soit disponible.
Le support
Maintenant que l'on a un joli logiciel et un prototype avec des câbles Dupont il faudrait réaliser un joli support. J'ai choisit de garder l'électronique apparente. Au niveau conformité CE ça va pas être fameux mais… on va pas le vendre.
Sur GitHub tout est dans le répertoire /hardware.
J'ai conçu un support qui s'imprime en ABS sans supports sur mon Ultimaker 2ex et une plaque de plastique acrylique de 3mm découpé à la CNC (ma 3018).
La modélisation a été faite avec FreeCad qui est un excellent produit!
A gauche la vue "Freecad" a droite la photo de la Vraie horloge.
Pour la réalisation il faudra :
- De l'ABS de la couleur de votre choix. (du PLA fera aussi l'affaire mais ne le poser pas derrière une fenêtre votre Horloge risque de "fondre au soleil")
- Une plaque d'acrylique transparent (semi-transparent ça peut le faire… je vais essayer d'en trouver).
- De la quincaillerie:
- Deux Vis a tête cylindrique six pans creux M4×30 pour fixer la vitre (sur la photo il y a deux rondelles mais c'est une option)
- 4 vis a tête bombée six pans creux M3×10
- 4 vis a tête cylindrique six pans creux M2.5×14 et son écrou pour fixer le breakout ESP32
- 4 inserts taraudés en laiton M2×4
- 4 inserts taraudés en laiton M3x5.7
- Une carte "breakout" ESP32 DevKit V2 (celle avec les support de broches jaunes et 2×19 broches et des trous de 2.5mm aux 4 coins)
- Une carte à base de 4 MAX7219 et4 afficheurs à LED 1088AS
Doit y en avoir pour 30€ max.