Présentation
Composants
Branchements
Code ESP32

Alimentation programmée de la Livebox
en 12V par panneau Photovoltaïque

La box ADSL consomme 10W X 24h X 31 jours = 7.44 KWh/mois.
Si je la coupe quand je dors, elle consomme 10W X 16h X 31 jours = 4.96 KWh/mois,
économie 2.48 KWh/mois

La box fibre consomme 4.8W sans Wifi, 10.9W avec Wifi.
Si je la coupe quand je dors, elle consomme 4.8W X 16h X 31 jours = 2.38 KWh/mois,
économie 1.19 KWh/mois

Donc pour économiser l'électricité, et produire moins de chaleur en été,
un ESP32 avec un bouton poussoir avec une LED permet d'allumer/éteindre la box avant de dormir.

Mais à 23h20 si elle est éteinte, l'ESP32 l'allume 20 minutes pour permettre à l'ESP32 Températures de se connecter au Wifi et envoyer ses données au serveur web, parce que le Wifi de la Box est activé automatiquement chaque jour seulement entre 23 heures et minuit.

Ainsi si je l'éteins avant de dormir, il la rallume à 23h20 pendant 20 minutes.
Ainsi si je pars longtemps en voyage ou travailler, la box n'est allumée que 20mn/jour, et pas de souci d'envoi des températures. Et comme le tout est alimenté par panneaux photovoltaïques je peux couper le disjoncteur général 220V avant de partir, et ils peuvent couper EDF dans l'immeuble/le quartier.
/* Livebox alimentée en 12V solaire. Version: 12 septembre 2025

 Au boot, l'ESP se connecte en Wifi à un Access Point du smartphone pour demander à un script PHP 
  le timestamp actuel pour faire settimeofday() et ensuite faire du gettimeofday().
 OU
 Je me réveille par Timer, il est 23h20. Si box éteinte je l'allume, me rendors 20mn,
    et quand me réveille l'éteins, recale le Timer RTC via wifi livebox, et regarde combien de secondes dormir jusqu'à 23h20 (environ 24h - 20 minutes).
    Si elle est déjà allumée, je ne fais rien car elle a été allumée par le bouton. Dormir 24h.
 OU
 Je me réveille parce que le bouton a été pressé:
    Si box éteinte je l'allume.
    Si box allumée: je l'éteins et m'endors jusqu'à 23h20.

 Ainsi je peux éteindre la box et dormir, ou partir 1 mois, ils peuvent couper EDF dans appart/immeuble/quartier,
 l'ESP l'allumera de 23h20 à 23h40 pour permettre à l'ESP Températures d'envoyer ses données.
 C'est mieux que de laisser la Box tourner 24/7: économie entre 3 et 7KWh/mois.

Le code pour ESP32-C3 est différent:
- ESP_SLEEP_WAKEUP_GPIO est la bonne raison du réveil par bouton (au lieu de ESP_SLEEP_WAKEUP_EXT0)
- Pour le réveil par bouton, à la place de
    esp_sleep_enable_ext0_wakeup((gpio_num_t)2,0); //Réveil par bouton 1 = High, 0 = Low
il faut
    esp_deep_sleep_enable_gpio_wakeup(1 << WAKEUP_PIN, ESP_GPIO_WAKEUP_GPIO_LOW);

*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <sys/time.h>
#include <esp_sleep.h>
/*=============================================================*/
//#define DBUG

#define BOUTON (gpio_num_t)2
#define LED    (gpio_num_t)3
#define RELAI  (gpio_num_t)4

