Aide téléinfo

Bonjour,
est ce que quelqu’un utilise l’arduino pour récupérer la télé-info EDF ?
j’ai besoin d’aide car je sèche complétement, si une âme charitable pouvez m’aider ce serai cool.
Voilà mon problème :
j’ai fait ce montage : http://blog.cquad.eu/wp-content/uploads/2012/02/Teleinfo-2-1024x625.png
j’utilise un arduino Duemilanove
je voudrai seulement récupérer ma consommation électrique toute les 15 minutes sur la micro SD du Shield ethernet.
mon premier problème, c’est toutes les 15 minutes car visiblement un delay (900 000 000) ne fonctionne pas, j’ai un relevé toutes les secondes.
voici mon code : (qui n’est pas de moi)

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SoftwareSerial.h>

// Mac address : a mac address must be unique
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// IP address : the value will depend on your network
IPAddress ip(10, 0, 0, 8);
char myIPAdress[]="10.0.0.8";

/***************** Teleinfo configuration part *******************/
char CaractereRecu ='\0';
char Checksum[32] = "";
char Ligne[32]="";
char Etiquette[9] = "";
char Donnee[13] = "";
char Trame[512] ="";
int i = 0;
int j = 0;
int a;

long BASE = 0;      // Index option Heures Creuses - Heures Creuses, 8 numériques, Wh
int check[11];  // Checksum by etiquette
int trame_ok = 1; // global trame checksum flag
int finTrame=0;
int sendHbeat;
/******************* END OF CONFIGURATION *******************/


/*********************** Global vars ************************/

// UDP related vars
EthernetUDP Udp;
SoftwareSerial cptSerial(2, 3);

// status
int result;
int seconde;

/********************* Set up arduino ***********************/
void setup() {

    // Serial to EDF cpt
    cptSerial.begin(1200);
    Serial.begin(115200); //A commenter pour une alim externe
    
    // Ethernet initialisation
    Ethernet.begin(mac, ip);
    
}

void loop(){
  
      getTeleinfo();
   delay(50000);
      
  }

/*------------------------------------------------------------------------------*/
/* Test checksum d'un message (Return 1 si checkum ok)				*/
/*------------------------------------------------------------------------------*/
int checksum_ok(char *etiquette, char *valeur, char checksum) 
{
	unsigned char sum = 32 ;		// Somme des codes ASCII du message + un espace
	int i ;
 
	for (i=0; i < strlen(etiquette); i++) sum = sum + etiquette[i] ;
	for (i=0; i < strlen(valeur); i++) sum = sum + valeur[i] ;
	sum = (sum & 63) + 32 ;
        //Serial.print(etiquette);Serial.print(" ");
        //Serial.print(valeur);Serial.print(" ");
	//Serial.println(checksum);
	//Serial.print("Sum = "); Serial.println(sum);
	//Serial.print("Cheksum = "); Serial.println(int(checksum));
	if ( sum == checksum) return 1 ;	// Return 1 si checkum ok.
	return 0 ;
}

/***********************************************
   getTeleinfo
   Decode Teleinfo from serial
   Input : n/a
   Output : n/a
***********************************************/
void getTeleinfo() { 
  /* vider les infos de la dernière trame lue */
  memset(Ligne,'\0',32); 
  memset(Trame,'\0',280);
  int trameComplete=0;

  BASE = 0;
  
  while (!trameComplete){
    while(CaractereRecu != 0x02) // boucle jusqu'a "Start Text 002" début de la trame
    {
       if (cptSerial.available()) {
         CaractereRecu = cptSerial.read() & 0x7F;
       }
    }

    i=0; 
    while(CaractereRecu != 0x03) // || !trame_ok ) // Tant qu'on est pas arrivé à "EndText 003" Fin de trame ou que la trame est incomplète
    { 
      if (cptSerial.available()) {
          CaractereRecu = cptSerial.read() & 0x7F;
  	  Trame[i++]=CaractereRecu;
      }	
    }
    finTrame = i;
    Trame[i++]='\0';

    //Serial.println(Trame);
  
    lireTrame(Trame);	

    // on vérifie si on a une trame complète ou non
    for (i=0; i<9; i++) {
      trameComplete+=check[i];
    }
    //Serial.print("Nb lignes valides :"); Serial.println(trameComplete);
    if (trameComplete < 9) trameComplete=0; // on a pas les 11 valeurs, il faut lire la trame suivante
    else trameComplete = 1;
  }
}

