Les Carnets de Byfeel domotique , Objets connectés , DIY , Programmation, Nouvelles Technologies ….

DIY Horloge et Notification Domotique ( Matrix LED ) avec Jeedom

Le but de cet article , est d’améliorer le projet Horloge Arduino.

en apportant les plus suivants :

  • Mise à jour en WIFI
  • Envoi des notification en WIFI
  • Gestion de la luminosité
  • Gestion et mise à jour de l’heure via service NTP
  • Ecran plus grand
  • Paramétrable via interface Web
  • Interopérabilité domotique

Pour cela nous aurons besoin de :

  • Wemos d1
  • Deux matrices LED de quatre éléments
  • Une photorésistance et une résistance

On va partir du sketch final de l’article : WIFI et OTA

Afin de gérer , l’affichage des différentes fonctionnalités ( horloge , notification , message information …. ) nous allons utiliser deux matrices LED ( composées de 4 matrices LED 8×8 ( basées sur Max7219 ).

Vue arrière
Vue côté
Matrice led – vue Avant

Il suffira de souder les deux modules , ce qui amène un affichage sur 8 x 64.

Une fois les deux modules assemblés ( soudures entre les deux circuits , à prévoir ).Nous allons relier la matrice au Wemos de la façon suivante :

  • Vcc -> 5v
  • Gnd -> Gnd
  • DIN -> D7
  • CS  -> D6
  • CLK -> D5

Nous allons maintenant intégrer au Sketch , les bibliothèques permettant de piloter la matrice  ( ne pas hésiter à se reporter à l’article horloge Arduino , pour plus de détails ).

// gestion de l’affichage matricielle
#include <MD_Parola.h>
#include <MD_MAX72xx.h>

Puis à définir les PIN sur lesquels sont reliés cette dernière , ainsi que le nombre d’afficheur. Puis à Initialiser la matrice.

// Parametrage matrice ( Pin Arduino où est branchée la matrice )
#define MAX_DEVICES 8 // ( nombre de matrice )
#define CLK_PIN D5
#define DATA_PIN D7
#define CS_PIN D6

// initialisation de la matrice
MD_Parola P = MD_Parola(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

Afin de pouvoir afficher des messages il faut démarrer le service d’affichage , dans la fonction Setup.

//démarrage Display
P.begin();

A partir de maintenant , nous sommes en mesure de pouvoir afficher un message sur la matrice avec la fonction :  P.print(« votre message« );

Le message à afficher peut être soit de type String ou Char(buffer).

Si vous aves des soucis d’affichage , des caractères à l’envers , des effets miroir ou autres ( penser à configurer dans la  bibliothèque master  : le fichier src/MD_MAX72xx_lib.h , comme expliqué dans cet article )

Ce qui donne :

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
// WIFI Manager , afin de gérer la connexion au WIFI de façon plus intuitive
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager

///includes nécessaires au fonctionnement de l'OTA :
#include <WiFiUdp.h>
#include <ArduinoOTA.h>


// gestion de l'affichage matricielle
#include <MD_Parola.h>
#include <MD_MAX72xx.h>


ESP8266WebServer server(80);         // serveur WEB sur port 80

// définition du numéro de LED interne 
int led = 2; // led built IN

// Paramétrage matrice  ( Pin Arduino où est branchée la matrice )
#define MAX_DEVICES 8 // ( nombre de matrice )
#define CLK_PIN   D5
#define DATA_PIN  D7
#define CS_PIN    D6
// initialisation de la matrice
MD_Parola P = MD_Parola(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); 

//variable systemes
#define  BUF_SIZE  60
char Notif[BUF_SIZE];

// fonction callback Wifimanager quand Mode AP en fonction
void configModeCallback (WiFiManager *myWiFiManager) {
  P.print("Choisir AP..");
  delay(3000);
  P.print(WiFi.softAPIP().toString());
    delay(3000);
    P.print(myWiFiManager->getConfigPortalSSID());
  //Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  //Serial.println(myWiFiManager->getConfigPortalSSID());
}

void setup() {
   //démarrage Display
   P.begin();

      //******** WiFiManager ************
    //Local intialization. Once its business is done, there is no need to keep it around
    WiFiManager wifiManager;

     //Si besoin de fixer une adresse IP
    //wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
    
    //Forcer à effacer les données WIFI dans l'eprom , permet de changer d'AP à chaque démarrage ou effacer les infos d'une AP dans la mémoire ( à valider , lors du premier lancement  )
    //wifiManager.resetSettings();
    //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
     wifiManager.setAPCallback(configModeCallback);
    
    //Recupère les identifiants   ssid et Mot de passe dans l'eprom  et essaye de se connecter
    //Si pas de connexion possible , il demarre un nouveau point d'accés avec comme nom , celui defini dans la commande autoconnect ( ici : AutoconnectAP )
    // wifiManager.autoConnect("AutoConnectAP");
    //Si rien indiqué le nom par défaut est  ESP + ChipID
    //wifiManager.autoConnect();
      if(!wifiManager.autoConnect("AP_ESP")) {
              P.print("erreur AP");;
              delay(3000);
              //reset and try again, or maybe put it to deep sleep
              ESP.reset();
              delay(5000);
        } 
    
// ****** Fin config WIFI Manager ************



 //******* OTA ***************
// Port defaults to 8266
  // ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setHostname("EspTestOTA");

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH)
      type = "sketch";
    else // U_SPIFFS
      type = "filesystem";
    digitalWrite(led, HIGH); // allume led au début du transfert
      P.print("Update ..."); 
    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    //Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
     P.print("Reboot ..."); 
    digitalWrite(led, LOW); // éteint à la fin de la mise à jour
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    sprintf(Notif,"Upload  %u%%", (progress / (total / 100)));
     P.print(Notif); 
    //Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    //Serial.printf("Error[%u]: ", error);
  });
  ArduinoOTA.begin();
  //********* Fin OTA ***************
   
 

  // on attend d'être connecté au WiFi avant de continuer
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  P.print("Wait ..."); 
  }
  // on affiche l'adresse IP attribuée pour le serveur DSN
  //Serial.print("IP address: ");
  //Serial.println(WiFi.localIP());
  P.print("Wifi Ready ...");
  delay(300);
  P.print(WiFi.localIP().toString());
  delay(2000);
  
  // on définit les points d'entrée (les URL à saisir dans le navigateur web) et on affiche un simple texte 
  server.on("/", [](){
    server.send(200, "text/plain", "Page d'accueil");
  });

 server.on("/led", []() {
  String Etat=server.arg("etat");
  if (Etat == "on") digitalWrite(led, LOW);
  else if (Etat == "off") digitalWrite(led, HIGH);
  server.send(200, "text/plain", "la led est  " + Etat);
});

  // on démarre le serveur web 
  server.begin();
  pinMode(led, OUTPUT);     // Initialise la broche "led" comme une sortie 
  digitalWrite(led, HIGH);
   P.print("OK ..."); 
}
 

