Optimiser la conso électrique du ESP32

De Wiki de Mémoire Vive
Aller à la navigation Aller à la recherche

Les possibilités sont limitées en ESPHome mais très supérieures avec du code Arduino. Ce qui prend tout son sens lorsqu'on est avec une alimentation sur batterie.

https://youtube.com/shorts/S9HAANlcVAg?si=NyX30GI7u0vbySkP

ESPHome est très pratique pour des projets simples et rapidement connectés. Mais Arduino ouvre la voie à :

- une maîtrise totale du matériel

- une consommation minimale

- une interface UX personnalisée

et des fonctionnalités avancées (stockage, communication, veille contextuelle).

Voici 1) le code Arduino et 2) le code d'origine en ESPHome.

Arduino

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Pins
#define HALL_SENSOR_PIN 25
#define LED_PIN 2

// Compteur
volatile int tour_count = 0;
unsigned long last_pedal_time = 0;
const int cadence_window_ms = 3000;
unsigned long pedal_times[20];  // Pour une fenêtre glissante
int pedal_index = 0;

// Cadence
float cadence_rpm = 0;

void IRAM_ATTR onPedal() {
  unsigned long now = millis();

  // Éviter les rebonds ou doubles déclenchements
  if (now - last_pedal_time < 150) return;
  last_pedal_time = now;

  // Incrémenter le compteur
  tour_count++;

  // Ajouter timestamp
  pedal_times[pedal_index % 20] = now;
  pedal_index++;
  
  // LED blink
  digitalWrite(LED_PIN, HIGH);
}

void setup() {
  pinMode(HALL_SENSOR_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  attachInterrupt(digitalPinToInterrupt(HALL_SENSOR_PIN), onPedal, FALLING);

  Serial.begin(115200);
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
}

void loop() {
  static unsigned long last_update = 0;
  unsigned long now = millis();

  if (now - last_update > 1000) {
    last_update = now;

    // Nettoyer les timestamps vieux de plus de 3 sec
    int count = 0;
    unsigned long first = 0, last = 0;
    for (int i = 0; i < 20; i++) {
      unsigned long t = pedal_times[i];
      if (now - t < cadence_window_ms) {
        if (count == 0) first = t;
        last = t;
        count++;
      }
    }

    if (count >= 2) {
      float elapsed_min = (last - first) / 60000.0;
      cadence_rpm = (count - 1) / elapsed_min;
    } else {
      cadence_rpm = 0;
    }

    // Affichage OLED
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    display.print("Cadence:");

    display.setTextSize(2);
    display.setCursor(0, 10);
    display.print(cadence_rpm, 0);
    display.print(" tpm");

    display.setTextSize(1);
    display.setCursor(0, 40);
    display.print("Tours:");

    display.setTextSize(2);
    display.setCursor(0, 50);
    display.print(tour_count);

    display.display();

    // Éteindre LED après affichage
    digitalWrite(LED_PIN, LOW);
  }
}

ESPHome

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <esp_sleep.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Pins
#define HALL_SENSOR_PIN 25
#define LED_PIN 2

RTC_DATA_ATTR int tour_count = 0;

const int cadence_window_ms = 3000;
unsigned long pedal_times[20];  // tableau circulaire
int pedal_index = 0;

unsigned long last_pedal_time = 0;
unsigned long last_activity_time = 0;

bool pedal_detected = false;
float cadence_rpm = 0;

void IRAM_ATTR onPedal() {
  pedal_detected = true;
}

void setup() {
  pinMode(HALL_SENSOR_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  attachInterrupt(digitalPinToInterrupt(HALL_SENSOR_PIN), onPedal, FALLING);

  Serial.begin(115200);
  Wire.begin();

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();

  last_pedal_time = millis();
  last_activity_time = millis();
}

void loop() {
  unsigned long now = millis();

  if (pedal_detected) {
    pedal_detected = false;
    last_pedal_time = now;
    last_activity_time = now;
    tour_count++;

    // Stocker l'instant du pédalage
    pedal_times[pedal_index % 20] = now;
    pedal_index++;

    // LED blink
    digitalWrite(LED_PIN, HIGH);
    delay(100);
    digitalWrite(LED_PIN, LOW);

    // Calcul de la cadence sur les 3 dernières secondes
    int count = 0;
    unsigned long first = 0, last = 0;

    for (int i = 0; i < 20; i++) {
      unsigned long t = pedal_times[i];
      if (now - t < cadence_window_ms) {
        if (count == 0) first = t;
        last = t;
        count++;
      }
    }

    if (count >= 2) {
      float elapsed_min = (last - first) / 60000.0;
      cadence_rpm = (count - 1) / elapsed_min;
    } else {
      cadence_rpm = 0;
    }

    // Affichage OLED
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    display.print("Cadence:");

    display.setTextSize(2);
    display.setCursor(0, 10);
    display.print(cadence_rpm, 0);
    display.print(" tpm");

    display.setTextSize(1);
    display.setCursor(0, 40);
    display.print("Tours:");

    display.setTextSize(2);
    display.setCursor(0, 50);
    display.print(tour_count);
    display.display();
  }

  // Si plus de 10s d'inactivité → deep sleep
  if (now - last_activity_time > 10000) {
    display.clearDisplay();
    display.display();
    display.ssd1306_command(SSD1306_DISPLAYOFF);

    esp_sleep_enable_ext0_wakeup(GPIO_NUM_25, 0);  // Réveil sur LOW (aimant)
    delay(100);
    esp_deep_sleep_start();
  }

  delay(50);
}