DIY : i-Notif’Heure ou comment mettre en place une horloge connectée avec Notification

Cet article vous présente comment configurer , la version V2.6 pour se fabriquer une horloge connectée avec Notification , et comment la relier facilement à votre domotique.

Etant sous jeedom , je ne vais parler que de cette solution , sachant que toute les requêtes passent par du http , cela devrait facilement être adaptable à toutes les autres box.

J’ai réalisé cette petite vidéo , pour vous monter les différentes options possibles.

Presentation de la version 2.6

Liste des courses :

Minimum requis  ( 10 € ) :

  • Un module ESP8266 ( j’utilise le WEMOS D1 , très simple à utiliser et surtout possédant une alimentation +5v ) Environ 5 € sur
wemos D1
Matrice led – vue Avant

En option :

  • Une Photo résistance ( pour gérer la luminosité en automatique )  – le pack de 20 à 0,59 € sur amazon.
Photo resistance , résistance sensible à la lumiére

Un bouton poussoir ( pour gérer différentes options directement depuis l’horloge )  – quelques centimes d’euro à 1 € en fonction des modèles.

Autres options possible :  ( le code est ouvert , il est modifiable facilement pour adapter selon vos envies )

  • Un capteur température / humidité type DHT
  • Un autre bouton poussoir
  • Un capteur de présence …..

Pré-requis logiciel

  • Le logiciel IDE Arduino ( dans cet article en version 1.8.5 ) , disponible pour la plupart des plateformes.
  • Configurer pour gérer les modules ESP8266 et avec les bibliothèques adéquates. ( Voir mes précédents articles , pour la configuration de l’interface Arduino ). Si vous avez des soucis de versions , avec les bibliothèques , ci joint un lien vers mon drive pour récupérer les bibliothèques utilisées .
  • J’utilise les dernières versions des bibliothèques MD_Parola et MD_MAX en version 3 minimum.
  • Pour la partie OTA ( si vous voulez pouvoir uploader avec ide arduino) , il faut que python soit installé.

Les Sources

Les sources sont récupérables sur mon github , elles sont composées de 3 fichiers à déposer dans le même dossier de travail.

  • Notifeur vx.x.ino  ( qui est le sketch qui sera déployé depuis l’interface Arduino )
  • Parola_font_data.h  ( qui est la police de caractère UTF 8 )
  • font_byfeel.h ( qui est la police de caractère pour l’horloge )

La compilation

Au début du programme , avant l’inclusion des bibliothèques.

.......
#define Ver 2.6-2

#define NOMMODULE "NotifHeure_nom"      // nom module
#define NTPSERVER "pool.ntp.org"     // Serveur NTP
#define ACTIVBOUTON false              // Si bouton installé
#define ACTIVCAPTLUM true              // Si capteur luminosité installé

#define  BUF_SIZE  60                   // Taille max des notification ( nb de caractéres max )

// Options horloge ( valeur par defaut )
boolean AutoIn=true;      // Auto / manu intensite
boolean TimeOn=true;      // ON - off Affichage horloge
boolean DisSec=true;    // on-off secondesboolean Alert=false;  

#define DEBUG false

......

A modifier si besoin :

NOMMODULE :  Le nom que vous souhaitez donner à votre Notif’Heure

ACTIVBOUTON et ACTIVCAPTLUM servent à indiquer si vous avez monté les options ( photo resistor et bouton poussoir ) .
Si pas utilisé laisser les sur “false”

Les variables AutoIn , TimeOn et DisSec servent à définir une valeur par défaut , lors du premier lancement . Par la suite, on récupére les valeurs enregistrées dans l’EEPROM.

DEBUG , me sert lors des différents tests. ( Laisser sur false ).Si vous souhaitez l’utiliser , brancher le module en USB , et ouvrir le moniteur série.

Suite aux inclusions des différentes bibliothèques , il faudra définir le type de matrice utilisée et comment elle est connectée .

// Définition des matrices
// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 8   // nombre de matrice    
#define MAX_ZONES   1   // 1 ou 2 zones
#if (MAX_ZONES == 1 ) 
#define ZONE_TIME (MAX_DEVICES)
#else
#define ZONE_TIME  4    // taille de l'horloge Si Zone = 2
#endif
#define ZONE_MSG (MAX_DEVICES-ZONE_TIME)
#define CLK_PIN   D5
#define DATA_PIN  D7
#define CS_PIN    D6

// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Si probleme avec detection auto SPI 
// MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

#define SPEED_TIME  30
#define PAUSE_TIME  1000

Dans l’ordre :

  • HARDWARE_TYPE : Le type de matrice utilisé ( voir mon article sur les types de matrices , pour plus de précisions ). Mes matrices correspondent au type FC16.
  • MAX_DEVICES : Le nombre de module de votre matrice
  • MAX_ZONES : 1 pour utiliser tout l’affichage pour l’horloge et les notifications , 2 pour partager la matrice ( horloge  et notification sur un écran séparé)
  • ZONE_TIME : Si le paramètre 2 a été défini sur MAX_ZONES , il est possible de donner le nombre de module que l’on souhaite utiliser pour l’affichage de l’horloge.
  • ZONE_MSG : est défini automatiquement

Exemple 1 :
j’ai un module de 4 Matrices  et je souhaite un affichage commun pour l’heure et les notifications.
Les valeurs à indiquer sont MAX_devices = 4 et Max_zones = 1

Exemple 2 : 
J’ai un module composé de 8 matrices ( 2 blocs de quatre )  et je souhaite avoir une Zone de 4 pour l’heure et une deuxième zone de 4 pour les messages.
Les valeurs à indiquer : MAX_devices = 8 , MAX_Zones = 2 et Zone_time = 4

Puis indiquer les PIN  où la matrice est branchée : ( notation WEMOS , ou GPIO)

  • CLK_PIN , DATA_PIN et CS_PIN

Et enfin SPEED_TIME , PAUSE_TIME  permettent de jouer sur les effets des notifications. SPEED_TIME  est la vitesse d’exécution de l’animation et PAUSE_TIME  est le temps de pause à la fin de l’animation.

Interaction avec box Domotique : Jeedom

