horloge chevet 4

Horloge de chevet NTP OLED ESP8266 sur Powercube Alocacoc

Lire l’heure en toute discrétion durant la nuit

horloge de NTP OLED ESP8266 sur Powercube

Objectif

Ne pas éveiller sa moitié en lisant l’heure pendant la nuit.

Description

  • L’horloge se met à l’heure par le protocole NTP toutes les 12 heures;
  • Le WiFi ne fonctionne que pendant la synchronisation NTP;
  • Elle passe automatiquement à l’heure d’été et d’hiver;
  • Le bouton poussoir permet d’éteindre et d’allumer l’écran;
  • Elle se fixe sur un powercube avec 2 prises USB;
  • L’alimentation est obtenue d’un USB du Powercube.

Composants

  • 1 Wemos D1 Mini;
  • 1 Ecran OLED I2C;
  • 1 bouton poussoir normalement ouvert;
  • 1 morceau de câble USB avec fiche type A;
  • 1 boîtier imprimé en 3D.

Les liens ci-dessus sont donnés à titre d’exemple.

Schéma

Schéma horloge de chevet

Boîtier

J’ai conçu ce boîtier pour qu’il puisse se coller à l’aide d’un adhésif double face réutilisable sur l’ USB d’un Powercube en laissant une prise USB libre.

Les fichiers 3D pourront bientôt être téléchargés en cliquant sur le bouton ci-dessous

Pour plus d'informations, cliquez le bouton

Si vous souhaitez les obtenir avant, laissez-moi un message.
Vous pouvez adapter les dimensions et modifier les formes à partir du fichier FreeCAD.

Code

J’ai récupéré la partie horloge du programme de mon article « Grande horloge… » .

Pour la programmation, j’utilise Platformio mais l’IDE Arduino convient également.
Il vous faudra adapter le code en fonction de votre fuseau horaire pour le passage à l’heure d’été/hiver !
Vous devrez également remplacer les x par vos propres adresses IP, les *** par votre SSID, votre mot de passe WiFi et les zzzz par le serveur NTP à utiliser.
L’écran peut être commuté par le bouton ON et OFF ou simplement ON avec une temporisation avant de s’éteindre.

Platformio.ini

platform = espressif8266
board = d1_mini
framework = arduino
lib_deps = 
	adafruit/Adafruit GFX Library@^1.11.11
	adafruit/Adafruit SSD1306@^2.5.13
	thomasfredericks/Bounce2@^2.72
	sstaub/Ticker@^4.4.0
monitor_speed = 115200

main.cpp

#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Fonts/FreeSans24pt7b.h>
#include <Fonts/FreeSansOblique9pt7b.h>
#include <Adafruit_SSD1306.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <bounce2.h>
#include <Ticker.h>
#include <jagprod.h>
#define SCREEN_WIDTH 128    // OLED display width, in pixels
#define SCREEN_HEIGHT 32    // OLED display height, in pixels
#define OLED_RESET -1       // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
#define display_pin D3
Bounce bouton_display = Bounce();
String heure;
unsigned int localPort = 2390;
const int NTP_PACKET_SIZE = 48;
byte packetBuffer[NTP_PACKET_SIZE];
IPAddress timeServerIP;
WiFiUDP udp;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int s;
int ds;
int m;
int dm;
int h;
int dh;
int gmtbe;
void quelleheure(IPAddress &address);
void plus1s();
Ticker uneseconde(plus1s, 1000);
bool temoinntp = true;
// Mettre la ligne suivante en remarque Si affichage temporisé
bool displaystate = true;
long secondes;

// Variables DSTAuto
int dst = 1;
unsigned long epoch;
unsigned long epochmars;
unsigned long epochoctobre;
unsigned long epochannee;
int seconde;
int minute;
int Heure;
int bis = 0;
int annee;
unsigned long epoch01012025 = 1735689600;
unsigned long nombredejours;
// int mois;
int nombredejoursannee;
int jour;
String joursemaine;
int queljoursemaine;
//void laps();
String mois;
String epoch2string;

void plus1s() // Action à réaliser lorsque le timer uneseconde est écoulé
{
  s = s + 1;
  Serial.println(s);
}

void setup()
{
  Serial.begin(115200);
  pinMode(D1, INPUT_PULLUP);
  pinMode(D2, INPUT_PULLUP);
  Wire.begin(D2, D1);
  pinMode(display_pin, INPUT_PULLUP);
  bouton_display.attach(display_pin);
  bouton_display.interval(10);
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ; // Don't proceed, loop forever
  }
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
}

