Téléinfo sans fil avec Arduino – Partie 2 : le capteur

Téléinfo sans fil avec Arduino – Partie 2 : le capteur

Transformation du signal

Comme on a vu dans la partie 1, le signal est composé d’une porteuse à 50kHz présente pour représenter un 0 et absente pour représenter un 1.

Détail de la trame téléinfo

Il va d’abord falloir convertir ce signal en vrai trame série avec les mêmes paramètres de transmission, à savoir 1200 7E1 (1200 baud, 7bits, parité paire, 1 bit de stop).

Trame téléinfo en jaune et trame décodée en bleu
Zoom sur la trame décodée

Le schéma

Schéma de l’émetteur téléinfo

A la base, le circuit est fait pour tourner sur un Atmega328p seul, sans être un arduino. Le circuit est alimenté avec un chargeur de téléphone portable sous 5V. Le bloc du bas basé sur un optocoupleur 6N138 permet de convertir le signal téléinfo en signal TTL compréhensible par l’uart de l’Atmega. Si on utilise un arduino, la partie conversion 5V vers 3.3V ainsi que la partie horloge (le quartz et ses deux condensateurs) sont inutiles car intégrées à l’arduino.

 

Le programme

Le programme est prévu pour une installation avec heures creuses et heures pleines (HCHC et HCHP). Pour d’autres types de contrat (Base ou Tempo) il est nécessaire de le modifier.

#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include <SoftwareSerial.h>

/* COMMON CONFIG*/
#define RF24_CH   25
#define DEBUG     0
/* ------- */

#define CNT_CS    180 
#define CNT_PA    5
#define VT_PIN    1
#define RF24_ON   7
#define BUFFER_TELEINFO_SIZE  768
#define START_FRAME           0x02
#define END_FRAME             0x03
#define START_LINE            0x0A
#define END_LINE              0x0D
#define END_DATA              0x04

/* COMMON */
uint16_t  nodeId = 1;
uint8_t   node_address[5]         = {"1Node"};
uint8_t   server_address[5]       = {"2Node"};
/* ------- */

RF24      radio(9,10);

uint8_t   plainRadioBuffer[32]    = {0};
char      bufferTeleinfo[BUFFER_TELEINFO_SIZE]  = {0};
uint16_t  bufferTeleinfoPos   = 0;
char      newChar             = 0;
uint8_t   serialStatus        = 0;
bool      readyForData  = false;
uint32_t  hchp          = 0;
uint32_t  hchc          = 0;
char      adco[12]      = {0};
char      opratif[4]    = {0};
uint8_t   isousc        = 0;
char      ptec[5]       = {0};
uint8_t   iinst         = 0;
uint8_t   adps          = 0;
uint8_t   imax          = 0;
uint16_t  papp          = 1;
char      hhphc         = 0;
char      motdetat[6]   = {0};
uint16_t  cntCS = 0;
uint16_t  cntPA = 0;

#if DEBUG==1
SoftwareSerial cptSerial(2, 3);
#endif

void setup_radio(){
  radio.begin();
  radio.setChannel(RF24_CH);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_MAX);
  radio.setCRCLength(RF24_CRC_16);
  radio.setRetries(3, 15);  
  radio.setAutoAck(1);
  radio.openReadingPipe(1, node_address);
  radio.openWritingPipe(server_address);

#if DEBUG==1
  radio.printDetails();
#endif  
}

void setup() {
   delay(100);
  
#if DEBUG==1
  Serial.begin(115200);
  printf_begin();
  Serial.println(F("Setup"));
#endif
  setup_radio();

  //start teleinfo listening
  #if DEBUG==1
  cptSerial.begin(1200);
  #else
  Serial.begin(1200, SERIAL_7N1);
  #endif
 
}

void incCnt(){
  ++cntCS;
  ++cntPA;
}