void loop() {
  // à chaque iteration, la fonction handleClient traite les requêtes 
  server.handleClient();
   // Surveillance des demandes de mise à jour en OTA
  ArduinoOTA.handle();
             
}

Qu’apporte ce script , par rapport à la version précédente : Des messages d’informations sur les différentes étapes de sketch.

  • Phase WifiManager : Une fonction de callback à été ajoutée , afin d’informer l’utilisateur de configurer son module en allant sur l’AP créé par le module ( le nom de l’AP et l’adresse IP du module s’affiche sur le Display ).
    P.print(WiFi.softAPIP().toString());
    P.print(myWiFiManager->getConfigPortalSSID());
  • Phase OTA : Une information sur chaque étape : Start , End et Progress qui permet d’afficher un compteur en pourcentage sur le téléchargement en cours .
    sprintf(Notif, »Upload %u%% », (progress / (total / 100)));
    P.print(Notif);
  • Phase 3 : Information sur la connexion à votre reseau WIFI , affichage de l’adresse IP obtenue.
    P.print(« Wifi Ready … »);
    delay(300);
    P.print(WiFi.localIP().toString());
  • Phase 4 : Fin de la boucle setup
[adsense]

Fonction Temps et affichage de l’heure

Nous pourrions utiliser un module RTC , comme dans le premier article , sur la conception de l’horloge avec le module Arduino. Mais étant donné que ce module dispose d’une connexion WIFI permanente , nous allons synchroniser l’heure système sur un serveur de temps afin de récupérer l’heure universelle régulièrement , et ainsi permettre d’être toujours à l’heure.

Pour cela nous allons utiliser , les deux librairies suivantes :

time et NTPclient . A ajouter par l’intermédiaire du gestionnaire de bibliothèque ou à télécharger directement sur leurs github associés.

On définit ensuite les paramètres NTP suivants :

// Paramètre NTP
// Serveur NTP
const char ntpserver[] = « pool.ntp.org »;
// TimeZone
int8_t timeZone = 1;
// Le fuseau utilise les horaires été / hiver
bool DLS = true;

Dans la boucle Setup() , on va démarrer le service NTP avec les instructions suivantes :

//******* Service NTP ********
// Démarrage du processus NTP
NTP.begin(ntpserver, timeZone, DLS);
// Intervalle de  synchronisation en seconde , 10 s au départ pour forcer une mise à jour rapide dès le démarrage.
NTP.setInterval (10);

Dans la boucle loop() , on définit la fonction de callback dédiée au process NTP , afin d’agir en fonction des différents évènements.

NTP.onNTPSyncEvent ([](NTPSyncEvent_t event) {
processNtpEvent(event);
});

La fonction processNTPEvent , est définie en dehors des deux boucles :

void processNtpEvent (NTPSyncEvent_t ntpEvent) {
if (ntpEvent) {
         if (ntpEvent == noResponse)
// action à définir si aucune réponse ou réponse erronée en retour
else if (ntpEvent == invalidAddress)
// action à definir si adresse serveur invalide
         }      else  {
// Réponse valide et serveur accessible  — Tout est OK
NTP.setInterval (1800);  // Apres première synchro , le temps de synchronisation est augmenté à 30 mn , afin d’éviter d’envoyer trop de requête )
         }
}

Une fois le service NTP synchronisé , l’heure peut être affichée à l’aide de la librairie Time.

par le biais des fonctions suivantes :

hour();            // L'heure (0-23)
minute();          // Minute (0-59)
second();          // Seconde (0-59)
day();             // Le jour(1-31)
weekday();         // Numéro de jour (1-7), Dimanche est le jour 1
month();           // Numéro du mois (1-12)
year();            // l'année sur 4 digit: (2017,2018 , etc )

Pour afficher l’heure , nous allons inclure dans la boucle loop , les instructions suivantes :

if (P.displayAnimate())   // Boucle pour contrôler les animations de l’afficheur
{
digitalClockDisplay().toCharArray(Notif,BUF_SIZE); // fonction pour récupérer l’heure et la formater.
P.displayText(Notif, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
 // affichage de l’horloge sur le display avec effet central 

}

Pour le formatage de l’heure , on utilise la fonction suivante :

// Fonction clockformat
String digitalClockDisplay()
     {
String message;
// si date pas récupérée affiche init …
if ( year() == 1970) {    message= »Init.. »;
    }
else {
message=hour();
message+=printDigits(minute());
// Affiche les secondes si variable DisSec sur true
if ( DisSec ) { message+=printDigits(second()); }
}
return message;
}

Fonction qui permet d’ajouter les deux points et le zéro avant les minutes et les secondes.

String printDigits(int digits)
{
String Digital;
Digital= »: »;
if (digits < 10) Digital+= »0″;
Digital+=digits;
return Digital;
}

Ce qui donne le script complet suivant :

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
// WIFI Manager , afin de gérer la connexion au WIFI de façon plus intuitive
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager

///includes nécessaires au fonctionnement de l'OTA :
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

// gestion de l'affichage matricielle
#include <MD_Parola.h>
#include <MD_MAX72xx.h>

// librairie temps
#include <TimeLib.h>
#include <NtpClientLib.h>

ESP8266WebServer server(80);         // serveur WEB sur port 80

// définition du numéro de LED interne 
int led = 2; // led built IN

// Paramétrage matrice  ( Pin Arduino où est branchée la matrice )
#define MAX_DEVICES 8 // ( nombre de matrice )
#define CLK_PIN   D5
#define DATA_PIN  D7
#define CS_PIN    D6
// initialisation de la matrice
MD_Parola P = MD_Parola(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); 

//variable systemes
#define  BUF_SIZE  60
char Notif[BUF_SIZE];
boolean DisSec = true;

// Parametre NTP
// Serveur NTP
const char ntpserver[] = "pool.ntp.org";
// TimeZone
int8_t timeZone = 1;
// Le fuseau utilise les horaires été / hiver
bool DLS = true;


void configModeCallback (WiFiManager *myWiFiManager) {
  P.print("Choisir AP..");
  delay(3000);
  P.print(WiFi.softAPIP().toString());
    delay(3000);
    P.print(myWiFiManager->getConfigPortalSSID());
  //Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  //Serial.println(myWiFiManager->getConfigPortalSSID());
}


void processNtpEvent (NTPSyncEvent_t ntpEvent) {
  if (ntpEvent) {
    if (ntpEvent == noResponse)
      P.print ("Serveur NTP injoignable");
    else if (ntpEvent == invalidAddress)
      P.print ("Adresse du serveur NTP invalide");
  } else {
    //P.print ("Récupération du temps NTP: ");
    //P.print (NTP.getTimeDateString (NTP.getLastNTPSync ()));
    NTP.setInterval (1800);
  }
}

void setup() {
   //démarrage Display
   P.begin();

      //******** WiFiManager ************
    //Local intialization. Once its business is done, there is no need to keep it around
    WiFiManager wifiManager;

     //Si besoin de fixer une adresse IP
    //wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
    
    //Forcer à effacer les données WIFI dans l'eprom , permet de changer d'AP à chaque démarrage ou effacer les infos d'une AP dans la mémoire (à valider , lors du premier lancement)
    //wifiManager.resetSettings();
    //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
     wifiManager.setAPCallback(configModeCallback);
    
    //Récupère les identifiants   ssid et Mot de passe dans l'eprom et essaye de se connecter
    //Si pas de connexion possible , il démarre un nouveau point d'accès avec comme nom , celui définit dans la commande autoconnect ( ici : AutoconnectAP )
    // wifiManager.autoConnect("AutoConnectAP");
    //Si rien indiqué le nom par défaut est  ESP + ChipID
    //wifiManager.autoConnect();
      if(!wifiManager.autoConnect("AP_ESP")) {
              P.print("erreur AP");;
              delay(3000);
              //reset and try again, or maybe put it to deep sleep
              ESP.reset();
              delay(5000);
        } 
    
// ****** Fin config WIFI Manager ************



 //******* OTA ***************
// Port defaults to 8266
  // ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setHostname("EspTestOTA");

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH)
      type = "sketch";
    else // U_SPIFFS
      type = "filesystem";
    digitalWrite(led, HIGH); // allume led au début du transfert
      P.print("Update ..."); 
    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    //Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
     P.print("Reboot ..."); 
    digitalWrite(led, LOW); // éteint à la fin de la mise à jour
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    sprintf(Notif,"Upload  %u%%", (progress / (total / 100)));
     P.print(Notif); 
    //Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    //Serial.printf("Error[%u]: ", error);
  });
  ArduinoOTA.begin();
  //********* Fin OTA ***************
   
 

  // on attend d'être connecté au WiFi avant de continuer
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  P.print("Wait ..."); 
  }
  // on affiche l'adresse IP attribuée pour le serveur DSN
  //Serial.print("IP address: ");
  //Serial.println(WiFi.localIP());
  P.print("Wifi Ready ...");
  delay(300);
  P.print(WiFi.localIP().toString());
  delay(2000);

 

  //*************************
  
  // on définit les points d'entrée (les URL à saisir dans le navigateur web) et on affiche un simple texte 
  server.on("/", [](){
    server.send(200, "text/plain", "Page d'accueil");
  });

 server.on("/led", []() {
  String Etat=server.arg("etat");
  if (Etat == "on") digitalWrite(led, LOW);
  else if (Etat == "off") digitalWrite(led, HIGH);
  server.send(200, "text/plain", "la led est  " + Etat);
});

  // on démarre le serveur web 
  server.begin();


    //******* Service NTP ********
