Abonnement aux commentaires

S'abonner pour recevoir les commentaires suivants par email

まこと の ブログ

MaKoTo no burogu — Journal de bord…

Aller au contenu | Aller au menu | Aller à la recherche

Surveiller l'état et la charge d'une batterie 12 Volts

  • Monitorer la vitesse du vent et la rotation de l'éolienne, c'est fait !!

Cependant quid de l'état de la batterie ?
Combien d'énergie la génératrice produit-elle ?
Cela est-il suffisant pour recharger la batterie ?

J'avais acheté un appareil pour mesurer ça en local, mais en définitive je ne m'en sert pas… Pas utile à moins d'aller au fond du jardin pour le consulter…

  • J'ai donc entrepris de construire un nouvel appareil de mesure, sur la même idée que l'Anémomètre Radio (Arduino + HC-12), avec transmission des données pour statistiques sur Grafana via InfluxDB (NodeMCU).

Attention cependant, Si on souhaite faire fonctionner l'Anémomètre et le Monitoring en même temps, il faudra prendre soin de différencier les canaux de fonctionnement des modules HC-12 (Voir la section Setup de chaque programmes)

Le monitoring Batterie, partie émetteur :

J'ai donc câblé un nouveau circuit :

dsc04270.jpg Matériel requis :

