Création d’un enregistreur autonome de puissance électrique monophasé basé sur un Wemos D1 mini, d’un shield RTC/SD et d’un PZEM004T (Capteur BB1)

Création d’un enregistreur autonome de puissance électrique monophasé basé sur un Wemos D1 mini, d’un shield RTC/SD et d’un PZEM004T (Capteur BB1)

23 août 2019 7 Par Jérôme Ferrari

Bonjour,

Il y a quelques temps, j’ai reçu comme problématique de trouver une solution pour monitorer la puissance du réseau monophasé sur un site ne disposant pas d’une infrastructure réseau. Je vous propose donc de vous partager ma solution que je nomme BB1 pour BlackBox1 afin que vous puissiez aussi en profiter. Elle sera capable de faire les choses suivantes:

  • Être auto-alimentée par le point de mesure et être mise dans un boitier railDIN (ceux utilisé pour les RaspberryPi)
  • Mesurer le courant, la tension, la puissance et la consommation (je viens de recevoir la V3 du PZEM004 donc je pense pouvoir avoir le facteur de puissance)
  • Horodatage des données et sauvegarde de celles-ci sur une carte SD
  • Embarquer son propre serveur wifi avec une page web qui permet de : (voir capture d’écran en pièce-jointe)
    • Récupérer directement le fichier CSV des données (je vous mettrai un exemple en fin d’article)
    • Écrire directement dans un fichier texte des notes (exemple observations, endroit où est placé le matériel,….)
    • Il sera possible dans une prochaine version de la connecter sur un réseau wifi et d’envoyer les données directement sur un serveur distant.
  • Être OpenSource et anti-obsolescence programmée (chaque module de la carte peut-être remplacé ou upgradé indépendamment tout en étant rétrocompatible)
  • Posséder une sortie permettant de piloter un relais si nécessaire (exemple: lancer automatiquement la machine à café le matin avant l’arrivée de l’équipe ^^)

Pour information, le code source et le typon pour le matériel final seront disponibles à la fin de cet article. Si vous faites un copier/coller du code présent dans cette page, les sources sont sous licence CC-BY-NC-SA https://creativecommons.org/licenses/by-nc-sa/3.0/fr/

Juste un dernier avertisseur, nous allons travailler avec du 220v donc si vous n’avez jamais suivi de formation d’électricien, je vous déconseille fortement de continuer ce tutoriel et dans tous les cas, pensez toujours à déconnecter votre installation de toute source de puissance lorsque vous travaillez sur celle-ci.

Partie 0: Le matériel choisi

Pour ce projet, nous allons utiliser le matériel suivant:

  • Un Wemos D1 mini
  • Un Shield combinant une RTC (Real Time Clock) et un lecteur de carte SD
  • Un Capteur de puissance PZEM004T (V1 ou V3 seul le code change)
  • Un transformateur 220V AC vers 5V DC
  • Un Transistor PNP 2N2907 (je vous expliquerai son utilité plus tard)
  • Un convertisseur TTL vers USB

Partie 1: Lire l’heure sur un Wemos D1 mini

Lorsque l’on veux enregistrer des données (par exemple de consommation), il est important de pouvoir les dater pour pouvoir les analyser correctement. La RTC (Real Time Clock) est un circuit qui nous permet de faire cela. La RTC est une horloge qui est alimentée avec un pile bouton afin de continuer à garder l’heure à jour même quand le montage n’est plus sous tension.

Pour cette première partie, le montage est vraiment simple. Il suffit de placer le shield comportant la RTC sur le Wemos de la façon suivante:

Maintenant il faut relier le Wemos à l’ordinateur et lancer Arduino.

Si vous n’avez jamais utilisé de Wemos, il vous faudra d’abord prendre la bibliothèque esp8266 dans le Gestionnaire de carte

Pour cela, je vous conseille ce wiki qui est vraiment bien fait:

http://www.wikidebrouillard.org/index.php?title=Wemos_D1_mini

Il vous faudra aussi la bibliothèque RTC. Elle est téléchargeable à l’adresse suivante:

https://github.com/adafruit/RTClib

Pour inclure cette librairie, dans l’IDE Arduino, cliquez sur Croquis –> Inclure une bibliothèque –> Ajouter la bibliothèque .Zip et indiquez l’emplacement de votre librairie

Maintenant que tout est OK, vous pouvez configurer l’IDE Arduino de la façon suivante:

Le code sera le suivant:

#include 
#include "RTClib.h"

// RTC variables
RTC_DS1307 rtc;
const int sclPin = D1;
const int sdaPin = D2;
char daysOfTheWeek[7][12] = {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};


void setup () {
// Pinout Setup
  Wire.begin(sdaPin, sclPin);

//Communication Setup
  Serial.begin(57600);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    rtc.adjust(DateTime(2019, 8, 28, 3, 15, 44)); // 
  }
  
}

void loop () {
// RTC Part
   DateTime now = rtc.now();
    Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.print(",  ");
   
    if (now.day() < 10)    {Serial.print('0');}
    Serial.print(now.day(), DEC);
    Serial.print('.');
    if (now.month() < 10)  {Serial.print('0');}
    Serial.print(now.month(), DEC);
    Serial.print('.');
    Serial.print(now.year(), DEC);
    Serial.print(",  ");
   
    if (now.hour() < 10)   {Serial.print('0');}
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    if (now.minute() < 10) {Serial.print('0');}
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    if (now.second() < 10) {Serial.print('0');}
    Serial.print(now.second(), DEC);
    Serial.print(",  ");
    Serial.println(); 
    delay(1000);
}  

Si c'est la première fois que vous mettez en route votre RTC, pensez à modifier la ligne rtc.adjust(DateTime(2019, 8, 28, 3, 15, 44)); // avec une date légèrement dans le futur afin de la calibrer une première fois.

Vous pouvez remarquer que l'on utilise aussi la librairie "wire" afin de forcer l'usage des pin D1 et D2 pour leur assigner la communication I2C.

Flashez le Wemos, ouvrez votre terminal et normalement, vous devriez avoir le résultat suivant:

Tadam! vous avez maintenant la possibilité d'horodater vos données!

Partie 2: Enregistrer les données sur une carte SD

Maintenant, nous allons passer à la partie enregistrement des données sur une carte SD.

Ce qui est cool avec le shield choisi, c'est qu'en plus de la RTC, il embarque aussi un support pour carte microSD.

Donc vous l'aurez compris, le montage sera ...... le même que pour la partie précédente!

Pour cette étape, il vous faudra aussi les librairies SD et SPI qui sont normalement embarquées nativement dans l'IDE Arduino grâce à l'ajout de la carte Wemos lors de l'étape précédente.

Avant de charger le code, il faut préparer la carte SD.

Pour cela, il faut la formater en FAT puis créer un fichier vide datalog.txt. Une fois cette opération faite, vous pouvez mettre la carte dans le shield et Flasher le programme suivant sur le Wemos.

#include 
#include 

// SDcard variables
const int chipSelect = D8;

void setup () {
//Communication Setup
  Serial.begin(57600);
  Serial.print("Initializing SD card...");

//SDcard Setup
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}

void loop () {
//SDCARD Part
    File dataFile = SD.open("datalog.txt", FILE_WRITE);
  // if the file is available, write to it:
  if (dataFile) {
    dataFile.print("toto");
    Serial.println("toto");
    dataFile.println();
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.csv");
  }
  delay(10000); //10secondes
}    

Si vous lancez le terminal, vous devriez voir apparaitre toutes les 10 secondes un toto

Maintenant arrêtez votre montage, enlevez la carte SD et mettez la sur votre PC. Si tout c'est bien passé, vous devriez avoir le fichier datalog.txt qui c'est rempli de totos.

C'est ok? Parfait!!!! Par contre, il est peu pratique de devoir arrêter ses mesures pour les relever... Mais heureusement, le Wemos embarque une puce wifi et nous offre la possibilité de faire notre propre point d'accès wifi!!!

Partie 3: Créer un point d'accès Wifi

Pour notre capteur, comme nous ne savons pas s'il y aura un routeur wifi accessible, j'ai décidé de partir sur la création du point d'accès wifi directement embarqué dans le Wemos.

Pour cela, il existe déjà un code tout fait dans les exemples de l'ESP8266

Pensez à changer le SSID ainsi que le mot de passe, flashez le code et ouvrez le terminal

Maintenant connectez vous sur le SSID que vous avez choisi (ici ESPap avec le mot de passe thereisnospoon)

Ouvrez un navigateur internet et tapez l'adresse suivante: 192.168.4.1

Normalement, vous devriez avoir cette page qui apparait.

Voilà, nous savons communiquer avec notre Wemos via le réseau Wifi!

Passons aux choses sérieuses en mixant l'usage de la carte SD avec les possibilités du Wifi.

Partie 4: Récupérer des fichiers sur une page Web embarquée

Comme ce que l'on a vu précédemment, ce qui nous intéresse, c'est de pouvoir récupérer un fichier sans devoir arrêter le capteur.

Pour cela, nous allons mixer deux exemples de code et rajouter quelques fichiers sur la carte SD.

Pour les codes qui seront mélangés, il s'agit du précédent avec le code SDWebServer qui se trouve dans les exemples ESP8266WebServer

Pour faire simple, on va utiliser les parties de création d'un Point d'accès wifi avec la possibilité de pouvoir lire et modifier ce qui existe sur la carte SD via une page WEB.

Le code à Flasher sur le Wemos est le suivant:

#include 
#include 
#include 
#include 
#include 

// SDcard variables
static bool hasSD = false;
const int chipSelect = D8;
File uploadFile;

// Wifi Variables
#ifndef APSSID
#define APSSID "ESPap"
#define APPSK  "thereisnospoon"
#endif
/* Set these to your desired credentials. */
int counter =0;
const char *ssid = APSSID;
const char *password = APPSK;
ESP8266WebServer server(80);
/* Just a little test message.  Go to http://192.168.4.1 in a web browser
   connected to this access point to see it.
*/

void returnOK() {
  server.send(200, "text/plain", "");
}

void returnFail(String msg) {
  server.send(500, "text/plain", msg + "\r\n");
}

bool loadFromSdCard(String path) {

  Serial.print(path);
  String dataType = "text/plain";
  if (path.endsWith("/")) {
    path += "index.htm";
  }

  if (path.endsWith(".src")) {
    path = path.substring(0, path.lastIndexOf("."));
  } else if (path.endsWith(".htm")) {
    dataType = "text/html";
  } else if (path.endsWith(".css")) {
    dataType = "text/css";
  } else if (path.endsWith(".js")) {
    dataType = "application/javascript";
  } else if (path.endsWith(".png")) {
    dataType = "image/png";
  } else if (path.endsWith(".gif")) {
    dataType = "image/gif";
  } else if (path.endsWith(".jpg")) {
    dataType = "image/jpeg";
  } else if (path.endsWith(".ico")) {
    dataType = "image/x-icon";
  } else if (path.endsWith(".xml")) {
    dataType = "text/xml";
  } else if (path.endsWith(".pdf")) {
    dataType = "application/pdf";
  } else if (path.endsWith(".zip")) {
    dataType = "application/zip";
  }

  File dataFile = SD.open(path.c_str());
  if (dataFile.isDirectory()) {
    path += "/index.htm";
    dataType = "text/html";
    Serial.print(path.c_str());
    dataFile = SD.open(path.c_str());
  }

  if (!dataFile) {

    return false;
  }

  if (server.hasArg("download")) {
    dataType = "application/octet-stream";
  }

  if (server.streamFile(dataFile, dataType) != dataFile.size()) {
    Serial.println("Sent less data than expected!");
  }

  dataFile.close();

  return true;
}

void handleFileUpload() {
  if (server.uri() != "/edit") {
    return;
  }
  HTTPUpload& upload = server.upload();
  if (upload.status == UPLOAD_FILE_START) {
    if (SD.exists((char *)upload.filename.c_str())) {
      SD.remove((char *)upload.filename.c_str());
    }
    uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
    Serial.print("Upload: START, filename: "); Serial.println(upload.filename);
  } else if (upload.status == UPLOAD_FILE_WRITE) {
    if (uploadFile) {
      uploadFile.write(upload.buf, upload.currentSize);
    }
    Serial.print("Upload: WRITE, Bytes: "); Serial.println(upload.currentSize);
  } else if (upload.status == UPLOAD_FILE_END) {
    if (uploadFile) {
      uploadFile.close();
    }
    Serial.print("Upload: END, Size: "); Serial.println(upload.totalSize);
  }
}

void deleteRecursive(String path) {
  File file = SD.open((char *)path.c_str());
  if (!file.isDirectory()) {
    file.close();
    SD.remove((char *)path.c_str());
    return;
  }

  file.rewindDirectory();
  while (true) {
    File entry = file.openNextFile();
    if (!entry) {
      break;
    }
    String entryPath = path + "/" + entry.name();
    if (entry.isDirectory()) {
      entry.close();
      deleteRecursive(entryPath);
    } else {
      entry.close();
      SD.remove((char *)entryPath.c_str());
    }
    yield();
  }

  SD.rmdir((char *)path.c_str());
  file.close();
}

void handleDelete() {
  if (server.args() == 0) {
    return returnFail("BAD ARGS");
  }
  String path = server.arg(0);
  if (path == "/" || !SD.exists((char *)path.c_str())) {
    returnFail("BAD PATH");
    return;
  }
  deleteRecursive(path);
  returnOK();
}

void handleCreate() {
  if (server.args() == 0) {
    return returnFail("BAD ARGS");
  }
  String path = server.arg(0);
  if (path == "/" || SD.exists((char *)path.c_str())) {
    returnFail("BAD PATH");
    return;
  }

  if (path.indexOf('.') > 0) {
    File file = SD.open((char *)path.c_str(), FILE_WRITE);
    if (file) {
      file.write((const char *)0);
      file.close();
    }
  } else {
    SD.mkdir((char *)path.c_str());
  }
  returnOK();
}

void printDirectory() {
  if (!server.hasArg("dir")) {
    return returnFail("BAD ARGS");
  }
  String path = server.arg("dir");
  if (path != "/" && !SD.exists((char *)path.c_str())) {
    return returnFail("BAD PATH");
  }
  File dir = SD.open((char *)path.c_str());
  path = String();
  if (!dir.isDirectory()) {
    dir.close();
    return returnFail("NOT DIR");
  }
  dir.rewindDirectory();
  server.setContentLength(CONTENT_LENGTH_UNKNOWN);
  server.send(200, "text/json", "");
  WiFiClient client = server.client();

  server.sendContent("[");
  for (int cnt = 0; true; ++cnt) {
    File entry = dir.openNextFile();
    if (!entry) {
      break;
    }

    String output;
    if (cnt > 0) {
      output = ',';
    }

    output += "{\"type\":\"";
    output += (entry.isDirectory()) ? "dir" : "file";
    output += "\",\"name\":\"";
    output += entry.name();
    output += "\"";
    output += "}";
    server.sendContent(output);
    entry.close();
  }
  server.sendContent("]");
  dir.close();
}

void handleNotFound() {
  if (hasSD && loadFromSdCard(server.uri())) {
    return;
  }
  String message = "SDCARD Not Detected\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " NAME:" + server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial.print(message);
}
// WEBSERVER declaration end



void setup () {
//Communication Setup
  Serial.begin(57600);
  Serial.print("Initializing SD card...");

//SDcard Setup
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
  hasSD = true;


// Wifi setup    
  Serial.print("Configuring access point...");
  /* You can remove the password parameter if you want the AP to be open. */
  WiFi.softAP(ssid, password);

  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
  server.on("/list", HTTP_GET, printDirectory);
  server.on("/edit", HTTP_DELETE, handleDelete);
  server.on("/edit", HTTP_PUT, handleCreate);
  server.on("/edit", HTTP_POST, []() {
    returnOK();
  }, handleFileUpload);
  server.onNotFound(handleNotFound);  
  
  server.begin();
  Serial.println("HTTP server started");
  
}

void loop () {
 server.handleClient();
 delay(100);
}    

Il faut aussi mettre les fichiers ci-dessous sur la carte SD (ne pas mettre le dossier SDRoot mais directement les fichiers et dossiers qui sont dedans):

Vous pouvez aussi les retrouver dans le dossier de la librairie Arduino du ESP8266 --> ESP8266Arduino-master\Arduino-master\libraries\ESP8266WebServer\examples\SDWebServer\SdRoot

Maintenant que vous avez flashé le Wemos, connectez vous sur le wifi de celui-ci. Une fois cela fais, allez sur la page web suivante: 192.168.4.1/edit

Vous tomberez sur cette page:

Si vous cliquez droit sur un fichier, vous aurez la possibilité de le modifier, de le télécharger ou de le supprimer. C'est plutôt cool non?

Maintenant que l'on ai capable d'horodater une donnée, de la stocker dans un fichier sur une carte SD et en plus de la récupérer via une page WEB, il nous reste à savoir comment communiquer avec un capteur PZEM004T. Vous êtes prêt? Oui? bon c'est parti!

Partie 5: Mesurer les valeurs électriques avec un PZEM004T

Le but de cette partie est de pouvoir lire un capteur de puissance électrique nommé PZEM004T. Mais que fait donc ce capteur me direz vous? Et bien ça dépend de sa version.

La version 1:

Cette version peut récupérer comme informations:

  • La tension du réseau (en V)
  • Le courant (en A)
  • La puissance active (en W)
  • La consommation (en kWh)
ValeurPlage de mesureRésolutionPrécision
Tension80~260V0.1V0.5%
Courant0~10A or 0~100A*0.01A or 0.02A*0.5%
Puissance
0~2.3kW or 0~23kW*0.1W0.5%
Énergie
0~9999.99kWh1Wh0.5%

