In questo capitolo della guida ci concentreremo sulla rilevazione dei fulmini della nostra stazione meteo basata sul sensore AS3935 e sul microcontrollore ESP8266.
La domanda che sorge spontanea è: come mai non gestiamo tutto con la scheda ESP32? Per una questione di semplicità di codice.
Il sensore è in grado di captare i disturbi radioelettrici causati dallo scoccare di archi e tramite un’opportuna elaborazione riesce a fornire un segnale che corrisponde al rilevamento di un fulmine e alla sua intensità. Per fare tutto ciò il microcontrollore rimane sempre in ascolto quindi inserire la parte di codice relativa alla rilevazione dei fulmini tra le righe già viste per gli altri sensori cominciava a risultare molto complesso.
Chiarito questo aspetto, andiamo ora a vedere la parte di programmazione relativa all’ESP8266 ed al sensore AS3935.
Al termine dell’articolo sarà possibile scaricare il file con il codice completo.
Iniziamo includendo le librerie necessarie:
#include <SPI.h> //per il traferimento dei dati via SPI
#include <AS3935.h> //per gestire il sensore AS3935
#include <ESP8266WiFi.h> //per gestire WifiClientSecure (collegamento a www.nome_sito.it)
#include <WiFiClient.h> //per gestire la connessione alla rete Wifi
#include "SafeString.h" //per gestire le stringhe
Dedichiamo qualche riga per parlare della libreria SafeString che merita sicuramente qualche attenzione in più. La classe String normalmente utilizzata in Arduino utilizza una grande quantità di memoria e tende a causare svariati problemi su progetti di una certa dimensione. In una piccola scheda MCU con poca memoria a disposizione l’utilizzo della classe String, a causa dell’allocazione e riallocazione dinamica della memoria, porta quasi sempre a grossi problemi.
Per evitare tutto questo abbiamo deciso di utilizzare SafeString come valida alternativa.
Come primo passo dichiariamo le informazioni necessarie per collegarsi alla rete wifi e al client per la trasmissione dei dati:
//dati per la connessione alla rete Wifi
const char* MY_SSID = "nome_rete_wifi";
const char* MY_PWD = "password_rete_wifi";
//dati per la connessione ad www.nome_sito.it
const char* host = "www.nome_sito.it";
const uint16_t port = 443;
Procediamo quindi a dichiarare tutte le variabili utili per il settaggio dei vari sensori:
//dichiarazione variabili
createSafeString(urlvariabile, 200); //oggetto SafeString di lunghezza 200 caratteri
createSafeString(urlcaricamento, 250); //oggetto SafeString di lunghezza 250 caratteri
//dati sensore fulmini AS3935
int valore_calibrazione; //valore calibrazione
void printAS3935Registers(); //funzione che rileva e stampa i parametri del sensore (rumore di fondo, spike rejection, soglia di controllo)
byte SPItransfer(byte sendByte); //funzione che si occupa del traferimento dei dati via SPI
void AS3935Irq(); //funzione che verifica se ci sono disturbi o fulmini e causa l'interrupt
AS3935 AS3935(SPItransfer,D2,D1); //primo parametro: funzione per il trasferimento dei dati via SPI
//secondo parametro: pin CS collegato alla scheda
//terzo parametro: pin IRQ collegato alla scheda
//variabili per i tempi di ciclo per l'invio dei dati
unsigned long tempo_start_invio_dati;
unsigned long intervallo_invio_dati;
//variabili rilevamento sensore
float numero_fulmini; //numero fulmini rilevati
float distanza_fulmini; //distanza fulmini
float disturbi_rilevati; //numero disturbi rilevati
E’ arrivato finalmente il momento di dedicarci alla parte di codice void setup(), ovvero al codice che viene processato solo una volta quando la scheda viene accesa ed alimentata.
Inizializziamo tutte le variabili che vogliamo monitorare ovvero numero_fulmini, distanza_fulmini e disturbi_rilevati. Dopodiché impostiamo l’invio dei dati raccolti ogni 600000 millisecondi, ovvero ogni 10 minuti, ed eseguiamo la connessione alla rete wifi (il sistema tenterà di connettersi alla rete ogni 1000 millisecondi fino alla buona riuscita dell’operazione) tramite la funzione connectWifi() che vedremo tra poco.
Non rimane altro che settare tutti i parametri di funzionamento del sensore AS3935 come riportato di seguito:
void setup()
{
//inizializzazione delle variabili rilevamento sensore
numero_fulmini = 0; //numero fulmini rilevati
distanza_fulmini = 0; //distanza fulmini
disturbi_rilevati = 0; //numero disturbi rilevati
//settaggio dei tempi di ciclo per l'invio dei dati
tempo_start_invio_dati = millis();
intervallo_invio_dati = 600000; //effettuiamo l'invio dei dati ogni 600 secondi (10 minuti)
//connessione Wifi
connectWifi();
//setup sensore fulmini AS3935
SPI.begin();
SPI.setDataMode(SPI_MODE1);
SPI.setClockDivider(SPI_CLOCK_DIV16);
SPI.setBitOrder(MSBFIRST);
AS3935.reset(); //ripristina tutti i valori di registro interni ai valori predefiniti
delay(100);
AS3935.setOutdoors(); //setta il sensore per il funzionamento all'esterno
AS3935.registerWrite(AS3935_NF_LEV,2); //scrive 2 nel Noise Level register
valore_calibrazione=AS3935.registerRead(AS3935_TUN_CAP); //il range è compreso tra 0 e 15
AS3935.enableDisturbers(); //attiva la rilevazione dei disturbi, è possibile disattivare questa funzione con disableDisturbers()
printAS3935Registers(); //rileva e stampa i parametri del sensore (rumore di fondo, spike rejection, soglia di controllo)
attachInterrupt(digitalPinToInterrupt(D1), AS3935Irq, RISING);
//usare interrupt significa che non serve controllare lo stato del pin continuamente, lo fa il chip da solo
}
Ci dedichiamo ora al cuore vero e proprio del programma ovvero alla sezione void loop(): questa parte viene eseguita continuamente dalla scheda fino al suo spegnimento (salvo problemi).
Trascorsi i 10 minuti procediamo ad aggiornare la variabile tempo_start_invio_dati = millis() ed effettuiamo il corretto collegamento all’host. Successivamente andiamo a calcolare la variabile distanza_fulmini come rapporto tra distanza_fulmini totale ed il numero_fulmini rilevati ottenendo così una distanza media dei fulmini monitorati nell’intervallo di tempo.
Fatta questa semplice operazione (previa verifica per evitare divisioni per 0) tutti i dati sono pronti ed il sistema invia i valori al database mysql tramite la pagina web aggiungi_fulmini.php ed utilizzando il metodo GET, ovvero indicando i dati all’interno del link per ogni singola variabile.
Infine azzeriamo le nostre 3 variabili di interesse per iniziare altri 10 minuti di rilevamenti.
void loop()
{
if ((millis()-tempo_start_invio_dati) > intervallo_invio_dati){
tempo_start_invio_dati = millis();
//collegamento all'host www.nome_sito.it
WiFiClientSecure client;
client.setInsecure(); //non si utilizzano certificati di sicurezza
//verifica se il collegamento non è andato a buon fine
if (!client.connect(host, port)) {
delay(5000);
return;
}
//se la connessione all'host www.nome_sito.it è avvenuta
if (client.connected()) {
if (numero_fulmini != 0) { //verifica se numero_fulmini è diverso da 0 per non effettuare una divisione per 0
distanza_fulmini = distanza_fulmini / numero_fulmini;
} else {
distanza_fulmini = 0;
}
urlvariabile = "numero_fulmini=";
urlvariabile += numero_fulmini;
urlvariabile += "&distanza_fulmini=";
urlvariabile += distanza_fulmini;
urlvariabile += "&disturbi_rilevati=";
urlvariabile += disturbi_rilevati;
urlcaricamento = "GET /aggiungi_fulmini.php?";
urlcaricamento += urlvariabile;
urlcaricamento += " HTTP/1.1";
//invio url all'host www.nome_sito.it per il salvataggio dei dati sul database mysql
client.println(urlcaricamento);
client.println("Host: www.nome_sito.it");
client.println("Access-Control-Allow-Origin: *");
client.println("Connection: close");
client.println();
delay(500); //delay fondamentale altrimenti a volte chiude la connessione prima che la pagina sia stata correttamente interrogata
client.stop();
}
//azzeramento delle variabili per il prossimo ciclo di rilevamento
numero_fulmini=0;
distanza_fulmini=0;
disturbi_rilevati=0;
}
}
Nel codice descritto fino ad ora abbiamo utilizzato 4 funzioni che adesso andiamo ad analizzare una per una.
La prima è printAS3935Registers(), funzione che rileva e stampa i parametri del sensore (rumore di fondo, spike rejection, soglia di controllo):
void printAS3935Registers()
{
int noiseFloor = AS3935.getNoiseFloor();
int spikeRejection = AS3935.getSpikeRejection();
int watchdogThreshold = AS3935.getWatchdogThreshold();
}
Un’altra funzione, molto semplice, è SPItransfer() che si occupa del traferimento dei dati via SPI:
byte SPItransfer(byte sendByte)
{
return SPI.transfer(sendByte);
}
Una funzione decisiva per il nostro progetto è AS3935Irq() che si occupa di verificare cosa ha causato l’interrupt:
ICACHE_RAM_ATTR void AS3935Irq()
{
//appena leggiamo l'interrupt, il pin IRQ diventa LOW
int irqSource = AS3935.interruptSource(); //restituisce bit 0: livello rumore troppo alto
// bit 2: rilevato disturbo
// bit 3: rilevato fulmine
if (irqSource & 0b0100){ //rilevato disturbo
disturbi_rilevati=disturbi_rilevati+1; //aumenta di 1 il contatore dei disturbi rilevati
}
if (irqSource & 0b1000){ //rilevato fulmine
int distanza_fulmine = AS3935.lightningDistanceKm(); //determina la distanza del fulmine in km
if (distanza_fulmine < 41 && distanza_fulmine > 0) //40 km è la distanza di rilevamento massima
{
numero_fulmini= numero_fulmini+1; //aumenta di 1 il contatore dei fulmini rilevati
distanza_fulmini=distanza_fulmini+distanza_fulmine; //somma tutte le distanze dei fulmini rilevati per fare al termine del ciclo una media
}
}
}
La prima cosa che balza all’occhio è la dicitura ICACHE_RAM_ATTR che ha lo scopo di caricare la funzione nella ram invece che nella flash. Senza questa operazione gli interrupt non funzionano con ESP8266.
La funzione AS3935.interruptSource() ci restituisce bit 0 se il livello di rumore è troppo alto, bit 2 se viene rilevato un disturbo e bit 3 nel caso di rilevamento di un fulmine.
La funzione quindi, sulla base del caso individuato, conteggia i disturbi, il numero di fulmini e le distanze per poi calcolarne la media.
Infine, semplice ma fondamentale, non ci rimane altro che vedere la funzione connectWifi() che si occupa della connessione alla rete wifi per l’invio dei dati:
void connectWifi()
{
WiFi.begin(MY_SSID, MY_PWD);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
}
}
Il file contenente il codice completo è disponibile cliccando qui ma ricordate di modificare i valori relativi alla vostra rete wifi ed al vostro sito web che ospita la pagina aggiungi_fulmini.php.