void lireTrame(char *trame){
    int i;
    int j=0;
    for (i=0; i < strlen(trame); i++){
      if (trame[i] != 0x0D) { // Tant qu'on est pas au CR, c'est qu'on est sur une ligne du groupe
          Ligne[j++]=trame[i];
      }
      else { //On vient de finir de lire une ligne, on la décode (récupération de l'etiquette + valeur + controle checksum
          decodeLigne(Ligne);
          memset(Ligne,'\0',32); // on vide la ligne pour la lecture suivante
          j=0;
      }

   }
}

int decodeLigne(char *ligne){ 
  
  
 
  //Checksum='\0';
  
  int debutValeur; 
  int debutChecksum;
  // Décomposer en fonction pour lire l'étiquette etc ...  
  debutValeur=lireEtiquette(ligne);
  debutChecksum=lireValeur(ligne, debutValeur);
  lireChecksum(ligne,debutValeur + debutChecksum -1);

  if (checksum_ok(Etiquette, Donnee, Checksum[0])){ // si la ligne est correcte (checksum ok) on affecte la valeur à l'étiquette
    return affecteEtiquette(Etiquette,Donnee);
  } 
  else return 0;

}


int lireEtiquette(char *ligne){
    int i;
    int j=0;
    memset(Etiquette,'\0',9);
    for (i=1; i < strlen(ligne); i++){ 
      if (ligne[i] != 0x20) { // Tant qu'on est pas au SP, c'est qu'on est sur l'étiquette
          Etiquette[j++]=ligne[i];
      }
      else { //On vient de finir de lire une etiquette
	//  Serial.print("Etiquette : ");
        //  Serial.println(Etiquette);
          return j+2; // on est sur le dernier caractère de l'etiquette, il faut passer l'espace aussi (donc +2) pour arriver à la valeur
      }

   }
}


int lireValeur(char *ligne, int offset){
    int i;
    int j=0;
    memset(Donnee,'\0',13);
    for (i=offset; i < strlen(ligne); i++){ 
      if (ligne[i] != 0x20) { // Tant qu'on est pas au SP, c'est qu'on est sur l'étiquette
          Donnee[j++]=ligne[i];
      }
      else { //On vient de finir de lire une etiquette
	//  Serial.print("Valeur : ");
        //  Serial.println(Donnee);
          return j+2; // on est sur le dernier caractère de la valeur, il faut passer l'espace aussi (donc +2) pour arriver à la valeur
      }

   }
}


void lireChecksum(char *ligne, int offset){
    int i;
    int j=0;
    memset(Checksum,'\0',32);
    for (i=offset; i < strlen(ligne); i++){ 
          Checksum[j++]=ligne[i];
	//  Serial.print("Chekcsum : ");
        //  Serial.println(Checksum);
      }

}

int affecteEtiquette(char *etiquette, char *valeur){

if(strcmp(etiquette,"BASE") == 0) { BASE = atol(valeur); check[2]=1;
   Serial.print("BASE="); Serial.print(BASE);Serial.println("Wh");
   //Serial.print("valeur="); Serial.println(valeur);
 }
 else

 return 0;

 return 1;
}

est ce que l’un d’entre vous utilise déjà un système similaire et pouvait m’aider ?
(petit précision, je ne comprend pas forcement tout ce que fait le code ci-dessus, car pour moi le C++ c’est pas mon domaine)
merci d’avance

Salut,

Si tu veux juste écrire sur la carte SD, pourquoi tout ce code qui pilote l'ethernet ? Vu tes questions j'ai le sentiment que tu veux mettre la charrue avant les boeufs ...

Vu le schéma tu dois déjà apprendre à manipuler les interruptions : http://arduino.cc/en/Reference/AttachInterrupt

Pour un stockage périodique ensuite il faut utiliser les interruptions temporelles : http://battomicro.wordpress.com/2013/06/07/tutorial-les-interruptions-temporelles-avec-arduino/

Commence par simplement récupérer les infos sur ton PC. Ensuite travaille le stockage SD. Vouloir tout faire d'un coup c'est aller dans le mur, même la perso je ferais étape par étape. Et visiblement il te manque des notions de base, donc tu risques d'être dégoutté avant même d'avoir écrit deux lignes de code, ça serait dommage ;)

