Lire télé information linky esp32-C3 Super mini
Description :
Ce projet consiste à concevoir un module de lecture et de décodage en temps réel du flux de Téléinformation Client (TIC) émis par les compteurs d’électricité Enedis (Linky ou électroniques). Développé pour le microcontrôleur ESP32-C3, ce programme extrait les métriques clés de consommation électrique directement depuis la sortie téléinformation du compteur pour les rendre exploitables localement.
Prérequis :
- 1 x ESP32-C3 Super Mini
- 1 x Résistance 3.3KΩ
- 1 x Résistance 330Ω
- 1 x SFH620A
Version IDE :
- Arduino IDE 2.3.7
Vidéo de démonstration :
NA
Schéma de câblage :

Code :
#define RX_PIN 20 // Broche de réception série sur ESP32-C3 (GPIO 20)
// Création d'une instance UART matérielle dédiée à la Téléinformation
HardwareSerial MySerial(1);
// --- Variables de contrôle et de parsing ---
int debug = 1; // 1 pour activer les logs sur le moniteur série
char msg[128]; // Tampon générique (non utilisé dans ce code)
char Trame_Teleinfo = 0; // Stocke le caractère en cours de lecture
int Donnee = 0; // État de l'automate : 0=hors trame, 1=Étiquette, 2=Valeur, 3=Checksum
String Ligne; // Reconstitution de "Étiquette Valeur" pour le calcul de somme de contrôle
String Etiquette; // Nom de la mesure reçue (ex: "PAPP", "BASE")
String Valeur; // Valeur associée à l'étiquette (sous forme de chaîne)
char Checksum; // Caractère de checksum envoyé par le compteur
char Controle = 0; // Valeur de checksum calculée localement pour vérification
// --- Variables stockant les données décodées du compteur ---
long Base = 0; // Index de consommation en Wh (Option Base)
int Papp = 0; // Puissance apparente en VA
int Iinst1 = 0; // Intensité instantanée phase 1 (en Ampères)
int Iinst2 = 0; // Intensité instantanée phase 2 (en Ampères)
int Iinst3 = 0; // Intensité instantanée phase 3 (en Ampères)
int Isousc = 0; // Intensité souscrite (en Ampères)
void setup() {
// Communication série principale pour le débogage (Moniteur Série USB)
Serial.begin(115200);
// Configuration du port Téléinfo : 1200 bauds, 8 bits de données, pas de parité, 1 bit de stop
// On passe -1 en broche TX pour indiquer qu'on est uniquement en écoute
MySerial.begin(1200, SERIAL_8N1, RX_PIN, -1);
Serial.println("Écoute sur le port RX (1200 bauds)...");
}
void loop(void) {
// Lecture continue de la Téléinformation
Recupere_la_Teleinfo();
}
/**
* Lit les caractères entrant sur l'UART et décode la trame Téléinfo au fil de l'eau.
* Format d'une ligne Téléinfo : <LF>ETIQUETTE<SP>VALEUR<SP>CHECKSUM<CR>
*/
void Recupere_la_Teleinfo() {
if (MySerial.available() > 0) {
// Masquage à 7 bits (0x7F) pour garantir la compatibilité ASCII (nettoyage bit de parité si présent)
Trame_Teleinfo = MySerial.read() & 0x7F;
switch (Trame_Teleinfo) {
case 0x0A: // <LF> (Line Feed) : Début d'une nouvelle ligne de données
if (debug == 1 && Etiquette.length() > 0) {
// Affiche le groupe d'informations précédent si disponible
Serial.print(Etiquette);
Serial.print("/");
Serial.print(Valeur);
Serial.print("/");
Serial.println(Checksum);
}
Etiquette = ""; // Réinitialise l'étiquette pour la nouvelle ligne
Donnee = 1; // Bascule l'état : on commence à lire l'étiquette
break;
case 0x20: // <SP> (Espace) : Séparateur entre Champ/Valeur et Valeur/Checksum
Donnee++;
if (Donnee == 2) {
Valeur = ""; // Fin de l'étiquette, préparation à la lecture de la valeur
}
if (Donnee == 3) {
Checksum = 0; // Fin de la valeur, préparation à la lecture du checksum
}
break;
case 0x0D: // <CR> (Carriage Return) : Fin de la ligne en cours
Controle = 0;
// Calcul de la somme ASCII du bloc "ETIQUETTE VALEUR"
Ligne = Etiquette + " " + Valeur;
for (byte i = 0; i < (Ligne.length()); i++) {
Controle += Ligne[i];
}
// Formule officielle Enedis pour dériver le checksum à partir de la somme
Controle = (Controle & 0x3F) + 0x20;
Donnee = 0; // Réinitialise l'état du découpage
// Si le calcul locale correspond au checksum reçu, la ligne est valide
if (Controle == Checksum) {
// Index heure de base (en Wh)
if (Etiquette.substring(0, 4) == "BASE") {
Base = Valeur.toFloat();
if (debug == 1) {
Serial.print(" => Consommation : ");
Serial.print(Base);
Serial.println(" Wh");
}
}
// Puissance Apparente (en VA)
if (Etiquette.substring(0, 4) == "PAPP") {
Papp = Valeur.toInt();
if (debug == 1) {
Serial.print(" => Puissance apparente : ");
Serial.print(Papp);
Serial.println(" VA");
}
}
// Intensité instantanée phase 1 (en A)
if (Etiquette.substring(0, 6) == "IINST1") {
Iinst1 = Valeur.toInt();
if (debug == 1) {
Serial.print(" => Intensite instantanee ph1 : ");
Serial.print(Iinst1);
Serial.println(" A");
}
}
// Intensité instantanée phase 2 (en A)
if (Etiquette.substring(0, 6) == "IINST2") {
Iinst2 = Valeur.toInt();
if (debug == 1) {
Serial.print(" => Intensite instantanee ph2 : ");
Serial.print(Iinst2);
Serial.println(" A");
}
}
// Intensité instantanée phase 3 (en A)
if (Etiquette.substring(0, 6) == "IINST3") {
Iinst3 = Valeur.toInt();
if (debug == 1) {
Serial.print(" => Intensite instantanee ph3 : ");
Serial.print(Iinst3);
Serial.println(" A");
}
}
// Intensité souscrite (en A)
if (Etiquette.substring(0, 6) == "ISOUSC") {
Isousc = Valeur.toInt();
if (debug == 1) {
Serial.print(" => Intensité souscrite : ");
Serial.print(Isousc);
Serial.println(" A");
}
}
}
break;
default:
// Accumulation des caractères selon la zone courante de la ligne
if (Donnee == 1) {
Etiquette = Etiquette + Trame_Teleinfo; // Reconstruction du nom d'étiquette
}
if (Donnee == 2) {
Valeur = Valeur + Trame_Teleinfo; // Reconstruction de la valeur
}
if (Donnee == 3) {
Checksum = Checksum + Trame_Teleinfo; // Récupération du caractère de checksum
}
break;
}
}
}
