1 / 4
Pomodoro Neopixel Puck — zdjęcie 1
1 / 4

Pomodoro Neopixel Puck

Zamów wydruk tego modelu

Obliczymy ostateczną cenę na podstawie wybranego pliku. Sprawdzisz ją i zaakceptujesz przed płatnością.

Zapisane na tym urządzeniu.

A simple Pomodoro timer (25 minutes) using Wemos D1 Mini and Neopixel ring

Ocena
0 / 5
Polubienia
11
Pobrania
13
Wydruki
0
Wyświetlenia
277
Oceny
0

Aktualizacja u źródła:

Informacje o modelu

Źródło
Printables
Kategoria
Other Gadgets
Licencja
Creative Commons — Attribution

I was looking for something with a single function: only counting down 25 minutes. Since I couldn’t find anything reasonable without multiple functions, I decided to build it myself. I generated the code using Canvas in Gemini.

🛠 Component List

To build this project, you will only need a few basic and inexpensive components:

  • Wemos D1 Mini – The "brain" of the entire device.

  • NeoPixel Ring (24 LEDs, WS2812B) – For the visual countdown display.

  • TTP223 Touch Sensor – A capacitive module for control.


🔌 Wiring Diagram

NeoPixel Ring:

  • VCC ➔ Wemos 5V

  • GND ➔ Wemos GND

  • DIN (Data In) ➔ Wemos D1

TTP223 Touch Sensor:

  • VCC ➔ Wemos 3V3

  • GND ➔ Wemos GND

  • SIG ➔ Wemos D2

🕹 How It Works

1. Standby Mode

After connecting the power, the ring remains completely dark. The timer does nothing and "sleeps," consuming minimal power.

2. Starting the Countdown

Briefly touch the sensor to immediately start the 25-minute countdown. The ring lights up in a full rainbow, and two things begin to happen:

  • Time Remaining: The LEDs gradually turn off one by one as time passes.

  • White "Second Hand": A white dot moves smoothly around the ring (counter-clockwise). It completes one rotation every 10 seconds, letting you know the device is active and time is running.

3. Pausing Time

Is someone talking to you, or do you need a quick break? Briefly touch the sensor. The moving white dot stops instantly, and the brightness of the entire ring dims significantly. This clearly indicates that time is frozen. Another brief touch resumes the countdown exactly where it left off, and the brightness returns to normal.

4. Resetting the Timer

Need to start over? At any point during the countdown or pause, hold your finger on the sensor for more than 1 second. The ring will flash blue to confirm, and the device will return to the dark standby mode, ready for a new cycle.

5. End of Countdown

Once the full 25 minutes have elapsed, the ring gently flashes green three times. It then turns off completely, and the device returns to deep sleep. The next touch will wake it up for your next work session.

💻 Source Code 

#include <Adafruit_NeoPixel.h>
#include <ESP8266WiFi.h> // Přidána knihovna pro ovládání Wi-Fi

// Přidáno pro přístup k hlubším systémovým funkcím (nastavení spánku CPU) extern "C" { #include "user_interface.h" }

#define PIN D1 #define NUMPIXELS 24 #define TOUCH_PIN D2 // Přidán pin pro dotykový senzor TTP223

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

// --- NASTAVENÍ POMODORO ČASOVAČE --- const int timerMinutes = 25; // Použito const - šetří RAM, hodnota se nemění

unsigned long durationMs; unsigned long startTime; bool isFinished = false; bool isRunning = false; // Nová proměnná hlídající, jestli už byl odpočet spuštěn

// Přidáno pro pokročilé ovládání dotykem (Pauza a Reset) bool isPaused = false; unsigned long elapsedAtPause = 0; bool lastTouchState = false; unsigned long touchPressTime = 0; bool isLongPressHandled = false;

// --- NASTAVENÍ ANIMACE --- const int jas = 30; // Konstantní jas // Zpomaleno na polovinu: Čas otáčky bílé LED zvýšen z 5000 ms na 10000 ms (10 s) const unsigned long dobaOtacky = 10000UL;

// Předpočítaný krok duhy pro jednu LED (zefektivní výpočet ve smyčce) const uint32_t HUE_KROK = 65536UL / NUMPIXELS;