Merci B@tto,
c’est exactement ce qui m’arrive, je suis dessus depuis 3 jours et franchement juste pour récupérer une valeur je deviens fou !!
j’ai cherché des heurs sur le net mais rien ne correspond à ce que je veux.
en fait il y a l’Ethernet car j’ai déja un UNO qui suit ma cuve d’eau de pluie, je récupère le niveau, l’inscrit sur la SD et le transfert par FTP sur mon serveur.
celui-la fonction très bien et je voudrai faire la même chose avec la téléinfo mais je bloc au niveau des 15 minutes.
tiens ça peut servir à d’autre je met mon code de la cuve.

#include <SPI.h>
#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <EthernetUdp.h>
#include <util.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>

#define FTPWRITE

RTC_DS1307 RTC;

//--- adresse mac = identifiant unique du shield
byte mac[] = { 0xF0, 0x7B, 0xCB, 0x15, 0xFE, 0xD2 };
//--- adresse IP fixe à utiliser pour le shield Ethernet
IPAddress ipLocal(10,0,0,7);
//--- adresse de la passerelle réseau
IPAddress passerelle(10,0,0,1);
//--- masque de sous réseau
IPAddress masque(255,255,255,240);

//--- adresse ip du serveur FTP
IPAddress server(10,0,0,2);
EthernetClient client;
EthernetClient dclient;

/* Utilisation du capteur Ultrason HC-SR04 */
// définition des broches utilisées
int trig = 9;
int echo = 8;
long lecture_echo;
long cm;
long niveau;
 
File myFile;

char outBuf[128];
char outCount;
// Nom du fichier sur SD (8.3 format!)
char fileName[13] = "20130714.CUV";

void setup()
{
  Serial.begin(19200); 
  Wire.begin();
  RTC.begin();

  Ethernet.begin(mac, ipLocal, passerelle, masque); // initialise la connexion Ethernet
  delay(2000); // donne le temps à la carte Ethernet de s'initialiser
  
  Serial.print(F("Initializing SD card..."));
  pinMode(10, OUTPUT);
  // Sur le module Ethernet, CS est la broche 4. Il est défini comme une sortie par défaut.
  // Notez que même si elle n'est pas utilisée comme broche CS, le matériel SS broches
  // (10 sur la plupart des cartes Arduino, 53 sur les Mega) doit être laissé comme une sortie
  // Ou les fonctions de la bibliothèque SD ne fonctionneront pas.
   pinMode(trig, OUTPUT);
   digitalWrite(trig, LOW);
   pinMode(echo, INPUT);
   
  if (!SD.begin(4)) {
    Serial.println(F("echec de l'initialisation!"));
    return;
  }
    Serial.println(F("initialisation fait."));
}
 
void loop()
{
     int days ;
     int months ;
     int years ;
     uint32_t tempunix; //permet d'avoir le timestamp complet
     DateTime now = RTC.now();
     days = now.day();
     months = now.month();
     years = now.year();

  /* création du nom du fichier du jour */
     sprintf(fileName,"%d%02d%02d.CUV", years,months,days);  //  %d pour un int et %02d pour deux chiffres       
  // ouvrir le fichier. noter qu'un seul fichier peut être ouvert à la fois,
  // Si vous devez fermer celui-ci avant d'ouvrir un autre.
      myFile = SD.open(fileName, FILE_WRITE);
 
  // Si le fichier ouvert ok, on y écrire:
  if (myFile) {
    digitalWrite(trig, HIGH);
    delayMicroseconds(30); //Stop le programme pendant la durée (en microsecondes) spécifiées en paramètres
    digitalWrite(trig, LOW);
    lecture_echo = pulseIn(echo, HIGH);
    cm = lecture_echo / 58; //valeur relevé par le capteur
    niveau = 207-cm; // hauteur max d'eau dans la cuve
    Serial.print(F("On ecrit dans : "));
    Serial.print(fileName);
    Serial.print(F(" la valeur => "));
    Serial.println(niveau);
    tempunix = (now.unixtime()-7200);// on fait -2h pour la zone france
    myFile.print(tempunix);
    myFile.print(";");
    myFile.print(niveau);
    myFile.println(";");
   // on ferme le fichier:
    myFile.close();}
  else {
   // Si le fichier ne s'ouvre pas, on affiche une erreur:
    Serial.print(F("erreur d'ouverture : "));
    Serial.println(fileName);
  }

  delay(3000); // délai avant transfere FTP 3 secondes

 // Suppression du fichier vieux de 5 jours si il existe
   // Nom du fichier sur SD (8.3 format!)
    char fileNameavant[13] = "20130714.CUV";
    int daysavant ;
    int monthsavant ;
    int Yearavant ;
    DateTime avant = (now.unixtime() - 5 * 86400L);
    daysavant = avant.day();
    monthsavant = avant.month();
    Yearavant = avant.year();
    sprintf(fileNameavant,"%d%02d%02d.CUV",Yearavant,monthsavant,daysavant);
       while(SD.exists(fileNameavant)){ // Verifiez si le fichier texte existe
       SD.remove(fileNameavant);}       //Si oui, alors le supprimer
       
 delay(9970); // délai avant transfere FTP 30 secondes 
 
   /*--- gestion du FTP ---*/
  byte inChar;
  inChar = Serial.read();
    if(doFTP()) Serial.println(F("FTP OK"));
    else Serial.println(F("Connexion FTP impossible"));Serial.println(); 
 
  delay(887000); // délai entre chaque relevé 840 secondes ou 14 minutes
}

