Build a Hydration Reminder Device

by rohanbarnwal in Circuits > Arduino

399 Views, 5 Favorites, 0 Comments

Build a Hydration Reminder Device

ChatGPT Image May 20, 2025, 01_52_51 PM.png
I was so focused on work, I forgot to drink water again."

I said this to myself too many times - until I decided to fix it with tech.

Why It Matters

We live in a world of hustle. Whether you're coding, designing, gaming, or just grinding away on work, it's easy to forget one of the most basic human needs: drinking water.

I used to skip drinking for hours without even realizing it. Over time, it took a toll-headaches, low energy, and trouble focusing. Not drinking enough water can lead to range of problems: fatigue, poor concentration, even long-term kidney issues.

Apps can remind you, but most people swipe them away. I wanted something more effective - something physical, subtle, and responsive.

Story Behind the Build

That's how I ended up designing this Smart Hydration Reminder - a compact, customizable gadget powered by Arduino, that tracks your water bottle and reminds you exactly when you need it.

It's more than just a time. It uses an IR sensor to detect if your bottle is placed, a rotary encoder to let you control the time interval, an OLED display to keep it visually intuitive, and a buzzer to alert you. All of it is beautifully enclosed in a 3D-printed case that you can customize.

Features That Make This Stand Out

  1. 4-line Large font OLED messages
  2. Encoder-controlled timer (1-20 minutes)
  3. Beep on every encoder value change
  4. Beep when bottle is placed
  5. 3 short beeps when it's time to drink
  6. Asks "why" if bottle is removed early
  7. Auto resume or restart timer based on your reply
  8. Auto restart timer after drinking - no encoder libraries required
  9. Custom designed 3D-printed enclosure via JUSTWAY

What I Learned

This project taught me more than just Arduino code. This taught me how habit-building can be engineered - literally. And that even a small, humble idea - like a "water reminder" - can create real lifestyle change

Finally Thoughts

This isn't a fancy small bottle. it won't tell you how alkaline your water is. It won't sync with 5 apps or offer gamification But what it will do is remind you to drink water, every time - consistency gently, and reliably.

Build habits. Build gadgets. Stay hydrated.


Supplies

IMG_4583_(2).jpg
download (20).jpeg
download (19).jpeg
download (16).jpeg
download (14).jpeg
download (12).jpeg

Electronics:

  1. Arduino UNO R4 Wi-Fi x1: I used this for performance + Wi-Fi (for future upgrades). But you can absolutely use any Arduino Board (Uno, Nano, etc.)


  1. IR Proximity Sensor x1: Detects whether bottle is placed or removed


  1. Rotary Encoder with Push Button Module x1: To navigate in between menus and select the timer


  1. 0.96" OLED I2C Display x1: To show timer, prompts, and messages


  1. Jumper Wires (as needed): For connecting all components together


  1. Active Buzzer x1: Gives short beeps on time change, alerts and bottle placement

I Designed a 3D Case for It - and Got It Printed via JUSTWAY

I wanted this project to not just work but look great too. So I designed a Compact, minimal 3D enclosure to house the electronics securely.

To bring the design to life, I used JUSTWAY's 3D Printing Service, and I can confidently say - it exceeded expectations.

Why JUSTWAY?

Unlock the Future of Manufacturing with JUSTWAY's 3D Printing Service!

Whether you're making prototypes, functional enclosure, or final products - JUSTWAY delivers precision, speed, and professionalism.

  1. Supports Technologies like SLA, SLS, FDM, SLM, MJF, DLP
  2. Offers a wide range of materials: resins, nylons, metals
  3. Super easy to order: Upload Get Instant Quote Track Order
  4. Finishing options + CNC, injection molding, and even metal fabrication
  5. Great customer support & fast delivery

How to Order Your Own Model Via JUSTWAY

11.png

It's super simple:

Step1: Upload Your Design in Seconds: Head to the JUSTWAY website, log in (or sign up if you're new), and jump straight into the "Get Instant Quote" section.

Upload your STP, STEP, or other supported CAD file

Choose Your Manufacturing Process

22.png

from resins, nylon, and PLA to metals and engineering grade polymers. Customize the finish and other specs - get your instant quote on the spot

Preview and Inspect Your Model

33.png
Want to double-check how it'll turn out?

JUSTWAY lets you preview the uploaded model in 3D right in the browser before placing the order. Zoom, pan, rotate -inspect every detail

Review Quote & Place Order

44.png

JUSTWAY will guarantee excellent production with stringent quality control inspections after your purchase is placed. you can anticipate receiving your 3D model withing the allotted lead time. Experience the ease and effectiveness of using JUSTWAY to bring your 3D creation to life!

They also offer:

  1. CNC machining
  2. Sheet metal fabrication
  3. Injection molding
  4. Surface finishing

Now let see How It Works (Step-by-Step Flow)

How It Works: Power on & Animation

IMG_4585.png

As soon as you power system via USB or 5V source, the OLED screen boots up with a custom splash screen of a Water drop appears.

Waiting for Bottle Placement

IMG_4586.png

The device now actively check the IR sensor if no bottle is detected the OLED displays:

This ensure the timer only starts after the user is ready.

Bottle Detected Set Time

IMG_4587 (1)(1).png

The moment you place the bottle, the IR sensor goes LOW (detection). The OLED now switches to time-setting mode using the rotary encoder

  1. Rotate encoder: Increase/decrease minutes (1-20 minutes)
  2. Press the encoder button to start

Countdown Starts

IMG_4588.png

After you press the encoder button, the timer starts counting down OLED shows something like this as shown above

Countdown Ends

IMG_4589.png

Reminder Triggered Once the countdown finishes, the system:

  1. Beeps 3 times
  2. OLED Shows the message "Drinking Time" as shown above

Place the Bottle Again

IMG_4588.png

Once the bottle is placed again, everything resumes smoothly - no need for manual resets. This step-based behavior makes it feel like a real assistant on you desk - one that understands and adapts to your routine.

If Bottle Removed

IMG_4597.png

If you remove the bottle in between the countdown, the system asks you a question:

  1. "Did the bottle fall?"
  2. "Or did you drink water?"

If you select "Drank Water" or "Bottle Fall" it will show same message "Resumes when bottle is placed"

But in case of "Drank water" the timer resets and starts from the original interval and in case of "bottle fell" the countdown resumes from where it paused.

Wiring Connections

wblmk.png

Here's how to connect each component to the Arduino UNO R4 Wi-Fi:

IR Sensor To Arduino Board

IR Sensor Pins → Arduino Board

GND → GND

VCC → 5v

OUT → D5

0.96" Inch Display To Arduino Board

OLED Display Pin → Arduino Board

GND → GND

VCC → 5v

SDA → SDA

SCL → SCL

Rotary Encoder To Arduino Board

Rotary Encoder Pin → Arduino Board

CLK → D2

DT → D3

SW → D4

GND → GND

VCC → 5v

Buzzer Pin To Arduino Board

Buzzer Pin → Arduino Board

Positive Pin → D6

Negative Pin → GND

These simple connections are enough to give life to your hydration reminder.

Upload the Code

//included the neccessary libraries like Wir.h Adafruit GFX.h AdafruitSSD1306
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//Defined the size of the oled display
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Defined Pins
#define CLK 2
#define DT 3
#define SW 4
#define IR_SENSOR 5
#define BUZZER 6

int setTime = 1;
int lastEncoderState;
bool bottlePresent = false;
bool timerRunning = false;
bool inQuestion = false;
bool sessionCompleted = false;
bool waitingAfterDrink = false;

unsigned long timerStart = 0;
unsigned long timerDuration = 0;
unsigned long timeRemaining = 0;

int menuOption = 0;

// --- Paste your 128x64 bitmap below ---
const unsigned char myBitmap [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xfe, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xfe, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xfc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xf8, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xe1, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x83, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

void setup() {
Serial.begin(9600);

pinMode(CLK, INPUT);
pinMode(DT, INPUT);
pinMode(SW, INPUT_PULLUP);
pinMode(IR_SENSOR, INPUT);
pinMode(BUZZER, OUTPUT);
digitalWrite(BUZZER, LOW);

lastEncoderState = digitalRead(CLK);

if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("OLED init failed"));
while (1);
}

display.clearDisplay();
display.drawBitmap(0, 0, myBitmap, 128, 64, SSD1306_WHITE);
display.display();
delay(2000);

displayMultiLine("Please", "place your", "water", "bottle");
}