void serialEvent() {

    #if DEBUG==1
    while (cptSerial.available()) {
    newChar = (char)(cptSerial.read() & 0x7F);    
    #else
    while (Serial.available()) {
    newChar = (char)(Serial.read() & 0x7F);     
    #endif
    
    if(newChar == START_FRAME){
        //new frame, reset the buffer
        #if DEBUG==1
        Serial.println();
        #endif
        bufferTeleinfoPos = 0;
        readyForData = true;
    }
    else if(readyForData && newChar == END_FRAME){
        readyForData = false;
        
        #if DEBUG==1
        cptSerial.end();
        Serial.println(F("-------"));
        #else
        Serial.end();
        #endif
        
        incCnt();
        parseData(bufferTeleinfoPos);
        sendPA_IFN();
        sendCS_IFN(false);

        #if DEBUG==1
        cptSerial.begin(1200);
        #else
        Serial.begin(1200, SERIAL_7N1);
        #endif
    }
    else if(readyForData && newChar == END_DATA){
        //End of transmission (during telereport)
        bufferTeleinfoPos = 0;
        readyForData = false;
    }   
    else if(readyForData && bufferTeleinfoPos<(BUFFER_TELEINFO_SIZE-2)){
        #if DEBUG==1
        Serial.print(newChar);
        #endif
        bufferTeleinfo[bufferTeleinfoPos] = newChar;
        ++bufferTeleinfoPos;         
    }
  } 
      
}    



void parseData(uint16_t  bufferTeleinfoMaxPos){
  bufferTeleinfo[bufferTeleinfoMaxPos] = '\0';
  
  uint16_t  offset    = 0;
  char*     startPtr  = NULL;
  char*     endPtr    = NULL;
  uint16_t  startPos  = 0;
  uint16_t  endPos    = 0;
    
  while(true)
  {
    startPtr = strchr(bufferTeleinfo + offset, START_LINE);
    endPtr   = strchr(startPtr, END_LINE);    
    if(startPtr == 0 || endPtr == 0) break;
    
    startPos = startPtr - bufferTeleinfo;
    endPos   = endPtr - bufferTeleinfo;    
    
    offset = endPos;
    
  
    //process the checksum
    uint16_t  iLoop = 0;
    uint8_t   sum   = 0;
    uint16_t frameLength = endPos-startPos;
    for(iLoop=1; iLoop<(frameLength-2); iLoop++)
    {
      sum = sum + bufferTeleinfo[startPos+iLoop];
    }
    sum = (sum & 0x3F) + 0x20;  
  
    if(sum == bufferTeleinfo[endPos-1])
    {
      if(strncmp_P(&bufferTeleinfo[startPos+1],      PSTR("ADCO "), 5) == 0){
        strlcpy(adco, &bufferTeleinfo[startPos+6], 12);
      }
      else if(strncmp_P(&bufferTeleinfo[startPos+1], PSTR("HCHP "), 5) == 0){
        hchp = atol(&bufferTeleinfo[startPos+6]);
      }
      else if(strncmp_P(&bufferTeleinfo[startPos+1], PSTR("HCHC "), 5) == 0){
        hchc = atol(&bufferTeleinfo[startPos+6]);
      }
      else if(strncmp_P(&bufferTeleinfo[startPos+1], PSTR("OPTARIF "), 8) == 0){
        strlcpy(opratif, &bufferTeleinfo[startPos+9], 4);        
      }
      else if(strncmp_P(&bufferTeleinfo[startPos+1], PSTR("ISOUSC "), 7) == 0){
        isousc = atol(&bufferTeleinfo[startPos+8]);
      }
      else if(strncmp_P(&bufferTeleinfo[startPos+1], PSTR("PTEC "), 5) == 0){
        if(strncmp(ptec, &bufferTeleinfo[startPos+6], 4) != 0){
          memcpy(ptec, &bufferTeleinfo[startPos+6], 4);
          sendCS_IFN(true);
        }   
      }
      else if(strncmp_P(&bufferTeleinfo[startPos+1], PSTR("IINST "), 6) == 0){
        iinst = atol(&bufferTeleinfo[startPos+7]);     
      }
      else if(strncmp_P(&bufferTeleinfo[startPos+1], PSTR("IMAX "), 5) == 0){
        imax = atol(&bufferTeleinfo[startPos+6]);   
      }
      else if(strncmp_P(&bufferTeleinfo[startPos+1], PSTR("PAPP "), 5) == 0){
        papp = atol(&bufferTeleinfo[startPos+6]);
      }
      else if(strncmp_P(&bufferTeleinfo[startPos+1], PSTR("HHPHC "), 6) == 0){
        //strlcpy(hhp, &bufferTeleinfo[startPos+7], 1);
      } 
      else if (strncmp_P(&bufferTeleinfo[startPos+1], PSTR("ADPS "), 5) == 0){
        adps = atol(&bufferTeleinfo[startPos+6]);
      }   
    }
  }
}


void sendCS_IFN(bool force ){
  if(cntCS >= CNT_CS || force)
  {
    memcpy(plainRadioBuffer,   "CS",       2);  
    memcpy(plainRadioBuffer+2,   &hchp,      4);
    memcpy(plainRadioBuffer+6,   &hchc,      4);
    memcpy(plainRadioBuffer+10,  &ptec,      4);  
    radio.write(plainRadioBuffer, 32);
    cntCS = 0;
  }
}

void sendPA_IFN(){
  if(cntPA >= CNT_PA)
  {  
    memcpy(plainRadioBuffer,   "PA",       2);  
    memcpy(plainRadioBuffer+2,   &papp,      4);    
    memset(plainRadioBuffer+6,   0,          24);  
    radio.write(plainRadioBuffer, 32);
    cntPA = 0;
  }
}
    

void loop() {
  serialEvent();
}

Installation

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *