Capteur sans fil pour compteur de gaz Gazpar

Capteur sans fil pour compteur de gaz Gazpar

Gazpar est le nom du nouveau compteur de gaz communiquant déployé en France par GRDF depuis maintenant quelques années. Ils émettent deux fois par jour la consommation vers un concentrateur situé à quelques km maximum sur une fréquence de 169MHz, puis les données du quartier sont transférées chez GRDF via le réseau 2G/3G. En tant que particulier nous n’avons pas accès à ces données directement, on ne peut que récupérer sa conso et son historique via le site de GRDF.

Néanmoins, ce compteur dispose d’une sortie impulsion que nous allons utiliser pour récupérer et transmettre en temps réel la consommation.

La sortie impulsion

Ce qui va nous intéresser ici c’est la prise située sur le côté du compteur, il s’agit d’une sortie impulsion. C’est une sortie à collecteur ouvert si c’est un transistor bipolaire ou à drain ouvert si c’est un mos  sur laquel on va venir capter l’impulsion émise.

Je ne sais pas si c’est le cas sur tous les modèles de compteur mais le miens émet une impulsion tous les daL, donc tous les 10L de gaz, soit 100 impulsions par m3.

Capter les impulsions

Pour capter l’impulsion, on va d’abord utiliser une résistance de tirage car quand le transistor interne au compteur n’est pas passant, c’est à dire la plupart du temps, le collecteur est « en l’air » et donc sa tension est indéterminée.

Avec ce schéma, en effectuant une mesure à l’oscilloscope, on obtient la courbe suivante où l’impulsion à durée environ 300ms. À noter que l’impulsion se déclenche lors du passage sur l’unité de litre 6. Au début je pensais que ça ne fonctionnait pas car je m’attendais à avoir l’impulsion au changement de dizaine quand les unités passent de 9 à 0.

Schéma du capteur

Le circuit s’articule autour d’un Atmega328p comme dans la plupart des circuits présentés sur ce blog. C’est le même que celui présent sur l’Arduino Uno. La partie sans fil est assurée par un module Nrf24l01+. Il est alimenté en 3.3V, avec un accu LiFePO4 par exemple, qui, vu la faible consommation, peut tenir plusieurs mois. Le connecteur relié à Rx, Tx et Reset avec C8 et R9 est facultatif, il sert à pouvoir programmer directement comme un arduino et à utiliser le débogage serie.

Branchement sur le compteur

Normalement il existe une prise spéciale fabriquée par JAE pour se brancher sur le compteur, elle est en vente en ligne sur divers sites pour très cher. Ça peut être intéressant de l’utiliser si votre compteur est dans un endroit très humide et sujet aux intempéries. Néanmoins, la plupart des connecteurs au pas de 2.54mm, ou même des connecteurs dupont fonctionnent très bien. Pour ma part, ça sera un connecteur molex kk que j’avais en stock et qui fait parfaitement l’affaire.

La masse est en haut, et l’impulsion en bas.

Le programme

Le fonctionnement est assez simple : Lors d’une impulsion générée par le compteur, une interruption incrémente un compteur qui est sauvegardé dans l’eeprom. Toutes les 5min, la valeur de ce compteur est transmise par radio. L’eeprom de l’atmega est donnée pour 100 000 cycles d’écriture, ce qui finalement est assez peu. En théorie la zone mémoire sur laquelle on écrit sera probablement morte au bout de 1000m3 de gaz consommés. Pour prolonger la durée de vie on peut modifier le programme pour déplacer la zone dans l’eeprom selon la valeur de l’index.

A la première programmation, il sera aussi nécessaire de mettre en mémoire l’index actuel du compteur de gaz.

Librairies utilisées :

#include <LowPower.h>
#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>
#include <EEPROM.h>
#include <stdint.h>

#include <PinChangeInterrupt.h>

/* -------CONFIG---------*/
#define LOGDEBUG  0
/* --------------------- */

#define NODE_ID   5
/* --------------------- */

#define EE_ADDR   0
/* --------------------- */

#define RF24_CH   25
/* --------------------- */

#define SLEEP_DT   36  //5min , 8s par cycle
#define SLEEP_VT   75  //10min
/* --------------------- */


#define VT_PIN    14    //ADC3
#define RF24_ON   6
#define LED_PIN   5
#define PULSE_PIN 16    //PCINT10
/* --------------------- */