void loop() {
int irStatus = digitalRead(IR_SENSOR);

if (inQuestion) {
handleQuestionMenu();
return;
}

if (irStatus == LOW) { // Bottle placed
if (!bottlePresent) {
bottlePresent = true;
beep(); // ✅ Beep on bottle placed
Serial.println("[INFO] Bottle placed.");

if (!timerRunning && timeRemaining > 0) {
Serial.println("[INFO] Resuming paused timer...");
timerStart = millis();
timerDuration = timeRemaining;
timerRunning = true;
timeRemaining = 0;
} else if (!timerRunning && timeRemaining == 0) {
if (waitingAfterDrink) {
Serial.println("[INFO] Restarting timer after drinking...");
timerDuration = setTime * 60 * 1000UL;
timerStart = millis();
timerRunning = true;
waitingAfterDrink = false;
sessionCompleted = false;
} else if (!sessionCompleted) {
displayTimer(setTime);
}
}
}

if (!timerRunning) {
handleEncoder();

if (digitalRead(SW) == LOW) {
timerDuration = setTime * 60 * 1000UL;
timerStart = millis();
timerRunning = true;
sessionCompleted = false;
Serial.print("[INFO] Timer started: ");
Serial.print(setTime);
Serial.println(" minutes");
delay(500);
}

} else {
unsigned long elapsed = millis() - timerStart;

if (elapsed >= timerDuration) {
Serial.println("[INFO] Drinking Time!");

for (int i = 0; i < 3; i++) {
beep();
delay(200);
}

displayMessage("Drinking\nTime ", 2);

while (digitalRead(IR_SENSOR) == LOW) {
delay(100);
}

timerRunning = false;
sessionCompleted = true;
waitingAfterDrink = true;
displayMultiLine("Please", "place your", "water", "bottle");
bottlePresent = false;
} else {
unsigned long remaining = (timerDuration - elapsed) / 1000;
int min = remaining / 60;
int sec = remaining % 60;
char buf[20];
sprintf(buf, "%02d:%02d", min, sec);
displayMessage(String("Next sip in:\n") + buf, 2);
Serial.print("[INFO] Time left: ");
Serial.println(buf);
delay(1000);
}
}

} else { // Bottle removed
if (bottlePresent && timerRunning) {
timeRemaining = timerDuration - (millis() - timerStart);
timerRunning = false;
inQuestion = true;
menuOption = 0;
displayQuestionMenu();
Serial.println("[INFO] Bottle removed during timer. Asking reason...");
}

if (!bottlePresent) {
displayMultiLine("Please", "place your", "water", "bottle");
}

bottlePresent = false;
}
}

// ------------------ Question Menu ------------------
void handleQuestionMenu() {
int currentState = digitalRead(CLK);
if (currentState != lastEncoderState) {
if (digitalRead(DT) != currentState) {
menuOption++;
} else {
menuOption--;
}
menuOption = constrain(menuOption, 0, 1);
displayQuestionMenu();
delay(100);
}
lastEncoderState = currentState;

if (digitalRead(SW) == LOW) {
delay(300);
Serial.println(menuOption == 0 ? "[SELECTED] Bottle Fell" : "[SELECTED] Drank Water");
displayMultiLine("Resume", "when", "bottle is", "placed");
waitForBottleReplacement(menuOption == 0);
inQuestion = false;
}
}

void displayQuestionMenu() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Why removed?");
display.setCursor(0, 20);
if (menuOption == 0) display.print("> ");
else display.print(" ");
display.println("Bottle fell");
display.setCursor(0, 35);
if (menuOption == 1) display.print("> ");
else display.print(" ");
display.println("I drank water");
display.display();
}

// ------------------ Helper Functions ------------------
void handleEncoder() {
int currentState = digitalRead(CLK);
if (currentState != lastEncoderState) {
if (digitalRead(DT) != currentState) {
setTime++;
} else {
setTime--;
}
setTime = constrain(setTime, 1, 20);
beep();
displayTimer(setTime);
delay(100);
}
lastEncoderState = currentState;
}

void beep() {
digitalWrite(BUZZER, HIGH);
delay(50);
digitalWrite(BUZZER, LOW);
}

void displayMessage(String msg, int textSize) {
display.clearDisplay();
display.setTextSize(textSize);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(msg);
display.display();
}

void displayTimer(int time) {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Set Time:");
display.setTextSize(3);
display.setCursor(20, 30);
display.print(time);
display.println(" min");
display.display();
}

void displayMultiLine(String l1, String l2, String l3, String l4) {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(l1);
display.println(l2);
display.println(l3);
display.println(l4);
display.display();
}

void waitForBottleRemoval() {
while (digitalRead(IR_SENSOR) == LOW) delay(100);
while (digitalRead(IR_SENSOR) == HIGH) delay(100);
}

void waitForBottleReplacement(bool resumePrevious) {
while (digitalRead(IR_SENSOR) == HIGH) delay(100);

if (resumePrevious) {
timerStart = millis();
timerDuration = timeRemaining;
Serial.print("[INFO] Resuming from: ");
Serial.print(timerDuration / 1000);
Serial.println(" seconds");
} else {
timerStart = millis();
timerDuration = setTime * 60 * 1000UL;
Serial.println("[INFO] Starting new timer.");
}

timerRunning = true;
timeRemaining = 0;
}

void loop(){
digitalWrite(10,HIGH);
dleay(1000);
}

The core functions include:

  1. IR Sensor check for bottle presence
  2. Rotary encoder sets time (1-20 minutes)
  3. OLED displays interval and countdown
  4. Buzzer gives single or repeated alerts
  5. Logic branches based on your response (Did bottle fall ? Or did you drink?)


Video Demonstration

I Built a $1000 Hydration Gadget for Just $10! #SmartGadget #arduinoprojects #iotdevice

Want to see it working in real life? Here's a complete video demo showing very interaction. In just 5 minutes, you'll understand everything about how the project works

A small request to all of you: if you find this project helpful or inspiring, please subscribe to my YouTube channel and share the video. That would be a huge support from your side and will help me keep building and sharing more!