// Démarrage du processus NTP  
NTP.begin(ntpserver, timeZone, DLS);
// Intervalle de synchronisation en seconde , 10 s au départ pour forcer une mise à jour rapide
NTP.setInterval (10);


  pinMode(led, OUTPUT);     // Initialise la broche "led" comme une sortie 
  digitalWrite(led, HIGH);
   P.print("OK ...");
}

 

void loop() {
  NTP.onNTPSyncEvent ([](NTPSyncEvent_t event) {
  processNtpEvent(event);
});
  // à chaque iteration, la fonction handleClient traite les requêtes 
  server.handleClient();
   // Surveillance des demandes de mise à jour en OTA
  ArduinoOTA.handle();

  if (P.displayAnimate())
{
         digitalClockDisplay().toCharArray(Notif,BUF_SIZE);
  
    P.displayText(Notif, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);    
}
}


// Fonction clockformat
String digitalClockDisplay()
    {
      String message;
      if ( year() == 1970) {
             message="Init..";
            }
        else {
          message=hour();
          message+=printDigits(minute());
          if ( DisSec ) { message+=printDigits(second()); }
          }
  return message;
  }

String printDigits(int digits)
{
  String Digital;
  Digital=":";
  if (digits < 10) Digital+="0";
  Digital+=digits;
  return Digital;
}

Avec la variable suivante :

boolean DisSec = true;

vous pouvez afficher les secondes ( true ) ou ne pas les afficher ( false ).

Ajout des Notifications

Les messages vont être envoyés par le biais du Wifi , en appelant l’adresse Web du serveur de notre module.

Sous la forme : http://ip_module/Notification?msg=test

Pour cela, nous allons mettre en place une page Web , dans notre programme sous la forme suivante :

server.on(« /Notification », [](){
// on récupère le paramètre msg dans l’url
message=server.arg(« msg »);
// on affecte le message à  l’écran et on passe la variable Alert a true , afin de signaler une demande d’affichage
message.toCharArray(Notif,BUF_SIZE);
Alert=true;
// on répond au client , en affichant le message récupéré
server.send(200, « text/plain », « message received: » + message);
});

Dans la boucle loop , au niveau de la boucle qui contrôle l’affichage du display , on va apporter les modifications suivantes :