#define VIA_WIFI_ANDROID true
#define VIA_WIFI_LIVEBOX false
/*=============================================================*/
RTC_DATA_ATTR bool allumé = false;
RTC_DATA_ATTR bool boxAlluméeParESP = false;
/*=============================================================*/
void set_timestamp(bool android)
{
  #ifdef DBUG
  Serial.print("Connecting to WIFI");
  #endif
  if(android) WiFi.begin("AndroidAP31CF", "mdp");
  else        WiFi.begin("box_ssid","mdp");
  while (WiFi.status() != WL_CONNECTED){
    #ifdef DBUG
    Serial.print(".");
    #endif
    digitalWrite(LED,HIGH);delay(200);
    digitalWrite(LED,LOW); delay(200);
  }
  #ifdef DBUG
  Serial.println("WiFi connected.");
  #endif
  HTTPClient http;
  http.begin("https://apps.masta.fr/timestamp.php");
  int httpCode = http.GET();
  if (httpCode==200){
    setenv("TZ","CET-1CEST,M3.5.0,M10.5.0/3",1); tzset();
    struct timeval tv;
    tv.tv_sec = uint64_t(atoi(http.getString().c_str()));
    tv.tv_usec = 0;
    settimeofday(&tv, NULL);
  }
  http.end();

  WiFi.disconnect(true); //plus besoin de Wifi
  WiFi.mode(WIFI_OFF);
}
/*=============================================================*/
void allumer(){
  #ifdef DBUG
  Serial.println("Allumer");
  #endif
  digitalWrite(LED, HIGH);
  gpio_hold_en(LED);// maintenir LED allumée pendant sommeil

  digitalWrite(RELAI, HIGH); // allumer la BOX
  gpio_hold_en(RELAI);// maintenir RELAI allumé pendant sommeil
  allumé = true;
  gpio_deep_sleep_hold_en();
}
/*=============================================================*/
void eteindre(){
  #ifdef DBUG
  Serial.println("Éteindre");
  #endif
  digitalWrite (LED, LOW);
  gpio_hold_dis(LED);

  digitalWrite (RELAI, LOW); // éteindre la box
  gpio_hold_dis(RELAI);

  allumé = false;
}
/*=============================================================*/
int combienDormir(){
  struct timeval tv;
  struct timezone tz;
  setenv("TZ","CET-1CEST,M3.5.0,M10.5.0/3",1); tzset();
  gettimeofday(&tv,&tz);
  struct tm* now = localtime(&tv.tv_sec);
  #ifdef DBUG
  Serial.print("il est ");
  Serial.print(now->tm_hour); Serial.print("h"); 
  Serial.print(now->tm_min); Serial.print("mn");
  Serial.print(now->tm_sec); Serial.print("s");
  #endif
  // Combien de secondes jusqu'à 23h20?
  int tstamp = now->tm_hour*3600 + now->tm_min*60 + now->tm_sec; // heure actuelle en secondes
  int heureh = 23*3600 + 20*60; // 23h20 heure h en secondes
  int dormirs =  heureh - tstamp;

  #ifdef DBUG
  //Serial.print(" dormirs="); Serial.print(dormirs);
  int dormirh = (int)(dormirs/3600);
  int dormirmn = dormirs/60 - dormirh*60;
  int sec = dormirs - dormirh*3600 - dormirmn*60;
  Serial.print(" Jusqu'à 23h20 dormir ");
  Serial.print(dormirh); Serial.print("h"); 
  Serial.print(dormirmn); Serial.print("mn");
  Serial.print(sec); Serial.println("s"); Serial.println("");
  #endif
  return dormirs;
}
/*=============================================================*/
void setup() {
  #ifdef DBUG
  Serial.begin(115200);
  delay(1000);
  //Serial.println("Reveil");
  #endif
  pinMode(BOUTON, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
  pinMode(RELAI, OUTPUT);

  uint64_t dormirs = 0;

  esp_sleep_wakeup_cause_t wakeup_reason= esp_sleep_get_wakeup_cause();

  // Réveil par bouton -------------------------------------------------
  if(wakeup_reason == ESP_SLEEP_WAKEUP_GPIO){
    #ifdef DBUG
    Serial.println("Reveil par bouton");
    #endif
    if(!allumé) allumer(); else eteindre();
    delay(200); // le temps de relacher le bouton
    dormirs = combienDormir(); // combien dormir jusqu'à 23h20?
  }
  // Réveil par Timer --------------------------------------------------
  else if(wakeup_reason == ESP_SLEEP_WAKEUP_TIMER){
    #ifdef DBUG
    Serial.println("Reveil par timer");
    #endif
    if(!allumé){
      allumer();
      boxAlluméeParESP = true;
      dormirs = 20*60;
    }
    // si c'est l'ESP qui l'a allumée 20mn avant, alors l'éteindre
    else if(boxAlluméeParESP){
      eteindre();
      boxAlluméeParESP = false;
      set_timestamp(VIA_WIFI_LIVEBOX); // Recale le timer RTC
      dormirs = combienDormir();  // Combien dormir jusqu'à 23h20? environ 24h - 20 minutes
    }
    // sinon c'est l'utilisateur qui l'a allumée avec le bouton: dormir 1 jour jusqu'à 23h20
    else {delay(1000); dormirs = combienDormir();}//24*60*60;
  }
  // Réveil par BOOT ou RESET -----------------------------------------
  // demande le timestamp à un script PHP pour faire settimeofday() et ensuite faire du gettimeofday()
  else{
    #ifdef DBUG
    Serial.println("Reveil par Reboot/reset");
    #endif
    set_timestamp(VIA_WIFI_ANDROID);
    dormirs = combienDormir(); // Combien de minutes dormir jusqu'à 23h20?
  }

  esp_deep_sleep_enable_gpio_wakeup(1 << BOUTON, ESP_GPIO_WAKEUP_GPIO_LOW); // réveil par bouton
  esp_sleep_enable_timer_wakeup(dormirs* 1000000ULL); // réveil par timer
  esp_deep_sleep_start();
}

void loop() {}












timestamp.php

<?php
echo time();
?>