- 1 Arduino Pro Mini 5V.
- Un ordi avec port USB et le soft Arduino IDE.
- 1 plaquette HC-12 et son antenne.
- 1 diode 1N4007.
- 1 Régulateur Négatif 9V L7909CV.
- 1 condensateur électrochimique polarisé de 220µF.
- 1 condensateur électrochimique polarisé de 2,2µF.
- 1 condensateur électrochimique polarisé de 1µF.
- 1 module ACS712 (20A) (Attention cependant !! > Je sais que mon générateur ne dépassera pas 5A, à moins d'une tempête de vent de fin du monde…).

dsc04272.jpg dsc04273.jpg

Principe de fonctionnement :
- À intervalle régulier, l'Arduino va envoyer les valeurs lues sur les entrées analogiques A0 et A1, sur le port série du HC-12.
- A0 pour mesurer la valeur de la tension aux bornes de la batterie ( On a fabriqué un voltmètre très précis câblé en parallèle ).
- A1 pour mesurer le courant sortant du générateur ( Un Ampèremètre câblé en série ).

  • Programme pour l’Arduino Pro Mini de transmission :

Édit du 15 mai 2020 !
Électro-Bidouilleur a enfin sorti une vidéo sur le module HC-12 et nous informe que la librairie <SoftwareSerial.h> est à éviter, ce que j'aurais bien voulu savoir à l'époque étant donné que j'ai effectivement rencontré des problèmes de réception. Il faut donc lui préférer la librairie <AltSoftSerial.h>. Je n'ai pas le temps de me pencher dessus, donc j'ai laissé tel quel le code suivant, sur github et en annexe du billet, à vous de changer la librairie.

#include <SoftwareSerial.h>

/****************/
/* DÉCLARATIONS */
/****************/
SoftwareSerial HC12(10, 11); // HC-12 TX Pin, HC-12 RX Pin

char MessageTensionBatterie[] = " VOL / "; // message to be sent; '\n' is a forced terminator char
char MessageCourant[] = " AMP\n"; // message to be sent; '\n' is a forced terminator char
String chaine;

#define ATpin 7 // used to switch HC-12 to AT mode

float Courant=0;
float SupplyVoltage=12;
const int Voie_0=0; // declaration constante de broche analogique
int mesure_brute=0; // Variable pour acquisition résultat brut de conversion analogique numérique
float mesuref=0.0;  // Variable pour calcul résultat décimal de conversion analogique numérique
float tension=0.0;  // Variable tension mesurée
float tension_batterie=0.0; // Variable tension batterie calculée
float tension_regulateur=8925.0;  // Variable tension réelle aux bornes du régulateur -9V (en mV)

int PIN_ACS712 = A1;
double Voltage = 0;
double Current = 0;

/*********/
/* SETUP */
/*********/  
void setup() {
//  Serial.begin(9600); // Debug
  HC12.begin(9600);               // Serial port to HC12
  // Pin capteurs
  pinMode(PIN_ACS712, INPUT);
  pinMode(ATpin, OUTPUT);
  digitalWrite(ATpin, LOW); // Set HC-12 into AT Command mode
  delay(500);
  HC12.print("AT+C056");  // passer sur le canal 006 (433.4Mhz + 56x400KHz)
  delay(500);
  digitalWrite(ATpin, HIGH); // HC-12 en normal mode
}

/*************/
/* PROGRAMME */
/*************/
void loop() {
  MesureCourant();
  MesureBrute();
  TensionMesuree();
  TensionBatterie();
  
  chaine = String(tension_batterie,3) + MessageTensionBatterie + String(Current,3) + MessageCourant;  // construction du message
  Serial.println ( "chaine String : " +chaine );
  HC12.print(chaine); // send radio data
  delay(100);
}

/*************/
/* FONCTIONS */
/*************/
void MesureCourant() {
//  Serial.print("Courant : ");
//  Serial.print(Courant);
//  Serial.print(" A | Puissance : ");
//  Serial.print(Courant*SupplyVoltage);
//  Serial.println(" Watt");

// Voltage is Sensed 1000 Times for precision
for(int i = 0; i < 1000; i++) { // ça ralentis tout, mais c'est indispensable !
Voltage = (Voltage + (0.004882812 * analogRead(PIN_ACS712))); // (5 V / 1024 (Analog) = 0.0049) which converter Measured analog input voltage to 5 V Range
delay(1);
}
Voltage = Voltage /1000;

Current = (Voltage -2.5)/ 0.100; // Sensed voltage is converter to current (0.100 pour modèle 20A)

Serial.print("\n Voltage Sensed (V) = "); // shows the measured voltage
Serial.print(Voltage,3); // the ‘2’ after voltage allows you to display 2 digits after decimal point
Serial.print("\t Current (A) = "); // shows the voltage measured
Serial.println(Current,3); // the ‘2’ after voltage allows you to display 2 digits after decimal point
}

void MesureBrute() {
//-------- mesure brute --------
  mesure_brute=analogRead(Voie_0);
//  Serial.print ("Valeur brute = "); 
//  Serial.print (mesure_brute); 
//  Serial.println (" "); // espace de propreté
}

void TensionMesuree() {
//---------- tension mesurée ---------
  mesuref=float(mesure_brute)*5000.0/1024.0;
  tension=mesuref/1000.0; // en Volts
//  Serial.print ("Tension = "); 
//  Serial.print(tension,3);  // float avec 2 décimales 
//  Serial.println(" V ");  // unité et espace de propreté
}

void TensionBatterie() {
//---------- tension batterie ---------
  tension_batterie=mesuref+tension_regulateur;
  tension_batterie=tension_batterie/1000.0; // en Volts
//  lcd.setCursor(0,1) ; // positionne le curseur à l'endroit voulu (colonne, ligne)
//  lcd.print ("Batt:"); 
//  lcd.print (tension_batterie,2); // float avec 2 décimales
//  lcd.print ("V "); // unité et espace de propreté
  Serial.print ("Batterie = "); 
  Serial.print(tension_batterie,3); // float avec 2 décimales 
  Serial.println(" V ");
//  Serial.println("  ");
}


Le boîtier client, partie récepteur avec affichage :

Voici le montage avec un afficheur LCD standard :
ClientAfficheurLCD_nodemcu_bb.png
dsc04268.jpg Matériel requis :

- 1 Arduino Pro Mini 5V.
- Un ordi avec port USB et le soft Arduino IDE.
- 1 plaquette HC-12 et son antenne.
- 1 diode 1N4007.
- 1 afficheur LCD type HD44780 16 ou 20 x 2.
- 1 NodeMCUv3 LoLin.
- 1 condensateur électrochimique polarisé de 220µF.


dsc04266.jpg dsc04274.jpg
dsc04275.jpg dsc04278.jpg

  • J'ai simulé le générateur avec une alimentation 12V et la batterie par une ampoule :


Principe de fonctionnement :
- L'Arduino reçoit les valeurs transmises par le port série du HC-12 et les affiche instantanément sur l'écran LCD.
- Le NodeMCU reçoit les valeurs transmises par le port série du HC-12 et les transmet à la Base de données InfluxDB.
- Grafana s'occupera de tracer les graphiques à partir des données.

  • Programme pour l’Arduino Pro Mini de réception :

Édit du 15 mai 2020 !
Électro-Bidouilleur a enfin sorti une vidéo sur le module HC-12 et nous informe que la librairie <SoftwareSerial.h> est à éviter, ce que j'aurais bien voulu savoir à l'époque étant donné que j'ai effectivement rencontré des problèmes de réception. Il faut donc lui préférer la librairie <AltSoftSerial.h>. Je n'ai pas le temps de me pencher dessus, donc j'ai laissé tel quel le code suivant, sur github et en annexe du billet, à vous de changer la librairie.

//———— Que fait ce programme ? ————
// ---> Récupére les données transmise par un module HC-12,
// ---> Affichage la mesure de la tension d'une batterie au plomb 12V sur un écran LCD.
// ---> Affichage l'intensité et la puissance fournie à la batterie par une génératrice 12V. 
//———— Fonctionnalités utilisées ————
// Utilise un afficheur LCD alphanumérique2x20 en mode 4 bits 
//———— Circuit à réaliser ————
// Broche 12 sur la broche RS du LCD
// Broche 11 sur la broche E du LCD
// Broche 5 sur la broche D4 du LCD
// Broche 4 sur la broche D5 du LCD
// Broche 3 sur la broche D6 du LCD
// Broche 2 sur la broche D7 du LCD
// Broche 7 sur HC-12 to AT mode
// Broche 8 HC-12 TX Pin
// Broche 9 HC-12 RX Pin
//———— Réglages possibles ————
// Canal de réception (voir setup)
// Voltage : Utilisé pour le calcul de la puissance en Watt.
// MiniC : pour régler le courant minimum mesuré en dessous duquel la valeur est forcée à 0, pour prendre
// en compte le fait que la mesure du zero ne tombe jamais pile.

#include <LiquidCrystal.h>  // lib LCD
#include <SoftwareSerial.h> // lib Transmission série

//################
//# DÉCLARATIONS #
//################
//——— Radio HC-12 ———//
SoftwareSerial HC12(8, 9);  // HC-12 TX Pin, HC-12 RX Pin
#define ATpin 7             // poir passer le HC-12 en AT mode
char acquis_data;
String chaine;
float Voltage=12;
float MiniC=0.08;           // courant minimum mesuré en dessous duquel la valeur est forcée à 0.
float tension_batterie_float;
float Courant_float;

//——— Écran LCD ———//
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2; // Déclaration LCD
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);                  // Pins LCD en mode 4 bits 
byte carre00[8] = {                                         // caractères personnalisés
  B11111,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111
};
byte carre01[8] = {
  B11111,
  B00000,
  B10000,
  B10000,
  B10000,
  B10000,
  B00000,
  B11111
};
byte carre02[8] = {
  B11111,
  B00000,
  B11000,
  B11000,
  B11000,
  B11000,
  B00000,
  B11111
};
byte carre03[8] = {
  B11111,
  B00000,
  B11100,
  B11100,
  B11100,
  B11100,
  B00000,
  B11111
};
byte carre04[8] = {
  B11111,
  B00000,
  B11110,
  B11110,
  B11110,
  B11110,
  B00000,
  B11111
};
byte carre05[8] = {
  B11111,
  B00000,
  B11111,
  B11111,
  B11111,
  B11111,
  B00000,
  B11111
};
byte crochetouvrant[8] = {
  B00011,
  B00010,
  B00010,
  B00010,
  B00010,
  B00010,
  B00010,
  B00011
};
byte crochetfermant[8] = {
  B11000,
  B01000,
  B01110,
  B01110,
  B01110,
  B01110,
  B01000,
  B11000
};

//——— Fonction pour pemettre le map avec variable float ———
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

//#########
//# SETUP #
//#########
void setup() {
//  Serial.begin(9600);         // Debug
  //——— HC12 ———//
  HC12.begin(9600);           // Serial port to HC12
  pinMode(ATpin, OUTPUT);
  digitalWrite(ATpin, LOW);   // HC-12 en mode commande AT
  delay(500);
  HC12.print("AT+C056");      // passer sur le canal 056 (433.4Mhz + 56x400KHz)
  delay(500);
  digitalWrite(ATpin, HIGH);  // HC-12 en normal mode

//——— LCD ———//
  lcd.begin(20,2);            // Initialise le LCD avec 20 colonnes x 2 lignes 
  delay(10);
  lcd.print("LCD OK");        // affiche LCD OK
  delay(2000);
  lcd.clear();
  delay(10);
  lcd.createChar(0, carre00); // Les 8 caractères personnalisés
  lcd.createChar(1, carre01);
  lcd.createChar(2, carre02);
  lcd.createChar(3, carre03);
  lcd.createChar(4, carre04);
  lcd.createChar(5, carre05);  
  lcd.createChar(6, crochetouvrant);
  lcd.createChar(7, crochetfermant);
} 

//#############
//# PROGRAMME #
//#############
void loop() {
  Reception();
  Jauge();
  delay(200);
} 