if (Alert) {
P.print(«  »);
P.setIntensity(MAX_INTENSITY); // intensité au max
P.displayText(Notif, PA_LEFT, 40, 1000, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
Alert=false;
}
else {
// Affichage heure
P.setIntensity(Intensite);
digitalClockDisplay().toCharArray(Notif,BUF_SIZE);
P.displayText(Notif, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
}

Si Alert est a True , on ajuste l’intensité de l’écran au Max, et on fait défiler le texte vers la gauche à une vitesse de défilement de 40 et une pause de 1000 Millisecondes.

Puis le paramètre Alert passe à False , afin d’afficher l’heure à la prochaine boucle. L’intensité du display , récupère sa valeur d’origine.

Gestion de la luminosité

Afin d’éviter que l’écran soit trop lumineux le soir , j’ai ajouté une fonction qui permet toutes les 5 secondes de contrôler la luminosité ambiante ( via une résistance sensible à la lumière ) et ajuster ainsi l’intensité des leds.

int Intensite=5;
const long interval = 5000;  // intervalle pour mesure luminosite réglé sur 5 s
unsigned long previousMillis=0 ;


// fonction réglage auto luminosité
void luminosite() {
  sensorValue = analogRead(A0); // read analog input pin 0
  Intensite =round((sensorValue*1.5)/100);
  if (Intensite < 1 ) Intensite = 1 ;
  if (Intensite > 15 ) Intensite = MAX_INTENSITY;
}


void loop () {
...........

 if( millis() - previousMillis >= interval) {
    previousMillis = millis();
  luminosite();
  }

..........
}

 

Pour mesurer l’intensité lumineuse , on utilise une résistance sensible à la lumière ( Photo résistance ). Cette résistance varie en fonction de la luminosité ambiante.

Photo résistance , résistance sensible à la lumière

Pour lire cette variation , on va réaliser le branchement suivant :

Schéma de montage du photoresistor . ( attention à bien brancher sur le 3,3 V et non sur le 5V , sous peine de détruire votre module )

Attention l’entrée Analogique A0 du module ESP8266 , ne doit pas dépasser 3,3 V .

Pour lire la valeur A0 , on utilise la fonction analogRead(A0) , qui en fonction de la variation de la Photo-résistance donnera une valeur comprise entre 0 ( Nuit ) et 1023 ( en pleine lumière ).

Sachant que l’intensité du display , varie de 0 à 15 ( 0 étant éteint ) , on applique la formule suivante :

round((sensorValue*1.5)/100);

Qui permet de récupérer une valeur entre 0 et 15. Afin d’éviter d’éteindre le display ou d’envoyer une valeur trop haute , le retour est compris entre 1 et 15 par les deux conditions if.

Ce qui donne le script final complet :

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
// WIFI Manager , afin de gerer la connexion au WIFI de façon plus intuitive
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager

///includes nécessaires au fonctionnement de l'OTA :
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

// gestion de l'affichage matricielle
#include <MD_Parola.h>
#include <MD_MAX72xx.h>

// librairie temps
#include <TimeLib.h>
#include <NtpClientLib.h>

ESP8266WebServer server(80);         // serveur WEB sur port 80

// définition du numéro de LED interne 
int led = 2; // led built IN
// variable pour stocker la valeur du photoresistor
int sensorValue;

// Paramétrage matrice  ( Pin Arduino où est branchée la matrice )
#define MAX_DEVICES 8 // ( nombre de matrice )
#define CLK_PIN   D5
#define DATA_PIN  D7
#define CS_PIN    D6
// initialisation de la matrice
MD_Parola P = MD_Parola(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); 

//variable systemes
#define  BUF_SIZE  60
char Notif[BUF_SIZE];
boolean DisSec = true;
boolean Alert=false;
int Intensite=5;
const long interval = 5000;  // interval pour mesure luminosite réglé sur 5 s
unsigned long previousMillis=0 ;
String message="";

// Paramètre NTP
// Serveur NTP
const char ntpserver[] = "pool.ntp.org";
// TimeZone
int8_t timeZone = 1;
// Le fuseau utilise les horaires été / hiver
bool DLS = true;


void configModeCallback (WiFiManager *myWiFiManager) {
  P.print("Choisir AP..");
  delay(3000);
  P.print(WiFi.softAPIP().toString());
    delay(3000);
    P.print(myWiFiManager->getConfigPortalSSID());
  //Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  //Serial.println(myWiFiManager->getConfigPortalSSID());
}


void processNtpEvent (NTPSyncEvent_t ntpEvent) {
  if (ntpEvent) {
    if (ntpEvent == noResponse)
      P.print ("Serveur NTP injoignable");
    else if (ntpEvent == invalidAddress)
      P.print ("Adresse du serveur NTP invalide");
  } else {
    //P.print ("Récupération du temps NTP: ");
    //P.print (NTP.getTimeDateString (NTP.getLastNTPSync ()));
    NTP.setInterval (1800);
  }
}


// fonction réglage auto luminosité
void luminosite() {
  sensorValue = analogRead(A0); // read analog input pin 0
  Intensite =round((sensorValue*1.5)/100);
  if (Intensite < 1 ) Intensite = 1 ;
  if (Intensite > 15 ) Intensite = MAX_INTENSITY;
}

void setup() {
   //démarrage Display
   P.begin();

      //******** WiFiManager ************
    //Local intialization. Once its business is done, there is no need to keep it around
    WiFiManager wifiManager;

     //Si besoin de fixer une adresse IP
    //wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
    
    //Forcer à effacer les données WIFI dans l'eprom , permet de changer d'AP à chaque démarrage ou effacer les infos d'une AP dans la mémoire (à valider , lors du premier lancement  )
    //wifiManager.resetSettings();
    //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
     wifiManager.setAPCallback(configModeCallback);
    
    //Récupère les identifiants   ssid et Mot de passe dans l'eprom  et essaye de se connecter
    //Si pas de connexion possible , il démarre un nouveau point d'accès avec comme nom , celui défini dans la commande autoconnect ( ici : AutoconnectAP )
    // wifiManager.autoConnect("AutoConnectAP");
    //Si rien indiqué le nom par défaut est  ESP + ChipID
    //wifiManager.autoConnect();
      if(!wifiManager.autoConnect("AP_ESP")) {
              P.print("erreur AP");;
              delay(3000);
              //reset and try again, or maybe put it to deep sleep
              ESP.reset();
              delay(5000);
        } 
    
// ****** Fin config WIFI Manager ************



 //******* OTA ***************
// Port defaults to 8266
  // ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setHostname("EspTestOTA");

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH)
      type = "sketch";
    else // U_SPIFFS
      type = "filesystem";
    digitalWrite(led, HIGH); // allume led au début du transfert
      P.print("Update ..."); 
    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    //Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
     P.print("Reboot ..."); 
    digitalWrite(led, LOW); // éteint à la fin de la mise à jour
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    sprintf(Notif,"Upload  %u%%", (progress / (total / 100)));
     P.print(Notif); 
    //Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    //Serial.printf("Error[%u]: ", error);
  });
  ArduinoOTA.begin();
  //********* Fin OTA ***************
   
 

  // on attend d'être connecté au WiFi avant de continuer
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  P.print("Wait ..."); 
  }
  // on affiche l'adresse IP attribuée pour le serveur DSN
  //Serial.print("IP address: ");
  //Serial.println(WiFi.localIP());
  P.print("Wifi Ready ...");
  delay(300);
  P.print(WiFi.localIP().toString());
  delay(2000);

 

  //*************************
  
  // on définit les points d'entrée (les URL à saisir dans le navigateur web) et on affiche un simple texte 
  server.on("/", [](){
    server.send(200, "text/plain", "Page d'accueil");
  });

 server.on("/Notification", [](){
    // on récupère le paramètre msg dans l'url
    message=server.arg("msg");
    message.toCharArray(Notif,BUF_SIZE); 
    Alert=true;
    //P.print(message);
    // on repond au client
    server.send(200, "text/plain", "message received:" + message);
  });
  
 server.on("/led", []() {
  String Etat=server.arg("etat");
  if (Etat == "on") digitalWrite(led, LOW);
  else if (Etat == "off") digitalWrite(led, HIGH);
  server.send(200, "text/plain", "la led est  " + Etat);
});

  // on demarre le serveur web 
  server.begin();


    //******* Service NTP ********
// Démarrage du processus NTP  
NTP.begin(ntpserver, timeZone, DLS);
// Intervalle de synchronisation en seconde , 10 s au départ pour forcer une mise à jour rapide
NTP.setInterval (10);


  pinMode(led, OUTPUT);     // Initialise la broche "led" comme une sortie 
  digitalWrite(led, HIGH);
   P.print("OK ...");
}

 

void loop() {
  if( millis() - previousMillis >= interval) {
    previousMillis = millis();
  luminosite();
  }
  
  NTP.onNTPSyncEvent ([](NTPSyncEvent_t event) {
  processNtpEvent(event);
});
  // à chaque iteration, la fonction handleClient traite les requêtes 
  server.handleClient();
   // Surveillance des demandes de mise à jour en OTA
  ArduinoOTA.handle();

  if (P.displayAnimate())
{
  if (Alert) {
    
    P.setIntensity(MAX_INTENSITY); // intensité au max
   P.displayText(Notif, PA_LEFT, 40, 1000, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
   Alert=false;
  }
  else {
  // Affichage heure
   P.setIntensity(Intensite); 
    digitalClockDisplay().toCharArray(Notif,BUF_SIZE);
    //P.print(Intensite); Debug pour afficher valeur luminosité
    P.displayText(Notif, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
  }
}
}


// Fonction clockformat
String digitalClockDisplay()
    {
      message;
      if ( year() == 1970) {
             message="Init..";
            }
        else {
          message=hour();
          message+=printDigits(minute());
          if ( DisSec ) { message+=printDigits(second()); }
          }
  return message;
  //Serial.print(day());
  //Serial.print(".");
  //Serial.print(month());
  //Serial.print(".");
  //Serial.print(year());
  //Serial.println();
  }

String printDigits(int digits)
{
  String Digital;
  Digital=":";
  if (digits < 10) Digital+="0";
  Digital+=digits;
  return Digital;
}
[adsense]

Integration Jeedom

Afin de permettre à Jeedom ( ou toute autre solution domotique ) , d’envoyer des notifications sur notre horloge . Nous allons créer un nouvel élément à l’aide du plugin Script de jeedom.

Aller dans Scipt , et ajouter . Choisisser un nom.

Puis dans l’onglet commande , ajouter une commande script.

Cette commande sera de type HTTP

commande notif jeedom
Commande de type http , dans le module Script de jeedom

Choisissez dans type : Action et type d’action : message.
Dans le champs requête :
 Ip_de_votre_module/Notification?msg=#message#

Sauvegarder puis tester , vous devriez voir défiler sur votre écran : Ceci est un test de message pour la commande notification.

exemple depuis Widget jeedom

 

test depuis le Widget Jeedom.

L’info titre n’est pas utilisé dans cet exemple.

Dans le script j’ai ajouté une variable type , qui peut être utilisée avec le mot clé « alert » afin de mettre l’intensité au max.

Il suffit alors de modifier la requête http de la commande script créée :

IP_Module_horloge/Notification?msg=#message#&type=#title#

Les notifications peuvent être appelées depuis un scénario.

Cela se présente sous la forme suivante :

Exemple appel depuis un scénario jeedom

Dans jeedom , il n’y a pas de limite aux types de notification. Elles peuvent servir à afficher :

  • Un message d’information
  • Un message d’alerte ( en indiquant alert dans l’onglet titre )
  • la date du jour et la saint du jour  ( #sjour# , #jour# #smois# #annee# Saint du jour : #[Admin / Info][INFO][Saint du jour]# )
  • des flash news
  • la météo du jour
  • etc ……

 

pour terminer cet article , il ne reste plus qu’a décrire , comment implanter une interface web pour le paramétrage du module

Paramétrage depuis interface WEB

Dans le cadre de cet article , nous allons mettre une page WEB , qui affichera les informations suivantes :

  • Etat du système
  • Parametrage de l’affichage des secondes
  • Parametrage Intensité

Avec ces différents exemples , vous serez en mesure d’apporter des paramètres supplémentaires , que vous jugerez utile , dans le cas d’une amélioration de l’horloge.

Voici la page WEB qui sera dédié aux réglages :

Parametrage du module ESP et Information

Pour cela nous allons modifier le script de la manière suivante :

..........
// dans la partie definition de notre serveur web
server.on("/", handleRoot);  // on ajoute la fonction handleRoot

server.on("/Notification", [](){
    // on recupere les parametre dans l'url
    message=server.arg("msg");
    message.toCharArray(Notif,BUF_SIZE);
    if (server.arg("type")=="alert") {
      P.setIntensity(MAX_INTENSITY); // intensité au max
    }
    Alert=true;
    //P.print(message);
    // on repond au client
    server.send(200, "text/plain", "message received:" + message + server.arg("type"));
  });
........

La fonction handleroot sera en charge d’intercepter tous les appels effectué à la racine du site WEB du module.

Avant la section setup() , nous allons insérerez les deux nouvelles fonctions :

handleRoot : qui sera en charge d’afficher la page HTML du formulaire ou de rediriger vers handleSubmit , si des données sont présentes dans le formulaire.
handleSubmit : Qui sera en charge de récupérer les variables soumis dans le formulaire et de les traiter.

// ******************
// Gestiuon page WEB
//******************

void handleRoot(){ 
  if ( server.hasArg("SEC") ) {
    handleSubmit();
  } 
  else {
    server.send ( 200, "text/html", getPage() );
  }  
}
 
void handleSubmit() {
  String SEC;
  SEC = server.arg("SEC");
  if ( server.arg("Autolum") =="manu" ) {
  AutoIn=false;
  Intensite=server.arg("ReglageInt").toInt();
  } else { AutoIn=true;}
  if ( server.arg("HOR") =="1" ) {
  TimeOn=true;
  } else { TimeOn=false;}
  
  if ( SEC == "1" ) {
    DisSec=true;
    server.send ( 200, "text/html", getPage() );
  } else if ( SEC == "0" ) {
    DisSec=false;
    server.send ( 200, "text/html", getPage() );
  } else {
   // Serial.println("Err Led Value");
  }
}

//***********************

Dans cette exemple , j’ai mis en place un formulaire permettant de :

  • Afficher les secondes
  • Gérer la luminosité
  • Afficher l’horloge ( écran vide , juste un point indique que l’horloge est active )

Quand à la fonction getPage , elle me permet d’aller chercher ma page WEB.

La fonction est écrite en fin de script , après la fonction loop().

........
//************************************
// Page WEB
// ***********************************
String getPage(){
  String page = "<html lang=fr-FR><head><meta http-equiv='refresh' content='120'/>";
  page += "<title>Horloge / Notification - Byfeel.info</title>";
  page += "<style> table.steelBlueCols { border: 3px solid #555555;background-color: #555555;width: 95%;text-align: left;border-collapse: collapse;}";
  page +="table.steelBlueCols td, table.steelBlueCols th { border: 1px solid #555555;padding: 4px 9px;}";
  page +="table.steelBlueCols tbody td {font-size: 1em;font-weight: bold;color: #FFFFFF;} table.steelBlueCols td:nth-child(even) {background: #398AA4;}";
  page +="fieldset { padding:0 20px 20px 20px; margin-bottom:10px;border:1px solid #398AA4;width:95%;} div.bloc {float:left;width:450px}";
  //page +="table.steelBlueCols tfoot .links a{display: inline-block;background: #FFFFFF;color: #398AA4;padding: 2px 8px;border-radius: 5px;"
  page +="}</style>";
  page += "</head><body><h1><span style='background-color: #398AA4; color: #ffffff; padding: 0 5px;'>Horloge - Notification</span></h1>";
   page += "<div class='bloc'><form action='/Notification' method='GET'>";
  page +="<fieldset><legend>Envoyer une Notification :</legend>";
  page += "<INPUT type='text' name='msg' id='msg'maxlength='59' style='width:400px;' placeholder='Votre Message - 60 caracteres max -'/>";
  page +="</fieldset>";
  page += "<INPUT type='submit' value='Envoyer Message' /></div>";
  page += "</form></div>";
  page +="<div style='clear:both;'></div>";
  page += "<div class='bloc'><h3>Systeme</h3>";
  page += "<table class='steelBlueCols'><tbody>";
  page += "<tr><td>Mise en Marche </td><td>"+ NTP.getUptimeString() + "</td></tr>";
  page += "<tr><td>Serveur NTP </td><td>";
  page += ntpserver;
  page +="</td></tr>";
  page += "<tr><td>Premiere synchro NTP </td><td>"+NTP.getTimeDateString(NTP.getFirstSync())+"</td></tr>";
  page += "<tr><td>Derniere synchro NTP </td><td>"+NTP.getTimeDateString(NTP.getLastNTPSync())+"</td></tr>";
  page +="</tbody></table></div>";
  page += "<div class='bloc'><h3>Resau</h3>";
  page += "<table class='steelBlueCols'><tbody>";
  page += "<tr><td>mac adress : </td><td>";
  page += WiFi.macAddress().c_str();
  page +="</td></tr>";
  page += "<tr><td>IP</td><td>"+ WiFi.localIP().toString() + "</td></tr>";
  page += "<tr><td>Masque </td><td>"+ WiFi.subnetMask().toString() + "</td></tr>";
  page += "<tr><td>Passerelle</td><td>"+ WiFi.gatewayIP().toString() + "</td></tr>";
  page += "<tr><td>DNS primaire</td><td>"+ WiFi.dnsIP().toString() + "</td></tr>";
  page += "<tr><td>DNS secondaire</td><td>"+ WiFi.dnsIP(1).toString() + "</td></tr>";
  page +="</tbody></table></div>";
  page +="<div class='bloc'><h3>Wifi</h3>";
  page += "<table class='steelBlueCols'><tbody>";
  page += "<tr><td>Hostname</td><td>"+ WiFi.hostname() + "</td></tr>";
  page += "<tr><td>SSID</td><td>"+ WiFi.SSID() + "</td></tr>";
  page += "<tr><td>Signal WIFI</td><td>";
  page += WiFi.RSSI();
  page +=" dBm</td></tr>";
  page += "<tr><td>BSSID </td><td>";
  page += WiFi.BSSIDstr().c_str();
  page +="</td></tr>";
  page +="</tbody></table></div>";
  page +="<div style='clear:both;'></div>";
  page += "<div class='bloc'><h3>Parametres :</h3>";
  page += "<form action='/' method='POST'>";
  page +="<fieldset><legend>Affichage des Secondes :</legend>";
  page += "<INPUT type='radio' name='SEC' value='1' id='on'";
  if (DisSec==true) page +=" checked ";
  page += "><label for='on'>ON</label>";
  page +="<INPUT type='radio' name='SEC' value='0' id='off'";
  if (DisSec==false) page +=" checked ";
  page += "><label for='off'>OFF</label></fieldset>";
  page +="<fieldset><legend>Affichage Horloge :</legend>";
  page += "<INPUT type='radio' name='HOR' value='1' id='horon'";
  if (TimeOn==true) page +=" checked ";
  page += "><label for='horon'>ON</label>";
  page +="<INPUT type='radio' name='HOR' value='0' id='horoff'";
  if (TimeOn==false) page +=" checked ";
  page += "><label for='horoff'>OFF</label></fieldset>";
  page +="<fieldset><legend>Gestion de la luminosit&eacute;e : </legend>";
  page += "<INPUT type='radio' name='Autolum' value='auto' id='auto'";
  if (AutoIn==true) page +=" checked ";
  page += "><label for='auto'>AUTO</label>";
  page +="<INPUT type='radio' name='Autolum' value='manu' id='manu'";
  if (AutoIn==false) page +=" checked ";
  page += "><label for='manu'>Manuel</label></P>";
  if (AutoIn==false) {
  page +="<p>Valeur luminosit&eacute;e : ";
  page +=Intensite;
  page +="</p>";
  page += "<p><input id='slider1' type='range' min='0' max='15' step='1' name='ReglageInt' list='tickmarks' value='";
  page +=Intensite;
  page +="'/>";
  page +="<datalist id='tickmarks'>";
  page +="<option value='0' label='0'>";
  page +="<option value='1'>";
  page +="<option value='2'>";
  page +="<option value='3'>";
  page +="<option value='4'>";
  page +="<option value='5' label='5'>";
  page +="<option value='6'>";
  page +="<option value='7'>";
  page +="<option value='8'>";
  page +="<option value='9'>";
  page +="<option value='10' label='10'>";
  page +="<option value='11'>";
  page +="<option value='12'>";
  page +="<option value='13'>";
  page +="<option value='14'>";
  page +="<option value='15' label='15'>";
  page +="</datalist></p>";
  };
  page +="</fieldset>";
  page += "<INPUT type='submit' value='Actualiser'name='parametres'/></div>";
  page += "</form>";
  page += "<br><br>";
  page += "</body></html>";
  return page;
}
........

Pour , vous aider à écrire votre page WEB , vous pouvez vous aider d’éditeurs en ligne comme Online HTML Editor .

Dans cette page , je gére deux formulaires :

  • le premier : Envoie d’une notification avec le formulaire « <form action=’/Notification’ method=’GET’> » , par la methode Get et appelle de la page /Notification ( celle utilisé par jeedom , pour l’envoie des notifications ).
  • Le second : Paramètres , utilise la méthode POST, « <form action=’/’ method=’POST’> »  , afin d’être traité par la fonction hndleSubmit .

Le script final au complet :

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
// WIFI Manager , afin de gerer la connexion au WIFI de façon plus intuitive
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager

///includes necessaires au fonctionnement de l'OTA :
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

// gestion de l'affichage matricielle
#include <MD_Parola.h>
#include <MD_MAX72xx.h>

// librairie temps
#include <TimeLib.h>
#include <NtpClientLib.h>

ESP8266WebServer server(80);         // serveur WEB sur port 80

// definition du numero de LED interne 
int led = 2; // led built IN
// variable pour stocker la valeur du photoresistor
int sensorValue;

// Parametrage matrice  ( Pin Arduino ou est branché la matrice )
#define MAX_DEVICES 8 // ( nombre de matrice )
#define CLK_PIN   D5
#define DATA_PIN  D7
#define CS_PIN    D6
// initialisation de la matrice
MD_Parola P = MD_Parola(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); 

//variable systemes
const char nom_module[] ="ESP_tuto-horloge";
#define  BUF_SIZE  60
char Notif[BUF_SIZE];
boolean DisSec = true;
boolean Alert=false;
boolean AutoIn=true;
boolean TimeOn=true;
int Intensite=5;
const long interval = 5000;  // interval pour mesure luminosite réglé sur 5 s
unsigned long previousMillis=0 ;
String message="";

// Parametre NTP
// Serveur NTP
const char ntpserver[] = "pool.ntp.org";
// TimeZone
int8_t timeZone = 1;
// Le fuseau utilise les horaires été / hiver
bool DLS = true;
boolean syncEventTriggered = false; // True if a time even has been triggered
NTPSyncEvent_t ntpEvent; // Last triggered event


void configModeCallback (WiFiManager *myWiFiManager) {
  P.print("Choisir AP..");
  delay(3000);
  P.print(WiFi.softAPIP().toString());
    delay(3000);
    P.print(myWiFiManager->getConfigPortalSSID());
  //Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  //Serial.println(myWiFiManager->getConfigPortalSSID());
}


//void processNtpEvent (NTPSyncEvent_t ntpEvent) {
 void processSyncEvent (NTPSyncEvent_t ntpEvent) {
  if (ntpEvent) {
    if (ntpEvent == noResponse)
      P.print ("Serveur NTP injoignable");
    else if (ntpEvent == invalidAddress)
      P.print ("Adresse du serveur NTP invalide");
  } else {
     if ( year() != 1970 or year() != 2036 ) {
             NTP.setInterval (1200);
            }
    
  }
  
}



// fonction reglage auto luminosite
void luminosite() {
  sensorValue = analogRead(A0); // read analog input pin 0
  Intensite =round((sensorValue*1.5)/100);
  if (Intensite < 1 ) Intensite = 0 ;
  if (Intensite > 15 ) Intensite = MAX_INTENSITY;
}


// ******************
// Gestiuon page WEB
//******************

void handleRoot(){ 
  if ( server.hasArg("SEC") ) {
    handleSubmit();
  } 
  else {
    server.send ( 200, "text/html", getPage() );
  }  
}
 
void handleSubmit() {
  String SEC;
  SEC = server.arg("SEC");
  if ( server.arg("Autolum") =="manu" ) {
  AutoIn=false;
  Intensite=server.arg("ReglageInt").toInt();
  } else { AutoIn=true;}
  if ( server.arg("HOR") =="1" ) {
  TimeOn=true;
  } else { TimeOn=false;}
  
  if ( SEC == "1" ) {
    DisSec=true;
    server.send ( 200, "text/html", getPage() );
  } else if ( SEC == "0" ) {
    DisSec=false;
    server.send ( 200, "text/html", getPage() );
  } else {
   // Serial.println("Err Led Value");
  }
}

//***********************

void setup() {
   //demarrage Display
   P.begin();

      //******** WiFiManager ************
    //Local intialization. Once its business is done, there is no need to keep it around
    WiFiManager wifiManager;

     //Si besoin de fixer une adresse IP
    //wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
    
    //Forcer à effacer les donnees WIFI dans l'eprom , permet de changer d'AP à chaque demmarrage ou effacer les infos d'une AP dans la memoire ( a valider , lors du premier lancement  )
    //wifiManager.resetSettings();
    //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
     wifiManager.setAPCallback(configModeCallback);
    
    //Recupere les identifiants   ssid et Mot de passe dans l'eprom  et essayes de se connecter
    //Si pas de connexion possible , il demarre un nouveau point d'accés avec comme nom , celui definit dans la commande autoconnect ( ici : AutoconnectAP )
    // wifiManager.autoConnect("AutoConnectAP");
    //Si rien indiqué le nom par defaut est  ESP + ChipID
    //wifiManager.autoConnect();
      if(!wifiManager.autoConnect("AP_ESP")) {
              P.print("erreur AP");;
              delay(3000);
              //reset and try again, or maybe put it to deep sleep
              ESP.reset();
              delay(5000);
        } 
    
// ****** Fin config WIFI Manager ************



 //******* OTA ***************
// Port defaults to 8266
  // ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setHostname(nom_module);

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH)
      type = "sketch";
    else // U_SPIFFS
      type = "filesystem";
    digitalWrite(led, HIGH); // allume led au debut du transfert
      P.print("Update ..."); 
    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    //Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
     P.print("Reboot ..."); 
    digitalWrite(led, LOW); // eteint a la fin de la mise a jour
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    sprintf(Notif,"Upload  %u%%", (progress / (total / 100)));
     P.print(Notif); 
    //Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    //Serial.printf("Error[%u]: ", error);
  });
  ArduinoOTA.begin();
  //********* Fin OTA ***************
   
 

  // on attend d'etre connecte au WiFi avant de continuer
  P.print("Wait ..."); 
  while (WiFi.status() != WL_CONNECTED) {
  }
  // on affiche l'adresse IP attribuee pour le serveur DSN et on affecte le nom reseau
   WiFi.hostname(nom_module);
  P.print("Wifi Ready ...");
  delay(300);
  P.print(WiFi.localIP().toString());
  delay(2000);

 

  //*************************
  
  // on definit les points d'entree (les URL a saisir dans le navigateur web) et on affiche un simple texte 
  server.on("/", handleRoot);

 server.on("/Notification", [](){
    // on recupere les parametre dans l'url
    message=server.arg("msg");
    message.toCharArray(Notif,BUF_SIZE);
    if (server.arg("type")=="alert") {
      P.setIntensity(MAX_INTENSITY); // intensité au max
    }
    Alert=true;
    //P.print(message);
    // on repond au client
    server.send(200, "text/plain", "message received:" + message + server.arg("type"));
  });
  

  // on demarre le serveur web 
  server.begin();


    //******* Service NTP ********
    NTP.onNTPSyncEvent ([](NTPSyncEvent_t event) {
        ntpEvent = event;
        syncEventTriggered = true;
    });

    
// Démarrage du processus NTP  
NTP.begin(ntpserver, timeZone, DLS);
// Interval de synchronisation en seconde , 10 s au depart pour forcer une mise a jour rapide
NTP.setInterval (10);


  pinMode(led, OUTPUT);     // Initialise la broche "led" comme une sortie 
  digitalWrite(led, HIGH);
   P.print("OK ...");
}

 