//DEBUG 
#if LOGDEBUG==1
#define DEBUG_PRINT(x)       Serial.print(x)
#define DEBUG_PRINTDEC(x)    Serial.print(x, DEC)
#define DEBUG_PRINTLN(x)     Serial.println(x)
#define DEBUG_RADIO()        radio.printDetails()
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTDEC(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_RADIO()
#endif
/* --------------------- */


uint8_t   server_address[5]       = {10, 20, 30, 40, 50};
uint8_t   node_address[5]         = {1, 20, 30, 40, 50};
/* --------------------- */


uint16_t  nodeId = NODE_ID;
RF24      radio(9,10);

uint8_t   radioBuffer[32]    = {0};

uint16_t  cntVT = SLEEP_VT;
uint16_t  cntDT = SLEEP_DT;

float     voltage       = 0;
uint32_t  daLCount      = 5018;


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

  DEBUG_RADIO();
}


void setup() {
  delay(500);

  #if LOGDEBUG==1
  Serial.begin(9600);
  printf_begin();
  #endif

  //EEPROM.put(EE_ADDR, daLCount);

  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);  

  pinMode(PULSE_PIN, INPUT);    
 
  pinMode(RF24_ON, OUTPUT);
  digitalWrite(RF24_ON, HIGH);  


  //flash led
  digitalWrite(LED_PIN, HIGH);
  delay(250);
  digitalWrite(LED_PIN, LOW);
  

  analogReference(INTERNAL);

  DEBUG_PRINTLN("Read EEPROM");
  EEPROM.get(EE_ADDR, daLCount);


  //flash led
  delay(500);
  digitalWrite(LED_PIN, HIGH);
  delay(1000);
  digitalWrite(LED_PIN, LOW);

  DEBUG_PRINTLN("attachPCIN");
  attachPCINT(digitalPinToPCINT(PULSE_PIN), pulseEvent, FALLING); 
}


void pulseEvent(){
  DEBUG_PRINT("Pulse.");  
  ++daLCount;
  
  //save to eeprom
  DEBUG_PRINT("Save to EEPROM daL=");
  DEBUG_PRINTLN(daLCount);
  EEPROM.put(EE_ADDR, daLCount);  
}


void loop() {
  DEBUG_PRINTLN(">");


  if( (cntDT >= SLEEP_DT) || (cntVT >= SLEEP_VT)){

    //power on radio
    digitalWrite(RF24_ON, LOW);
    
    delay(100);
    radioSetup();
    
    DEBUG_PRINTLN("Radio up");

    if(cntDT >= SLEEP_DT){
      //send message
      memcpy(radioBuffer,     &nodeId,               2);
      memcpy(radioBuffer+2,   "CS",                  2);
      memcpy(radioBuffer+4,   &daLCount,             4);
               
      if(radio.write(radioBuffer, 32)){
        cntDT = 0;
      }
      else{
        if(cntDT >= (SLEEP_DT+5)){
          //retry up to 5 cycles of 8s.
          cntDT = 0;
        }
      }     
  
    }

    delay(250);
    radio.flush_tx();


       
    if(cntVT >= SLEEP_VT){
      voltage = analogRead(VT_PIN);
      voltage = voltage * 1.1 * ((1670000.0)/470000.0) / 1024.0;
    
      DEBUG_PRINT("V=");
      DEBUG_PRINTLN(voltage);

     
      memcpy(radioBuffer,     &nodeId,           2);
      memcpy(radioBuffer+2,   "VT",              2);
    
      memcpy(radioBuffer+4,   &voltage,          4);
    
      if(radio.write(radioBuffer, 32)){
        cntVT = 0;
      }
      else{
        if(cntVT >= (SLEEP_VT+5)){
          //retry up to 5 cycles of 8s.
          cntVT = 0;
        }
      }
    }   


    delay(50);
    
    //power down radio
    radio.powerDown();
    digitalWrite(RF24_ON, HIGH);
  }
     
  ++cntVT;
  ++cntDT;
  
  //flash led
  digitalWrite(LED_PIN, HIGH);
  delay(1);
  digitalWrite(LED_PIN, LOW);

  DEBUG_PRINTLN("."); 

  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);

}
Capteur Gazpar

La consommation est stockée dans une base de donnée, et il est possible de générer un graph en temps réel de la consommation. Si le compteur envoyait la consommation aussi souvent à GRDF, ils seraient en mesure de savoir à quelle heure vous avez pris votre douche… contrairement au linky qui n’a pas trop de soucis à se faire niveau alimentation électrique, le gazpar fonctionne sur une pile lithium, le nombre de relevé n’est pas illimité.

 

Laisser un commentaire

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