//#############
//# FONCTIONS #
//#############
void Reception() {
// surtout pas de delay dans cette boucle, sinon les data reçues sont erronnées.
  while (HC12.available()) {        // If HC-12 has data
    acquis_data = HC12.read();
    chaine = chaine + acquis_data;
//    Serial.println (chaine);      // Attention, chaine est donc une String
/* message reçu de la forme 
12.665 VOL / 0.045 AMP
pour chaque ligne on fait :*/

    if (chaine.endsWith("\n")) {      //détection de fin de ligne : méthodes String
//      Serial.println ("fin de ligne");          // debug
//      String phrase = "12.665 VOL / 0.045 AMP";  //debug
      char tension_batterie[5];   // chaine de 6 caractères pour stocker le texte avant le mot VOL
      char Courant[3];            // chaine de 4 caractères pour stocker le texte avant le mot AMP
//      sscanf(phrase.c_str(), "%s VOL / %s AMP", tension_batterie, &Courant);  //debug
      sscanf(chaine.c_str(), "%s VOL / %s AMP", tension_batterie, &Courant);  // la chaine à parser est dans une String, avec la méthode c_str()

      tension_batterie_float = atof(tension_batterie),3;  // char convertie en Float, avec 3 décimales
      Courant_float = atof(Courant),2;                    // char convertie en Float, avec 2 décimales

      Serial.print("VOLTS: ");
      Serial.println(tension_batterie_float,3); // float avec 3 décimales
      Serial.print("AMPERES: ");
      Serial.println(Courant_float,3);
      Serial.print("Watt: ");
      Serial.println(Courant_float*Voltage,0); // float avec 0 décimales
      Serial.println(' ');
      
// Affichage LCD courant et Puissance
      if ( Courant_float < MiniC ){   // remise à zero forcée si valeur mesurée très petite
        Courant_float = 0;
      }
      lcd.setCursor(0,0);
      lcd.print ("Power:"); 
      lcd.print (Courant_float,2);    // float avec 2 décimales
      lcd.print ("A ");               // unité et espace
      lcd.setCursor(12,0);
      lcd.write(0b01111110);          // caractère : fleche, depuis le Standard Character Pattern du LCD
      lcd.print (" ");
      lcd.print (Courant_float*Voltage,0);
      lcd.print ("Watt ");   

// Affichage LCD Batterie
      lcd.setCursor(0,1);
      lcd.print ("Batt:"); 
      lcd.print (tension_batterie_float,3); 
      lcd.print ("V ");

      chaine = "";    // vide la String chaine
    }
  }
}

void Jauge() {          // Jauge de charge batterie
  lcd.setCursor(12, 1);
  lcd.write(byte(6)); // crochet ouvrant
  lcd.setCursor(19, 1);
  lcd.write(byte(7));   // crochet fermant
  float NiveauBatterie = mapfloat(tension_batterie_float, 11.4, 12.73, 0, 30); // Discrétise la valeur de la tension batterie
  int NiveauBatterieBarre = (int)NiveauBatterie;                      // conversion en entier

  if (NiveauBatterie > 30) {  // en cas de dépassement des limites haute et basse et permettre l'affichage non-erroné
    NiveauBatterieBarre = 30;
    lcd.setCursor(13, 1);
    lcd.print ("Pleine"); 
    delay (1000);
  }
  else if (NiveauBatterie < 0) {
    NiveauBatterieBarre = 0; 
    lcd.setCursor(13, 1);
    lcd.print ("Erreur"); 
    delay (1000);
  }
//  Serial.print ("NiveauBatterieBarre = "); 
//  Serial.print(NiveauBatterieBarre);
//  Serial.println("  ");
  
  switch (NiveauBatterieBarre) {
    case 0:
    lcd.setCursor(13, 1);
    lcd.write(byte(0)); // carre00  
    lcd.setCursor(14, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 1:
    lcd.setCursor(13, 1);
    lcd.write(byte(1)); // carre01
    lcd.setCursor(14, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 2:
    lcd.setCursor(13, 1);
    lcd.write(byte(2)); // carre02
    lcd.setCursor(14, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 3:
    lcd.setCursor(13, 1);
    lcd.write(byte(3)); // carre03
    lcd.setCursor(14, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 4:
    lcd.setCursor(13, 1);
    lcd.write(byte(4)); // carre04
    lcd.setCursor(14, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 5:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 6:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(1)); // carre01
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 7:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(2)); // carre02
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 8:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(3)); // carre03
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 9:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(4)); // carre04
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 10:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 11:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(1)); // carre01
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 12:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(2)); // carre02
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 13:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(3)); // carre03
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 14:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(4)); // carre04
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 15:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
    case 16:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(1)); // carre01
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
     case 17:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(2)); // carre02
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
     case 18:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(3)); // carre03
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
     case 19:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(4)); // carre04
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
     case 20:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(0)); // carre00
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
     case 21:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(1)); // carre01
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
     case 22:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(2)); // carre02
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
     case 23:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(3)); // carre03
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
     case 24:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(4)); // carre04
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
     case 25:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(18, 1);
    lcd.write(byte(0)); // carre00
      break;
     case 26:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(18, 1);
    lcd.write(byte(1)); // carre01
      break;
     case 27:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(18, 1);
    lcd.write(byte(2)); // carre02
      break;
     case 28:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(18, 1);
    lcd.write(byte(3)); // carre03
      break;
      case 29:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(18, 1);
    lcd.write(byte(4)); // carre04
      break;    
      case 30:
    lcd.setCursor(13, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(14, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(15, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(16, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(17, 1);
    lcd.write(byte(5)); // carre05
    lcd.setCursor(18, 1);
    lcd.write(byte(5)); // carre05
      break;       
    default:
      // statements
      break;
  }
}
  • Programme pour le NodeMCU de réception :

Édit du 15 mai 2020 !
Électro-Bidouilleur a enfin sorti une vidéo sur le module HC-12 et nous informe que la librairie <SoftwareSerial.h> est à éviter, ce que j'aurais bien voulu savoir à l'époque étant donné que j'ai effectivement rencontré des problèmes de réception. Il faut donc lui préférer la librairie <AltSoftSerial.h>. Je n'ai pas le temps de me pencher dessus, donc j'ai laissé tel quel le code suivant, sur github et en annexe du billet, à vous de changer la librairie.

// Ressources :
//https://forum.arduino.cc/index.php?topic=553743.0
//https://plaisirarduino.fr/moniteur-serie/

#include "ESPinfluxdb.h"    // lib ESP InfluxDB
#include <SoftwareSerial.h> // lib Transmission série
#include <ESP8266WiFi.h>    // lib ESP Wifi
#include <ESP8266WiFiMulti.h>

//################
//# DÉCLARATIONS #
//################
//——— Radio HC-12 ———//
SoftwareSerial HC12(D5, D6);  // HC-12 TX Pin et RX Pin
char acquis_data;
String chaine;
float Voltage=12;
float MiniC=0.08;             // courant minimum mesuré en dessous duquel la valeur est forcée à 0.
float tension_batterie_float;
float Courant_float;

//——— InfluxDB ———//
const char *INFLUXDB_HOST = "xx.org";
const uint16_t INFLUXDB_PORT = xx;
const char *DATABASE = "xx";
const char *DB_USER = "xx";
const char *DB_PASSWORD = "xxxx";
Influxdb influxdb(INFLUXDB_HOST, INFLUXDB_PORT);  //https://github.com/projetsdiy/grafana-dashboard-influxdb-exp8266-ina219-solar-panel-monitoring/tree/master/solar_panel_monitoring
int compteur = 1;

//——— WiFi ———//
char ssid[] = "xx";
char password[] = "xxxxx";
ESP8266WiFiMulti WiFiMulti;

//#########
//# SETUP #
//#########
void setup() {
  Serial.begin(9600); // Debug
//——— HC12 ———//
  HC12.begin(9600);           // Serial port to HC12
        
//——— WiFi ———//
  WiFiMulti.addAP(ssid, password);  // Connection au réseau WiFi
  while (WiFiMulti.run() != WL_CONNECTED) {
    delay(100);
  }
  Serial.println ("WiFi Connecté"); 
  
//——— InfluxDB ———//
  while (influxdb.opendb(DATABASE, DB_USER, DB_PASSWORD)!=DB_SUCCESS) { // Connexion à la base InfluxDB
    delay(10000);
  }
  Serial.println ("Connexion DataBase OK"); 
}

//#############
//# PROGRAMME #
//#############
void loop() {
  Reception();
  if (compteur > 100) { // envoie la data toutes les 6 secondes (delay 10 x 100 = 1000 ms, et l'opération prend 5 secondes à transférer/écrire en base)
    SendDataToInfluxdbServer();  
    compteur = 1;
  }
  else {
    compteur++;
  }
  delay(10);  // refresh la data sur l'afficheur toutes les 10 ms
} 

//#############
//# FONCTIONS #
//#############
void Reception() {
// surtout pas de delay dans cette boucle, sinon les data reçues sont erronnées.
  while (HC12.available()) {        // If HC-12 has data
    acquis_data = HC12.read();
    chaine = chaine + acquis_data;
//    Serial.println (chaine);      // Attention, chaine est donc une String
/* message reçu de la forme 
12.665 VOL / 0.045 AMP
pour chaque ligne on fait :*/

    if (chaine.endsWith("\n")) {      //détection de fin de ligne : méthodes String
//      Serial.println ("fin de ligne");          // debug
//      String phrase = "12.665 VOL / 0.045 AMP";  //debug
      char tension_batterie[5];   // chaine de 6 caractères pour stocker le texte avant le mot VOL
      char Courant[3];            // chaine de 4 caractères pour stocker le texte avant le mot AMP
//      sscanf(phrase.c_str(), "%s VOL / %s AMP", tension_batterie, &Courant);  //debug
      sscanf(chaine.c_str(), "%s VOL / %s AMP", tension_batterie, &Courant);  // la chaine à parser est dans une String, avec la méthode c_str()

      tension_batterie_float = atof(tension_batterie),3;  // char convertie en Float, avec 3 décimales
      Courant_float = atof(Courant),2;                    // char convertie en Float, avec 2 décimales

      Serial.print("VOLTS: ");
      Serial.println(tension_batterie_float,3); // float avec 3 décimales
      Serial.print("AMPERES: ");
      Serial.println(Courant_float,3);
      Serial.print("Watt: ");
      Serial.println(Courant_float*Voltage,0); // float avec 0 décimales
      Serial.println(' ');
      
// Affichage LCD courant et Puissance
      if ( Courant_float < MiniC ){   // remise à zero forcée si valeur mesurée très petite
        Courant_float = 0;
      }

      chaine = "";    // vide la String chaine
    }
  }
}

void SendDataToInfluxdbServer() { //Writing data with influxdb HTTP API: https://docs.influxdata.com/influxdb/v1.5/guides/writing_data/
                                  //Querying Data: https://docs.influxdata.com/influxdb/v1.5/query_language/
  dbMeasurement rowDATA("Data");
  rowDATA.addField("tension_batterie", tension_batterie_float);
  rowDATA.addField("Courant", Courant_float);
//  Serial.println(influxdb.write(rowDATA) == DB_SUCCESS ? " - rowDATA write success" : " - Writing failed");
  influxdb.write(rowDATA);

  // Vide les données - Empty field object.
  rowDATA.empty();
}

Configuration de la Grafana :

  • Concernant cette partie, je vous laisse voir la fin de ce billet, vu que c'est la même chose !

Vous pourriez obtenir ce genre de chose :


Le code est aussi documenté ici, et en annexe du billet.
Boîtiers 3D dispos sur Thingiverse

Ressources :
https://wiki.mchobby.be/index.php?title=SENSEUR-COURANT-ACS712
https://www.sparkfun.com/datasheets/BreakoutBoards/0712.pdf
http://www.mon-club-elec.fr/pmwiki_mon_club_elec/pmwiki.php?n=MAIN.ProjetBatterieMesureTension

À Suivre…

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.

Fil des commentaires de ce billet