/* Fonctions pour le FTP */
File fh;

byte doFTP()
{
#ifdef FTPWRITE
  fh = SD.open(fileName,FILE_READ);
#else
  SD.remove(fileName);
  fh = SD.open(fileName,FILE_WRITE);
#endif

  if(!fh)
  {
    Serial.println(F("SD open fail"));
    return 0;    
  }

#ifndef FTPWRITE  
  if(!fh.seek(0))
  {
    Serial.println(F("Rewind fail"));
    fh.close();
    return 0;    
  }
#endif

  Serial.println(F("SD opened"));

  if (client.connect(server,21)) {
    Serial.println(F("Command connected"));
  } 
  else {
    fh.close();
    Serial.println(F("Command connection failed"));
    return 0;
  }

  if(!eRcv()) return 0;

  client.println(F("USER cuve"));

  if(!eRcv()) return 0;

  client.println(F("PASS cuvepluie"));

  if(!eRcv()) return 0;

  client.println(F("SYST"));

  if(!eRcv()) return 0;

  client.println(F("PASV"));

  if(!eRcv()) return 0;

  char *tStr = strtok(outBuf,"(,");
  int array_pasv[6];
  for ( int i = 0; i < 6; i++) {
    tStr = strtok(NULL,"(,");
    array_pasv[i] = atoi(tStr);
    if(tStr == NULL)
    {
      Serial.println(F("Bad PASV Answer"));    

    }
  }

  unsigned int hiPort,loPort;

  hiPort = array_pasv[4] << 8;
  loPort = array_pasv[5] & 255;

  Serial.print(F("Data port: "));
  hiPort = hiPort | loPort;
  Serial.println(hiPort);

  if (dclient.connect(server,hiPort)) {
    Serial.println(F("Data connected"));
  } 
  else {
    Serial.println(F("Data connection failed"));
    client.stop();
    fh.close();
    return 0;
  }

#ifdef FTPWRITE 
  client.print(F("STOR "));
  client.println(fileName);
#else
  client.print(F("RETR "));
  client.println(fileName);
#endif

  if(!eRcv())
  {
    dclient.stop();
    return 0;
  }

#ifdef FTPWRITE
  Serial.println(F("Writing"));

  byte clientBuf[64];
  int clientCount = 0;

  while(fh.available())
  {
    clientBuf[clientCount] = fh.read();
    clientCount++;

    if(clientCount > 63)
    {
      dclient.write(clientBuf,64);
      clientCount = 0;
    }
  }

  if(clientCount > 0) dclient.write(clientBuf,clientCount);

#else
  while(dclient.connected())
  {
    while(dclient.available())
    {
      char c = dclient.read();
      fh.write(c);      
      Serial.write(c); 
    }
  }
#endif

  dclient.stop();
  Serial.println(F("Data disconnected"));

  if(!eRcv()) return 0;

  client.println(F("QUIT"));

  if(!eRcv()) return 0;

  client.stop();
  Serial.println(F("Command disconnected"));

  fh.close();
  Serial.println(F("SD closed"));
  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;

  while(!client.available()) delay(1);

  respCode = client.peek();

  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);

    if(outCount < 127)
    {
      outBuf[outCount] = thisByte;
      outCount++;      
      outBuf[outCount] = 0;
    }
  }

  if(respCode >= '4')
  {
    efail();
    return 0;  
  }

  return 1;
}

void efail()
{
  byte thisByte = 0;

  client.println(F("QUIT"));

  while(!client.available()) delay(1);

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }

  client.stop();
  Serial.println(F("Command disconnected"));
  fh.close();
  Serial.println(F("SD closed"));
}

en tout cas merci de ton intérêt je regarde tes liens.

Le problème c'est que tu ne récupères pas les données du compteur ou c'est les 15 minutes?

Si c'est juste les 15 minutes, est-ce que tu as écrit 900000 ou 900000L? Le L est important pour définir une constant de type long.

je récupère bien l'info qui m’intéresse mais toute les secondes. j'ai essayé "delay(5000)" , "delay(10000)", ...... mais aucun ne fonction j'ai toujours un relevé par seconde ceci dit je ne mets pas le "L" je viens de faire un teste avec "delay(50000L)" mais toujours pareil !! :(

Comme souvent dans ces cas là, il faut élargir son champs d'investigations, à la recherche d'autres suspects potentiels.

Ne serait-ce pas plutôt ta fonction getTeleInfo() qui ne rend jamais la main ? Dans ta fonction loop, essaye d'ajouter un Serial.println("coucou") entre l'appel à cette fonction et le delay

Hypothèse : dans getTeleInfo(), on ne sort jamais du premier while, et le second while est l'endroit où ton arduino attend systématiquement une seconde avant de recevoir une nouvelle trame.

ah voilà une bonne piste, en effet j'ai fait ceci

void loop(){
  
      getTeleinfo();
      Serial.println("coucou");
   delay(50000L);
      
  }

et ça donne ça : BASE=2604259Wh BASE=2604260Wh BASE=2604262Wh BASE=2604263Wh BASE=2604265Wh BASE=2604266Wh BASE=2604268Wh BASE=2604270Wh BASE=2604271Wh BASE=2604273Wh BASE=2604274Wh BASE=2604276Wh

pas de coucou !!! maintenant sais-tu comment sortir du getTeleinfo ? merci de ton aide

De manière simple : Non

Ce source est mal codé (désolé). Il y a plein de variables globales, mises à jour dans certaines fonctions et utilisées dans d'autres. Un vrai plat de spaghettis Les instructions while utilisées tombent dans des cas de boucle infinie.

Par exemple : tu ne sors jamais de ton while(!trameComplete) car cette variable est toujours égale à zéro. En cause : une variable globale int check[11], dont seule check[2] est valorisée dans ton programme.

Et même si ton while fonctionnait correctement, le code montre que le programme serait sensible aux mauvaises lectures / interférences : boucle infinie si le caractère 0x02 n'est pas reçu.

Il faudrait prendre du temps pour entrer dans le code et le réécrire intégralement mais proprement, à partir des spécifications des trames reçues. Ou alors repartir d'une base plus propre.

Surtout que la com avec le téléinfo me semble très basique (juste une interruption à gérer par kw/h?). Donc si interruption sur D2 ==> incrémentation d'une variable Interruption temporelle toute les 15 minutes ==> stockage de la variable et remise à zéro

Bon ba voilà j'ai complétement décroché là :~ vous avez surement raison mais ce qui paraît simple pour vous ne l'ai pas pour moi. je vais mettre ce projet de côté et reprendre tranquillement les bases de l'arduino et du C++. merci encore beaucoup pour votre aide en tout cas. bonne soirée à tous

Pourquoi tu ne regardes pas ce qui a déjà été fait et le mettre à ta sauce ?

bluemax2001, c'est ce que j'ai essayé, mais visiblement il n'y a pas beaucoup a trouver et le peux je ne parviens pas à l'exploiter. :disappointed_relieved:

B@tto: Surtout que la com avec le téléinfo me semble très basique (juste une interruption à gérer par kw/h?). Donc si interruption sur D2 ==> incrémentation d'une variable Interruption temporelle toute les 15 minutes ==> stockage de la variable et remise à zéro

Non Là il s'agit de téléinfo en sortie d'un compteur électronique EDF : des données restituées sur un genre de liaison série. Exemple de doc ici : http://www.erdfdistribution.fr/medias/DTR_Racc_Comptage/ERDF-NOI-CPT_02E.pdf

