lampe chevet horloge 5

Lampe de chevet Dimmable avec Horloge NTP ESP32

Belle ambiance

lampe chevet dimmable avec horloge NTP

Présentation

J’ai récupéré une ancienne lampe de chevet pour ne garder que le cylindre que je trouvais joli. J’ai remplacé la partie éclairage par une LED dimmable alimentée en 5V, un bouton pour allumer et éteindre la lampe et un bouton pour afficher l’heure pendant un laps de temps ou jusqu’a une nouvelle pression sur le bouton poussoir.
L’horloge se met à l’heure par le protocole NTP toutes les 12 heures et le wifi ne fonctionne que pendant ces courts instants.
Le passage aux heures d’hiver et d’été est automatique.
Une prise USB permet également de brancher un appareil à alimenter en 5V.

Composants

  • 1 Microcontrôleur ESP32 C3 Zéro ou Supermini;
  • 1 Ecran OLED I2C;
  • 1 LED 3V 3W;
  • 2 boutons poussoirs normalements ouverts;
  • 1 prise USB type A et type C;
  • 1 transistor BD243 ou équivalent;
  • 1 transistor 2N2222 ou équivalent;
  • 1 relais 5 V DC SPST;
  • 1 diode type 1N914 ou équivalente;
  • 1 résistance 82 ohms;
  • 2 résistances 1200 ohms;
  • 1 potentiomètre 1000 ohms
  • 1 condensateur 1000 µF 5 V ou +;
  • 1 boîtier imprimé en 3D;
  • 1 câble d’alimentation muni d’une fiche plate;
  • 1 alimentation Meanwell IRM10-05.

Schéma

lampe chevet horloge schema

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

Boîtier

J’ai conçu ce boîtier en fonction de la partie de lampe récupérée. J’ai également dessiné un support pour le module LED en 3D afin qu’il se clipse simplement dessus.

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

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 !

Platformio.ini

[env:esp32-c3-devkitm-1]
platform = espressif32
board = esp32-c3-devkitm-1
framework = arduino
monitor_speed=115200
build_flags = 
  -DARDUINO_USB_MODE=1
  -DARDUINO_USB_CDC_ON_BOOT=1
lib_deps = 
	thomasfredericks/Bounce2@^2.72
	sstaub/TickTwo@^4.4.0
	marvinroger/AsyncMqttClient@^0.9.0
	adafruit/Adafruit SSD1306@^2.5.15
	adafruit/Adafruit NeoPixel@^1.15.2

jagprod.h

#ifndef jagprod_h
#define jagprod_h

// WiFi
#define sid "votre SSID"
#define wifi_sesame "Votre mot de passe WiFi"

// IP (Si utilisation en DHCP, supprimer cette partie)
const uint8_t ip[4] = {Adresse IP de l'hôte dans votre réseau};
const uint8_t mask[4] = {Masque de sous-réseaux};
const uint8_t ns[4] = {Adresse IP du serveur DNS};
const uint8_t gw[4] = {Adresse de la passerelle};

#endif

main.cpp

Vous devrez remplacer les *** le serveur NTP à utiliser.

#include <Arduino.h>
#include <WiFi.h>
#include <TickTwo.h>
#include <Bounce2.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Fonts/FreeSans24pt7b.h>
#include <Fonts/FreeSansOblique9pt7b.h>
#include <Adafruit_SSD1306.h>
#include <WiFiUdp.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

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);
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;
String mois;
String epoch2string;
bool premierefois = true;
void plus1s();

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

// Relais et bouton
const int relais_pin = 3;
bool etatrelais = false;
const int poussoir_onoff_pin = 1;
const int poussoir_ecran_pin = 0;
Bounce2::Button poussoir_onoff = Bounce2::Button();
Bounce2::Button poussoir_ecran = Bounce2::Button();

TickTwo uneseconde(plus1s, 1000);

void setup()
{
  Serial.begin(115200);

  // Bouton
  poussoir_onoff.attach(poussoir_onoff_pin, INPUT_PULLUP);
  poussoir_onoff.setPressedState(LOW);
  poussoir_onoff.interval(5);
  poussoir_ecran.attach(poussoir_ecran_pin, INPUT_PULLUP);
  poussoir_ecran.setPressedState(LOW);
  poussoir_ecran.interval(5);

  // Relais
  pinMode(relais_pin, OUTPUT);
  digitalWrite(relais_pin, etatrelais);
  Wire.begin();

  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ; // Don't proceed, loop forever
  }
  display.setRotation(2);
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
}

void loop()
{
  uneseconde.update();
  poussoir_onoff.update();
  poussoir_ecran.update();

  if (poussoir_onoff.pressed())
  {
    etatrelais = !etatrelais;
    digitalWrite(relais_pin, etatrelais);
  }

  if (poussoir_ecran.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(0, 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(sid, wifi_sesame);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1000);
  }
  display.clearDisplay();
  display.setCursor(10, 20);
  display.print("WIFI OK");
  display.display();
  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;
  }
  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);
  if (premierefois == true)
  {
    displaystate = true;
    premierefois = false;
    display.clearDisplay();
    display.setFont(&FreeSans24pt7b);
    display.setCursor(0, 32);
    display.print(heure);
    display.display();
  }
  else
  {
    displaystate = false;
  }
}

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 *