ESP32 et qualité de l’air

Réalisation d’une mini station de mesure de qualité de l’air avec horloge intégrée

Le matériel nécessaire :

Un ESP32 (ici l’image représente un clone : un ESP32-WROVER de chez Freenove)

Un écran OLED 128-32 pixels

Un composant CJMCU-8128

Une horloge RTC DS1307

3 Boutons poussoirs (Rouge, Blanc et Bleu)

 

 

 

 

 

 

Horloge RTC

 

Le CJMCU-8128 est une carte étonnante :

Dans la taille d’un timbre poste se trouve 3 composants accessible en I2C, chacun ayant sa propre adresse (non modifiable)

Il permet de mesurer à lui seul :

  • La température ambiante
  • Le taux d’humidité
  • La pression atmosphérique (que je n’utilise pas dans l’exemple)
  • La concentration de CO2 dans l’air.
  • Le TVOC (mesure totale de composants volatiles polluants)

L’écran Oled que j’ai utilisé est le plus petit sur le marché (presque trop petit) il doit faire 1cm de haut par 3cm de large (0,91 pouce de diagonale). Accessible également en I2C à l’adresse 0x3C

L’horloge RTC es une DS1307 qu’on pilote aisément sans bibliothèque particulière.

La connexion est classique :

  • Ces trois périphériques s’alimentent en 3,3V
  • Ils utilisent les briches SDA et SCL (I2c) qui sur cette version de l’ESP32 sont respectivement les 21 et 22.
  • Le CJMCU-8128 doit aussi avoir sa broche “Wake” connectée au port GPIO 23 sur cet version de l’ESP32
  • Les boutons auront la masse en commun et sont branchés respectivement sur les broches 14 pour le rouge, 12 pour le blanc et 13 pour le bleu.

Les fonctionnalités :

Au démarrage, le programme affiche l’heure sur la 1ère ligne et la date sur la seconde.

2 boutons sont alors disponibles :

  • Le bouton bleu permet, par un appuie long ( 1 sec ou plus)  de passer à l’autre affichage : température, humidité, quantité de CO2 et TVOC de l’air ambiant. Un autre appuie long sur le bouton bleu revient à l’affichage de la date et de l’heure.
  • Lors la date et l’heure sont affichées : un appuie long sue le bouton rouge permet de régler la date et l’heure !
  • Une fois entré dans le mode “mise à l’heure”, le bouton bleu permet d’ajouter 1, le blanc de retirer 1 à la valeur en cours de mise à jour. Et le bouton rouge, par un appuie court permet de passer de l’heure aux minutes, aux secondes, aux jours, aux mois puis à l’année et enfin de revenir à l’affichage normale.

La programmation :

Comme j”utilise de gros boutons poussoirs, je n’ai pas renontrer de problèmes de rebonds, le soft ne gère donc pas se problème. Avec de petits boutons poussoir, cela pourrait se produire, en ce cas 2 options : soit un condensateur 100nF par bouton, soit un filtre à programmer dans le code.

Si l’utilisation de ces composants avec des Arduino (Uno ou Nano) est largement détaillée sur le Web, ce n’est pas le cas lorsqu’on souhaite les utiliser un ESP-32 !

Aucune des bibliothèques du CJMCU-8124 que j’ai essayée n’a fonctionné :

  • Soit le Si7021 qui se trouve dans le CJMCU-8128 ne répondait pas
  • Soit la connexion se faisait mais j’obtenais toujours les valeurs maximales de températures et d’humidité (126°C)

J’ai donc fini par faire ma propre bibliothèque en m’inspirant largement de ce que j’ai trouvé sur le web.