Dans le cas où vous désirez vous connecter à votre box domotique jeedom , les paramétrages se font ici.

//**********************//
//interaction Jeedom
#define JEEDOM false                 // Activation interaction avec Jeedom ( veuillez renseigner tous les champs )
String ApiKey   = ""; // cle API Jeedom  ex :mVuQikcXm620321DMYZiCsLj0wamT0HsCcrBCuXRxntJDO1kn
String IPJeedom = "192.168.x.x";
String PortJeedom = "80";
// ID equipement a modifier     
// id SDJ
String idHor  = "10821";
String idLum ="10822";
String idSec = "10823";

Mettre JEEDOM à True , si on désire remonter les infos à Jeedom . ( Pas obligatoire , si vous désirez seulement communiquer dans un sens . Jeedom vers i-Notif’Heure ).

Pré-requis jeedom :

  • Création d’un équipement SCRIPT  qui servira à envoyer les requêtes pour commander les différentes options du Notif’Heure.
  • Création d’un Virtuel , pour gérer les états (retour d’information jeedom, Activation JEEDOM=true nécessaire )

Puis renseigner les champs suivants , en fonction de votre virtuel

  • ApiKey : La clé Jeedom pour le connecteur Virtuel
  • IPJeedom : L’adresse IP de votre box
  • PortJeedom : Le numéro de port
  • idHor , idLum et idSec : correspondent aux numéros id des commandes virtuels à renseigner.

Plus d’information dans mon article précédent.

Une fois tous ces paramètres renseignés , il ne vous reste plus qu’à compiler votre sketch et l’envoyer via USB dans votre module.

Lors de vos  prochaines mises à jour , le transfert , pourra se faire via OTA.

Les Nouveautés de cette version

Il suffit d’intégrer la bibliothèque suivante :

//********** eeprom
#include <EEPROM.h>

Dans la boucle Setup , initialiser par la commande : EEPROM.begin(512); Qui indique d’utiliser les 512 premières adresses.

Pour lire une valeur en mémoire EEPROM , il suffit d’utiliser la fonction : valEPROM = EEPROM.read(100), qui permet de lire la valeur située à l’adresse 100.

Pour enregistrer , il suffit d’utiliser la fonction :  EEPROM.write(100,valEPROM); qui permet d’écrire la valeur valEPROM à l’adresse 100 .

Puis pour valider tous les enregistrements la commande : EEPROM.commit();

Chaque adresse est de type Byte ( valeur de 0 à 255 ) codés sur 8 bits. Dans mon programme les options sont de type Boolean ( soit 0 ou 1 ) , je me sers donc de la commande : bitWrite(valEPROM, 7, true) , pour ne bouger qu’un seul bit sur ma valeur sauvegardée.

Ansi valEprom stocke la valeur des trois options boolean sur les 4 derniers bits

le bit 7 : Sert à indiquer qu’un enregistrement existe
le bit 4 : Sert à indiquer l’état des secondes
le bit 5 : Sert à indiquer si horloge est sur off ou non
le bit 6 : Sert à indiquer si mode Manuel ou Auto

Les bits ( 0 à 3 )  servent à stocker la valeur de l’intensité en mode Manuel.

Ansi si valEPROM vaut : 175 , cela équivaut en binaire à : 1010 1111 qui signifie un enregistrement existe , Secondes désactivées , horloge allumée, mode Manuel et intensité sur 15.

Exemple code pour lecture de la mémoire

......
....
// init systéme - lecture Eeprom si existe et envoie info à jeedom
valEPROM = EEPROM.read(100);
if (bitRead(valEPROM, 7))  // Si Enregistrement existe
      {
    DisSec=bitRead(valEPROM, 4);
    TimeOn=bitRead(valEPROM, 5);
    AutoIn=bitRead(valEPROM, 6);
    if (!AutoIn) Intensite=valEPROM&15;  // masque sur les 4 derniers bits , pour recuperer valeur intensite en mode manuel
    if (DEBUG) {
      Serial.println(" Valeur lu en Memoire : ");
      Serial.println(" valeur intensite : "+String(Intensite));
    }
  }
...
.....

l’enregistrement s’effectue dans la fonction Options().

  • Modifier les polices de caractères :

Pour l’affichage de l’horloge , j’ai modifié la police utilisée , afin d’avoir tous les chiffres de même largeur et ainsi éviter les déplacements de l’affichage lorsque le 1 s’affiche.

Le choix de la police s’effectue par la commande : P.setFont(0,ExtASCII); 0 indique la zone où utiliser la police , ExtASCII indique le nom de la police utilisée.

Pour la Police de l’horloge , je me suis basé sur la police existante dans la bibliothèque MAX ( numeric7Seg ).

/ Data file for user example user defined fonts
#ifndef FONTDATA_H
#define FONTDATA_H

