WITTY ESP-12F

Un système complet de surveillance pour moins de 10€

Présentation du projet autour de WITTY, un module très complet

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é.

Schéma du module et de son interface série:

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é.

Et en final plus qu'une page web, un vrai outil de surveillance

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.



Récupérer l'heure et la date sur le net, puis synchroniser le module.

Charger le programme en sélectionnant la carte "NodeMCU ESP-12E".

Au démarrage witty affiche sur le moniteur série de l'IDE Arduino, les infos suivantes:

			
............
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.

Le code source :

#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
}

Envoi de mails grace a votre compte free ou gmail

D'abord, activer SMTP authentifié dans la gestion de vos comptes mails :

L'original: ESP8266_Gmail_Sender.zip

Mettre Gsender.h et Gsender.cpp dans le même dossier que le sketch et vérifier à l'ouverture de l'ide Arduino que les 2 onglets sont présents:


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 .

Le code source :
#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é.");
  }
}

Envoyer un SMS a un téléphone FreeMobile.

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.


Le SMS est contenu dans l'URL, il faut donc l'encoder. Une petite piqure de rappel: ICI
Au démarrage witty affiche sur le moniteur série de l'IDE Arduino, les infos suivantes:

			
...........
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

Le code source :

// 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");
}

CONTACT


Toutes vos remarques et critiques éventuelles sont les bienvenues et surtout si ce partage vous a été utile.
Désolé, je n'assure aucun support sur ce projet.
Si vous avez amélioré ce projet, je suis preneur. Envoyez moi un lien, MERCI!
Attention le serveur de Mails (pages perso) est quelquefois lent et souvent capricieux (pas merci FREE!).
Reéssayez si erreur directement avec votre messagerie ici