De plus, j’ai rencontré beaucoup de problème avec le logiciel Arduino :

  • Avec mon portable sous Windows 11 et la dernière version de Arduino (2.06) : impossible de téléverser le programme dans l’ESP-32. J’ai même pensé que l’ESP-32 était HS
  • Avec mon autre portable sous Linux Fedora et Arduino 1.86 : aucun soucis
  • Avec mon autre portable sous Windows 10 et Arduino 2.06 : même problème : flashage de l’ESP-32 impossible
  • Avec ce dernier portable (sous Windows 10) et Arduino 1.86 : aucun soucis.
  • Dans tous les cas des réinstallations/  réinstallation du pilote ou de Arduino n’ont rien changé, même après nettoyage de la base de registre.

Donc le problème ne vient pas du pilote, ni de windows mais visiblement de la toute dernière version du logiciel Arduino.

Les bibliothèques nécessaires :

  • Adafruit_SSD1306
  • Adafruit_GFX
  • ClosedCube_HDC1080
  • CCS811 de Marteen Pennings , dont les liens de téléchargement sont ci-dessous (surtout pas celle des dépôts Arduino)

 

Le code

/***************************************************
ESP32
VCC - 3.3V
GND - G
SCL - 22
SDA - 21
WAK - 23
RED BTN - D14
WHITE BTN - D12
BLUE BTN - D13

****************************************************/
#include <Wire.h>
#include <ClosedCube_HDC1080.h> 
#include "ccs811.h"


#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define Addr_SSD1306 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define temp_correction -2.60
#define hmd_correction +6.50

//RTC I2C Adresse
#define Addr_DS3231 0x68

byte sec, mnt, hr, sjour, mjour, mois, annee;
byte old_sec=0;
uint16_t eco2=0, etvoc=0;
uint16_t old_eco2=0, old_etvoc=0;
float hmd=0, temp=0;
float old_hmd=0, old_temp=0;
float last_hmd_for_co2=0, last_temp_for_co2=0;

#define BTN_RED_PIN 14 
#define BTN_WHITE_PIN 12
#define BTN_BLUE_PIN 13

byte settings_mode=0; /*0 : désactivé, 1 : heure, 2 min, 3 sec, 4 : jour, 5 : mois, 6 : année; */
byte typeaff=0; /*0 = affichache date-heure , 1 = affichage données sonde */
long last_time_data=0; /*quand l'heure a-t-elle été prise la dernière fois */
long last_time_time=0; /*quand les mesures de la sonde ont-elles été prises la dernière fois */

//Global sensor objects
#ifdef ARDUINO_ARCH_ESP8266
#define CCS811_WAK D3
#elif defined ARDUINO_ARCH_ESP32
#define CCS811_WAK 23
#endif

CCS811 ccs811(CCS811_WAK);
ClosedCube_HDC1080 hdc1080;

#define DEVICE_NAME "CJMCU-8118"