MD_MAX72XX::fontType_t numeric7Seg[] PROGMEM = 
{
	0,		// 0
	0,		// 1
	0,		// 2
	0,		// 3
	0,		// 4
	0,		// 5
	0,		// 6
	0,		// 7
	0,		// 8
	0,		// 9
	0,		// 10
	0,		// 11
	0,		// 12
	0,		// 13
	0,		// 14
	0,		// 15
	0,		// 16
	0,		// 17
	0,		// 18
	0,		// 19
	0,		// 20
	0,		// 21
	0,		// 22
	0,		// 23
	0,		// 24
	0,		// 25
	0,		// 26
	0,		// 27
	0,		// 28
	0,		// 29
	0,		// 30
	0,		// 31
	1, 0,		// 32 - 'Space'
	0,		// 33 - '!'
	0,		// 34 - '"'
	0,		// 35 - '#'
	0,  	// 36 - '

j’ai modifié les codes ASCII allant de 48 à 57 ( chiffre 0 à 9 ) , afin de resserrer légèrement les chiffres  pour que tout rentre en un écran de 4 modules.

La modification est assez simple à faire :

principe pour modifier affichage sur matrice LED.

Chaque Module est codé sur 8 lignes x 8 colonnes .

Dans cette exemple , pour coder le 2 sur 4 colonnes seulement , il faudra définir les valeurs décimales suivantes : 121,73,73,79

Si on regarde la colonne 1 du 2 :
0111 1001 ( en binaire ) soit 121 en décimal ou 79 en Hexa.

  4, 127, 65, 65,127,  // 48 - '0'
  4, 0, 0, 127, 0,      // 49 - '1'
  4, 121, 73, 73, 79,   // 50 - '2'
  4, 73, 73, 73, 127,   // 51 - '3'
  4, 15, 8, 8, 127,   // 52 - '4'
  4, 79, 73, 73, 121,   // 53 - '5'
  4, 127, 73, 73, 121,  // 54 - '6'
  4, 1, 1, 1, 127,    // 55 - '7'
  4, 127, 73, 73, 127,  // 56 - '8'
  4, 79, 73, 73, 127,   // 57 - '9'

le premier nombre désigne le nombre de colonne , les suivants correspondent aux valeurs de ces colonnes.

Pour les petits chiffres , j’ai agis sur le même principe , mais codé sur 3 colonnes seulement.

Le 2 codé sur 3 colonnes

Ce qui donne :

  3, 124, 68, 124,    // 71 - '0' petit caractere pour secondes
  3, 0, 124, 0,    // 72 - '1'
  3, 116,84,92,   // 76 - '2'
  3, 84, 84, 124,   // 74 - '3'
  3, 28,16,124,    // 75 - '4'
  3, 92,84, 116,   // 73 - '5'
  3, 124,84,116,    // 77 - '6'
  3, 4,4,124,    // 78 - '7'
  3, 124,84,124,    // 79 - '8'
  3, 92,84,124,   // 80 - '9'

Pou vos aider à calculer automatiquement les bonnes valeurs , vous pouvez utiliser un fichier Excel fournis avec la bibliothèque  MAX . Parola-font_builder.xls

Mes deux jeux de caractères sont codés  mais comment utiliser les mini chiffres pour les secondes ?

Car si je demande d’afficher le 2 , c’est le grand chiffre qui s’affiche. Pour afficher le mini 2 il faut écrire la lettre I ( i majuscule ) . Afin de pouvoir utiliser la même police de caractère dans l’affichage de l’horloge , j’ai dû décaler les mini chiffres dans la table ASCII ( ils sont positionnés entre le code 71 et 80 , qui correspondent aux lettres G à P.

D’où la petite translation de code ASCII , dans la fonction digitalClockDisplay() , par l’instruction secondes[0]=secondes[0]+23;

23 correspondant au décalage entre le chiffre 0 et le G.

// Fonction clockformat ( ajoute les zeros devant les unités )
void digitalClockDisplay(char *heure,bool flash)
    {
   // Si affichage de l'heure      
  if (TimeOn) { 
     P.setIntensity(Intensite);
  if ( DisSec ) 
  {  // si affichage des Secondes  00:00 (secondes en petit )
    char secondes[2];  // pour affichage des secondes
   sprintf(secondes,"%02d",second());
    secondes[0]=secondes[0]+23;  // permutation codes AScci 71 à 80
    secondes[1]=secondes[1]+23;
  if (DEBUG) { 
      Serial.println("debug des secondes : ");
      Serial.println(second());
      Serial.println(secondes[0]);
      Serial.println(secondes[1]);
  } 
    sprintf(heure,"%02d:%02d %c%c",hour(),minute(),secondes[0],secondes[1]);
    //sprintf(heure,"%02d%c%02d%c%c",hour(),(flash ? ':' : ' '),minute(),secondes[0],secondes[1]);
  }
  // Affichage 00:00  avec : Clignottant ( flasher )
   else sprintf(heure,"%02d%c%02d",hour(),(flash ? ':' : ' '),minute());
  }
  else  // sinon point clignottant uniquement
    {
       P.setIntensity(0);
      sprintf(heure,"%c",(flash ? '.' : ' '));
    }
  }

A vous maintenant , d’imaginez votre police d’affichage.

  • optimisation du code , ainsi que de quelques fonctions .

Ci-dessous le code complet :

//**************************
// **** i-Notif'Heure
// Hotloge / notification
// OTA + Interface Web + Connecté
// Gestion Zone + enregistrement eeprom
// Juin 2018
// Byfeel
// *************************

String Ver="2.632";
#define NTPSERVER "pool.ntp.org" // Serveur NTP
#define ACTIVBOUTON false // Si bouton installé
#define ACTIVCAPTLUM true // Si capteur luminosité installé
#define BUF_SIZE 60 // Taille max des notification ( nb de caractéres max )

#define NOMMODULE "NotifHeure_salon" // nom module

// Options horloge à définir avant programmation
boolean AutoIn=true; // Auto / manu intensite
boolean TimeOn=true; // ON - off Affichage horloge
boolean DisSec=false; // on-off secondesboolean Alert=false;

#define DEBUG false

// ******************************//
//******** Bibliotheque *********//
//******************************//
//***** Gestion reseau
#include <EthernetClient.h>
#include <Ethernet.h>
#include <Dhcp.h>
#include <EthernetServer.h>
#include <Dns.h>
#include <EthernetUdp.h>
//****** Gestion WIFI
#include <ESP8266WiFi.h>
//****** Serveur WEB
#include <ESP8266WebServer.h>
//****** Client WEB
#include <ESP8266HTTPClient.h>
// WIFI Manager , afin de gerer la connexion au WIFI de façon plus intuitive
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
// ***** OTA
///includes necessaires au fonctionnement de l'OTA :
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
// **** Bibliotheque Matrice LED
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include "Parola_Fonts_data.h"
#include "Font_Byfeel.h"
// **** Temps
// librairie temps
#include <TimeLib.h>
#include <NtpClientLib.h>
//********** eeprom
#include <EEPROM.h>
//*************************
#if (ACTIVBOUTON)
//librairies click bouton
#include <ClickButton.h>
#endif
// ******************************//

// Definir le nombre de module
//la taille de la zone time si plus de deux modules
// et les PINS ou sont branches les modules
// ***************************************
// ***** Doit etre verifié avant chaque compilation
//**********************************************
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4 // nombre de matrice
#define MAX_ZONES 1 // 1 ou 2 zones
#if (MAX_ZONES == 1 )
#define ZONE_TIME (MAX_DEVICES)
#else
#define ZONE_TIME 4 // taille de l'horloge Si Zone = 2
#endif
#define ZONE_MSG (MAX_DEVICES-ZONE_TIME)
#define CLK_PIN D5
#define DATA_PIN D7
#define CS_PIN D6

// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Si probleme avec detection auto SPI
// MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

#define SPEED_TIME 30
#define PAUSE_TIME 1000

//**********************//
//interaction Jeedom
#define JEEDOM false // Activation interaction avec Jeedom ( veuillez renseigner tous les champs )
String ApiKey = ""; // cle API Jeedom ex :mVuQikcXm620321DMYZiCsLj0wamT0HsCcrBCuXRxntJDO1kn
String IPJeedom = "192.168.x.x";
String PortJeedom = "80";
// ID equipement a modifier // id SDJ
String idHor = "10821";
String idLum ="10822";
String idSec = "10823";
String idAuto ="10834";
// id salon

//base URL jeedom Virtuel

String BaseUrlJeedom ="http://"+IPJeedom+":"+PortJeedom+"/core/api/jeeApi.php?apikey=" + ApiKey + "&type=virtual&id=";

//**************************
//**** Varaible & service ***
// *************************

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

#if (JEEDOM)
HTTPClient http; // init client WEB
#endif

// definition du numero de LED interne
#define led 2 // led built IN

// Bouton
#if (ACTIVBOUTON)
#define bouton 0 // GPIO0 ( pullup integré - D8 pour R1 ou D3 pour R2 )
ClickButton boutonClick(bouton, LOW, CLICKBTN_PULLUP);
#endif

// variable pour stocker la valeur du photoresistor
#if (ACTIVCAPTLUM)
int sensorValue;
#endif

//variable systemes
char Notif[BUF_SIZE];
char Horloge[BUF_SIZE];
boolean Alert=false;
boolean FinMsg=false;
byte Intensite=5;
byte BkIntensite=Intensite;
const long interval = 20000; // interval pour mesure luminosite réglé sur 20 s
unsigned long previousMillis=0 ;
byte clic=0;
byte clicstate=1;
String message="";
String type="";
int httpCode=200;
byte NTPcount=0;
byte valEPROM;

//******** fx *******
textEffect_t effect[] =
{
PA_RANDOM,
PA_PRINT,
PA_SCAN_HORIZ,
PA_SCROLL_LEFT,
PA_NO_EFFECT,
PA_WIPE,
PA_SCAN_VERTX,
PA_SCROLL_UP_LEFT,
PA_SCROLL_UP,
PA_FADE,
PA_OPENING_CURSOR,
PA_GROW_UP,
PA_SCROLL_UP_RIGHT,
PA_BLINDS,
PA_SPRITE,
PA_CLOSING,
PA_GROW_DOWN,
PA_SCAN_VERT,
PA_SCROLL_DOWN_LEFT,
PA_WIPE_CURSOR,
PA_SCAN_HORIZX,
PA_DISSOLVE,
PA_MESH,
PA_OPENING,
PA_CLOSING_CURSOR,
PA_SCROLL_DOWN_RIGHT,
PA_SCROLL_RIGHT,
PA_SLICE,
PA_SCROLL_DOWN,
};

byte fx_in=3;
byte fx_out=3;
bool fx_center;

//*****************************************
// UTF8 - Ascii etendu
//*****************************************
uint8_t utf8Ascii(uint8_t ascii)
// Convert a single Character from UTF8 to Extended ASCII according to ISO 8859-1,
// also called ISO Latin-1. Codes 128-159 contain the Microsoft Windows Latin-1
// extended characters:
// - codes 0..127 are identical in ASCII and UTF-8
// - codes 160..191 in ISO-8859-1 and Windows-1252 are two-byte characters in UTF-8
// + 0xC2 then second byte identical to the extended ASCII code.
// - codes 192..255 in ISO-8859-1 and Windows-1252 are two-byte characters in UTF-8
// + 0xC3 then second byte differs only in the first two bits to extended ASCII code.
// - codes 128..159 in Windows-1252 are different, but usually only the €-symbol will be needed from this range.
// + The euro symbol is 0x80 in Windows-1252, 0xa4 in ISO-8859-15, and 0xe2 0x82 0xac in UTF-8.
//
// Modified from original code at http://playground.arduino.cc/Main/Utf8ascii
// Extended ASCII encoding should match the characters at http://www.ascii-code.com/
//
// Return "0" if a byte has to be ignored.
{
static uint8_t cPrev;
uint8_t c = '\0';

if (ascii < 0x7f) // Standard ASCII-set 0..0x7F, no conversion
{
cPrev = '\0';
c = ascii;
}
else
{
switch (cPrev) // Conversion depending on preceding UTF8-character
{
case 0xC2: c = ascii; break;
case 0xC3: c = ascii | 0xC0; break;
case 0x82: if (ascii==0xAC ) c = 0x80; // Euro symbol special case

}
cPrev = ascii; // save last char
}

return(c);
}

void utf8Ascii(char* s)
// In place conversion UTF-8 string to Extended ASCII
// The extended ASCII string is always shorter.
{
uint8_t c, k = 0;
char *cp = s;

while (*s != '\0')
{
c = utf8Ascii(*s++);
if (c != '\0')
*cp++ = c;
}
*cp = '\0'; // terminate the new string
}

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

// **************************
// Parametre NTP
// Serveur NTP
// **************************

// 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 {
// dateNum2 = datenum(dateStr2,'dd-mmm-yyyy HH:MM:SS');
if ( NTPcount>14 ) {
NTP.setInterval (1200);
}
else ++NTPcount;
}

}

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

