1 / 1
Minuteur Pomodoro — image 1

Minuteur Pomodoro

Order a print of this model

We calculate the final price from your selected file. You review and accept it before payment.

Saved on this device.

Un Pomodoro physique avec écran OLED, encodeur rotatif et leds

Rating
0 / 5
Likes
2
Downloads
74
Makes
1
Views
105
Reviews
0

Updated at source:

Model information

Category
Electronics
License
Creative Commons — Attribution — Noncommercial — Share Alike

Contrôleur Pomodoro DIY

Ce projet est un timer Pomodoro physique imprimé en 3D conçu pour structurer les sessions de travail et de pause.

L'objectif est simple : transformer une méthode de productivité abstraite en un objet concret posé sur le bureau.

Grâce à un encodeur rotatif, il est possible de régler facilement la durée du timer.
Un bouton permet ensuite de lancer la session.

Pendant le fonctionnement :

  • l'écran OLED affiche les informations du timer

  • un anneau de LEDs indique visuellement l'état de la session

Le cycle fonctionne ainsi :

  • 25 minutes de travail

  • 5 minutes de pause

  • puis le cycle recommence automatiquement.

Composants utilisés :  

L'acrylique nécessite un léger ponçage sur les bords pour entrer en force dans la pièce supérieur

Le code du projet :

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

#define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64

#define SDA_PIN 8 #define SCL_PIN 9

#define LED_PIN 2 #define LED_COUNT 8

#define ENC_A 4 #define ENC_B 5 #define BTN 3 // bouton externe

#define BREAK_MINUTES 5 #define BREAK_INTERVAL_MINUTES 25 #define STEP_MINUTES 30

#define BREAK_INTERVAL_SECONDS (BREAK_INTERVAL_MINUTES * 60)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800); Encoder encoder(ENC_A, ENC_B);

enum Mode { MODE_SET, MODE_WORK, MODE_BREAK };

Mode mode = MODE_SET;

int workMinutes = STEP_MINUTES;

int workRemainingSeconds = STEP_MINUTES * 60; int breakRemainingSeconds = 0; int remainingSeconds = STEP_MINUTES * 60;

int workElapsedSinceBreak = 0;

unsigned long totalWorkSeconds = 0; unsigned long lastTick = 0;

long lastEncoderPos = 0; bool lastButtonState = HIGH;

// ===== PROTOTYPES ===== void handleEncoder(); void handleButton(); void updateTimer(); void drawScreen(); void updateLEDs(); String formatDuration(int seconds); String formatHoursMinutes(int seconds);

// ====================== // SETUP // ====================== void setup() { Serial.begin(115200); delay(500);

pinMode(BTN, INPUT_PULLUP);

Wire.begin(SDA_PIN, SCL_PIN);

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println("OLED FAIL"); while(true); }

display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.display();

strip.begin(); strip.setBrightness(100); strip.show();

drawScreen(); updateLEDs(); }

// ====================== // LOOP // ====================== void loop() { handleEncoder(); handleButton(); updateTimer(); }

// ====================== // ENCODER // ====================== void handleEncoder() { if(mode != MODE_SET) return;

long pos = encoder.read() / 4;

if(pos != lastEncoderPos) { int delta = pos - lastEncoderPos;

workMinutes += delta * STEP_MINUTES;

if(workMinutes &lt; STEP_MINUTES)
  workMinutes = STEP_MINUTES;

if(workMinutes &gt; 720)
  workMinutes = 720;

workRemainingSeconds = workMinutes * 60;
remainingSeconds = workRemainingSeconds;

lastEncoderPos = pos;

drawScreen();
updateLEDs();

} }

// ====================== // BUTTON // ====================== void handleButton() { bool state = digitalRead(BTN);

if(lastButtonState == HIGH && state == LOW) { if(mode == MODE_SET) { mode = MODE_WORK; workRemainingSeconds = workMinutes * 60; remainingSeconds = workRemainingSeconds; workElapsedSinceBreak = 0; totalWorkSeconds = 0; } else { mode = MODE_SET; workRemainingSeconds = workMinutes * 60; remainingSeconds = workRemainingSeconds; }

drawScreen();
updateLEDs();
delay(200); // anti-rebond simple

}

lastButtonState = state; }

// ====================== // TIMER // ====================== void updateTimer() { if(mode == MODE_SET) return;

if(millis() - lastTick >= 1000) { lastTick = millis();

if(mode == MODE_WORK)
{
  workRemainingSeconds--;
  remainingSeconds = workRemainingSeconds;

  totalWorkSeconds++;
  workElapsedSinceBreak++;

  if(workElapsedSinceBreak &gt;= BREAK_INTERVAL_SECONDS &amp;&amp;
     workRemainingSeconds &gt; 0)
  {
    mode = MODE_BREAK;
    breakRemainingSeconds = BREAK_MINUTES * 60;
    remainingSeconds = breakRemainingSeconds;
    workElapsedSinceBreak = 0;
  }

  if(workRemainingSeconds &lt;= 0)
  {
    mode = MODE_SET;
    workRemainingSeconds = workMinutes * 60;
    remainingSeconds = workRemainingSeconds;
  }
}

else if(mode == MODE_BREAK)
{
  breakRemainingSeconds--;
  remainingSeconds = breakRemainingSeconds;

  if(breakRemainingSeconds &lt;= 0)
  {
    mode = MODE_WORK;
    remainingSeconds = workRemainingSeconds;
  }
}

drawScreen();
updateLEDs();

} }

// ====================== // DISPLAY // ====================== void drawScreen() { display.clearDisplay();

String timeStr = formatDuration(remainingSeconds);

display.setTextSize(4); // très gros

int16_t x1, y1; uint16_t w, h;

display.getTextBounds(timeStr, 0, 0, &x1, &y1, &w, &h);

int x = (SCREEN_WIDTH - w) / 2; int y = (SCREEN_HEIGHT - h) / 2;

display.setCursor(x, y); display.print(timeStr);

display.display(); }

// ====================== // FORMAT FUNCTIONS // ====================== String formatDuration(int seconds) { int hours = seconds / 3600; int minutes = (seconds % 3600) / 60; int secs = seconds % 60;

char buffer[16];

if(hours > 0) sprintf(buffer,"%dh%02d",hours,minutes); else sprintf(buffer,"%02d:%02d",minutes,secs);

return String(buffer); }

String formatHoursMinutes(int seconds) { int hours = seconds / 3600; int minutes = (seconds % 3600) / 60;

char buffer[16]; sprintf(buffer,"%dh%02d",hours,minutes);

return String(buffer); }

// ====================== // LED CONTROL // ====================== void updateLEDs() { if(mode == MODE_SET) { for(int i=0;i<LED_COUNT;i++) strip.setPixelColor(i, strip.Color(60,60,60)); }

else if(mode == MODE_WORK) { int ledsOn = map(remainingSeconds, 0, workMinutes*60, 0, LED_COUNT);

for(int i=0;i&lt;LED_COUNT;i++)
{
  if(i &lt; ledsOn)
    strip.setPixelColor(i, strip.Color(0,150,0));
  else
    strip.setPixelColor(i, 0);
}

}

else { int ledsOn = map(remainingSeconds, 0, BREAK_MINUTES*60, 0, LED_COUNT);

for(int i=0;i&lt;LED_COUNT;i++)
{
  if(i &lt; ledsOn)
    strip.setPixelColor(i, strip.Color(0,0,150));
  else
    strip.setPixelColor(i, 0);
}

}

strip.show(); }

Tags