Elle se différencie de la version 3 par son tore (la bobine noire qui permet d'avoir une image du courant qui ne peux pas s'ouvrir dans cette version) et sa possibilité de rajouter un afficheur directement sur le capteur.

La version 3:

Cette version est plus évoluée car elle est capable de mesurer les valeurs suivantes:

ValeurPlage de mesureRésolutionPrécision
Tension80~260V0.1V0.5%
Courant0~10A or 0~100A*0.01A or 0.02A*0.5%
Puissance
0~2.3kW or 0~23kW*0.1W0.5%
Énergie
0~9999.99kWh1Wh0.5%
Fréquence45~65Hz0.1Hz0.5%
Facteur de puissance
0.00~1.000.011%

Et il a pour avantage de posséder un tore sécable donc plus besoin de démonter le circuit complet pour l'installer.

Maintenant que nous connaissons ces capacités, nous pouvons passer à sa mise en œuvre. Au niveau matériel, nous aurons besoin de rajouter un transistor PNP ainsi qu'un convertisseur FTDI TTL <-> USB

Pour ce qui est du câblage du point de mesure, les 2 versions sont identiques et s'effectue de la façon suivante:

En ce qui concerne le câblage entre le PZEM et le Wemos il y a une légère différence selon la version utilisée.

Version 1:

Une modification est aussi à faire sur le PZEM004T v1 afin de le rendre compatible avec le TTL du Wemos qui est en 3.3v. Il faut rajouter une résistance de 1k Ω comme la photo ci-dessous.

Version 3:

Pas besoin de modification du PZEM pour cette version.

La présence du transistor permet de mettre le GPIO15 du Wemos au 0 logique et lui permettre de booter sur le Flash SPI. Si l'on reliait directement les 2 connecteurs ensemble l'octocoupleur forcerait au 1 logique le GPIO15 ce qui ferait reseter tout le temps le Wemos.

On utilise aussi le convertisseur FTDI TTL<->USB car le Wemos possède 2 UARTs UART0 (qui servira pour la communication avec le PZEM) et UART1 (qui est unidirectionnel ce qui veux dire qu'il ne sert qu'à envoyer des informations mais ne peux pas en récupérer)

Ces explications sont tirées du site: https://github.com/olehs/PZEM004T/wiki/Connecting-PZEM-to-ESP8266

Maintenant que le câblage est fait, passons au code:

Vous aurez besoin de 2 librairies en plus (Une par version de PZEM)

La première pour la version1 se trouve ici: https://github.com/olehs/PZEM004T

La deuxième pour la version 3 se trouve ici: https://github.com/mandulaj/PZEM-004T-v30

Utilisez la même méthode pour les inclurent que pour les librairies précédentes.

Maintenant voici les codes pour chacune des versions:

Version 1:

#include 

// Pzem004 variables
float v = 0;
float i = 0; 
float p =0;
float e = 0;
HardwareSerial hwSerial(UART0);     // Use hwSerial1 UART0 at pins GPIO1 (TX) and GPIO3 (RX)
PZEM004T pzem(&hwSerial);           // Attach PZEM to hwSerial1
IPAddress ip(192,168,1,1);
bool pzemrdy = false;

void setup () {
//Communication Setup
  Serial1.begin(57600);

// PZEM004T Setup
  while (!pzemrdy) {
      Serial1.println("Connecting to PZEM...");
      pzemrdy = pzem.setAddress(ip);
      delay(1000);
   }
}

void loop () {
//PZEM Part
  v = pzem.voltage(ip);
  if (v < 0.0) v = 0.0;
   Serial1.print(v);Serial1.print("V; ");
   i = pzem.current(ip);
   if(i >= 0.0){ Serial1.print(i);Serial1.print("A; "); }
  p = pzem.power(ip);
   if(p >= 0.0){ Serial1.print(p);Serial1.print("W; "); }
   e = pzem.energy(ip);
   if(e >= 0.0){ Serial1.print(e);Serial1.print("Wh; "); } 
   Serial1.println();
}    

Version 3:

#include 

// Pzem004 variables
float v = 0;
float i = 0; 
float p =0;
float e = 0;
float freq;
float pf;
HardwareSerial hwSerial(UART0);     // Use hwSerial1 UART0 at pins GPIO1 (TX) and GPIO3 (RX)
PZEM004Tv30 pzem(&hwSerial);           // Attach PZEM to hwSerial1
bool pzemrdy = false;

void setup () {
//Communication Setup
  Serial1.begin(57600);
//PZEM
pzem.setAddress(0x42);
}

void loop () {
//PZEM Part
  v = pzem.voltage();
  if (v < 0.0) v = 0.0;
   Serial1.print(v);Serial1.print("V; ");
   i = pzem.current();
   if(i >= 0.0){ Serial1.print(i);Serial1.print("A; "); }
  p = pzem.power();
   if(p >= 0.0){ Serial1.print(p);Serial1.print("W; "); }
   e = pzem.energy();
   if(e >= 0.0){ Serial1.print(e);Serial1.print("Wh; "); } 
  freq = pzem.frequency();
  Serial1.print("Frequency: ");
  Serial1.print(freq);
  Serial1.print("Hz;");
  pf = pzem.pf();
  Serial1.print("PF: ");
  Serial1.println(pf);
}    

Vous pouvez flasher le Wemos, débrancher le câble USB, mettre en route votre installation électrique et brancher le FTDI sur votre PC. Choisissez ensuite le port COM correspondant et regardez sur le terminal ce que cela donne.

Vous devriez avoir ce genre de résultat:

Version 1:

Version 3:

Voilà maintenant nous maitrisons toutes les facettes du capteur. Nous pouvons maintenant les assembler.

Partie 6: Montage électronique final

J'ai réuni tous les composants sur une plaque test pour tester ensemble et vous montrer les différentes parties.

A droite le transformateur 200v->5V, en haut le PZEM, en Bas le Wemos avec le shield RTC+SD

Maintenant que tous les éléments sont testés, il nous reste à les assembler sur une "carte mère" afin de créer notre capteur tout en un qui soit utilisable dans une armoire électrique.

Voici le pdf du typon

Sur le design de la carte, j'ai laissé la possibilité d'avoir un bouton de reset ainsi que d'utiliser la pin D0 en signal d'entrée ou de sortie.

J'ai ajouter le mini transformateur 220v AC vers 5V DC

J'ai aussi modifier le PZEM afin qu'il n'y ai pas de fil volant.

La carte finale normalement donne cela:

Partie 7: Code final

Pour le code final, j'ai apporté quelques menues modifications afin que les données soient écrites dans un fichier .csv et non .txt. J'ai aussi modifié les fichiers de la carte SD afin de mettre le logo du laboratoire.

Pour la version PZEM004T V1

#include 
#include 
#include "RTClib.h"
#include 
#include 
#include 
#include 
#include 

// Echantillonage
int temps = 10; //en secondes

// Pzem004 variables
float v = 0;
float i = 0; 
float p =0;
float e = 0;
HardwareSerial hwSerial(UART0);     // Use hwSerial1 UART0 at pins GPIO1 (TX) and GPIO3 (RX)
PZEM004T pzem(&hwSerial);           // Attach PZEM to hwSerial1
IPAddress ip(192,168,1,1);
bool pzemrdy = false;

// RTC variables
RTC_DS1307 rtc;
const int sclPin = D1;
const int sdaPin = D2;
char daysOfTheWeek[7][12] = {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};

// SDcard variables
static bool hasSD = false;
const int chipSelect = D8;
File uploadFile;

// Wifi Variables
#ifndef APSSID
#define APSSID "ESPap"
#define APPSK  "thereisnospoon"
#endif
/* Set these to your desired credentials. */
int counter =0;
const char *ssid = APSSID;
const char *password = APPSK;
ESP8266WebServer server(80);
/* Just a little test message.  Go to http://192.168.4.1 in a web browser
   connected to this access point to see it.
*/

// Prototypes des fonctions
void MesureLectureEcriture(void);

void returnOK() {
  server.send(200, "text/plain", "");
}

void returnFail(String msg) {
  server.send(500, "text/plain", msg + "\r\n");
}

bool loadFromSdCard(String path) {

  Serial1.print(path);
  String dataType = "text/plain";
  if (path.endsWith("/")) {
    path += "index.htm";
  }

  if (path.endsWith(".src")) {
    path = path.substring(0, path.lastIndexOf("."));
  } else if (path.endsWith(".htm")) {
    dataType = "text/html";
  } else if (path.endsWith(".css")) {
    dataType = "text/css";
  } else if (path.endsWith(".js")) {
    dataType = "application/javascript";
  } else if (path.endsWith(".png")) {
    dataType = "image/png";
  } else if (path.endsWith(".gif")) {
    dataType = "image/gif";
  } else if (path.endsWith(".jpg")) {
    dataType = "image/jpeg";
  } else if (path.endsWith(".ico")) {
    dataType = "image/x-icon";
  } else if (path.endsWith(".xml")) {
    dataType = "text/xml";
  } else if (path.endsWith(".pdf")) {
    dataType = "application/pdf";
  } else if (path.endsWith(".zip")) {
    dataType = "application/zip";
  }

  File dataFile = SD.open(path.c_str());
  if (dataFile.isDirectory()) {
    path += "/index.htm";
    dataType = "text/html";
    Serial1.print(path.c_str());
    dataFile = SD.open(path.c_str());
  }

  if (!dataFile) {

    return false;
  }

  if (server.hasArg("download")) {
    dataType = "application/octet-stream";
  }

  if (server.streamFile(dataFile, dataType) != dataFile.size()) {
    Serial1.println("Sent less data than expected!");
  }

  dataFile.close();

  return true;
}

void handleFileUpload() {
  if (server.uri() != "/edit") {
    return;
  }
  HTTPUpload& upload = server.upload();
  if (upload.status == UPLOAD_FILE_START) {
    if (SD.exists((char *)upload.filename.c_str())) {
      SD.remove((char *)upload.filename.c_str());
    }
    uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
    Serial1.print("Upload: START, filename: "); Serial1.println(upload.filename);
  } else if (upload.status == UPLOAD_FILE_WRITE) {
    if (uploadFile) {
      uploadFile.write(upload.buf, upload.currentSize);
    }
    Serial1.print("Upload: WRITE, Bytes: "); Serial1.println(upload.currentSize);
  } else if (upload.status == UPLOAD_FILE_END) {
    if (uploadFile) {
      uploadFile.close();
    }
    Serial1.print("Upload: END, Size: "); Serial1.println(upload.totalSize);
  }
}

void deleteRecursive(String path) {
  File file = SD.open((char *)path.c_str());
  if (!file.isDirectory()) {
    file.close();
    SD.remove((char *)path.c_str());
    return;
  }

  file.rewindDirectory();
  while (true) {
    File entry = file.openNextFile();
    if (!entry) {
      break;
    }
    String entryPath = path + "/" + entry.name();
    if (entry.isDirectory()) {
      entry.close();
      deleteRecursive(entryPath);
    } else {
      entry.close();
      SD.remove((char *)entryPath.c_str());
    }
    yield();
  }

  SD.rmdir((char *)path.c_str());
  file.close();
}

void handleDelete() {
  if (server.args() == 0) {
    return returnFail("BAD ARGS");
  }
  String path = server.arg(0);
  if (path == "/" || !SD.exists((char *)path.c_str())) {
    returnFail("BAD PATH");
    return;
  }
  deleteRecursive(path);
  returnOK();
}

void handleCreate() {
  if (server.args() == 0) {
    return returnFail("BAD ARGS");
  }
  String path = server.arg(0);
  if (path == "/" || SD.exists((char *)path.c_str())) {
    returnFail("BAD PATH");
    return;
  }

  if (path.indexOf('.') > 0) {
    File file = SD.open((char *)path.c_str(), FILE_WRITE);
    if (file) {
      file.write((const char *)0);
      file.close();
    }
  } else {
    SD.mkdir((char *)path.c_str());
  }
  returnOK();
}

void printDirectory() {
  if (!server.hasArg("dir")) {
    return returnFail("BAD ARGS");
  }
  String path = server.arg("dir");
  if (path != "/" && !SD.exists((char *)path.c_str())) {
    return returnFail("BAD PATH");
  }
  File dir = SD.open((char *)path.c_str());
  path = String();
  if (!dir.isDirectory()) {
    dir.close();
    return returnFail("NOT DIR");
  }
  dir.rewindDirectory();
  server.setContentLength(CONTENT_LENGTH_UNKNOWN);
  server.send(200, "text/json", "");
  WiFiClient client = server.client();

  server.sendContent("[");
  for (int cnt = 0; true; ++cnt) {
    File entry = dir.openNextFile();
    if (!entry) {
      break;
    }

    String output;
    if (cnt > 0) {
      output = ',';
    }

    output += "{\"type\":\"";
    output += (entry.isDirectory()) ? "dir" : "file";
    output += "\",\"name\":\"";
    output += entry.name();
    output += "\"";
    output += "}";
    server.sendContent(output);
    entry.close();
  }
  server.sendContent("]");
  dir.close();
}

void handleNotFound() {
  if (hasSD && loadFromSdCard(server.uri())) {
    return;
  }
  String message = "SDCARD Not Detected\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " NAME:" + server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial1.print(message);
}
// WEBSERVER declaration end



void setup () {
// Pinout Setup
  Wire.begin(sdaPin, sclPin);
  pinMode(16,INPUT);

//Communication Setup
  Serial1.begin(57600);

// PZEM004T Setup
  while (!pzemrdy) {
      Serial1.println("Connecting to PZEM...");
      pzemrdy = pzem.setAddress(ip);
      delay(1000);
   }
   
// RTC Setup 
  if (! rtc.begin()) {
    Serial1.println("Couldn't find RTC");
    while (1);
  }
  if (! rtc.isrunning()) {
    Serial1.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
    rtc.adjust(DateTime(2019, 8, 23, 10, 11, 0));
  }
  Serial1.print("Initializing SD card...");

//SDcard Setup
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial1.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial1.println("card initialized.");
  hasSD = true;


// Wifi setup    
  Serial1.print("Configuring access point...");
  /* You can remove the password parameter if you want the AP to be open. */
  WiFi.softAP(ssid, password);

  IPAddress myIP = WiFi.softAPIP();
  Serial1.print("AP IP address: ");
  Serial1.println(myIP);
  server.on("/list", HTTP_GET, printDirectory);
  server.on("/edit", HTTP_DELETE, handleDelete);
  server.on("/edit", HTTP_PUT, handleCreate);
  server.on("/edit", HTTP_POST, []() {
    returnOK();
  }, handleFileUpload);
  server.onNotFound(handleNotFound);  
  
  server.begin();
  Serial1.println("HTTP server started");
  
}

void loop () {
 server.handleClient();
 delay(100);
 counter = counter+1;
 if(counter==(10*temps)){
 MesureLectureEcriture();
 counter =0;
 }
}


void MesureLectureEcriture(){
//PZEM Part
  v = pzem.voltage(ip);
  if (v < 0.0) v = 0.0;
   Serial1.print(v);Serial1.print("V; ");
   i = pzem.current(ip);
   if(i >= 0.0){ Serial1.print(i);Serial1.print("A; "); }
  p = pzem.power(ip);
   if(p >= 0.0){ Serial1.print(p);Serial1.print("W; "); }
   e = pzem.energy(ip);
   if(e >= 0.0){ Serial1.print(e);Serial1.print("Wh; "); } 
   Serial1.println();
   
// RTC Part
   DateTime now = rtc.now();
    Serial1.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial1.print(",  ");
   
    if (now.day() < 10)    {Serial1.print('0');}
    Serial1.print(now.day(), DEC);
    Serial1.print('.');
    if (now.month() < 10)  {Serial1.print('0');}
    Serial1.print(now.month(), DEC);
    Serial1.print('.');
    Serial1.print(now.year(), DEC);
    Serial1.print(",  ");
   
    if (now.hour() < 10)   {Serial1.print('0');}
    Serial1.print(now.hour(), DEC);
    Serial1.print(':');
    if (now.minute() < 10) {Serial1.print('0');}
    Serial1.print(now.minute(), DEC);
    Serial1.print(':');
    if (now.second() < 10) {Serial1.print('0');}
    Serial1.print(now.second(), DEC);
    Serial1.print(",  ");
    Serial1.println(); 

//SDCARD Part
    File dataFile = SD.open("datalog.csv", FILE_WRITE);
  // if the file is available, write to it:
  if (dataFile) {
    if (now.day() < 10)    {dataFile.print('0');}
    dataFile.print(now.day(), DEC);
    dataFile.print('-');
    if (now.month() < 10)  {dataFile.print('0');}
    dataFile.print(now.month(), DEC);
    dataFile.print('-');
    dataFile.print(now.year(), DEC);
    dataFile.print("  ");
    if (now.hour() < 10)   {dataFile.print('0');}
    dataFile.print(now.hour(), DEC);
    dataFile.print(':');
    if (now.minute() < 10) {dataFile.print('0');}
    dataFile.print(now.minute(), DEC);
    dataFile.print(':');
    if (now.second() < 10) {dataFile.print('0');}
    dataFile.print(now.second(), DEC);   
    dataFile.print(";");
    dataFile.print(v);
    dataFile.print(';');
    dataFile.print(i);
    dataFile.print(';');
    dataFile.print(p);
    dataFile.print(';');
    dataFile.print(e);
    dataFile.println();
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial1.println("error opening datalog.csv");
  }
}
    

Pour le PZEM004T V3

#include 
#include 
#include "RTClib.h"
#include 
#include 
#include 
#include 
#include 

// Echantillonage
int temps = 10; //en secondes

// Pzem004 variables
float v = 0;
float i = 0; 
float p =0;
float e = 0;
float freq;
float pf;
HardwareSerial hwSerial(UART0);     // Use hwSerial1 UART0 at pins GPIO1 (TX) and GPIO3 (RX)
PZEM004Tv30 pzem(&hwSerial);           // Attach PZEM to hwSerial1
bool pzemrdy = false;

// RTC variables
RTC_DS1307 rtc;
const int sclPin = D1;
const int sdaPin = D2;
char daysOfTheWeek[7][12] = {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};

// SDcard variables
static bool hasSD = false;
const int chipSelect = D8;
File uploadFile;

// Wifi Variables
#ifndef APSSID
#define APSSID "ESPap"
#define APPSK  "thereisnospoon"
#endif
/* Set these to your desired credentials. */
int counter =0;
const char *ssid = APSSID;
const char *password = APPSK;
ESP8266WebServer server(80);
/* Just a little test message.  Go to http://192.168.4.1 in a web browser
   connected to this access point to see it.
*/

// Prototypes des fonctions
void MesureLectureEcriture(void);

void returnOK() {
  server.send(200, "text/plain", "");
}

void returnFail(String msg) {
  server.send(500, "text/plain", msg + "\r\n");
}

bool loadFromSdCard(String path) {

  Serial1.print(path);
  String dataType = "text/plain";
  if (path.endsWith("/")) {
    path += "index.htm";
  }

  if (path.endsWith(".src")) {
    path = path.substring(0, path.lastIndexOf("."));
  } else if (path.endsWith(".htm")) {
    dataType = "text/html";
  } else if (path.endsWith(".css")) {
    dataType = "text/css";
  } else if (path.endsWith(".js")) {
    dataType = "application/javascript";
  } else if (path.endsWith(".png")) {
    dataType = "image/png";
  } else if (path.endsWith(".gif")) {
    dataType = "image/gif";
  } else if (path.endsWith(".jpg")) {
    dataType = "image/jpeg";
  } else if (path.endsWith(".ico")) {
    dataType = "image/x-icon";
  } else if (path.endsWith(".xml")) {
    dataType = "text/xml";
  } else if (path.endsWith(".pdf")) {
    dataType = "application/pdf";
  } else if (path.endsWith(".zip")) {
    dataType = "application/zip";
  }

  File dataFile = SD.open(path.c_str());
  if (dataFile.isDirectory()) {
    path += "/index.htm";
    dataType = "text/html";
    Serial1.print(path.c_str());
    dataFile = SD.open(path.c_str());
  }

  if (!dataFile) {

    return false;
  }

  if (server.hasArg("download")) {
    dataType = "application/octet-stream";
  }

  if (server.streamFile(dataFile, dataType) != dataFile.size()) {
    Serial1.println("Sent less data than expected!");
  }

  dataFile.close();

  return true;
}

void handleFileUpload() {
  if (server.uri() != "/edit") {
    return;
  }
  HTTPUpload& upload = server.upload();
  if (upload.status == UPLOAD_FILE_START) {
    if (SD.exists((char *)upload.filename.c_str())) {
      SD.remove((char *)upload.filename.c_str());
    }
    uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
    Serial1.print("Upload: START, filename: "); Serial1.println(upload.filename);
  } else if (upload.status == UPLOAD_FILE_WRITE) {
    if (uploadFile) {
      uploadFile.write(upload.buf, upload.currentSize);
    }
    Serial1.print("Upload: WRITE, Bytes: "); Serial1.println(upload.currentSize);
  } else if (upload.status == UPLOAD_FILE_END) {
    if (uploadFile) {
      uploadFile.close();
    }
    Serial1.print("Upload: END, Size: "); Serial1.println(upload.totalSize);
  }
}

void deleteRecursive(String path) {
  File file = SD.open((char *)path.c_str());
  if (!file.isDirectory()) {
    file.close();
    SD.remove((char *)path.c_str());
    return;
  }

  file.rewindDirectory();
  while (true) {
    File entry = file.openNextFile();
    if (!entry) {
      break;
    }
    String entryPath = path + "/" + entry.name();
    if (entry.isDirectory()) {
      entry.close();
      deleteRecursive(entryPath);
    } else {
      entry.close();
      SD.remove((char *)entryPath.c_str());
    }
    yield();
  }

  SD.rmdir((char *)path.c_str());
  file.close();
}

void handleDelete() {
  if (server.args() == 0) {
    return returnFail("BAD ARGS");
  }
  String path = server.arg(0);
  if (path == "/" || !SD.exists((char *)path.c_str())) {
    returnFail("BAD PATH");
    return;
  }
  deleteRecursive(path);
  returnOK();
}

void handleCreate() {
  if (server.args() == 0) {
    return returnFail("BAD ARGS");
  }
  String path = server.arg(0);
  if (path == "/" || SD.exists((char *)path.c_str())) {
    returnFail("BAD PATH");
    return;
  }

  if (path.indexOf('.') > 0) {
    File file = SD.open((char *)path.c_str(), FILE_WRITE);
    if (file) {
      file.write((const char *)0);
      file.close();
    }
  } else {
    SD.mkdir((char *)path.c_str());
  }
  returnOK();
}

void printDirectory() {
  if (!server.hasArg("dir")) {
    return returnFail("BAD ARGS");
  }
  String path = server.arg("dir");
  if (path != "/" && !SD.exists((char *)path.c_str())) {
    return returnFail("BAD PATH");
  }
  File dir = SD.open((char *)path.c_str());
  path = String();
  if (!dir.isDirectory()) {
    dir.close();
    return returnFail("NOT DIR");
  }
  dir.rewindDirectory();
  server.setContentLength(CONTENT_LENGTH_UNKNOWN);
  server.send(200, "text/json", "");
  WiFiClient client = server.client();

  server.sendContent("[");
  for (int cnt = 0; true; ++cnt) {
    File entry = dir.openNextFile();
    if (!entry) {
      break;
    }

    String output;
    if (cnt > 0) {
      output = ',';
    }

    output += "{\"type\":\"";
    output += (entry.isDirectory()) ? "dir" : "file";
    output += "\",\"name\":\"";
    output += entry.name();
    output += "\"";
    output += "}";
    server.sendContent(output);
    entry.close();
  }
  server.sendContent("]");
  dir.close();
}

void handleNotFound() {
  if (hasSD && loadFromSdCard(server.uri())) {
    return;
  }
  String message = "SDCARD Not Detected\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " NAME:" + server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial1.print(message);
}
// WEBSERVER declaration end



void setup () {
// Pinout Setup
  Wire.begin(sdaPin, sclPin);
  pinMode(16,INPUT);

//Communication Setup
  Serial1.begin(57600);
/*
// PZEM004T Setup
  while (!pzemrdy) {
      Serial1.println("Connecting to PZEM...");
      pzemrdy = pzem.setAddress(ip);
      delay(1000);
   }
*/
pzem.setAddress(0x42);
   
// RTC Setup 
  if (! rtc.begin()) {
    Serial1.println("Couldn't find RTC");
    while (1);
  }
  if (! rtc.isrunning()) {
    Serial1.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
    rtc.adjust(DateTime(2019, 8, 23, 10, 11, 0));
  }
  Serial1.print("Initializing SD card...");

//SDcard Setup
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial1.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial1.println("card initialized.");
  hasSD = true;


// Wifi setup    
  Serial1.print("Configuring access point...");
  /* You can remove the password parameter if you want the AP to be open. */
  WiFi.softAP(ssid, password);

  IPAddress myIP = WiFi.softAPIP();
  Serial1.print("AP IP address: ");
  Serial1.println(myIP);
  server.on("/list", HTTP_GET, printDirectory);
  server.on("/edit", HTTP_DELETE, handleDelete);
  server.on("/edit", HTTP_PUT, handleCreate);
  server.on("/edit", HTTP_POST, []() {
    returnOK();
  }, handleFileUpload);
  server.onNotFound(handleNotFound);  
  
  server.begin();
  Serial1.println("HTTP server started");
  
}

void loop () {
 server.handleClient();


 delay(100);
 counter = counter+1;

 if(counter==(10*temps)){
 MesureLectureEcriture();
 counter =0;
 }
}


void MesureLectureEcriture(){
//PZEM Part
  v = pzem.voltage();
  if (v < 0.0) v = 0.0;
   Serial1.print(v);Serial1.print("V; ");
   i = pzem.current();
   if(i >= 0.0){ Serial1.print(i);Serial1.print("A; "); }
  p = pzem.power();
   if(p >= 0.0){ Serial1.print(p);Serial1.print("W; "); }
   e = pzem.energy();
   if(e >= 0.0){ Serial1.print(e);Serial1.print("Wh; "); } 
  freq = pzem.frequency();
  Serial1.print("Frequency: ");
  Serial1.print(freq);
  Serial1.print("Hz");
  pf = pzem.pf();
  Serial1.print("PF: ");
  Serial1.println(pf);
   
// RTC Part
   DateTime now = rtc.now();
    Serial1.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial1.print(",  ");
   
    if (now.day() < 10)    {Serial1.print('0');}
    Serial1.print(now.day(), DEC);
    Serial1.print('.');
    if (now.month() < 10)  {Serial1.print('0');}
    Serial1.print(now.month(), DEC);
    Serial1.print('.');
    Serial1.print(now.year(), DEC);
    Serial1.print(",  ");
   
    if (now.hour() < 10)   {Serial1.print('0');}
    Serial1.print(now.hour(), DEC);
    Serial1.print(':');
    if (now.minute() < 10) {Serial1.print('0');}
    Serial1.print(now.minute(), DEC);
    Serial1.print(':');
    if (now.second() < 10) {Serial1.print('0');}
    Serial1.print(now.second(), DEC);
    Serial1.print(",  ");
    Serial1.println(); 

//SDCARD Part
    File dataFile = SD.open("datalog.csv", FILE_WRITE);
  // if the file is available, write to it:
  if (dataFile) {
    if (now.day() < 10)    {dataFile.print('0');}
    dataFile.print(now.day(), DEC);
    dataFile.print('-');
    if (now.month() < 10)  {dataFile.print('0');}
    dataFile.print(now.month(), DEC);
    dataFile.print('-');
    dataFile.print(now.year(), DEC);
    dataFile.print("  ");
    if (now.hour() < 10)   {dataFile.print('0');}
    dataFile.print(now.hour(), DEC);
    dataFile.print(':');
    if (now.minute() < 10) {dataFile.print('0');}
    dataFile.print(now.minute(), DEC);
    dataFile.print(':');
    if (now.second() < 10) {dataFile.print('0');}
    dataFile.print(now.second(), DEC);   
    dataFile.print(";");
    dataFile.print(v);
    dataFile.print(';');
    dataFile.print(i);
    dataFile.print(';');
    dataFile.print(p);
    dataFile.print(';');
    dataFile.print(e);
    dataFile.print(';');
    dataFile.print(pf);
    dataFile.print(';');
    dataFile.print(freq);
    dataFile.println();
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial1.println("error opening datalog.csv");
  }
}    

Partie 8: Analyse des données

Maintenant que tout est fini, on peut brancher le datalogger BB1 sur son point de mesure final et venir de temps en temps chercher le fichier datalog.csv

On peut ensuite extraire les données fichier datalog.csv afin d'analyser celle-ci. (Attention en fonction de la version du logiciel que vous utilisé, il faudra remplacer les points par des virgules)

Voilà ce tutoriel est fini. J'espère qu'il vous sera utile.

Ci-dessous l'archive avec toutes les sources utilisées.

N'hésitez pas à me faire des retours sur l'utilisation de vos dataloggeurs et je vous souhaite une bonne expérimentation.

Jérôme Ferrari