Un système complet de surveillance pour moins de 10€
La réalisation de cet objet connecté autour d'un module Witty ESP-12F ESP8266 est liée a un ensemble de difficutés que je vais essayer de vous aider a franchir. D'abord, ne pas se lancer dans une usine a gaz dès le début et penser à fractionner le projet en plusieurs étapes.
Cet article a été a l'origine de ma curiosité.
Il vous faut un minimum avant d'acheter le module Witty et le mini detecteur infra rouge : (HC-SR505 Mini Infrared PIR Motion Sensor)
- Avoir un réseau WIFI disponible ( SSID,Password ) et accès a l'interface de votre box pour la redirection des ports pour internet.
- Avoir des connaissances de programation en C# ou avoir "bidouillé" avec un Arduino.
- Installer sur votre ordinateur le dernier IDE Arduino: Téléchargez l'IDE.
- Installer les librairies ESP8266 et les cartes.
- Utiliser Chrome pour avoir accès à la traduction en ligne, beaucoup de documents sont en anglais, et quelque fois en chinois ou cette adresse.
- Si vous êtes abonné FREE-MOBILE vous pourrez, avec ce module envoyer des SMS sur votre téléphone GRATUITEMENT .
- Si vous avez une adresse mail Google ou FREE, vous pourrez, avec ce module envoyer des Emails sécurisés.
- Un peu de matériel: Cordon micro USB complet(5v + datas), Fer a souder etc....
- Et beaucoup de curiosité.
En effet ce module WIFI peut etre employé en entreprise comme a son domicile et peut se loger dans n'importe quel boitier, étant donné sa petite taille. Le mien est logé dans un ancien boitier CPL a demeure sur une prise. Il peut surveiller l'activité dans un local, un passage, etc...
Si vous interrogez le module en local (192.168.0.xxx:PORT) ou par internet (votre IP fixe:PORT) il vous donne , l'activité zoomable sur 10 jours par tranches de 2 minutes.
Le module stocke les datas toutes les 2 minutes sur un compte gratuit de thingspeak.com (1an renouvelable et jusqu'a 8 paramètres (channels), ici seuls 4 sont exploités ).
La page web utilise l'API highcharts.com et est "embarquée" dans le module en mémoire flash, l'affichage est réactualisé toutes les 120s.
Par défaut le zoom déplaçable est sur 24h, par bouton il est de 3h,6h,12h,24h ou semaine, et manuellement avec les index.
La "Chart" peut être enregistrée directement en trois clics dans plusieurs formats: PDF, JPG, PNG et SVG.
Une fenêtre datée donne l'état du module au moment de l'interrogation.
L'alarme consiste a vous envoyer discrètement à l'insu de l'intrus un sms et un email lors d'une présence, détection PIR.
............ Connecte a XXXXXXXXXXX IP adresse: 192.168.0.34 Start UDP Local port: 8084 Synchronisation en cours NTP Request NTP Reponse: OK Calcule Timezone NTP Request NTP Reponse: OK Timezone: 2 Nous sommes aujourd'hui le: Dimanche 30/07/2017 à 23:35:29 Synchronise l'heure toutes les 300 secondes Initialisé le: Dimanche 30/07/2017 à 23:35:29 Timestamp UNIX: 1501457729 Dimanche 30/07/2017 à 23:35:29 Timestamp UNIX: 1501457731 Dimanche 30/07/2017 à 23:35:31 Timestamp UNIX: 1501457733 Dimanche 30/07/2017 à 23:35:33 Timestamp UNIX: 1501457735 Dimanche 30/07/2017 à 23:35:35 Timestamp UNIX: 1501457737 Dimanche 30/07/2017 à 23:35:37 Timestamp UNIX: 1501457739 Dimanche 30/07/2017 à 23:35:39 Timestamp UNIX: 1501457741 Dimanche 30/07/2017 à 23:35:41 Timestamp UNIX: 1501457743 Dimanche 30/07/2017 à 23:35:43
Pour info: Timestamp UNIX.
Ne pas oublier de mettre en français dans DateStrings.h les mois et les jours de la semaine dans la librairie Time.
Ce programme donne le jour la date et l'heure en français toutes les 2 secondes.
Il faut remplacer dans le source les XXXXXXXXXXX par vos identifiants WIFI.
#include <ESP8266WiFi.h> // pour la connexion WiFi. https://github.com/esp8266/Arduino #include <WiFiUdp.h> // pour récuperer la date et l'heure sur un time serveur . https://github.com/esp8266/Arduino #include <TimeLib.h> // low level time and date functions. https://github.com/PaulStoffregen/Time //************************ WiFi ************************* const char* ssid = "XXXXXXXX"; const char* password = "XXXXXXXX"; unsigned int localPort = 8084; //************************* 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 unsigned long aujourdHui; unsigned long heureEte; unsigned long heureHiver; //************************* INITIALISE ************************* void setup(){ Serial.begin(115200); WiFi.begin(ssid, password); Serial.println(""); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } 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 Serial.println("Calcule Timezone"); calculTimeZone(); Serial.println(""); Serial.println("Synchronise l'heure toutes les 300 secondes "); setSyncInterval ( 300 ); strDateInit = actualStringDate(); // date et heure de l'initialisation Serial.print("Initialisé le: "); Serial.println(strDateInit); Serial.println(""); } void loop() { // envoie sur le port serie la date toutes les 2 secondes Serial.print("Timestamp UNIX: "); Serial.println(now()); Serial.println( actualStringDate()); delay(2000); } //********************************* Récuperation de l'heure sur le net (UTC) ********************************* time_t getNtpTime() { while (Udp.parsePacket() > 0) ; // Jeter tous les paquets précédemment reçus Serial.println("NTP Request"); sendNTPpacket(timeServer); uint32_t beginWait = millis(); while (millis() - beginWait < 1500) { int size = Udp.parsePacket(); if (size >= NTP_PACKET_SIZE) { Serial.println ("NTP Reponse: OK "); Udp.read(packetBuffer, NTP_PACKET_SIZE); // Lire le paquet dans le buffer unsigned long secsSince1900; // Convertir quatre octets à partir de l'emplacement 40 à un entier long secsSince1900 = (unsigned long)packetBuffer[40] << 24; secsSince1900 |= (unsigned long)packetBuffer[41] << 16; secsSince1900 |= (unsigned long)packetBuffer[42] << 8; secsSince1900 |= (unsigned long)packetBuffer[43]; return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR; } } Serial.println("Pas de NTP Reponse :-("); //return 0; // Retourne 0 si impossible d'obtenir le temps --> bug? count a 0 si return 0 } void sendNTPpacket(IPAddress & address) { memset(packetBuffer, 0, NTP_PACKET_SIZE); packetBuffer[0] = 0b11100011; packetBuffer[1] = 0; packetBuffer[2] = 6; packetBuffer[3] = 0xEC; packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; Udp.beginPacket(address, 123); //NTP requete port 123 Udp.write(packetBuffer, NTP_PACKET_SIZE); Udp.endPacket(); } //******************************* 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; } //**************************************** fonction calcul DST et synchronise millis ******************************************************** void calculTimeZone() // fonction qui calcule DST (Daylight Saving Time pour la France : heure d'hiver timeZone = 1 , heure d'été timeZone = 2) https://en.wikipedia.org/wiki/Daylight_saving_time_by_country { aujourdHui = now(); int k = int( 1.2425 * year()); //year() pour le calcul de k et des dates et heures de basculement été/hiver int heureEte = 31 - (33 + k) % 7; // dernier dimanche de mars passage a l'heure d'été int heureHiver = 31 - (51 + k) % 7; // dernier dimanche d'octobre passage a l'heure d'hiver setTime(1, 59, 59, heureEte, 3, year()); // (heures, minutes,secondes,jour,dernier dimanche de mars,année en cours) heureEte = now(); //timestamp dernier dimanche de mars a 1h59m59s setTime(2, 59, 59, heureHiver, 10, year()); //(heures, minutes,secondes,jour,dernier dimanche d'octobre,année en cours) heureHiver = now(); //timestamp dernier dimanche d'octobre a 2h59m59s if (aujourdHui > heureEte && aujourdHui < heureHiver) timeZone = 2; else timeZone = 1; // où se situe aujourd'hui ? setSyncProvider(getNtpTime); Serial.print("Timezone: "); Serial.print(timeZone); Serial.print(" Nous sommes aujourd'hui le: "); Serial.print(actualStringDate()); // Debug }
ATTENTION !... pour encoder en base64, un soft a télécharger , gratuit.
Pour votre sécurité évitez de convertir en ligne en base64 vos identifiants et mots de passe.
Il existe aussi une librairie base64 Arduino sur github.
Au démarrage witty affiche sur le moniteur série de l'IDE Arduino le dialogue avec le serveur SMTP de FREE:
Connecte a XXXXXXXX IP adresse: 192.168.0.34 essai de mail (a la ligne , en mode etendu) Connecting to :smtp.free.fr 220 smtp6-g21.free.fr ESMTP Postfix HELO friend: 250 smtp6-g21.free.fr AUTH LOGIN: AUTH LOGIN 334 VXNlcm5hbWU6 EMAILBASE64_LOGIN:XXXXXXXX== 334 UGFzc3dvcmQ6 EMAILBASE64_PASSWORD: XXXXXXXX== 235 2.7.0 Authentication successful MAIL FROM: <XXXXXXXX@free.fr> 250 2.1.0 Ok RCPT TO: <XXXXXXXX@gmail.com> 250 2.1.5 Ok DATA: From: <XXXXXXXX@free.fr> To: <XXXXXXXX@gmail.com> Subject: ESP8266 Witty Message Mime-Version: 1.0 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: 7bit <!DOCTYPE html><html lang="en">essai de mail (a la ligne , en mode etendu) </html> . 354 End data with <CR><LF>.<CR><LF> 250 2.0.0 Ok: queued as C610E780371 221 2.0.0 Bye Message envoyé. essai de mail <br> (a la ligne <br> , en mode etendu) Connecting to :smtp.free.fr 220 smtp6-g21.free.fr ESMTP Postfix HELO friend: 250 smtp6-g21.free.fr AUTH LOGIN: AUTH LOGIN 334 VXNlcm5hbWU6 EMAILBASE64_LOGIN:XXXXXXXX== 334 UGFzc3dvcmQ6 EMAILBASE64_PASSWORD: XXXXXXXX== 235 2.7.0 Authentication successful MAIL FROM: <XXXXXXXX@free.fr> 250 2.1.0 Ok RCPT TO: <XXXXXXXX@gmail.com> 250 2.1.5 Ok DATA: From: <XXXXXXXX@free.fr> To: <XXXXXXXX@gmail.com> Subject: ESP8266 Witty Message Mime-Version: 1.0 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: 7bit <!DOCTYPE html><html lang="en">essai de mail <br> (a la ligne <br> , en mode etendu) </html> . 354 End data with <CR><LF>.<CR><LF> 250 2.0.0 Ok: queued as 18DDC7803A9 221 2.0.0 Bye Message envoyé.
Puis ouvrez votre boite mail pour consulter les 2 messages .
dans le premier mail les \n sont ignorés, dans le deuxième ils sont interprétés .
#include "Gsender.h" // pour l'envoi de mails, attention bien mettre Gsender.h entre guillemets, // l'original trouvé ici http://www.instructables.com/id/ESP8266-GMail-Sender/ // modifier Gsender.h (identifiant et mot de passe) // et mettre Gsender.cpp et Gsender.h dans le dossier de ce sketch #include <ESP8266WiFi.h> // pour la connexion WiFi. https://github.com/esp8266/Arduino //************************ WiFi ************************* const char* ssid = "XXXXXXXX"; const char* password = "XXXXXXXX"; unsigned int localPort = 8084; //********************** email free SMTP ********************** // Activation du SMTP authentifié, a activer sur https://subscribe.free.fr/login/ ,gérer mes emails, // puis renseigner ( comme noté à la suite, 5 lignes) 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 partir de laquelle vous envoyez l'Email // ATTENTION !... pour encoder en base64, un soft a télécharcher, https://sourceforge.net/projects/base64-binary/ , gratuit // pour votre sécurité évitez de convertir en ligne en base64 vos identifiants et mots de passe // Il existe aussi une librairie Arduino sur github //************************* INITIALISE ************************* void setup() { Serial.begin(115200); WiFi.begin(ssid, password); Serial.println(""); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println("");// Debug Serial.print("Connecte a ");// Debug Serial.println(ssid);// Debug Serial.print("IP adresse: ");// Debug Serial.println(WiFi.localIP());// Debug Serial.println(""); // // Certaines chaines de caractères contiennent des caractères indésirables ou ignorés, // pour essais envoi de 2 mails pour voir avant et après encodage, // dans votre boite mail destinataire. // String mailText = "essai de mail \n (a la ligne \n , en mode etendu) "; Serial.println(mailText); envoi_email(mailText, "XXXXXXXX@gmail.com"); delay(5000); mailText.replace ( "\n", "<br>"); // encode la chaine \n Serial.println(mailText); envoi_email(mailText, "XXXXXXXX@gmail.com"); Serial.println(""); } void loop() { } //*************** fonction envoi du mail ************************* void envoi_email(String message_email, String destinataire) { Gsender *gsender = Gsender::Instance(); String subject = "ESP8266 Witty Message"; if (gsender->Subject(subject)->Send(destinataire, message_email)) { Serial.println("Message envoyé."); } }
L'envoi de SMS gratuitement sur votre mobile Free demande un préalable: sur le compte free-mobile/Gerer mon compte/Mes options, l'option "Notifications par SMS" activée
Attention! la désactivation puis l'activation de la notification entraine la modification de la "clé d'identification au service" ou "pass", cela peut vous être utile.
........... Connecte a XXXXXXXX IP adresse: 192.168.0.34 essai de sms free-mobile a partir de Witty. %20essai%20de%20sms%20free-mobile%20%0D%0A%20a%20partir%20de%20Witty. connection.... smsapi.free-mobile.fr certificat correct requesting URL: /sendmsg?user=XXXXXXXX&pass=XXXXXXXX&msg=%20essai%20de%20sms%20free-mobile%20%0D%0A%20a%20partir%20de%20Witty. Lecture des headers HTTP/1.1 200 OK close connection
Votre téléphone devrait vous avertir qu'un SMS vient d'arriver!........
Un truc au passage: pour récupérer le certificat (fingerprint)pour la connexion HTTPS
Se connecter avec chrome par exemple à https://smsapi.free-mobile.fr puis,clic a la suite:
clic droit sur la page,inspecter/securité/voir le certificat/détails/empreinte numérique
// IDE Arduino Esp8266 Witty/Gizwits esp-12F // Envoi de SMS sur mobile Free. // Le N° portable doit avoir l'option "Notifications par SMS" validée. (interface free mobile) (Gratuit) // voir https://www.freenews.fr/freenews-edition-nationale-299/free-mobile-170/nouvelle-option-notifications-par-sms-chez-free-mobile-14817 #include <ESP8266WiFi.h> // pour la connexion WiFi. https://github.com/esp8266/Arduino #include <WiFiClientSecure.h> // connexion https //************************ WiFi ************************* const char* ssid = "XXXXXXXX"; const char* password = "XXXXXXXX"; unsigned int localPort = 8084; //************************* INITIALISE ************************* void setup() { Serial.begin(115200); WiFi.begin(ssid, password); Serial.println(""); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println("");// Debug Serial.print("Connecte a ");// Debug Serial.println(ssid);// Debug Serial.print("IP adresse: ");// Debug Serial.println(WiFi.localIP());// Debug Serial.println(""); // // certains caractères sont indésirables dans l'URL il faut l'encoder String sms = " essai de sms free-mobile \n a partir de Witty."; Serial.println(sms); sms.replace(" ", "%20"); // encode URL espace " " par "%20" sms.replace("\n", "%0D%0A"); // encode URL a la ligne "\n" par "%0D%0A" Serial.println(sms); envoiSms(sms); } void loop() { } //*************** fonction envoi du SMS FREE ************************* void envoiSms(String messageSms) { const char* host = "smsapi.free-mobile.fr"; const int httpsPort = 443; const char* user = "XXXXXXXX"; const char* pass = "XXXXXXXX"; // Pour trouver le fingerprint de free sms, se connecter avec votre navigateur // à https://smsapi.free-mobile.fr puis,clic a la suite: // clic droit,inspecter,securité,voir le certificat,détails,empreinte numérique const char* fingerprint = "18 EB 36 0D AD 38 0D 0E D1 87 8B 09 4D 44 CF 45 38 90 F7 DC"; WiFiClientSecure client; Serial.print("connection.... "); Serial.println(host); if (!client.connect(host, httpsPort)) { Serial.println("connection erreur"); return; } if (client.verify(fingerprint, host)) { Serial.println("certificat correct"); } else { Serial.println("certificat incorrect"); } String url = "/sendmsg?user=" + String(user) + "&pass=" + pass + "&msg=" + messageSms; Serial.print("requesting URL: "); Serial.println(url); client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "User-Agent: Esp8266_Witty_Gizwits\r\n" + "Connection: close\r\n\r\n"); while (client.connected()) { String line = client.readStringUntil('\r'); Serial.println("Lecture des headers "); Serial.println(line); break; } Serial.println("close connection"); }