void luminosite() {
#if (ACTIVCAPTLUM)
// fonction reglage auto luminosite
byte bkint = Intensite;
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;
if (bkint != Intensite ) ToJeedom( idLum ,Intensite);
#endif
}

// ******************
// Gestion page WEB
//******************

void handleRoot(){
if ( server.hasArg("SEC") || server.hasArg("LUM") || server.hasArg("HOR")) {
handleSubmit();
}
else {
server.send ( 200, "text/html", getPage() );
}
}

void handleSubmit() {
String SEC = server.arg("SEC");
String LUM = server.arg("LUM");
String HOR = server.arg("HOR");
if ( LUM =="manu" ) {
if (server.arg("INT") !="") Intensite=server.arg("INT").toInt();
ToJeedom(idLum , Intensite);
Option(&AutoIn,false);
} else if ( LUM == "auto")
{
Option(&AutoIn,true);
}

if ( HOR =="off" ) Option(&TimeOn,false);
else if ( HOR =="on") Option(&TimeOn,true);

if ( SEC == "on" ) Option(&DisSec,true);
else if ( SEC == "off" ) Option(&DisSec,false);

if ( server.arg("RAZ") =="1" ) {
P.print("reboot");
delay(3000);
ESP.reset();

}
server.send ( 200, "text/html", getPage() );
}