void setup() { // Vypnutí Wi-Fi pro maximální úsporu baterie WiFi.mode(WIFI_OFF); WiFi.forceSleepBegin(); delay(1);

// Povolení Light Sleep módu - procesor bude během funkce delay() "spát" a šetřit energii wifi_set_sleep_type(LIGHT_SLEEP_T);

pinMode(TOUCH_PIN, INPUT); // Nastavení pinu senzoru pro čtení dotyku

pixels.begin(); pixels.clear(); pixels.show(); // Zaručí, že po zapnutí Wemosu bude pásek zaručeně tmavý

durationMs = timerMinutes * 60UL * 1000UL; // Zrušili jsme startTime = millis(); - ten se nyní zaznamená až po dotyku }

void loop() { unsigned long currentMillis = millis(); bool currentTouch = digitalRead(TOUCH_PIN) == HIGH;

// --- OBSLUHA DOTYKOVÉHO SENZORU ---

// 1. Zaznamenání začátku dotyku if (currentTouch && !lastTouchState) { touchPressTime = currentMillis; isLongPressHandled = false; }

// 2. Kontrola dlouhého stisku (více než 1000 ms) if (currentTouch && lastTouchState) { if ((currentMillis - touchPressTime > 1000) && !isLongPressHandled) { isLongPressHandled = true; // Označíme, ať se nevolá znovu

  // RESET ČASOVAČE
  isRunning = false;
  isPaused = false;
  isFinished = false;
  elapsedAtPause = 0;
  
  // Vizuální potvrzení resetu - rychlé modré probliknutí
  pixels.fill(pixels.Color(0, 0, jas + 20));
  pixels.show();
  delay(300);
  pixels.clear();
  pixels.show();
}

}

// 3. Kontrola krátkého stisku (při uvolnění) if (!currentTouch && lastTouchState) { if (!isLongPressHandled) { if (!isRunning) { // První spuštění z klidu isRunning = true; isFinished = false; isPaused = false; startTime = millis(); } else if (isFinished) { // Spuštění nového odpočtu po dokončení předchozího isFinished = false; isRunning = true; startTime = millis(); } else { // Pauza / Odpauznutí probíhajícího odpočtu isPaused = !isPaused; if (isPaused) { elapsedAtPause = currentMillis - startTime; // Uložíme si uplynulý čas } else { startTime = currentMillis - elapsedAtPause; // Posuneme start o dobu, co to spalo } } } } lastTouchState = currentTouch;

// --- KLIDOVÉ STAVY --- if (!isRunning && !isFinished) { delay(50); // Úspora baterie, když čekáme na spuštění return; }

if (isFinished) { // Sníženo z 1000 na 50 ms. Potřebujeme číst senzor pro restart, // ale 50 ms s Light Sleep stále odebírá zanedbatelné minimum energie. delay(50); return; }

// --- VÝPOČET ČASU PRO ANIMACI --- unsigned long elapsed;

if (isPaused) { elapsed = elapsedAtPause; } else { elapsed = currentMillis - startTime; }

// KONTROLA KONCE ČASU if (elapsed >= durationMs) { // 3x zabliká zeleně na konci časovače for(int i = 0; i < 3; i++) { pixels.fill(pixels.Color(0, 50, 0)); pixels.show(); delay(500); pixels.clear(); pixels.show(); delay(500); } isFinished = true; return; }

// VÝPOČET ZBÝVAJÍCÍCH LED (Optimalizováno bez použití desetinných čísel float) unsigned long remainingMs = durationMs - elapsed; // Celočíselná matematika je na ESP8266 mnohem rychlejší a šetří procesor int activeLEDs = (remainingMs * NUMPIXELS + (durationMs / 2)) / durationMs;

if (activeLEDs < 1) activeLEDs = 1; if (activeLEDs > NUMPIXELS) activeLEDs = NUMPIXELS;

// --- ANIMACE: STATICKÁ DUHA ---

pixels.clear();

// Základní odstín je nyní pevný, takže barvy na diodách se nebudou posouvat uint32_t zakladniOdstin = 0;

// Nastavení jasu (výrazně ztlumíme při pauze pro vizuální odlišení) int aktualniJas = isPaused ? 4 : jas;

// Výpočet pozice putující bílé LED (krouží PROTI směru hodinových ručiček) // Použijeme rovnou 'elapsed', díky čemuž je tečka absolutně svázaná s odpočtem // a při pauze přesně zamrzne na svém aktuálním místě bez jakéhokoliv skoku. int bilaLED = (NUMPIXELS - 1) - (((elapsed % dobaOtacky) * NUMPIXELS) / dobaOtacky);

// Projdeme VŠECHNY LED na kroužku for(int i = 0; i < NUMPIXELS; i++) { // 1. Putující tečka if (i == bilaLED) { // Bílá tečka bude mít vždy o něco vyšší jas než okolí, aby vynikla pixels.setPixelColor(i, pixels.ColorHSV(0, 0, aktualniJas + 20)); } // 2. Aktivní oblast s duhou else if (i < activeLEDs) { // Použití předpočítané konstanty HUE_KROK zrychluje tento výpočet uint32_t pixelHue = zakladniOdstin + (i * HUE_KROK); // Použijeme aktualniJas (proměnlivý podle toho, jestli je pauza) pixels.setPixelColor(i, pixels.ColorHSV(pixelHue, 255, aktualniJas)); } }

pixels.show();

// Zvýšeno z 15 na 30 ms (cca 33 snímků za sekundu). // Stále naprosto plynulé pro oko, ale procesor má 2x více času na spánek v Light Sleep módu! delay(30); }

Tagi