/*ajout d'un jour (sans changer ni le mois ni l'année)*/
byte addday(int nbtoadd, byte d, byte m, byte y)
{
int n=nbtoadd;
byte result=d;
boolean bissex=false;
bissex=((int(2000+y)%4==0) and ((int(2000+y)%100!=0) or (int(2000+y)%400==0)));
byte lastmonthday[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; 
if (bissex==true) { lastmonthday[2]=29; }
while ( n > 0 ) 
{ 
result+=1;
if (result>lastmonthday[m]) { result=1;}
n-=1;
}
while ( n < 0 ) 
{ 
result-=1;
if (result<1) { result=lastmonthday[m]; }
n+=1;
}
return result;
}


//convertion normal to binary (RTC)
byte dectobcd(byte val)
{
return ((val / 10 * 16)+ (val%10) );
}

//convertion binaire decimal vers decimaux normaux
byte bcdtodec(byte val)
{
return ((val / 16 * 10)+ (val%16) );
}

//Lecture à jour RTC
void read_DS3231time()
{
Wire.beginTransmission(Addr_DS3231);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(Addr_DS3231,7);
sec=bcdtodec(Wire.read() & 0x7f);
mnt=bcdtodec(Wire.read());
hr=bcdtodec(Wire.read() & 0x3f);
sjour=bcdtodec(Wire.read());
mjour=bcdtodec(Wire.read());
mois=bcdtodec(Wire.read());
annee=bcdtodec(Wire.read());
last_time_time=millis();
}

//Maj RTC
void set_DS3231time(byte sec, byte mnt, byte hr, byte sjour, byte mjour, byte mois, byte annee)
{

Wire.beginTransmission(Addr_DS3231);
Wire.write(0); // set next input to start at the seconds register
Wire.write(dectobcd(sec)); // set seconds
Wire.write(dectobcd(mnt)); // set minutes
Wire.write(dectobcd(hr)); // set hours
Wire.write(dectobcd(sjour)); // set day of week (1=Sunday, 7=Saturday)
Wire.write(dectobcd(mjour)); // set date (1 to 31)
Wire.write(dectobcd(mois)); // set month
Wire.write(dectobcd(annee)); // set year (0 to 99)
Wire.endTransmission();
}

//Affichage date/heure
void displaydatetime(byte refreshtime)
{
if (millis()-last_time_time>refreshtime*1000) read_DS3231time();
if (sec!=old_sec)
{
old_sec=sec;
if (hr<10) Serial.print("0");
Serial.print(hr);
Serial.print(":");
if (mnt<10) Serial.print("0");
Serial.print(mnt);
Serial.print(":");
if (sec<10) Serial.print("0");
Serial.print(sec);
Serial.print(" ");
if (mjour<10) Serial.print("0");
Serial.print(mjour);
Serial.print("/");
if (mois<10) Serial.print("0");
Serial.print(mois);
Serial.print("/20");
if (annee<10) Serial.print("0");
Serial.println(annee);

display.clearDisplay();
display.setTextSize(1); 
display.setCursor(0, 0);
if (hr<10) display.print("0");
display.print(hr);
display.print(":");
if (mnt<10) display.print("0");
display.print(mnt);
display.print(":");
if (sec<10) display.print("0");
display.print(sec);
display.setCursor(0, 16);
if (mjour<10) display.print("0");
display.print(mjour);
display.print("/");
if (mois<10) display.print("0");
display.print(mois);
display.print("/20");
if (annee<10) display.print("0"); 
display.print(annee);
display.display(); 
}
}

void setup()
{
Serial.begin(115200);
delay(10);
Serial.println("");
pinMode(BTN_RED_PIN, INPUT_PULLUP);
pinMode(BTN_WHITE_PIN, INPUT_PULLUP);
pinMode(BTN_BLUE_PIN, INPUT_PULLUP);

#ifdef ARDUINO_ARCH_ESP8266
Serial.println("ARDUINO_ARCH_ESP8266");
#elif defined ARDUINO_ARCH_ESP32
Serial.println("ARDUINO_ARCH_ESP32");
#else
Serial.println("ARDUINO_ARCH_UNKNOWN");
#endif

// hdc1080 info
hdc1080.begin(0x40);
Serial.print("Manufacturer ID=0x");
Serial.println(hdc1080.readManufacturerId(), HEX); // 0x5449 ID of Texas Instruments
Serial.print("Device ID=0x");
Serial.println(hdc1080.readDeviceId(), HEX); // 0x1050 ID of the device

// Enable I2C for ESP8266 NodeMCU boards [VDD to 3V3, GND to GND, nWAKE to D3, SDA to D2, SCL to D1]
//Wire.begin(4, 5);
Wire.begin();

Serial.println("CCS811 test");
// Enable CCS811
ccs811.set_i2cdelay(50); // Needed for ESP8266 because it doesn't handle I2C clock stretch correctly
bool ok = ccs811.begin();
if ( !ok ) Serial.println("setup: CCS811 begin FAILED");

// Print CCS811 versions
Serial.print("setup: hardware version: "); Serial.println(ccs811.hardware_version(), HEX);
Serial.print("setup: bootloader version: "); Serial.println(ccs811.bootloader_version(), HEX);
Serial.print("setup: application version: "); Serial.println(ccs811.application_version(), HEX);

// Start measuring
ok = ccs811.start(CCS811_MODE_1SEC);
if ( !ok ) Serial.println("init: CCS811 start FAILED");

byte n=0;
while(!display.begin(SSD1306_SWITCHCAPVCC, Addr_SSD1306) and n<10) { sleep(1000); n+=1; }

if(!display.begin(SSD1306_SWITCHCAPVCC, Addr_SSD1306)) { 
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}

display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE); // Draw white text
}


//Lecture Sonde
void read_cjmcu8124()
{
uint16_t new_eco2, new_etvoc, new_errstat, new_raw;
float new_hmd, new_temp; 
new_temp=float(hdc1080.readTemperature());
new_hmd=float(hdc1080.readHumidity());
if ((abs(last_hmd_for_co2-new_hmd)>5) or (abs(last_temp_for_co2-new_temp)>1))
{
Serial.print("CCS811: Réglage");
ccs811.set_envdata(new_temp, new_hmd); //inutile avec la version 201 du firmware (ou set_envdata210 ???)
last_hmd_for_co2=new_hmd;
last_temp_for_co2=new_temp;
delay(500);
}
ccs811.read(&new_eco2,&new_etvoc,&new_errstat,&new_raw);
/*
Serial.print("CCS811: Read : ");
Serial.println(new_eco2);
Serial.println(new_etvoc);
Serial.println(new_errstat);
Serial.println(new_raw);
Serial.println(CCS811_ERRSTAT_OK);
*/
if ( new_errstat == CCS811_ERRSTAT_OK ) 
{
new_temp+=temp_correction;
if ((hmd_correction+new_hmd<=100) and (hmd_correction+new_hmd>=0)) new_hmd+=hmd_correction;
temp=new_temp;
hmd=new_hmd;
eco2=new_eco2;
etvoc=new_etvoc;
} else if ( new_errstat == CCS811_ERRSTAT_OK_NODATA ) {
Serial.println("CCS811: waiting for (new) data");
} else if ( new_errstat & CCS811_ERRSTAT_I2CFAIL ) {
Serial.println("CCS811: I2C error");
} else {
Serial.print("CCS811: errstat="); Serial.print(new_errstat, HEX);
Serial.print("="); Serial.println( ccs811.errstat_str(new_errstat) );
}

last_time_data=millis();
Serial.println("Waiting...");
}

void display_sonde( byte refreshtime)
{
/* pas trop de relecture, ça perturbe la sonde*/
if (millis()-last_time_data>refreshtime * 1000) read_cjmcu8124();

if ((old_temp!=temp) or (old_hmd!=hmd) or (old_etvoc!=etvoc) or (old_eco2!=eco2))
{
old_temp=temp;
old_hmd=hmd;
old_etvoc=etvoc;
old_eco2=eco2;

Serial.print("\n\ntemperature: ");
Serial.print(temp);
Serial.print(" C");

Serial.print("\nhumidity: ");
Serial.print(hmd);
Serial.print(" %");

Serial.print("\neCO2 concentration: ");
Serial.print(eco2);
Serial.print(" ppm");

Serial.print("\nTVOC concentration: ");
Serial.print(etvoc);
Serial.print(" ppb");

display.clearDisplay();
display.setTextSize(1); 

display.setCursor(0, 0);
display.print("T ");
display.print(temp,2);
display.print("C Hmd ");
display.print(hmd,2);
display.print("%");

display.setCursor(0, 16);
display.print("CO2 ");
display.print(eco2,0);
if ((etvoc<1000) and (eco2<1000)) { display.print("ppm TVOC "); }
else { display.print(" TVOC "); }
display.print(etvoc,0);

display.display();
}
}

/*si appuie du bouton bleu, on change d'affichage : Time (0) ou CO2 (1)*/
void swap_display()
{
if (get_btn_status(BTN_BLUE_PIN)==1)
{
Serial.println("Btn BLUE");
if (typeaff==0) typeaff=1;
else typeaff=0;
}
}

//Bouton rouge, appuie long (> 1 sec) pour passer en mode settings et en sortir
//ne rien faire en mode affichage sonde
void swap_settings_mode()
{
if (typeaff==1) return;
byte btn_status=get_btn_status(BTN_RED_PIN);
if (btn_status==2)
{
if (settings_mode>0) 
{
Serial.println("Sortie du mode settings");
settings_mode=0;
typeaff=0;
}
else
{
Serial.println("Entré mode settings");
settings_mode=1;/*afficher heure et permettre le réglage*/
}
}
if ((btn_status==1) and (settings_mode>0))
{
settings_mode=(settings_mode+1)%7;
typeaff=0;
}
}

/************************************************/
/*détecter le bouton enfoncé et combien de temps*/
/* 0 : pas d'apuie, 1 : court, 2 : long
/************************************************/
byte get_btn_status(byte BTN_PIN)
{
boolean btn_is_up=true;
long btn_time_on=0;
long btn_enlapsed_on=0;

btn_is_up = digitalRead(BTN_PIN);
/*******************************************************/
if (!btn_is_up) 
{
btn_time_on=millis();
while (!btn_is_up) { delay(10); btn_is_up = digitalRead(BTN_PIN); }
btn_enlapsed_on=millis()-btn_time_on;
}
if (btn_enlapsed_on<10) return 0;
if (btn_enlapsed_on<1000) return 1;
if (btn_enlapsed_on>=1000) return 2;
}




void reglage()
{
bool first_disp=false;
byte red_btn_status=0;
if (settings_mode==0) return;
display.clearDisplay();
display.setTextSize(2); 
display.setCursor(20, 0);
read_DS3231time(); 
/*******************************************************/
while (settings_mode==1) /* réglage heure */
{
if (!first_disp)
{
display.clearDisplay();
display.setCursor(10, 0);
display.print("Hr ");
if (hr<10) display.print("0");
display.print(hr);
display.display();
first_disp=true;
}
if (get_btn_status(BTN_BLUE_PIN)==1)
{
read_DS3231time(); 
if (int(hr)+1<=23) { hr+=1; }
else { hr=0; }
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
if (get_btn_status(BTN_WHITE_PIN)==1)
{
read_DS3231time(); 
if (int(hr)-1>=0) { hr-=1; }
else { hr=23; }
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
red_btn_status=get_btn_status(BTN_RED_PIN);
if (red_btn_status==1) 
{
settings_mode=2;
first_disp=false; 
}
if (red_btn_status==2) 
{
settings_mode=0;
typeaff=0;
}
}
/*******************************************************/
while (settings_mode==2) /* minute */
{
if (!first_disp)
{
display.clearDisplay();
display.setCursor(10, 0);
display.print("Min "); 
if (mnt<10) display.print("0");
display.print(mnt);
display.display();
first_disp=true;
}
if (get_btn_status(BTN_BLUE_PIN)==1)
{
read_DS3231time(); 
if (int(mnt)+1<60) { mnt+=1; }
else { mnt=0; }
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
if (get_btn_status(BTN_WHITE_PIN)==1)
{
read_DS3231time(); 
if (int(mnt)-1>=0) { mnt-=1; }
else { mnt=59; }
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
red_btn_status=get_btn_status(BTN_RED_PIN);
if (red_btn_status==1) 
{
settings_mode=3;
first_disp=false; 
}
if (red_btn_status==2) 
{
settings_mode=0;
typeaff=0;
}
} 

/*******************************************************/
while (settings_mode==3) /* secondes */
{
if (!first_disp)
{
display.clearDisplay();
display.setCursor(10, 0);
display.print("Sec "); 
if (sec<10) display.print("0");
display.print(sec);
display.display();
first_disp=true;
}
/*******************************************************/
if (get_btn_status(BTN_BLUE_PIN)==1)
{
read_DS3231time(); 
sec=0; /*même action que le bouton bleu*/
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
if (get_btn_status(BTN_WHITE_PIN)==1)
{
read_DS3231time(); 
sec=0; /*même action que le bouton bleu*/
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
red_btn_status=get_btn_status(BTN_RED_PIN);
if (red_btn_status==1) 
{
settings_mode=4;
first_disp=false; 
}
if (red_btn_status==2) 
{
settings_mode=0;
typeaff=0;
}
} 
/*******************************************************/
while (settings_mode==4) /* jour */
{
if (!first_disp)
{
display.clearDisplay();
display.setCursor(10, 0);
display.print("Jr "); 
if (mjour<10) display.print("0");
display.print(mjour);
display.display();
first_disp=true;
}
/*******************************************************/
if (get_btn_status(BTN_BLUE_PIN)==1)
{
read_DS3231time(); 
mjour=addday(1,mjour,mois,annee);
sjour=int(sjour+1)%7;
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
if (get_btn_status(BTN_WHITE_PIN)==1)
{
read_DS3231time(); 
mjour=addday(-1,mjour,mois,annee);
sjour=int(sjour-1)%7;
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
red_btn_status=get_btn_status(BTN_RED_PIN);
if (red_btn_status==1) 
{
settings_mode=5;
first_disp=false; 
}
if (red_btn_status==2) 
{
settings_mode=0;
typeaff=0;
}
} 
/*******************************************************/
while (settings_mode==5) /* mois */
{
if (!first_disp)
{
display.clearDisplay();
display.setCursor(5, 0);
display.print("Mois "); 
if (mois<10) display.print("0");
display.print(mois);
display.display();
first_disp=true;
}
/*******************************************************/
if (get_btn_status(BTN_BLUE_PIN)==1)
{
read_DS3231time(); 
if (int(mois)+1<=12) { mois+=1;}
else { mois=1;}
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
if (get_btn_status(BTN_WHITE_PIN)==1)
{
read_DS3231time(); 
if (int(mois)-1>0) { mois-=1;}
else { mois=12;}
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
red_btn_status=get_btn_status(BTN_RED_PIN);
if (red_btn_status==1) 
{
settings_mode=6;
first_disp=false; 
}
if (red_btn_status==2) 
{
settings_mode=0;
typeaff=0;
}
}

/*******************************************************/
while (settings_mode==6) /* annee */
{
if (!first_disp)
{
display.clearDisplay();
display.setCursor(2, 0);
display.print("Annee 20"); 
if (annee<10) display.print("0");
display.print(annee);
display.display();
first_disp=true;
}
/*******************************************************/
if (get_btn_status(BTN_BLUE_PIN)==1)
{
read_DS3231time(); 
if (annee+1<=99) { annee+=1;}
else { annee=0; }
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
if (get_btn_status(BTN_WHITE_PIN)==1)
{
read_DS3231time(); 
if (int(annee)-1>=0) { annee-=1;}
else { annee=99; }
set_DS3231time(sec, mnt, hr, sjour, mjour, mois, annee);
first_disp=false; 
}
/*******************************************************/
red_btn_status=get_btn_status(BTN_RED_PIN);
if (red_btn_status==1) 
{
settings_mode=1;
first_disp=false; 
}
if (red_btn_status==2) 
{
settings_mode=0;
typeaff=0;
}
} 
}

void loop()
{
//Serial.print("settings_mode:");
//Serial.println(settings_mode);
//Serial.print("typeaff:");
//Serial.println(typeaff);

if (settings_mode==0)
{
display.setTextSize(1); 
if (typeaff==0) 
{ 
Serial.println("display date time"); 
displaydatetime(1);
}
if (typeaff==1) 
{ 
Serial.println("display co2"); 
display_sonde(3);
}
swap_display(); 
}
else reglage();
Serial.println("Waiting...");
swap_settings_mode();
delay(250); 
}

Laisser un commentaire

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

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.