// *****************************
// ANIMATION
// SPRITE DEFINITION (PAC MAn )
// *****************************

const uint8_t F_PMAN1 = 6;
const uint8_t W_PMAN1 = 8;
static uint8_t pacman1[F_PMAN1 * W_PMAN1] = // gobbling pacman animation
{
0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c,
0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c,
0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c,
0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c,
0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c,
0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c,
};

const uint8_t F_PMAN2 = 6;
const uint8_t W_PMAN2 = 18;
static uint8_t pacman2[F_PMAN2 * W_PMAN2] = // ghost pursued by a pacman
{
0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe,
0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe,
0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe,
};

// ***************************
// Fonction gestion des Options
// TimeOn , DisSec / AutoIn
//*****************************

void Option(boolean *Poption, boolean valeur) {
String *Pid = NULL ;
int value=valeur;
// afectation de la valeur à l'option ( via pointeur )
*Poption = valeur;
byte UpVal = valEPROM;
if ( Poption == &DisSec ) {
Pid = &idSec ;
bitWrite(valEPROM, 4, valeur);
}
else if ( Poption == &AutoIn ) {
Pid = &idAuto ;
if (!bitRead(UpVal,6) && valeur ) NotifMsg("Auto",Intensite,true);
bitWrite(valEPROM, 6, valeur);
if ( !valeur ) {
if ( Intensite == 0 ) message="Min";
else if ( Intensite == 15 ) message="Max";
else message="LUM :"+String(Intensite);
NotifMsg(message,Intensite,true);
valEPROM=valEPROM&240; // masque sur les 4 derniers bits
valEPROM+=Intensite;
P.setIntensity(Intensite);
if (DEBUG) {
Serial.println(" Menu Option");
Serial.println("valeur enregistrement EPROM " + String(valEPROM) );
}
}
}
else if ( Poption == &TimeOn ) {
Pid = &idHor ;
bitWrite(valEPROM, 5, valeur);
if (!valeur)
{
NotifMsg("OFF",Intensite,true);
}
}
if (UpVal != valEPROM ) {
// enregistre en EEprom les options si changement
bitWrite(valEPROM, 7, true);
EEPROM.write(100,valEPROM);
EEPROM.commit();
}
// envoie a jeedom des modifications effectués en fonction de l 'option
ToJeedom(*Pid,value);
}

void NotifMsg(String Msg,byte lum,boolean Info)
{
P.setFont(0,ExtASCII);
Alert=true;
Msg.toCharArray(Notif,BUF_SIZE);
if (Info) {
//P.displayZoneText(0,Notif,PA_CENTER,SPEED_TIME, PAUSE_TIME,PA_PRINT,PA_NO_EFFECT);
fx_center=true;
fx_in=1;
fx_out=4;
}
else
{
P.setTextAlignment(0,PA_LEFT) ;
// P.displayZoneText(0, Notif, PA_LEFT, SPEED_TIME, PAUSE_TIME, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
fx_in=3;
fx_out=3;
}

}