void loop()
{
  uneseconde.update();
  bouton_display.update();
  //--------------------------------
  if (bouton_display.fell())
  {

    // Pour l'affichage temporisé
    /*  display.ssd1306_command(SSD1306_DISPLAYON);
        uneseconde.pause();
        delay(4000);
        uneseconde.resume();
        display.ssd1306_command(SSD1306_DISPLAYOFF);
        s = s - 4;
    */
    // Pour l'affichage switché
    displaystate = !displaystate;
    if (displaystate == true)
    {
      display.ssd1306_command(SSD1306_DISPLAYON);
    }
    else
    {
      display.ssd1306_command(SSD1306_DISPLAYOFF);
    }
  }
  secondes = dh * 36000 + h * 3600 + dm * 600 + m * 60 + ds * 10 + s;
  if (secondes == 32400 or secondes == 75600)
  { // Synchro NTP à 9h et 21h
    temoinntp = true;
  }
  if (temoinntp == true) // il faut faire une synchro NTP
  {
    quelleheure(timeServerIP);
    temoinntp = false;
  }
  if (s > 9)
  {
    s = 0;
    ds = ds + 1;
    if (ds > 5)
    {
      ds = 0;
      m = m + 1;
      if (m > 9)
      {
        m = 0;
        dm = dm + 1;
        if (dm > 5)
        {
          dm = 0;
          h = h + 1;
          if (dh == 2 and h == 4)
          {
            dh = 0;
            h = 0;
          }
          if (h > 9)
          {
            h = 0;
            dh = dh + 1;
          }
        }
      }
      heure = String(dh) + String(h) + ":" + String(dm) + String(m);
      Serial.println(heure);
      display.clearDisplay();
      display.setFont(&FreeSans24pt7b);
      display.setCursor(5, 32);
      display.print(heure);
      display.display();
      // Mettre la ligne suivante en remarque si affichage switché
      // display.ssd1306_command(SSD1306_DISPLAYOFF);
    }
  }
}

