Vedremo come utilizzare Wemos D1 Mini Lite ESP8266 come un Voltmetro Wifi, avremo la possibilità di poter misurare da remoto una tensione tra 0 e 12V. Questo è utile se ci occorre controllare lo stato di carica della batteria di un camper o dell’auto o se vogliamo acquisire un segnale di tensione proveniente da un sensore (esempio: temperatura, umidità, luminosità, ecc).
Il server privato di Blynk riceverà i dati acquisti dalla scheda e che poi verranno inviati all’applicazione installata sul nostro smartphone.
Qui sotto ho inserito uno schema di come sarà il nostro Voltmetro Wifi.

Per questo nuovo progetto saranno necessari:
- Wemos D1 Mini Lite
- Resistenza 1MΩ
- Cavi Dupont Maschio Femmina
- Battery Pack Usb o CaricaBatteria “Solare”
In qualità di affiliato Amazon io ricevo un guadagno dagli acquisti idonei. A voi non costerà nulla di più e avrete modo di supportare così il mio lavoro. Grazie.
L’ESP8266 possiede al suo interno un Convertitore Analogico Digitale (ADC) a 10 bit che può convertire la tensione analogica da 0 a 1V in 1024 valori digitali compresi tra 0 e 1023.
Sul PCB del Wemos D1 Mini è già presente un partitore di tensione che ci permette di misurare tensioni fino a 3.3V, ma non è sufficiente per misurare tensioni maggiori come quelle di una batteria LiPo (3.7V) , di un battery Pack USB (5V) o di una batteria per auto/moto(12V). Qui sotto è rappresentato il pinout della scheda Wemos da dove si nota che il pin A0 è l’unico ingresso analogico.

Partitore di Tensione
Possiamo vedere lo schema elettrico della scheda sul sito ufficiale.
Vediamo che il partitore interno è composto da due resistenze: R1 = 220 KΩ e R2 = 100 KΩ ,
questo permette che sul pin A0 ci sia una tensione di 3.3V e all’ingresso dell’ADC 1V.

Ricordo la formula generica del partitore di tensione :

Per misurare tensioni superiori bisogna modificare il partitore presente aggiungendo in serie a R1 un’ulteriore Resistenza esterna.
La tensione sull’ADC interno all’ESP8266 sarà uguale alla Vout calcolata qui sotto:

Ma come si calcola la Resterna??? Vi risparmio tutti i passaggi e vi indico la formula matematica finale:

Ipotizzando una tensione massima misurabile Vin:
- Vin=5V e Vout=1 ottengo una Resterna da 180KOhm.
- Vin=12V e Vout=1 ottengo una Resterna da 880KOhm.
- Vin=18V e Vout=1 ottengo una Resterna da 1480KOhm.
- Vin=24V e Vout=1 ottengo una Resterna da 2080KOhm.
- Vin=32V e Vout=1 ottengo una Resterna da 2880KOhm
Questi sono valori teorici matematici, poi la realtà è sempre diversa! Vediamo se una comune resistenza da 1MOhm può andare bene lo stesso per misurare 12V:



Avremo che la tensione Vout presente all’ingresso dell’ADC sarà di circa 0,91Volt.
Quindi con una resistenza esterna da 1MΩ siamo sicuri di non causare problemi al microcontrollore perché lavoriamo nell’intervallo delle tensioni consentite, 0V<Vout<0,91V<1V
La vera tensione che ci interessa misurare Vin è calcolata in questo modo:

Quando la tensione sarà di 0,91V l’ADC attribuirà il valore di campionamento pari a 1023, quando la tensione sarà 0 il valore di campionamento sarà 0.
raw = analogRead(A0); // è il campione preso dall'ADC e può valere da 0 a 1023 compresi. se raw è 1023 la tensione è 0,91V , se raw è 0 la tensione è 0V
volt = raw /1023;
volt = volt / 0.07575; // divido per rapporto di conversione trovato dalla formula del partitore
Risparmio Energetico
Per questa tipologia di progetti dove la nostra scheda è alimentata da una batteria esterna e che le operazioni compiute terminano dopo solo una decina di secondi, si possono minimizzare i consumi elettrici facendo “addormentare” la scheda. Così facendo si allunga l’autonomia della batteria di alimentazione.
Nello specifico il Voltmetro Wifi controllerà la tensione in alcuni momenti della giornata questo per evitare di scaricare velocemente il battery pack usb che lo alimenta.
Per arrivare a questo obiettivo bisogna attivare la modalità DeepSleep del Wemos D1 Mini, questa garantisce consumi più bassi rispetto le altre due modalità, come indicato dal manuale del produttore:

In questa modalità, il chip disattiverà la connettività Wi-Fi e la connessione dati, rimane solo funzionante il modulo RTC, cioè “l’orologio interno” che sarà il responsabile
della sveglia. Per abilitare la modalità DeepSleep serve la seguente riga di codice nel nostro sketch:
ESP.deepSleep(durataTemporale);
la funzione necessita di una durata temporarel per cui l’ESP8266 si risveglierà dalla modalità di sonno profondo.
Il tempo massimo nel sonno profondo è 4.294.967.295 µs, ovvero circa 71 minuti. Se volete un tempo ancora più grande potete usare questo comando:
ESP.deepSleep(ESP.deepSleepMax());
Così facendo si ottiene una durata (sempre diversa) che si aggira su 14270595065μs –> 14270s–> circa 4 ore!
Dopo questo tempo, l’ESP8266 verrà riattivato da un impulso di ripristino dal pin D0 (GPIO16), che è definito appunto come linea di riattivazione.
Serve connettere fisicamente D0 con RST.

Configurazione dell’applicazione su Blynk del Voltmetro Wifi
Dopo esservi loggati sulla vostra applicazione di Blynk potete cliccare in alto a destra come mostrato nell’immagine qui sotto per importare un clone del progetto.

Basta inquadrare il codice QR mostrato qui sotto per avere già tutto pronto:

Se tutto è andato per il meglio l’interfaccia grafica si presenterà in questo modo:

Ho inserito la data e l’ora dell’ultima acquisizione fatta in modo da capire se la scheda sta effettivamente inviando dati al server di Blynk.
Codice dello sketch del Voltmetro Wifi
Qui potete copiare il programma e adattarlo alla vostre esigenze.
// Collega RST al pin D0 del Wemos!
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <TimeLib.h>
#include <time.h>
#include <Timezone.h> // https://github.com/JChristensen/Timezone
char auth[] = "VostroToken"; //token progetto server Blynk
char ssid[] = "VostraReteWifi";
char pass[] = "VostraPasswordWifi";
unsigned int raw = 0;
float volt = 0.0;
String voltString = "";
String currentDate = "";
const int sleepTimeS = 60; // Time to sleep (in seconds):
WiFiUDP ntpUDP;
int GTMOffset = 0; // SET TO UTC TIME
NTPClient timeClient(ntpUDP, "it.pool.ntp.org", GTMOffset * 60 * 60, 60 * 60 * 1000);
// Central European Time (Frankfurt, Paris)
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; // Central European Summer Time
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; // Central European Standard Time
Timezone CE(CEST, CET);
static tm getDateTimeByParams(long time) {
struct tm *newtime;
const time_t tim = time;
newtime = localtime(&tim);
return *newtime;
}
/**
Input tm time format and return String with format pattern
*/
static String getDateTimeStringByParams(tm *newtime, char* pattern = (char *)" %H:%M:%S %d/%m/%Y") {
char buffer[30];
strftime(buffer, 30, pattern, newtime);
return buffer;
}
/**
Input time in epoch format format and return String with format pattern
*/
static String getEpochStringByParams(long time, char* pattern = (char *)" %H:%M:%S %d/%m/%Y") {
tm newtime;
newtime = getDateTimeByParams(time);
return getDateTimeStringByParams(&newtime, pattern);
}
void setup() {
Serial.begin(115200);
pinMode(A0, INPUT);
Serial.println("Mi sono svegliato");
leggiTensione();
Serial.println("tensione letta al setup"); //per debug
Serial.println(voltString); //per debug
Blynk.begin(auth, ssid, pass, IPAddress(x, y, z, w), 8080); //al posto di x, y, z, w mettere il vostro ip del server Blynk
orologio();
}
void loop() {
Blynk.run();
//
Serial.println("tensione inviata dal loop"); //per debug
Serial.println(voltString); //per debug
Blynk.virtualWrite(V2, voltString);
Serial.println("data inviata nel loop"); //per debug
//Serial.println(currentDate); //per debug
Blynk.virtualWrite(V3, currentDate );
delay(250); //per connessione a blynk
Serial.println("mi addormento");
//ESP.deepSleep(sleepTimeS * 1000000); // nel caso volessi impostare una durata in secondi per il DeepSleep
Serial.println("max deep sleep: " + uint64ToString(ESP.deepSleepMax())); //per debug
ESP.deepSleep(ESP.deepSleepMax());//serve per avere la massima durata di sospensione
}
String leggiTensione() {
unsigned int x;
for (int i = 0; i < 100; i++) {
raw = analogRead(A0) - 5 ; //5 è un offset trovato collegando A0 a GND
volt = (raw + i * raw ) / (i + 1); //calcola il valore medio per 100 acquisizioni
yield(); //per evitare riavvi per causa del watchdog(WDT)
}
volt = raw /1023;
volt = volt / 0.07575; // divido per rapporto di conversione trovato dalla formula del partitore
voltString = String(volt);
return voltString;
}
String orologio() { // scarica l'ora del server ntp secondo il formato definito all'inizio
timeClient.begin();
delay ( 1000 );
if (timeClient.update()) {
unsigned long epoch = timeClient.getEpochTime();
setTime(epoch);
} else {
Serial.print ( "aggiornamento ora fallito" );
}
currentDate = String (getEpochStringByParams(CE.toLocal(now())));
Serial.println ( currentDate);
return currentDate;
}
String uint64ToString(uint64_t input) { //permette di stampare sul monitor seriale un uint64
String result = "";
uint8_t base = 10;
do {
char c = input % base;
input /= base;
if (c < 10)
c +='0';
else
c += 'A' - 10;
result = c + result;
} while (input);
return result;
}
Il codice è commentato in modo che sia di facile comprensione. Riepilogando velocemente:
Alla prima accensione, a wifi spento, viene invocata leggiTensione() che acquisisce 100 campioni di tensione e ne fa la media, calcolando poi la tensione reale.
Successivamente viene attivato il wifi, quindi la connessione al Blynk Server, viene scaricata l’ora corrente dall’ntp server. successivamente vengono inviati i valori della tensione e dell’ora.
Dopo la scheda si iberna. Dopo sleepTimeS secondi la scheda si sveglia e viene rieseguito il codice contenuto nel setup() e poi nel loop().
Concludendo: abbiamo costruito un voltmetro wifi che ci permette di controllare da remoto una tensione come quella di una batteria per auto/camper/moto. Abbiamo imparato anche come ibernare la scheda far risparmiare più energia possibile.