Détecteur d’orage avec un nodemcu et un AS3935

Pour compléter la station météo, il était important d’avoir un détecteur de foudre. Couplée à un webservice qui enverra les données sur le site, nous pourrons avoir un vrai historique de l’activité orageuse autour de la maison.

Matériel

Pour réaliser ce projet, j’ai d’abord choisi le nodemcu pour son côté sans fil wifi, qui permettra de le positionner presque n’importe où dans la maison. Ensuite, pour le détecteur d’orage, je me suis basé sur le module AS3935 produit par Sparkfun.

Branché en I2C, ce module a une connectique et un fonctionnement simple : on branche le module en I2C, on branche la pin IRQ sur un port d’interruption du nodemcu et c’est parti. A chaque détection de foudre, une interruption est levée sur la pin choisie (D8 ici) et le programme affiche alors la distance et l’énergie de l’impact.

Câblage AS3935 – Nodemcu:

  • VCC (V) – 3V
  • GND(G) – GND
  • SCL (CL) – D1
  • SDA (DA) – D2
  • MI – /
  • IRQ – D8
  • SI – 3V
  • CS – /

Attention : ne pas brancher l’IRQ sur les pin D3 et D4, ca fait planter le nodemcu et on ne peut pas téléverser le code.

Remarque : les pins d’interruptions du nodemcu sont de D0 à D8.

Le module AS3935

J’ai décidé d’ajouter 3 led au montage :

  • une verte, qui s’allume et clignote quand l’accès au webservice via le réseau est OK
  • une rouge, qui signale une erreur (module ou réseau)
  • une bleu, qui s’allume quand des orages sont détectés

Les 3 LEDS sont branchées sur les ports D5/D6/D7. J’ai soudé les 3 masses pour n’avoir qu’un seul fil à brancher.

Le montage complet

Pour la mise en boite, j’aime bien faire simple et utiliser des boites de dérivation, ça fait assez propre et les led sont faciles à encastrer (led de 5mm = mèche de 4,8mm).

Montage
La boite finie

Le code

Pour commencer, on va installer la librairie AS3935MI de Gregor Christandl qui marche directement sur Nodemcu. Un grand merci à lui. Les sources sont sinon ici.

Ensuite, une fois le câblage fait, il faut détecter l’adresse I2C du module. Vous pouvez le faire avec le scanner I2C Arduino.

Mon module est en 0x03. Par défaut, la librairie de Gregor est configurée pour 0x01. Pour mettre 0x03 en adresse, il faut passer la variable AS3935I2C::AS3935I2C_A11 au lieu de AS3935I2C::AS3935I2C_A01.

AS3935I2C as3935(AS3935I2C::AS3935I2C_A11, PIN_IRQ);
//0x01 = AS3935I2C_A01
//0x02 = AS3935I2C_A10
//0x03 = AS3935I2C_A11

Comme sur nos autres programmes, il faut paramétrer le wifi du module et la clé du webservice.

const char* ssid = "xxxxx";
const char* password = "xxxxx";
char server[] = "192.168.1.2";  
WiFiClient client;
String KEY_WS="45698753349560223"; 

Puis on initialise les variables d’orage et les variables pour la boucle d’envoi du webservice.

int storm = 0;
int dist = 0;
int energy = 0;

unsigned long previousMillis=   0;
unsigned long delaiProgramme =  60000L;   //60 sec

Dans le setup, pour identifier le démarrage du programme, je fais une séquence d’affichage/extinction des LED.

  pinMode(LED_TRANSMISSION, OUTPUT); 
  pinMode(LED_STORM, OUTPUT);
  pinMode(LED_ERROR, OUTPUT);

  digitalWrite(LED_TRANSMISSION, HIGH);
  digitalWrite(LED_STORM, HIGH);
  digitalWrite(LED_ERROR, HIGH);

  delay(1000);

  digitalWrite(LED_TRANSMISSION, LOW);
  digitalWrite(LED_STORM, LOW);
  digitalWrite(LED_ERROR, LOW);

Une fois connecté au wifi (je ne re-détaille pas le code, voir ici), je refais une séquence de led pour valider qu’on est connecté.

//sequence led reseau OK
  digitalWrite(LED_TRANSMISSION, HIGH);
  delay(500);
  digitalWrite(LED_TRANSMISSION, LOW);
  delay(500);
  digitalWrite(LED_TRANSMISSION, HIGH);
  delay(500);
  digitalWrite(LED_TRANSMISSION, LOW);
  delay(500);

Sur le code de l’initialisation de l’AS3935, je n’ai pas touché grand chose si ce n’est 2 paramètres : le mode indoor/outdoor que j’ai mis indoor et le nombre de détection avant de déclencher l’interruption (5 ici, 1 par défaut, choix entre 1/5/9/16)

as3935.writeAFE(AS3935MI::AS3935_INDOORS);
  //outdoor = AS3935_OUTDOORS
...
as3935.writeMinLightnings(AS3935MI::AS3935_MNL_5);
  //AS3935_MNL_1 or AS3935_MNL_5 or AS3935_MNL_9 or AS3935_MNL_16

A l’intérieur du loop, je ne touche presque rien au code original. Dans l’interruption, j’ajoute ceci : l’incrément de la variable storm qui compte le nombre d’impacts, la distance et l’énergie du dernier impact. Je fais clignoter la led bleu et la laisser allumer.

else if (event == AS3935MI::AS3935_INT_L)
		{     
			Serial.print("Lightning detected! Storm Front is ");
			Serial.print(as3935.readStormDistance());
			Serial.println("km away.");

      dist = as3935.readStormDistance();
      energy = as3935.readEnergy();
      storm += 1;
      digitalWrite(LED_STORM, HIGH);
      delay (250);
      digitalWrite(LED_STORM, LOW);
      delay (250);
      digitalWrite(LED_STORM, HIGH);
     
}

Puis j’ajoute le traditionnel appel à webservice pour envoyer les valeurs au serveur. A la fin de la séquence, je remet à zéro et variable et éteint la led bleu. Elle se rallumera si un nouvel impact est détecté. La led n’est donc allumé que pendant la minute où l’impact est détecté.

unsigned long currentMillis = millis();      
   if (currentMillis - previousMillis > delaiProgramme){
     previousMillis = millis();     

      String url = "/stationmeteo/storm.php?key="+KEY_WS+"&storm="+storm+"&distance="+dist+"&energy="+energy;
    
      HTTPClient http;  
      String Link = "http://192.168.1.2:81"+url;
      
      http.begin(Link); 
      
      int httpCode = http.GET();          
      String payload = http.getString();  
     
      Serial.println(httpCode);   
      Serial.println(payload);  

      if(httpCode != 200){
        digitalWrite(LED_TRANSMISSION, LOW);
        digitalWrite(LED_ERROR, HIGH);
        
      }
      if(httpCode == 200){
        digitalWrite(LED_TRANSMISSION, HIGH);
        delay (250);
        digitalWrite(LED_TRANSMISSION, LOW);
        delay (250);
        digitalWrite(LED_TRANSMISSION, HIGH);
        digitalWrite(LED_ERROR, LOW);
      }     
      http.end(); 

    //RAZ valeurs
    storm = 0;
    dist = 0;
    energy = 0;
    digitalWrite(LED_STORM, LOW);
   }

Le webservice est quand à lui tout simple : il loggue le résultat courant dans un fichier texte sur le serveur et historique le résultat dans un fichier journalier. L’ensemble est récupéré alors par un autre script qui traitera les données.

<?php
$REFKEY = '45698753349560223';

if(isset($_GET['key'])){
	$key = $_GET['key'];
	if($key == $REFKEY){
		if(isset($_GET['storm'])){
			$storm = $_GET['storm'];
			$dist = $_GET['distance'];
			$energy = $_GET['energy'];
			$file = 'storm.txt';
			$line = $storm.';'.$dist.';'.$energy;
			file_put_contents($file, $line);
			echo 'data added to '.$file;

			$folder = 'datas/'.date('Y').'/'.date('m').'/';
			$file = $folder.date('Ymd').'_storm.txt';
			$date = date('Y-m-d H:i');
			$line = $date.';'.$storm.';'.$dist.';'.$energy;
			$line .= "\n";	
			file_put_contents($file, $line, FILE_APPEND);
			echo 'data added to '.$file;
		}
	}
	else{
		echo 'Mauvaise clé utilisée';
	}
}
else{
	echo 'Erreur formatage URL';
}
?>

Le code complet est à retrouver sur Github.

Conclusion

J’ai trouvé peu de ressources pour faire ce projet, et j’ai pas mal galéré pour avoir un truc stable. Mais je suis content du résultat et de la fiabilité du module. J’ai eu quelques faux positifs en test, j’avoue être impatient qu’il y ait des orages pour le tester 🙂

9 Comments

Laisser un commentaire

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