void quelleheure(IPAddress &address) // Synchronisation du temps via NTP
{
  uneseconde.pause();
  WiFi.mode(WIFI_STA);
  display.setFont(&FreeSansOblique9pt7b);
  display.clearDisplay();
  display.setCursor(37, 14);
  display.print("Mise a");
  display.setCursor(37, 31);
  display.println("l'heure");
  display.display();
  if (!WiFi.config(ip, gw, mask, ns))
  {
  }
  WiFi.begin(ssid, wifi_sesame);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1000);
  }
  udp.begin(localPort);
  WiFi.hostByName(ntpServerName, timeServerIP);
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  packetBuffer[0] = 0b11100011;
  packetBuffer[1] = 0;
  packetBuffer[2] = 6;
  packetBuffer[3] = 0xEC;
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;
  udp.beginPacket(address, 123);
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  udp.endPacket();
  delay(1000);
  int cb = udp.parsePacket();
  while (!cb)
  {
    cb = udp.parsePacket();
  }
  udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
  unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
  unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
  unsigned long secsSince1900 = highWord << 16 | lowWord;
  const unsigned long seventyYears = 2208988800UL;
  unsigned long epoch = secsSince1900 - seventyYears - 1; // moins délais udp
  WiFi.mode(WIFI_OFF);
  annee = 2025;
  bis = 0;
  epochannee = epoch01012025;
  nombredejours = (epoch - epoch01012025) / 86400L + 1; // car le 1 janvier correspond aux secondes 0 à 86400 soit le jour 0
  nombredejoursannee = nombredejours;
  while (nombredejoursannee > 365 + bis)
  {
    nombredejoursannee = nombredejoursannee - (365 + bis);
    annee = annee + 1;
    epochannee = epochannee + (365 + bis) * 86400L;
    bis = 0;
    if (annee % 400 == 0 or (annee % 4 == 0 and annee % 100 != 0))
    {
      bis = 1;
    }
  }
  if (nombredejoursannee <= 31)
  {
    mois = "janvier";
    jour = nombredejoursannee;
  }
  else if (nombredejoursannee <= (59 + bis))
  {
    mois = "fevrier";
    jour = nombredejoursannee - 31;
  }
  else if (nombredejoursannee <= 90 + bis)
  {
    mois = "mars";
    jour = nombredejoursannee - (59 + bis);
  }
  else if (nombredejoursannee <= 120 + bis)
  {
    mois = "avril";
    jour = nombredejoursannee - (90 + bis);
  }
  else if (nombredejoursannee <= 151 + bis)
  {
    mois = "mai";
    jour = nombredejoursannee - (120 + bis);
  }
  else if (nombredejoursannee <= 181 + bis)
  {
    mois = "juin";
    jour = nombredejoursannee - (151 + bis);
  }
  else if (nombredejoursannee <= 212 + bis)
  {
    mois = "juillet";
    jour = nombredejoursannee - (181 + bis);
  }
  else if (nombredejoursannee <= 243 + bis)
  {
    mois = "aout";
    jour = nombredejoursannee - (212 + bis);
  }
  else if (nombredejoursannee <= 273 + bis)
  {
    mois = "septembre";
    jour = nombredejoursannee - (243 + bis);
  }
  else if (nombredejoursannee <= 304 + bis)
  {
    mois = "octobre";
    jour = nombredejoursannee - (273 + bis);
  }
  else if (nombredejoursannee <= 334 + bis)
  {
    mois = "novembre";
    jour = nombredejoursannee - (304 + bis);
  }
  else if (nombredejoursannee <= 365 + bis)
  {
    mois = "decembre";
    jour = nombredejoursannee - (334 + bis);
  }
  queljoursemaine = (epoch / 86400L + 4) % 7; // +4 car 1/1/1970 = jeudi = jour 4 (si dimanche = 0)
  switch (queljoursemaine)
  {
  case 0:
    joursemaine = "Dimanche";
    break;
  case 1:
    joursemaine = "Lundi";
    break;
  case 2:
    joursemaine = "Mardi";
    break;
  case 3:
    joursemaine = "Mercredi";
    break;
  case 4:
    joursemaine = "Jeudi";
    break;
  case 5:
    joursemaine = "Vendredi";
    break;
  case 6:
    joursemaine = "Samedi";
    break;
  }

  epochmars = epochannee + (90 + bis) * 86400UL;   // correspond au dernier jour de de mars
  queljoursemaine = (epochmars / 86400UL + 4) % 7; // +4 car 1/1/1970 = jeudi = jour 4 (si dimanche = 0)
  while (queljoursemaine != 0)
  {
    epochmars = epochmars - 86400UL;
    queljoursemaine = (epochmars / 86400UL + 4) % 7;
  }
  epochmars = epochmars + 1 * 3600UL; // le changement se fait à UTC+1 soit +2H car UTC+1 +DST hiver

  epochoctobre = epochannee + (303 + bis) * 86400UL;  // correspond au dernier jour d'octobre
  queljoursemaine = (epochoctobre / 86400UL + 4) % 7; // +4 car 1/1/1970 = jeudi = jour 4 (si dimanche = 0)
  while (queljoursemaine != 0)
  {
    epochoctobre = epochoctobre - 86400UL;
    queljoursemaine = (epochoctobre / 86400UL + 4) % 7;
  }
  epochoctobre = epochoctobre + 1 * 3600UL; // le changement se fait à UTC+1 soit +3H car UTC+1 +DST été
  if (epoch >= epochmars and epoch < epochoctobre)
  {
    dst = 2;
  }
  else
  {
    dst = 1;
  }

  Heure = ((epoch % 86400UL) / 3600UL) + dst; // +1 = Heure d'hiver et +2 = Heure d'été
  if (Heure >= 24)
  {
    Heure = Heure - 24;
  }
  Serial.print("epoch = ");
Serial.println(epoch);

Serial.print("epochmars = ");
Serial.println(epochmars);

Serial.print("epochoctobre = ");
Serial.println(epochoctobre);

Serial.print("dst = ");
Serial.println(dst);
  minute = ((epoch % 3600) / 60);
  seconde = (epoch % 60);

  // Mise en forme pour l'affichage

  dh = Heure / 10;
  h = Heure - (dh * 10);
  dm = minute / 10;
  m = minute - (dm * 10);
  ds = seconde / 10;
  s = seconde - (ds * 10);
  uneseconde.resume();
  heure = String(dh) + String(h) + ":" + String(dm) + String(m);
  Serial.println(heure);
  Serial.println(dst); 
  display.clearDisplay();
  displaystate = false;
  display.display();
}

Laissez un commentaire et posez vos questions ci-dessous

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *