Schéma du module et de son "Pyroelectric (ou Passive) InfraRed sensor" ou capteur PIR , capteur détecteur de mouvement:
Le mini detecteur infra rouge : (HC-SR505 Mini Infrared PIR Motion Sensor) présente l'avantage d'avoir sa sortie en 3v avec une temporisation d'environ 8 secondes non règlables.
Si vous utilisez un autre PIR avec une sortie 5v ou sans temporisation, attention, il faudra faire un pont diviseur avec 2 résistances (2k et 1k) ou gérer éventuellement par programme la temporisation.
L'alimentation est a prévoir en phase finale, en cours de développement le module est alimenté par l'USB de l'ordi.
Pour l'alim. j'utilise un ancien chargeur téléphone 220v/5v.
witty_temp.zipQuelques explications sur le programme:
D'abord les librairies,#include <ESP8266WiFi.h> // pour la connexion WiFi #include <ESP8266WebServer.h> // Pour l'ecoute et la communication sur le port (localPort) #include <WiFiClientSecure.h> // pour l'envoi de https #include <WiFiUdp.h> // pour récuperer la date et l'heure sur un time serveur #include <TimeLib.h> // pour synchroniser l'horloge (millis) de l'esp8266 sur le temps universel(UTC) #include "ThingSpeak.h" // Pour archiver les stats sur cloud (gratuit un an renouvelable) #include "Gsender.h" // pour l'envoi de mails, attention bien mettre entre guillemets, modifier Gsender.h // (identifiant et mot de passe) et mettre Gsender.cpp et Gsender.h dans le dossier de ce sketch.Puis les pages stockées en flash
#include "chart.h" // Page Web pour client, affichage des stats sur 24 heures #include "err404.h" // Page Web erreur 404
Avant le téléversement ou la compilation vérifier que tous les onglets sont présents
const char* vers = " Version: 201707302249";
int LDR = A0; // mesure de la lumiere ambiante en %
int luminositeTemp; // valeur max de luminosité dans le créneau de 2mn
const int rouge = 15; // pour tests de fonctionnement
const int bleue = 12; // les gpio bleue/verte varient en fonction des modeles
const int verte = 13; // bleue/verte pour tests de fonctionnement
bool visible = true; // sur les modules witty-gizwits active ou pas les leds pour Debug
unsigned int i = 0;
unsigned int count = 0; // nombre de détections depuis la reinitialisation
//************************ WiFi *************************
const char* ssid = "XXXXXXXX";
const char* password = "XXXXXXXX";
unsigned int localPort = 49999; // pour acces par internet ( parametrer routeur ou box , baux statiques IP , et redirection des ports)
// attention aux ports serveurs (8080,8081, etc....) tres interrogés par les robots! (koréens, Russes, USA etc....)
// définir dans la plage des ports privés ( comprise entre 49152 et 65535 )
const char* zone = "Entrée"; // zone ou est placé le detecteur
ESP8266WebServer server(localPort); // ecoute le port localPort
//********************** email free SMTP **********************
bool flag_email = false;
// Activation du SMTP authentifié, a activer sur https://subscribe.free.fr/login/ ,gérer mes emails,
// puis renseigner ( comme noté à la suite) votre compte smtp dans Gsender.h dans le repertoire (dossier) de ce sketch
//const int SMTP_PORT = 465; // securisé
//const char* SMTP_SERVER = "smtp.free.fr";
//const char* EMAILBASE64_LOGIN = "xxxxxxxxxxxxxxxxxx";// en base64
//const char* EMAILBASE64_PASSWORD = "xxxxxxxxxxxxxxxx";// en base64
//const char* FROM = "xxxxxxxxxxx@free.fr";// en clair l'adresse a laquelle vous envoyez l'Email
// ATTENTION !... pour encoder en base64, un soft a télécharcher, https://sourceforge.net/projects/gbm64/ , gratuit
// pour votre sécurité évitez de convertir en ligne en base64 vos identifiants et mots de passe
// Il existe aussi une librairie sur github
//****************** paramètres du serveur sms free-mobile ************************
bool flag_sms = false;
const char* host = "smsapi.free-mobile.fr";
const int httpsPort = 443;
const char* fingerprint = "18 EB 36 0D AD 38 0D 0E D1 87 8B 09 4D 44 CF 45 38 90 F7 DC";
// ----------------------- paramètres abonné -------------------------------
const String user = "XXXXXXXX"; // identifiant abonné
const String pass = "XXXXXXXX"; // pour obtenir un nouveau password (desactiver/activer le service chez FREE)
//**************************** Commandes ************************
// Paramètres et commandes acceptés a modifier selon votre projet!... exemple avec PIN: "/1234sms_on"....etc...
// les 2 premiers ne doivent pas être modifiés,( "/" et "/favicon.ico" )
const char* uriArray[15] = {"/", "/favicon.ico", "/sms_on", "/sms_off", "/email_on", "/email_off", "/bleue_on", "/bleue_off", "/alarme_on", "/alarme_off", "/visible_on", "/visible_off", "/check", "/reset", "/check24"};
String message = ""; // message en retour
String reponse = ""; // message encodé (web,sms ou mail)
//************************* UDP NTP TIME **************************
// ntp-p1.obspm.fr (IP : 145.238.203.14) : serveur primaire (de strate 1) installé au LNE-SYRTE (campus parisien de l'Observatoire).
IPAddress timeServer(145, 238, 203, 14);
//IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov
int timeZone = 0; // UTC=0, Heure Europe centrale +1(heure d'hiver) +2 pour l'été en france
const int NTP_PACKET_SIZE = 48; // L'horodatage NTP est dans les 48 premiers octets du message
byte packetBuffer[ NTP_PACKET_SIZE]; //Buffer pour contenir les paquets entrants et sortants
WiFiUDP Udp;
//-------------------------------- Time ----------------------------------
// Mettre en français les mois et les jours dans la librairie Time, DateStrings.h
String strDateInit = ""; // Date au redémarrage
String strDatePir = ""; //derniere detection pir
int anneeEnCours;
unsigned long aujourdHui;
unsigned long heureEte;
unsigned long heureHiver;
unsigned long heureCount;
//************************* detection PIR *************************
const int pir = 14; // raccordé a la sortie du PIR ( attention 3.3v max) si PIR 5v branchement: gnd_____2k_____gpio14______1k_____PIRdata
bool flag_pir = false; // déclenché par une présence
bool flag_alarme = false; // active l'alarme
//************************* Thingspeak *************************
int delayThingspeak = 120; //120 secondes
const char* serverThingspeak = "api.thingspeak.com";
unsigned long channel = XXXXXXXX;
const char * apiKey = "XXXXXXXX";
unsigned long timeThingspeak ;
//************************* fin des déclarations ***********************
L'initialisation du module
void setup()
{
pinMode(rouge, OUTPUT);
pinMode(bleue, OUTPUT);
pinMode(verte, OUTPUT);
pinMode(pir, INPUT);
digitalWrite(rouge, !visible);
digitalWrite(bleue, !visible);
digitalWrite(verte, !visible);
visible = false;
Serial.begin(115200);
WiFi.begin(ssid, password);
//Serial.println("");// Debug
while (WiFi.status() != WL_CONNECTED) {
//Serial.print(".");// Debug
digitalWrite(rouge, 1); delay(250); digitalWrite(rouge, 0); delay(250);
}
Serial.println("");// Debug
Serial.print("Connecte a ");// Debug
Serial.println(ssid);// Debug
Serial.print("IP adresse: ");// Debug
Serial.println(WiFi.localIP());// Debug
Serial.println("Start UDP");
Udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(Udp.localPort());
Serial.println("Synchronisation en cours");
setSyncProvider(getNtpTime);//utc timeZone =0
count = readThingspeak(3); // récupere derniere date et heure de comptage en cas de reinit dans la journée
Serial.print("compteur de detections: ");
Serial.println(count) ;
calculTimeZone(); // calcul heure d'été ou d'hiver
setSyncInterval ( 300 ); // Synchronise toutes les 300 secondes
strDateInit = actualStringDate(); // date et heure de l'initialisation
timeThingspeak = now(); // Initialise l'horloge de l'archivage, prochain dans 120s
checkParam(); // affiche les parametres actuels
server.begin(); // démarre l'écoute de local port
//-----------------------------------------------------------------------------------------------
server.on(uriArray[0], []() {
message = " Bonjour ! L'accès à cette page nécessite des autorisations .....";
envoi_reponse(200);
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[1], []() {
envoi_reponse(404);
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[2], []() {
flag_sms = true;
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[3], []() {
flag_sms = false;
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[4], []() {
flag_email = true;
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[5], []() {
flag_email = false;
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[6], []() {
digitalWrite(bleue, 1);
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[7], []() {
digitalWrite(bleue, 0);
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[8], []() {
flag_alarme = true;
flag_email = true;
flag_sms = true;
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[9], []() {
flag_alarme = false;
//flag_email = false;
//flag_sms = false;
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[10], []() {
visible = true;
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[11], []() {
visible = false;
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[12], []() {
checkParam();
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[13], []() {
message = " Bonjour ! Le sytème va être réinitialisé dans 2 secondes et un SMS sera envoyé";
envoi_reponse(200);
delay(2000);
ESP.restart(); // RESET
});
//-----------------------------------------------------------------------------------------------
server.on(uriArray[14], []() {
checkParam24();
});
//-----------------------------------------------------------------------------------------------
server.onNotFound( []() { // requête inconnue ?...... Analyse de de la requête et envoi de sms si activé (sms_on)
server.send(404, "text/html", err404);
});
//-------------- fin du setup et envoi du message de réinitialisation (email et sms)-----------------
flag_sms = true;
flag_email = true;
message = "REINITIALISATION : " + String(zone) + " , mode visible désactivé, attention! l'ALERTE PIR par mail et sms va être désactivée après ce message ";
envoi_reponse(200);
flag_sms = false;
flag_email = false;
delay(10000);// attend la fin detection pir (environ 8s)
}
La boucle
void loop() {
if (hour() == 23 && minute() == 59 && (second() >= 50))count = 0; // met le compteur de détections a 0, pendant 10s avant minuit
if (WiFi.status() == WL_CONNECTED) { // si coupure temporaire de WIFI, inutile de faire les lignes suivantes)
server.handleClient();
if ( (millis() % 3000 == 0) && (luminositeTemp <= luminosite())) luminositeTemp = luminosite() ; // toutes les 3 secondes m.a.j luminosité max
digitalWrite(verte, ( flag_pir & visible)); // éclaire led verte, détection pir en mode visible
if ( now() >= (timeThingspeak + delayThingspeak))sendThingspeak();// envoi des datas stats vers thingspeak.com toutes les 2mn
if (digitalRead(pir)) pir_alarme(); // déclenche l'alarme si activée
if ((now() > heureEte && now() < heureHiver && timeZone == 1) || (now() > heureHiver && timeZone == 2) || anneeEnCours != year() || timeZone > 2 || timeZone < 1 ) calculTimeZone(); // Recalcule timezone si fausse (dépassement millis()) ou au changement d'année
}
}
Les fonctions
le serveur a l'écoute du port 8081 lit l'uri "/check",
uriArray[12] contient la string "/check"
cette partie du programme est concernée, checkParam() est lancé :
//-----------------------------------------------------------------------------------------------
server.on(uriArray[12], []() {
checkParam();
});
//-----------------------------------------------------------------------------------------------
checkParam() s'exécute et le module vous répond:
//********************* Renvoie les paramètres en cours **************************
void checkParam() {
param();
//Serial.println(message);// Debug
envoi_reponse(200);
}
//********************************************************************************************************
String param() {
message = vers ; // version du sketch
message += " " + actualStringDate() + "\n";
message += "Paramètres actuels du détecteur de la maison: " + String(zone);
message += "\n";
message += "Reinitialisé le: " + strDateInit;
message += "\n";
message += "Nombre de détections depuis minuit: " + String(count);
message += "\n";
message += "LUMINOSITE:" + String(luminositeTemp) + "%";
message += "\n";
message += (flag_sms) ? "SMS ACTIVES" : "SMS désactivés" ;
message += "\n";
message += (flag_email) ? "EMAILS ACTIVES" : "EMAILS désactivés" ;
message += "\n";
message += (digitalRead(bleue)) ? "LED BLEUE ALLUMEE" : "LED BLEUE éteinte" ;
message += "\n";
message += (visible) ? "Mode visible ACTIVE (les témoins lumineux s'allument lors de détections)" : "Mode visible désactivé (aucun témoin lumineux allumé automatiquement)";
message += "\n";
message += (flag_alarme) ? "ALARME ACTIVE " : "ALARME désactivée " ;
message += "\n";
message += "Dernière détection après réinitialisation le: " + strDatePir;
message += "\n";
return message;
Réponse:
Version: 201707151312 Lundi 07/08/2017 à 08:36:17 Paramètres actuels du détecteur de la maison: Entrée Reinitialisé le: Samedi 15/07/2017 à 18:57:39 Nombre de détections depuis minuit: 12 LUMINOSITE:7% SMS désactivés EMAILS désactivés LED BLEUE éteinte Mode visible ACTIVE (les témoins lumineux s'allument lors de détections) ALARME désactivée Dernière détection après réinitialisation le: Lundi 07/08/2017 à 08:23:21
//**************************************** Envoi des datas vers le compte thingspeak.com ********************************************************
void sendThingspeak()
{
timeThingspeak = now();
count += flag_pir; // incrémente le nbre de détections si une détection a eu lieu dans les 2mn
writeThingspeak(flag_pir, luminositeTemp, count);
flag_pir = false;
luminositeTemp = 0;
}
//**************************************** écrit marqueur reinit + lit la date du dernier enregistrement ********************************************************
int readThingspeak(int field) // retourne le nombre de detections si c'est le meme jour, sinon 0
{ WiFiClient client;
ThingSpeak.begin(client);
ThingSpeak.setField(4, 1);
ThingSpeak.writeFields(channel, apiKey);// envoie 1 pour marqeur de reinitialisation
int fieldInf = ThingSpeak.readIntField(channel, field, apiKey);
if ( ThingSpeak.readCreatedAt(channel, apiKey).substring(0, 10) != String(year()) + "-" + toDigits(month()) + "-" + toDigits(day())) // compare date UTC du jour et date dernier enregistrement
{
fieldInf = 0;
}
return fieldInf;
}
//**************************************** ecrit des datas sur le compte thingspeak.com ********************************************************
void writeThingspeak(int field1, int field2, int field3)
{ WiFiClient client;
ThingSpeak.begin(client);
ThingSpeak.setField(1, field1);
ThingSpeak.setField(2, field2);
ThingSpeak.setField(3, field3);
ThingSpeak.writeFields(channel, apiKey);
}
//**************************************** Fin compte thingspeak.com *******************************************************
//******************************* formate date ***************************************
String actualStringDate() { // formate l'affichage de la date et de l'heure en Français
String strDate = String(dayStr(weekday())) + " "; // a mettre en français dans la librairie Time, DateStrings.h
strDate += toDigits(day()) + "/" + toDigits(month()) + "/" + String(year()) + " à ";
strDate += toDigits(hour()) + ":" + toDigits(minute()) + ":" + toDigits(second());
return strDate;
}
//************************ affiche les nombres 0->9 , 00->09 a deux "digits"********************
String toDigits(int digits) {
String s = "";
s = (digits < 10) ? "0" + String(digits) : String(digits);
return s;
}
//******************************** Détection de mouvement PIR ************************************************
void pir_alarme() { // déclenche l'alarme si activée
if (!flag_pir ) {
flag_pir = true;
strDatePir = actualStringDate();
Serial.print(" Detection PIR ! ");// Debug
Serial.println(count);// Debug
digitalWrite(verte, 0); digitalWrite(rouge, visible); delay(500); digitalWrite(rouge, 0); // Debug
if (flag_alarme) { // si uri "/alarme_on"
flag_sms = true; flag_email = true;
message = "Alarme détection de présence!...port: " + String(localPort) + " " + String(zone);
envoi_reponse(200);
checkParam();
flag_sms = false; flag_email = false;
}
}
}
L'intégration dans le boitier d'un CPL Hors Sevice, permet facilement la réalisation du projet:
Vue de l'intérieur, les éléments sont collés (mastic silicone pour l'alim et le pir)
220v/5v est de la récup d'un ancien chargeur de téléphone, ce module peut etre remplacé par n'importe quel autre 5v délivrant au moins 500mA.
exemple ici.