void loop() {
  // Si gestion Auto luminositée activé
  if (AutoIn) {
  if( millis() - previousMillis >= interval) {
    previousMillis = millis();
  luminosite();
  }
  }
  
// NTP.onNTPSyncEvent ([](NTPSyncEvent_t event) {
//  processNtpEvent(event);
//});
   if (syncEventTriggered) {
        processSyncEvent (ntpEvent);
        syncEventTriggered = false;
    }


  // a chaque iteration, la fonction handleClient traite les requetes 
  server.handleClient();
   // Surveillance des demandes de mise a jour en OTA
  ArduinoOTA.handle();

  if (P.displayAnimate())
{
  if (Alert) {
    
   P.displayText(Notif, PA_LEFT, 40, 1000, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
   Alert=false;
  }
  else {
  // Affichage heure
  if (TimeOn) {
   P.setIntensity(Intensite); 
    digitalClockDisplay().toCharArray(Notif,BUF_SIZE);
    //P.print(Intensite); Debug pour afficher valeur luminosite
    P.displayText(Notif, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
    } else  P.print(".");
  }
}
}


// Fonction clockformat
String digitalClockDisplay()
    {
          message=hour();
          message+=printDigits(minute());
          if ( DisSec ) { message+=printDigits(second()); }
  return message;
  //Serial.print(day());
  //Serial.print(".");
  //Serial.print(month());
  //Serial.print(".");
  //Serial.print(year());
  //Serial.println();
  }

String printDigits(int digits)
{
  String Digital;
  Digital=":";
  if (digits < 10) Digital+="0";
  Digital+=digits;
  return Digital;
}


//************************************
// Page WEB
// ***********************************
String getPage(){
  String page = "<html lang=fr-FR><head><meta http-equiv='refresh' content='120'/>";
  page += "<title>Horloge / Notification - Byfeel.info</title>";
  page += "<style> table.steelBlueCols { border: 3px solid #555555;background-color: #555555;width: 95%;text-align: left;border-collapse: collapse;}";
  page +="table.steelBlueCols td, table.steelBlueCols th { border: 1px solid #555555;padding: 4px 9px;}";
  page +="table.steelBlueCols tbody td {font-size: 1em;font-weight: bold;color: #FFFFFF;} table.steelBlueCols td:nth-child(even) {background: #398AA4;}";
  page +="fieldset { padding:0 20px 20px 20px; margin-bottom:10px;border:1px solid #398AA4;width:95%;} div.bloc {float:left;width:450px}";
  //page +="table.steelBlueCols tfoot .links a{display: inline-block;background: #FFFFFF;color: #398AA4;padding: 2px 8px;border-radius: 5px;"
  page +="}</style>";
  page += "</head><body><h1><span style='background-color: #398AA4; color: #ffffff; padding: 0 5px;'>Horloge - Notification</span></h1>";
   page += "<div class='bloc'><form action='/Notification' method='GET'>";
  page +="<fieldset><legend>Envoyer une Notification :</legend>";
  page += "<INPUT type='text' name='msg' id='msg'maxlength='59' style='width:400px;' placeholder='Votre Message - 60 caracteres max -'/>";
  page +="</fieldset>";
  page += "<INPUT type='submit' value='Envoyer Message' /></div>";
  page += "</form></div>";
  page +="<div style='clear:both;'></div>";
  page += "<div class='bloc'><h3>Systeme</h3>";
  page += "<table class='steelBlueCols'><tbody>";
  page += "<tr><td>Mise en Marche </td><td>"+ NTP.getUptimeString() + "</td></tr>";
  page += "<tr><td>Serveur NTP </td><td>";
  page += ntpserver;
  page +="</td></tr>";
  page += "<tr><td>Premiere synchro NTP </td><td>"+NTP.getTimeDateString(NTP.getFirstSync())+"</td></tr>";
  page += "<tr><td>Derniere synchro NTP </td><td>"+NTP.getTimeDateString(NTP.getLastNTPSync())+"</td></tr>";
  page +="</tbody></table></div>";
  page += "<div class='bloc'><h3>Resau</h3>";
  page += "<table class='steelBlueCols'><tbody>";
  page += "<tr><td>mac adress : </td><td>";
  page += WiFi.macAddress().c_str();
  page +="</td></tr>";
  page += "<tr><td>IP</td><td>"+ WiFi.localIP().toString() + "</td></tr>";
  page += "<tr><td>Masque </td><td>"+ WiFi.subnetMask().toString() + "</td></tr>";
  page += "<tr><td>Passerelle</td><td>"+ WiFi.gatewayIP().toString() + "</td></tr>";
  page += "<tr><td>DNS primaire</td><td>"+ WiFi.dnsIP().toString() + "</td></tr>";
  page += "<tr><td>DNS secondaire</td><td>"+ WiFi.dnsIP(1).toString() + "</td></tr>";
  page +="</tbody></table></div>";
  page +="<div class='bloc'><h3>Wifi</h3>";
  page += "<table class='steelBlueCols'><tbody>";
  page += "<tr><td>Hostname</td><td>"+ WiFi.hostname() + "</td></tr>";
  page += "<tr><td>SSID</td><td>"+ WiFi.SSID() + "</td></tr>";
  page += "<tr><td>Signal WIFI</td><td>";
  page += WiFi.RSSI();
  page +=" dBm</td></tr>";
  page += "<tr><td>BSSID </td><td>";
  page += WiFi.BSSIDstr().c_str();
  page +="</td></tr>";
  page +="</tbody></table></div>";
  page +="<div style='clear:both;'></div>";
  page += "<div class='bloc'><h3>Parametres :</h3>";
  page += "<form action='/' method='POST'>";
  page +="<fieldset><legend>Affichage des Secondes :</legend>";
  page += "<INPUT type='radio' name='SEC' value='1' id='on'";
  if (DisSec==true) page +=" checked ";
  page += "><label for='on'>ON</label>";
  page +="<INPUT type='radio' name='SEC' value='0' id='off'";
  if (DisSec==false) page +=" checked ";
  page += "><label for='off'>OFF</label></fieldset>";
  page +="<fieldset><legend>Affichage Horloge :</legend>";
  page += "<INPUT type='radio' name='HOR' value='1' id='horon'";
  if (TimeOn==true) page +=" checked ";
  page += "><label for='horon'>ON</label>";
  page +="<INPUT type='radio' name='HOR' value='0' id='horoff'";
  if (TimeOn==false) page +=" checked ";
  page += "><label for='horoff'>OFF</label></fieldset>";
  page +="<fieldset><legend>Gestion de la luminosit&eacute;e : </legend>";
  page += "<INPUT type='radio' name='Autolum' value='auto' id='auto'";
  if (AutoIn==true) page +=" checked ";
  page += "><label for='auto'>AUTO</label>";
  page +="<INPUT type='radio' name='Autolum' value='manu' id='manu'";
  if (AutoIn==false) page +=" checked ";
  page += "><label for='manu'>Manuel</label></P>";
  if (AutoIn==false) {
  page +="<p>Valeur luminosit&eacute;e : ";
  page +=Intensite;
  page +="</p>";
  page += "<p><input id='slider1' type='range' min='0' max='15' step='1' name='ReglageInt' list='tickmarks' value='";
  page +=Intensite;
  page +="'/>";
  page +="<datalist id='tickmarks'>";
  page +="<option value='0' label='0'>";
  page +="<option value='1'>";
  page +="<option value='2'>";
  page +="<option value='3'>";
  page +="<option value='4'>";
  page +="<option value='5' label='5'>";
  page +="<option value='6'>";
  page +="<option value='7'>";
  page +="<option value='8'>";
  page +="<option value='9'>";
  page +="<option value='10' label='10'>";
  page +="<option value='11'>";
  page +="<option value='12'>";
  page +="<option value='13'>";
  page +="<option value='14'>";
  page +="<option value='15' label='15'>";
  page +="</datalist></p>";
  };
  page +="</fieldset>";
  page += "<INPUT type='submit' value='Actualiser'name='parametres'/></div>";
  page += "</form>";
  page += "<br><br>";
  page += "</body></html>";
  return page;
}

 

Il ne reste plus qu’à vous trouver une petite boîte , ou en fabriquer une pour mettre votre horloge dedans.

 

 

 

37 commentaires sur “DIY Horloge et Notification Domotique ( Matrix LED ) avec Jeedom”

Les commentaires sont fermés.