Pomodoro Timer
When I work on programming projects, I often get so focused that I forget to take breaks for long periods. To solve this, I created a Pomodoro timer that organizes my work and break sessions. An ultrasonic sensor is integrated to detect whether I am present or away—if I leave, the timer automatically pauses.
This project is part of my concept of Smart Devices for My Work Desk, designed to make working more efficient, healthier, and smarter
A red wire connects the 5V pin on the Arduino to the positive (+) rail of the breadboard.
A black wire connects the Arduino’s GND pin to one side pin of the slide switch.
The switch’s common pin is connected to the negative (–) rail of the breadboard.
GND → Negative rail
VCC → Positive rail
TRIG → Arduino pin 6
ECHO → Arduino pin 5
GND → Negative rail
VCC → Positive rail
SDL → Arduino pin A5
SDA → Arduino pin A4
LCD Configuration:
Set the I2C address to 0x27 (this address for our LCD).
Select the type of I2C as image (like our I2C).
Full Circuit Link
one Side →Negative rail
Other Side → A2
Outputs:
LCD Screen
Buzzer
Inputs:
Ultrasonic Sensor
Push button
Controls:
ON/OFF Switch → powers the circuit
Push Button Functions:
Single click → Pause/Resume timer (Manual Mode)
Double click → Change mode
Long click → Reset timer
Power Supply:
9V DC from a 9V 2A adapter for Arduino
Full Circuit Link 🔗
First, I started by creating an Arduino Timer class that implements a non-blocking countdown timer using the millis() function, allowing the main code to run without interruption. The timer can be started with a duration in minutes, and it automatically adds two extra seconds to the countdown.
A key feature of this class is its ability to pause and resume. When paused, it stops counting by recording the pause time. When resumed, it calculates the elapsed pause duration and extends the final end time accordingly, ensuring the countdown remains accurate.
The class also provides:
is_finished() → checks if the countdown has ended.
get_remaining_seconds() → returns the remaining time, freezing the value when paused.
isSeconds() → a helper function that allows actions (like updating a display) to trigger exactly once per second.
This code defines a modern C++ enumeration called enState. It provides a set of distinct, named states for the program, making the code safer and more readable than using plain numbers. A variable of this type can only hold one of the predefined states at a time. This enumeration serves as the foundation for managing the timer’s phases, such as Working or Pause.
This Arduino code defines a complete PomodoroTimer class, which functions as a self-contained state machine to manage the entire Pomodoro workflow—from work sessions to breaks.
The class uses a modern enum class enState to safely represent its different phases: Idle, Working, Pause, ShortBreak, and LongBreak. This makes the code more reliable and readable compared to using raw values.
At its core, the class encapsulates a separate Timer object to handle countdowns. The main logic is driven by the update() method, which should be called continuously inside the Arduino loop().
When a timer finishes, the private transition_to_next_phase() function is triggered automatically. This acts as the “brain” of the system, deciding whether to start a short or long break based on how many work cycles have been completed.
The class also integrates sound feedback. Private methods such as playSound_WorkStart() use the tone() function to generate unique audio cues for each phase, enhancing the user experience.
Control is simple through public methods like start(), pause(), and resume(). Helper functions such as get_enState() and get_remaining_time() return user-friendly strings for displaying the current status and remaining time on an LCD screen or the Serial Monitor.
Finally, the durations for work and break sessions are defined as constants at the top, making them easy to adjust without changing the core logic. The constructor requires a buzzerPin, ensuring the hardware setup is seamlessly integrated when creating the object.
At the top of the code, several libraries are included to provide essential functionality:
LiquidCrystal_I2C → for controlling the LCD screen.
OneButton → for handling advanced button presses such as single, double, and long clicks.
pomodoro.h → for managing the Pomodoro timer’s logic.
Next, the code defines which Arduino pins are used for the button, buzzer, and ultrasonic distance sensor. After that, the main global objects are created:
lcd_1 → an object to control the LCD screen.
pomodoroTimer → the main object that manages the timer’s state, initialized by passing in the buzzerPin.
button1 → a OneButton object that detects single, double, and long presses.
The setup() Function Explained
The setup() function runs once when the Arduino is powered on or reset. Step by step, it performs the following:
Starts Serial Communication
Serial.begin(9600); opens communication with the computer so debug messages can be viewed in the Serial Monitor.
Attaches Button Functions
The button1.attach... lines link button actions to specific callback functions.
For example: button1.attachClick(click1); ensures the program runs the click1() function whenever a single click is detected.
Initializes the LCD
lcd_1.init(); and lcd_1.backlight(); turn on the display.
setCursor() and clear() prepare the screen for displaying text
Starts the Timer
pomodoroTimer.start(); immediately begins the Pomodoro workflow, usually entering the Working state as soon as the device is powered on.
The loop() runs continuously and handles the program’s active tasks:
Button Monitoring: button1.tick(); checks the button state to detect single, double, or long presses.
Automatic Pause (Ultrasonic): readUltrasonicInCM() measures distance. If you’re within 100 cm, the timer runs; if farther, it pauses automatically.
Display Update (Once/Second): pomodoroTimer.get_timer().IsSeconds() ensures the LCD and Serial Monitor update only once per second, preventing flicker and saving resources.
click1() (Single Click): Toggles pause/resume.
doubleclick1() (Double Click): Resets the Pomodoro cycle.
readUltrasonicInCM(): Converts sensor readings into distance (cm).
longPress...(): Placeholders that currently just print messages to the Serial Monitor.
First, we gathered the required components: jumpers, small breadboard, Arduino, on/off switch, push button ,ultrasonic sensor, buzzer ,and 9V adapter .
Connect the buzzer’s negative (–) pin to the Arduino GND and the positive (+) pin to Arduino digital pin 11.
Connect one side of the push button to Arduino GND, and the other side to analog pin A2.
Then, connect the Arduino GND and 5V pins to the power rails of the small breadboard.
Then, connect the ultrasonic sensor exactly as the same way we did in our Tinkercad simulator.
Then, we connected four wires to the LCD exactly as the same way we did in our Tinkercad simulator.
Then, we connected the yellow (SCL) and orange (SDA ) wires to Arduino pins A4 and A5, just like in the circuit simulation.
Then, upload the code to the Arduino and test the circuit before placing the components inside the enclosure.
Then, we connected the yellow (SCL) and orange (SDA ) wires to Arduino pins A4 and A5, just like in the circuit simulation.
Then, upload the code to the Arduino and test the circuit before placing the components inside the enclosure.
First, after preparing the component slots, I started by fixing the ON/OFF switch in place.
Then, I fixed the ultrasonic sensor and the DC jack in place.
Then, I fixed the push button and the LCD on the top layer.
Then, I started assembling the two layers together and fixed the Arduino and the breadboard in place.
Finally, I fixed the two layers together using hot glue, connected the adapter, and powered on the system.
My peer Ahmed asked me how he could make a timer lock for his phone as part of his final project. I suggested that he could use an LCD with a keypad or push buttons for input. When he asked if he should use an external timer, I recommended using the Arduino’s internal timer since it is easier to implement than an external one. I also told him that he could use a library like OneButton, which simplifies working with push buttons by detecting single, double, long, and even multiple clicks.
In the first code (shown in first image), when I tried the automatic mode, I noticed that the timer did not pause correctly—it kept running instead of stopping. However, in manual mode, the pause state worked as expected. After debugging the code, I discovered that the issue was caused by repeatedly calling the pause function when the timer was already paused, or calling resume when it was already running. To fix this, I added a condition to check the current state before calling pause or resume (as shown in the second image). This solved the bug.
Chess clock🕒
This week was an introduction to Arduino programming, where I learned how to create a timer using Arduino, similar to the one I developed in this week’s assignment. The skills and knowledge I gained—such as designing electronic circuits in Tinkercad, troubleshooting them, and practicing Arduino coding—will be highly valuable for my chess clock project. These experiences will help me integrate Arduino with sensors, design and prototype components more efficiently, simulate and test ideas before implementation, and solve technical issues with greater confidence.
system senses the soil moisture level using a moisture sensor, and measures temperature and humidity with a DHT sensor, in order to control a DC pump and a DC fan. We built and programmed two modes—Manual and Automatic—using a slide switch. In Manual Mode, the pump and fan could be controlled directly through ON/OFF switches. In Automatic Mode, the pump was triggered by the soil moisture level, while the fan operated based on temperature and humidity conditions, with readings displayed on an LCD screen. This project helped us practice sensor integration, circuit design, and Arduino programming in a practical and collaborative way.
Smart planet system