//***********************
// Boucle SETUP
// *********************
void setup(void)
{
//init demmarrage
P.begin();
if (DEBUG) {
Serial.begin(9600);
}
EEPROM.begin(512);
P.print("Start ...");

//******** WiFiManager ************
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 ************

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

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

// 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([]() {
digitalWrite(led, HIGH); // allume led au debut du transfert
P.begin();
P.setFont(0,ExtASCII);
});
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) {

if (MAX_DEVICES<5) sprintf(Notif,"Up %u%%", (progress / (total / 100)));
else 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
while (WiFi.status() != WL_CONNECTED) {
}
// on affiche l'adresse IP attribuee pour le serveur DSN et on affecte le nom reseau
WiFi.hostname(NOMMODULE);
//*************************

// on definit les points d'entree (les URL a saisir dans le navigateur web) : Racine du site est géré par la fonction handleRoot
server.on("/", handleRoot);

server.on("/Notification", [](){
// on recupere les parametre dans l'url dans la partie /Notification?msg="notification a affiocher"&type="PAC"
if ( server.hasArg("msg")) {
message=server.arg("msg");
if (message ) {
// message.toCharArray(Notif,BUF_SIZE);
if (server.hasArg("intnotif") && server.arg("intnotif").length() > 0 ) {
BkIntensite=Intensite;
Intensite = server.arg("intnotif").toInt();
if (Intensite < 1 ) Intensite = 0 ;
if (Intensite > 14 ) Intensite = MAX_INTENSITY;
}
if (server.arg("type")) {
type=server.arg("type");
}
P.setIntensity(Intensite); // intensité pour les notifs si pas de valeur Intensité par defaut
// on repond au client
NotifMsg(message,Intensite,false);
server.send(200, "text/plain", "message :" + message + " & Animation : "+server.arg("type") + " & Intensite : "+Intensite);
}
}

});

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

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

P.print("init");
// 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);

//************************************
// init systéme - lecture Eeprom si existe et envoie info à jeedom
valEPROM = EEPROM.read(100);
if (bitRead(valEPROM, 7)) // Si Enregistrement existe
{
DisSec=bitRead(valEPROM, 4);
TimeOn=bitRead(valEPROM, 5);
AutoIn=bitRead(valEPROM, 6);
if (!AutoIn) Intensite=valEPROM&15; // masque sur les 4 derniers bits , pour recuperer valeur intensite mode manuel
if (DEBUG) {
Serial.println(" Valeur lu en Memoire : ");
Serial.println(" valeur intensite : "+String(Intensite));
}
}

ToJeedom(idSec,DisSec);
ToJeedom(idHor,TimeOn);
ToJeedom(idAuto,AutoIn);
// *********************************

//************ Initialisation des Zones
P.begin(MAX_ZONES);
P.setSpriteData(pacman1, W_PMAN1, F_PMAN1,pacman2, W_PMAN2, F_PMAN2); // chargement animation en memoire
P.setInvert(false);

#if (MAX_ZONES >1 && ZONE_MSG >0 )
P.setZone(0, 0, (ZONE_MSG-1));
P.setZone(1, ZONE_MSG,(MAX_DEVICES -1));
//P.setZone(1, 1,3);
#else
P.setZone(0, 0, MAX_DEVICES);
#endif

P.displayZoneText(0, "", PA_LEFT, SPEED_TIME, PAUSE_TIME, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
if (MAX_ZONES > 1 ) P.displayZoneText(1, Horloge, PA_CENTER, 0,0, PA_PRINT, PA_NO_EFFECT);

// Fin de Setup
message = " Systeme OK - Adresse ip : ";
message += WiFi.localIP().toString();
//message.toCharArray(Notif,BUF_SIZE);
//Alert=true;
NotifMsg(message,Intensite,false);

}

//***********************************
//***********************************
//********* Boucle loop *************
//***********************************
//**********************************

void loop(void)
{
static uint32_t lastTime = 0; // millis() memory
static bool flasher = false; // seconds passing flasher

// ******** Gestion luminosite

// Si Horloge activé
if (TimeOn) {
// Si gestion Auto luminositée activé
if (AutoIn) {
#if (ACTIVCAPTLUM)
if( millis() - previousMillis >= interval) {
previousMillis = millis();
luminosite();
}
#endif
}
//P.setIntensity(Intensite);
}
// if (DEBUG) Serial.println("valeur luminosité "+ String(Intensite));

// ********** Fin gestion luminosite

// *********** Gestion bouton
#if (ACTIVBOUTON)
// etat bouton
boutonClick.Update();
// Sauvegarde de la valeur dans la variable click
if (boutonClick.clicks != 0) clic = boutonClick.clicks;
if (DEBUG && clic ) Serial.print("valeur clic : "+ String(clic));
switch (clic) {
case 1: // double clic - Affiche ou non les secondes
Option(&DisSec,!DisSec);
clic=0;
break;
case 2: // double clic - ON / OFF horloge
Option(&TimeOn,!TimeOn);
clic=0;
break;
case 3: // Simple clic - boucle : Manuel intensite à 0 / Manu Intensite MAX / Auto
if (clicstate==1) {
Intensite = 0;
Option(&AutoIn,false);
}
if (clicstate==2) {
Intensite = 15;
Option(&AutoIn,false);
}
if (clicstate==3) {
Option(&AutoIn,true);
clicstate=0;
}
ToJeedom(idLum , Intensite);
P.setIntensity(Intensite);
++clicstate;
clic=0;
break;
case 255: // simple clic mais long sur dernier - diminue
--Intensite;
if (Intensite<0) Intensite=0;
NotifMsg("LUM :"+String(Intensite),Intensite,true);
clic=0;
break;
case 254: // double clic mais long sur dernier - Augmente
++Intensite;
if (Intensite>15) Intensite=MAX_INTENSITY;
NotifMsg("LUM :"+String(Intensite),Intensite,true);
clic=0;
break;
default:
// default is optional
break;
}
#endif
// ******** Fin gestion bouton

// ********* Gestion Reseau : Pages WEB , NTP et OTA
// ********* Service NTP
if (syncEventTriggered) {
processSyncEvent (ntpEvent);
syncEventTriggered = false;
}

// ****** Page WEb : a chaque iteration, la fonction handleClient traite les requetes
server.handleClient();

// ******* OTA
// Surveillance des demandes de mise a jour en OTA
ArduinoOTA.handle();

// ******** Fin gestion reseau

//********** flasher
if (millis() - lastTime >= 1000)
{
lastTime = millis();
flasher = !flasher;
}

if (P.displayAnimate())
{

if (Alert) {
if (P.getZoneStatus(0))
{
P.setFont(0,ExtASCII); // chargement caractere etendue
// Type de demande
if (type=="PAC" ) { // animation PAC MAn
P.displayZoneText(0,"Notif", PA_LEFT, 40, 1, PA_SPRITE, PA_SPRITE);
type="";
}
else if (type=="BLINDS" ) { // animation de type volet
P.displayZoneText(0,"", PA_CENTER, 40, 1, PA_BLINDS, PA_BLINDS);
type="";
}
else if (type=="OPENING" ) { // animation Ouverture
P.displayZoneText(0,"Notif", PA_CENTER, 60, 100, PA_OPENING_CURSOR, PA_OPENING_CURSOR);
type="";
}
else {
P.displayClear(0);
P.displayZoneText(0, Notif, PA_LEFT,SPEED_TIME, PAUSE_TIME, effect[fx_in], effect[fx_out]);
if (fx_center) {
P.setTextAlignment(0,PA_CENTER);
fx_center=false;
}
else FinMsg=true;
Alert=false;
//Intensite=BkIntensite; // reviens a intensite avant notif
if (DEBUG) Serial.println("valeur de intensite : "+String(Intensite) +" Valeur de bk : "+String(BkIntensite));
}

}
}
else {
if (MAX_ZONES == 1) {
P.setFont(0, numeric7Seg_Byfeel);
digitalClockDisplay(Notif,flasher);
P.displayZoneText(0, Notif, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);

}
}

if (MAX_ZONES > 1) {
if (P.getZoneStatus(0)) P.displayClear(0);
P.setFont(1, numeric7Seg_Byfeel);
digitalClockDisplay(Horloge,flasher);
P.displayZoneText(1, Horloge, PA_CENTER, SPEED_TIME, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);

}

// Check for individual zone completion. Note that we check the status of the zone rather than use the
// return status of the displayAnimate() method as the other unused zones are completed, but we
// still need to call it to run the animations.
//while (!P.getZoneStatus(MAX_ZONES-1))

} // fin displayanimate

}
//********************** fin boucle

// Fonction envoie requete vers Jeedom
void ToJeedom( String id , byte valeur){
#if (JEEDOM)
String url;
String value;
if (id=="idSec" || id=="idHor") {
if (valeur==0) value="off";
else value="on";
}
else if ( id=="idAuto" ) {
if (valeur==0) value="manu";
else value="auto";
}
else {
value=valeur;
}

url = BaseUrlJeedom;
url +=id;
url +="&value="+value;
http.begin(url);
httpCode = http.GET();
http.end();
#endif
}

// Fonction clockformat ( ajoute les zeros devant les unités )
void digitalClockDisplay(char *heure,bool flash)
{
// Si affichage de l'heure
if (TimeOn) {
if (FinMsg) {
Intensite=BkIntensite;
FinMsg=false;
}
P.setIntensity(Intensite);
if ( DisSec )
{ // si affichage des Secondes 00:00 (secondes en petit )
char secondes[2]; // pour affichage des secondes
sprintf(secondes,"%02d",second());
secondes[0]=secondes[0]+23; // permutation codes AScci 71 à 80
secondes[1]=secondes[1]+23;
if (DEBUG) {
//Serial.println("debug des secondes : ");
//Serial.println(second());
//Serial.println(secondes[0]);
//Serial.println(secondes[1]);
}
sprintf(heure,"%02d:%02d %c%c",hour(),minute(),secondes[0],secondes[1]);
//sprintf(heure,"%02d%c%02d%c%c",hour(),(flash ? ':' : ' '),minute(),secondes[0],secondes[1]);
}
// Affichage 00:00 avec : Clignottant ( flasher )
else sprintf(heure,"%02d%c%02d",hour(),(flash ? ':' : ' '),minute());
}
else // sinon point clignottant uniquement
{
P.setIntensity(0);
sprintf(heure,"%c",(flash ? '.' : ' '));
}
}

//************************************
// Page WEB Accueil
// ***********************************
String getPage(){
char ddj[30];
sprintf(ddj,"%02d:%02d:%02d - Date : %02d/%02d/%4d",hour(),minute(),second(),day(),month(),year());
String page = "<html lang=fr-FR><head><meta http-equiv='content-type' content='text/html;charset=ISO-8859-15' /><meta http-equiv='refresh' content='120'/>";
page += "<title>i-Notif'Heure - 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;'>i-Notif\'Heure</span></h1>";
page += "<h3><span style='background-color: #398AA4; color: #ffffff; padding: 0 5px;'> Heure : ";
page += ddj;
page += "</span></h3>";
page += "<div class='bloc'><form action='/Notification' method='GET' accept-charset='ISO-8859-1'>";
page +="<fieldset><legend>Envoyer une Notification :</legend>";
page +="<label for='msg'>Message </label><br />";
page += "<INPUT type='text' name='msg' id='msg'maxlength='59' style='width:400px;' placeholder='Votre Message - "+String(BUF_SIZE) +" caracteres max -'/>";
page +="<label for='type'>type : </label>";
page +="<select name='type' id='type'>";
page +="<option value=''>Defaut</option>";
page +="<option value='PAC'>PAC MAN</option>";
page +="<option value='BLINDS'>BLINDS</option>";
page +="<option value='OPENING'>Opening</option>";
page +="</select><br />";
page +="<label for='intnotif'>Intensite : </label><br />";
page += "<p><input id='sliderINT' type='range' min='0' max='15' step='1' name='intnotif' list='tickmarks' />";
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='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>Version </td><td>";
page += Ver;
page +="</td></tr>";
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='on' id='on'";
if (DisSec==true) page +=" checked ";
page += "><label for='on'>ON</label>";
page +="<INPUT type='radio' name='SEC' value='off' 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='on' id='horon'";
if (TimeOn==true) page +=" checked ";
page += "><label for='horon'>ON</label>";
page +="<INPUT type='radio' name='HOR' value='off' id='horoff'";
if (TimeOn==false) page +=" checked ";
page += "><label for='horoff'>OFF</label></fieldset>";
page +="<fieldset><legend>Gestion de la luminositée ( ";
page +=Intensite;
page +=" ) : </legend>";
page += "<INPUT type='radio' name='LUM' value='auto' id='auto'";
if (AutoIn==true) page +=" checked ";
page += "><label for='auto'>AUTO</label>";
page +="<INPUT type='radio' name='LUM' value='manu' id='manu'";
if (AutoIn==false) page +=" checked ";
page += "><label for='manu'>Manuel</label></P>";
if (AutoIn==false) {
page +="<p>Valeur luminositée : ";
page +=Intensite;
page +="</p>";
page += "<p><input id='slider1' type='range' min='0' max='15' step='1' name='INT' 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 +="<fieldset><legend>Redemarrage Module :</legend>";
page += "<INPUT type='radio' name='RAZ' value='1' id='reset'";
page += "><label for='reset'>Redemmarage</label>";
page += "</fieldset>";
page +="</fieldset>";
page += "<INPUT type='submit' value='Actualiser'name='parametres'/></div>";
page += "</form>";
page += "<br><br>";
page += "</body></html>";
return page;
}

Code complet script font numeric7 modifié.

// Definition des polices de caractéres pour affichage
// Horloge avec notif.
// Modification du fichier Font.h de la bibliotheque Parola
// Byfeel : Juin 2018
// Definition des chiffres principaux sur 4 rangées , definition de 7 led en hauteur / et 4 led en largeur
// Definition des mini chiffres ( pour affichage secondes
// Sur 5 led en hauteur / 3 led en largeur
// Espaces caracteres de 3 , pour les petits chiffres.
// Mini chiffre : definit à la place des lettres G à P.

#ifndef FONTDATA_H
#define FONTDATA_H

MD_MAX72XX::fontType_t numeric7Seg_Byfeel[] PROGMEM =
{
0, // 0
0, // 1
0, // 2
0, // 3
0, // 4
0, // 5
0, // 6
0, // 7
0, // 8
0, // 9
0, // 10
0, // 11
0, // 12
0, // 13
0, // 14
0, // 15
0, // 16
0, // 17
0, // 18
0, // 19
0, // 20
0, // 21
0, // 22
0, // 23
0, // 24
0, // 25
0, // 26
0, // 27
0, // 28
0, // 29
0, // 30
0, // 31
1, 0, // 32 - 'Space'
0, // 33 - '!'
0, // 34 - '"'
0, // 35 - '#'
0, // 36 -
0, // 37 - '%'
0, // 38 - '&'
0, // 39 - '''
0, // 40 - '('
0, // 41 - ')'
0, // 42 - '*'
0, // 43 - '+'
0, // 44 - ','
0, // 45 - '-'
1, 64, // 46 - '.'
0, // 47 - '/'
4, 127, 65, 65,127, // 48 - '0'
4, 0, 0, 127, 0, // 49 - '1'
4, 121, 73, 73, 79, // 50 - '2'
4, 73, 73, 73, 127, // 51 - '3'
4, 15, 8, 8, 127, // 52 - '4'
4, 79, 73, 73, 121, // 53 - '5'
4, 127, 73, 73, 121, // 54 - '6'
4, 1, 1, 1, 127, // 55 - '7'
4, 127, 73, 73, 127, // 56 - '8'
4, 79, 73, 73, 127, // 57 - '9'
1, 20, // 58 - ':'
0, // 59 - ';'
0, // 60 - '<'
0, // 61 - '='
0, // 62 - '>'
0, // 63 - '?'
0, // 64 - '@'
5, 127, 9, 9, 9, 127, // 65 - 'A'
5, 127, 73, 73, 73, 54, // 66 - 'B'
5, 127, 65, 65, 65, 65, // 67 - 'C'
5, 127, 65, 65, 65, 62, // 68 - 'D'
5, 127, 73, 73, 73, 73, // 69 - 'E'
5, 127, 9, 9, 9, 9, // 70 - 'F'
3, 124, 68, 124, // 71 - '0' petit caractere pour secondes
3, 0, 124, 0, // 72 - '1'
3, 116,84,92, // 76 - '2'
3, 84, 84, 124, // 74 - '3'
3, 28,16,124, // 75 - '4'
3, 92,84, 116, // 73 - '5'
3, 124,84,116, // 77 - '6'
3, 4,4,124, // 78 - '7'
3, 124,84,124, // 79 - '8'
3, 92,84,124, // 80 - '9'
0, // 81 - 'Q'
0, // 82 - 'R'
0, // 83 - 'S'
0, // 84 - 'T'
0, // 85 - 'U'
0, // 86 - 'V'
0, // 87 - 'W'
0, // 88 - 'X'
0, // 89 - 'Y'
0, // 90 - 'Z'
0, // 91 - '['
0, // 92 - '\'
0, // 93 - ']'
0, // 94 - '^'
0, // 95 - '_'
0, // 96 - '`'
5, 127, 9, 9, 9, 127, // 97 - 'a'
5, 127, 73, 73, 73, 54, // 98 - 'b'
5, 127, 65, 65, 65, 65, // 99 - 'c'
5, 127, 65, 65, 65, 62, // 100 - 'd'
5, 127, 73, 73, 73, 73, // 101 - 'e'
5, 127, 9, 9, 9, 9, // 102 - 'f'
0, // 103 - 'g'
0, // 104 - 'h'
0, // 105 - 'i'
0, // 106 - 'j'
0, // 107 - 'k'
0, // 108 - 'l'
0, // 109 - 'm'
0, // 110 - 'n'
0, // 111 - 'o'
0, // 112 - 'p'
0, // 113 - 'q'
0, // 114 - 'r'
0, // 115 - 's'
0, // 116 - 't'
0, // 117 - 'u'
0, // 118 - 'v'
0, // 119 - 'w'
0, // 120 - 'x'
0, // 121 - 'y'
0, // 122 - 'z'
0, // 123 - '{'
1, 127, // 124 - '|'
0, // 125
0, // 126
0, // 127
0, // 128
0, // 129
0, // 130
0, // 131
0, // 132
0, // 133
0, // 134
0, // 135
0, // 136
0, // 137
0, // 138
0, // 139
0, // 140
0, // 141
0, // 142
0, // 143
0, // 144
0, // 145
0, // 146
0, // 147
0, // 148
0, // 149
0, // 150
0, // 151
0, // 152
0, // 153
0, // 154
0, // 155
0, // 156
0, // 157
0, // 158
0, // 159
0, // 160
0, // 161
0, // 162
0, // 163
0, // 164
0, // 165
0, // 166
0, // 167
0, // 168
0, // 169
0, // 170
0, // 171
0, // 172
0, // 173
0, // 174
0, // 175
0, // 176
0, // 177
0, // 178
0, // 179
0, // 180
0, // 181
0, // 182
0, // 183
0, // 184
0, // 185
0, // 186
0, // 187
0, // 188
0, // 189
0, // 190
0, // 191
0, // 192
0, // 193
0, // 194
0, // 195
0, // 196
0, // 197
0, // 198
0, // 199
0, // 200
0, // 201
0, // 202
0, // 203
0, // 204
0, // 205
0, // 206
0, // 207
0, // 208
0, // 209
0, // 210
0, // 211
0, // 212
0, // 213
0, // 214
0, // 215
0, // 216
0, // 217
0, // 218
0, // 219
0, // 220
0, // 221
0, // 222
0, // 223
0, // 224
0, // 225
0, // 226
0, // 227
0, // 228
0, // 229
0, // 230
0, // 231
0, // 232
0, // 233
0, // 234
0, // 235
0, // 236
0, // 237
0, // 238
0, // 239
0, // 240
0, // 241
0, // 242
0, // 243
0, // 244
0, // 245
0, // 246
0, // 247
0, // 248
0, // 249
0, // 250
0, // 251
0, // 252
0, // 253
0, // 254
0, // 255
};

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

37 commentaires sur “DIY : i-Notif’Heure ou comment mettre en place une horloge connectée avec Notification”

%d blogueurs aiment cette page :