Et avec les futurs compteurs linky je pense qu'il va y avoir des petits projets sympa à faire avec arduino

[edit : j'ai trouvé la doc linky http://www.erdfdistribution.fr/medias/DTR_Generalites/ERDF-NOI-CPT_44E.pdf ]

B@tto:
Surtout que la com avec le téléinfo me semble très basique (juste une interruption à gérer par kw/h?). Donc si interruption sur D2 ==> incrémentation d’une variable
Interruption temporelle toute les 15 minutes ==> stockage de la variable et remise à zéro

Non, il y a un message d’une centaine de caractères toutes les secondes environ.

@tiotbrev tu peux allez voir là un exemple la partie Téléinformation 2/5 (Arduino SW) http://jojoflyhigh.blogspot.fr/

Edit: Je crois que j’ai été un peu grillé par bricoleau

Bonsoir fdufnews, lors de mes recherches je suis aller sur http://jojoflyhigh.blogspot.fr/, mais j'ai trouvé très compliqué par rapport à ce que je veux faire. je voulais juste récupérer une info, ma consommation, et la stoker sur la micro SD du Shield ethernet. si j'ai bien compris mon code est pas trop mauvais, c'est juste qu'il ne sort pas du getTeleinfo();

tiotbrev:
si j’ai bien compris mon code est pas trop mauvais, c’est juste qu’il ne sort pas du getTeleinfo();

Ben en vrai si, je le trouve affreux ]:slight_smile:

Il est toutefois probable que certains aient réussi à le faire marcher.
Ton principal problème est dans la fonction affecteEtiquette, où le code a été tronqué pour ne garder que ce qui concerne l’étiquette BASE. C’est ça qui doit faire que ce code à l’origine pas terrible (pour rester poli) ne marche plus du tout.

De surcroît, ton code (du moins la version d’origine, celle qui était complète) part du principe que le compteur va lui transmettre 11 étiquettes, alors que cela dépend de la version du compteur, et peut-être même de ton abonnement EDF.

Pour savoir à quoi s’en tenir, le mieux est d’afficher cette fameuse trame en entier.

Tu peux nous dire ce que tu obtiens dans le moniteur série, à l’exécution du code ci dessous ?

#include <SoftwareSerial.h>

SoftwareSerial cptSerial(2, 3);

void setup()
{
  cptSerial.begin(1200);
  Serial.begin(115200);
}

void loop()
{
  char c;

  while (cptSerial.available()) //vidons les tuyaux
  {
    c = cptSerial.read();
    if (!cptSerial.available())
    {
      delay(10); // entrée à 1200 baud... c'est lent !
    }
  }

  while (!cptSerial.available()) //et attendons la vague
  {
    delay(10);
  }

  afficherTrame(); //c'est parti !

  delay(30000);
}

void afficherTrame()
{
  char c;
  byte i;

  Serial.println("Trame************");

  i=0;
  while (cptSerial.available())
  {
    c = cptSerial.read() & 0x7F;
    if (c < (char) 0x10) //affichage du zero non significatif
    {
      Serial.print('0');
    }
    Serial.print((byte) c, HEX); //affichage du caractère recu en hexadécimal
    if (c >= ' ')
    {
      Serial.print(c); // affichage du caractère reçu
    }
    else //caractère non affichable
    {
      Serial.print('*');
    }
    i++;
    if (i >= 20) //retour à la ligne
    {
      Serial.println();
      i = 0;
    }
    else
    {
      Serial.print(' '); //au suivant
    }
    if (!cptSerial.available())
    {
      delay(10); // entrée à 1200 baud... c'est lent !
    }
  }
  if (i) //soyons propres
  {
    Serial.println();
  }
}

Petite retouche de code : comme je n'étais pas sûr que la fonction available() intègre une tempo, ajout d'un delay(10) en fin de boucle, histoire de bien traiter entièrement la trame en cours de réception.

