Articles récents
DOMOTIQUE : Détecteur d'ouverture porte de garage avec ESP32 et LORAWAN
Dans cet article, je vais vous montrer comment j'ai réalisé un détecteur d'ouverture de porte pour mon garage avec transmission de la détection LORA.
J'ai bien essayé de le faire en WIFI avec un raspberry Zero W, mais cette solution n'est pas assez stable (perte de réseau, plantage du raspberry). Donc j'ai opté pour l'utilisation d'un microcontrôleur (ESP32) et l'utilisation d'un protocole de transmission aérien fiable (LORA)
Principe
Je souhaite être averti lorsque la porte de mon garage est ouverte. En sachant qu'il est un peu écarté et donc que la réception WIFI n'est pas terrible. Et la bande passante en 433Mhz est très encombrée. Donc le protocole LORA en 868Mhz m'avait semblé une bonne solution. Pour cela j'utilise des modules RFM95.Pour la détection, j'ai opté pour le sonar HY-SRF05 qui va permettre de détecter la distance entre l'émetteur et un obstacle, la porte en l’occurrence, et donc de sa position ouverte ou fermée.
La tâche étant assez simple et répétitive, un microcontrôleur est tout indiqué pour notre petit système. J'ai choisi, l'ESP32.
Le matériel
Pour notre système il faudra donc:Le schéma de câblage
Pour l'émetteur du garage:
Pour le récepteur de la maison:
La réalisation
Voici quelques photos de la réalisation de l’émetteur du garage, au départ tests sur breadboard, puis construction sur d'une plaquette PCB de prototypage. Le tout dans un boite de dérivation électrique.Le code
On va distinguer trois parties: le code de l’émetteur, celui du récepteur de la maison et enfin celui de la mise à jour de la base de données pour mémoriser le changement de position.Code de l'émetteur du garage: L'émetteur mesure distance avec la porte et la transmet sur le réseau LORA.
/*********
Robert Dorigny le 14 février 2019
www.doritique.fr
*********/
#include (SPI.h) //remplacer les () par <>
#include (LoRa.h)
//define the pins used by the transceiver module
#define ss 5
#define rst 14
#define dio0 2
const unsigned int TRIG_PIN=13;
const unsigned int ECHO_PIN=12;
int counter = 0;
//Calcul de la distance en cm
int dist() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
const unsigned long duration= pulseIn(ECHO_PIN, HIGH);
return(duration/29/2);
}
void setup() {
//Initialisation entrées/sorties sonar
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
//Initialisation série
Serial.begin(115200);
while (!Serial);
Serial.println("LoRa Sender");
//setup LoRa transceiver module
LoRa.setPins(ss, rst, dio0);
//replace the LoRa.begin(---E-) argument with your location's frequency
//433E6 for Asia
//866E6 for Europe
//915E6 for North America
while (!LoRa.begin(866E6)) {
Serial.println(".");
delay(500);
}
// Change sync word (0xF3) to match the receiver
// The sync word assures you don't get LoRa messages from other LoRa transceivers
// ranges from 0-0xFF
LoRa.setSyncWord(0xF3);
Serial.println("LoRa Initializing OK!");
}
void loop() {
Serial.print("Sending packet: ");
Serial.println(counter);
//Send LoRa packet to receiver
LoRa.beginPacket();
LoRa.print("dpg: "); //distance porte garage
LoRa.print(dist());
LoRa.endPacket();
counter++;
delay(10000);
}
Code du récepteur de la maison: Le récepteur réceptionne la trame LORA et récupère la distance. Au bout de 3 dépassements du seuil, la porte est considérée comme ouverte et donc il y a mis à jour de la base de données avec une api en PHP; puis transmission d'un SMS (en utilisant l'api de l'opérateur Free).
/*********
Robert DORIGNY le 10 mars 2019
rdorigny@free.fr - www.doritique.fr
*********/
#include (WiFi.h) //remplacer les () par <>
#include (HTTPClient.h)
#include (SPI.h)
#include (LoRa.h)
#include "esp_system.h"
//Definition des pins du module de transmission
#define ss 5
#define rst 14
#define dio0 2
//Pour le wifi
const char* ssid = "votreréseau";
const char* password = "votremotdepasse";
int position=0; //Conserve en memoire la position de la porte, 0 pour fermee et 1 pour ouverte
int Mem[] = {0, 0, 0}; //Conserve en memoire les dernieres mesures
int Longueur_Seuil=300;
int cpt=0;
String LoRaData;
//Cette fonction initialise la variable position +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int Recup_position(){
if(WiFi.status()== WL_CONNECTED) //Check WiFi connection status
{
//Emission de la requete vers l'API
HTTPClient http;
//Recup dans la base de données
http.begin("http://www.votresite.fr/monapi.php?action=get&var=garage");
http.addHeader("Content-Type", "text/plain"); //Specify content-type header
int httpResponseCode = http.POST("POSTING from ESP32"); //Send the actual POST request
if(httpResponseCode>0)
{
String response = http.getString();
Serial.println(httpResponseCode); //Print return code
Serial.println("Position intiale:"+response);
return(String(response).toInt());
}
}
}
//Cette fonction est appelée lorsqu'un changement de position de la porte est détecté+++++++++++++++++++++++++++++++
void Send_Data(){
if(WiFi.status()== WL_CONNECTED) //Check WiFi connection status
{
//Emission de la requete vers l'API
HTTPClient http;
//Mise à jour de la base de données
http.begin("http://www.votresite.fr/monapi.php?action=set&var=garage&data="+String(position));
http.addHeader("Content-Type", "text/plain"); //Specify content-type header
int httpResponseCode = http.POST("POSTING from ESP32"); //Send the actual POST request
if(httpResponseCode>0)
{
String response = http.getString(); //Get the response to the request
Serial.println(httpResponseCode); //Print return code
Serial.println(response); //Print request answer
}
else
{
Serial.print("Error on sending POST: ");
Serial.println(httpResponseCode);
}
delay(2000);
//Envoi du SMS
String str="";
if (position==1)
str="ouverte";
else
str="fermée";
http.begin("https://smsapi.free-mobile.fr/sendmsg?user=codeuser&pass=clefreeK&msg=Porte%20garage%20"+str);
http.addHeader("Content-Type", "text/plain"); //Specify content-type header
httpResponseCode = http.POST("POSTING from ESP32"); //Send the actual POST request
if(httpResponseCode>0)
{
String response = http.getString(); //Get the response to the request
Serial.println(httpResponseCode); //Print return code
Serial.println(response); //Print request answer
}
else
{
Serial.print("Error on sending POST: ");
Serial.println(httpResponseCode);
}
http.end(); //Free resources
}
else
{
Serial.println("Perte de la connexion WIFI. Reboot automatique.");
esp_restart();
}
}
//Phase d'initialisation++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void setup() {
//initialize Serial Monitor
Serial.begin(115200);
delay(4000); //Délais nécessaire avant d'appeler le wifi
//Connexion au wifi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { //Check la connexion
delay(1000);
Serial.println("Tentative de connexion au WiFi...");
cpt++;
if (cpt>30)
{
Serial.println("Pas de connexion au wifi! Reboot automatique...");
esp_restart();
}
}
Serial.println("Connexion au réseau local wifi: OK!");
while (!Serial);
Serial.println("LoRa Receiver");
//setup position
position=Recup_position();
//setup LoRa transceiver module
LoRa.setPins(ss, rst, dio0);
//replace the LoRa.begin(---E-) argument with your location's frequency
//433E6 for Asia
//866E6 for Europe
//915E6 for North America
while (!LoRa.begin(866E6)) {
Serial.println(".");
delay(500);
}
// Change sync word (0xF3) to match the receiver
// The sync word assures you don't get LoRa messages from other LoRa transceivers
// ranges from 0-0xFF
LoRa.setSyncWord(0xF3);
Serial.println("LoRa Initializing OK!");
}
//Boucle d'attente de réception de la distance+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void loop() {
//delay(1000);
cpt++;
// try to parse packet
int packetSize = LoRa.parsePacket();
if (packetSize) {
// received a packet
Serial.print("Received packet '");
cpt=0;
// read packet
while (LoRa.available()) {
LoRaData = LoRa.readString();
Serial.print(LoRaData);
}
// print RSSI of packet
Serial.print("' with RSSI ");
Serial.println(LoRa.packetRssi());
//traitement de la distance
if (LoRaData.startsWith("dpg: ")){ //test si le paquet est valable
LoRaData.replace("dpg: ",""); //Vire le protocol
Serial.println(LoRaData);
int distance=LoRaData.toInt();
//Mise en mémoire des dernières positions
Mem[2]=Mem[1];
Mem[1]=Mem[0];
//Traitement de la distance
if (distance>Longueur_Seuil)
{
Serial.println("Porte ouverte");
Mem[0]=1;
if ((position==0)&&(Mem[0]==1)&&(Mem[1]==1)&&(Mem[2]==1))
{
position=1;
Serial.println("Chargement base: ouverte");
//Met à jour la base et envoie un SMS
Send_Data();
}
}
else
{
Serial.println("Porte fermée");
Mem[0]=0;
if ((position==1)&&(Mem[0]==0)&&(Mem[1]==0)&&(Mem[2]==0))
{
position=0;
Serial.println("Chargement base: fermée");
//Met à jour la base et envoie un SMS
Send_Data();
}
}
//Affiche la mémoire
for (int i = 0; i <= 2; i++) {
Serial.print(Mem[i]);
}
Serial.println(" ");
}
}
if (cpt>1000000) esp_restart();
}
Extrait de monapi.php: Voici un extrait de code pour mettre à jour un changement de position de la porte ou plus simplement connaitre le dernier état connue de la porte pour initialiser la variable position.
//******************************************************************************************
//Fonction d'injection des données
function api_set($var)
{
global $Connection;
global $_GET;
switch ($var)
{
case ("garage") : //insertion des logs d'ouverture et fermeture du garage
$data=$_GET["data"];
if (($data=="0")||($data=="1"))
{
$requete="insert into mon_garage (date,position) values ('".date("Y-m-d H:i:s")."',".$data.")";
$resultat=mysqli_query($Connection,$requete);
}
break;
default:
print("La variable appelée n'existe pas.");
}
}
//******************************************************************************************
//Fonction de récupération des données
function api_get($var)
{
global $Connection;
switch ($var)
{
case ("garage") : //Récupération de la position de la porte du garage
$requete="select position from mon_garage ORDER BY num DESC LIMIT 1 ";
$resultat=mysqli_query($Connection,$requete);
if ($resultat)
{
$t2=mysqli_fetch_row($resultat);
print($t2[0]);
}
break;
default:
print("La variable appelée n'existe pas.");
}
}
Ce qui donne sur le moniteur du récepteur:
Conclusion
Après un mois de test, mon système fonctionne très bien. Aucun plantage, comme j'avais avant avec le Raspberry pi qui perdait la connexion wifi. Je connais désormais l'état d'ouverture de ma porte de garage.Pour le moment, le récepteur maison est assez sommaire mais je prévois de le transformer en tant que centrale domotique avec un petit écran LED (surement basée sur un écran Nextion), un buzzer pour avertir de l'ouverture du garage et quelques options pas encore clairement définies. On en recause.
© 2024 www.doritique.fr par Robert DORIGNY