[edit : après vérif, délai ajusté à 10ms car d'après la doc les trames sont émises en continu avec une pause comprise entre 16,7 et 33,4 ms entre deux]

Bonjour Bricoleau,
d’abord merci vraiment.
alors avec le code j’ai ceci :
Trame************
02* 0A* 41A 44D 43C 4FO 20 300 322 311 322 322 388 355 355 322 377 333 377 20
43C 0D* 0A* 4FO 50P 54T 41A 52R 49I 46F 20 42B 41A 53S 45E 20 300 0D* 0A* 49I
53S 4FO 55U 53S 43C 20 366 300 20 3C< 0D* 0A* 42B 41A 53S 45E 20 300 300 322
366 333 377 388 333 333 20 2B+ 0D* 0A* 50P 54T 45E 43C 20 54T 48H 2E. 2E. 20
24$ 0D* 0A* 49I 49I 4EN 53S 54T 20 300 300 366 20 5D] 0D* 0A* 49I 4DM 41A 58X
20 300 355 399 20 4DM 0D* 0A* 50P 41A 50P 50P 20 300 311 333 333 300 20 28(
0D* 0A* 4DM 4FO 54T 44D 45E 54T 41A 54T 20 300 300 300 300 300 300 20 42B 0D*
03*

là pour moi c’est du chinois !!

Super !
Meuh non c’est pas compliqué. Je parie que je peux te donner un cours de chinois accéléré.

Ton compteur EDF t’envoie des trames.
Chaque trame est une suite de caractères, dont le format est défini à partir de la page 11 du document ci-dessous
http://www.erdfdistribution.fr/medias/DTR_Racc_Comptage/ERDF-NOI-CPT_02E.pdf

Prend un moment pour lire la spécification et la comprendre. C’est tout à fait accessible.

La trame que tu as reçue fait 141 caractères.
C’est ce qui s’affiche dans ton moniteur série, à raison de 20 caractères par ligne.
Comme tous les caractères reçus du compteur ne sont pas affichables tels quels directement, je les ai tous affichés dans le moniteur série sous forme de 4 caractères :
1er et 2nd caractères : la valeur hexadécimale du caractère reçu
3ème caractère : le caractère reçu si affichable (* si non affichable)
4ème caractère : un séparateur blanc

Ainsi, correctement présenté, cela donne

02* 0A* 41A 44D 43C 4FO 20  300 322 311 322 322 388 355 355 322 377 333 377 20 
43C 0D* 0A* 4FO 50P 54T 41A 52R 49I 46F 20  42B 41A 53S 45E 20  300 0D* 0A* 49I
53S 4FO 55U 53S 43C 20  366 300 20  3C< 0D* 0A* 42B 41A 53S 45E 20  300 300 322
366 333 377 388 333 333 20  2B+ 0D* 0A* 50P 54T 45E 43C 20  54T 48H 2E. 2E. 20 
24$ 0D* 0A* 49I 49I 4EN 53S 54T 20  300 300 366 20  5D] 0D* 0A* 49I 4DM 41A 58X
20  300 355 399 20  4DM 0D* 0A* 50P 41A 50P 50P 20  300 311 333 333 300 20  28(
0D* 0A* 4DM 4FO 54T 44D 45E 54T 41A 54T 20  300 300 300 300 300 300 20  42B 0D*
03*

Si je lis la première ligne : les caractères reçus sont :
0x02 (non affichable)
0x0A (non affichable)
0x41 (A)
0x44 (D)
0x43 (C)
0x4F (O)
0x20 (blanc)
etc.

Cela correspond bien pile poil à ce qui est annoncé dans la doc ERDF.
On retrouve bien les balises annoncées (0x02, 0x0A, 0x0D, 0x03, …)

Et en clair, cela donne

ADCO=021228552737 (checksum=C)
OPTARIF=BASE (checksum=0)
ISOUSC=60 (checksum=<)
BASE=002637833 (checksum=+)
PTEC=TH.. (checksum=$)
IINST=006 (checksum=])
IMAX=059 (checksum=M)
PAPP=01330 (checksum=()
MOTDETAT=00000 (checksum=B)

Ton compteur t’envoie 9 étiquettes.
Tu as un abonnement de base (c’est-à-dire pas d’option heure creuse, ni EJP)
L’intensité souscrite est de 60 A
Ton index de consommation est à 2637833 Wh
L’intensité instantanée tirée au moment de le trame était de 6 A
L’intensité maxi délivrable est de 59 A

Etc. Tout est dans la doc, y compris la méthode à utiliser pour recalculer le checksum et vérifier l’intégrité des données reçues.

A partir de là, techniquement le plus dur est fait.
En terme de programmation, il s’agit juste de manipuler une suite de 141 caractères pour en extraire les informations qui t’intéressent.

C’est du C de base :wink:

C'est même plus drôle il a plus rien à comprendre :p

Beau boulot !