Hack Your Productivity with This Next-Level Arduino Hydration Device!
This Arduino-powered device keeps you perfectly hydrated by reminding you at the right time-so your energy focus, and health never take a hit.
Components and supplies
1
Arduino UNO R4 WiFi LED Matrix
1
0.96 OLED display
1
rotary encoder
1
IR Obstacle Sensor
1
10 jumper wires 150mm male
Apps and platforms
1
Arduino IDE 2.0 (beta)
Project description
Code
Code
c
1//included the neccessary libraries like Wir.h Adafruit GFX.h AdafruitSSD1306 2#include <Wire.h> 3#include <Adafruit_GFX.h> 4#include <Adafruit_SSD1306.h> 5//Defined the size of the oled display 6#define SCREEN_WIDTH 128 7#define SCREEN_HEIGHT 64 8#define OLED_RESET -1 9Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); 10 11// Defined Pins 12#define CLK 2 13#define DT 3 14#define SW 4 15#define IR_SENSOR 5 16#define BUZZER 6 17 18int setTime = 1; 19int lastEncoderState; 20bool bottlePresent = false; 21bool timerRunning = false; 22bool inQuestion = false; 23bool sessionCompleted = false; 24bool waitingAfterDrink = false; 25 26unsigned long timerStart = 0; 27unsigned long timerDuration = 0; 28unsigned long timeRemaining = 0; 29 30int menuOption = 0; 31 32// --- Paste your 128x64 bitmap below --- 33const unsigned char myBitmap [] PROGMEM = { 34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 70 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 71 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 75 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 76 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 78 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 79 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xfe, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xfe, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xfc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xf8, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xe1, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x83, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 98}; 99 100void setup() { 101 Serial.begin(9600); 102 103 pinMode(CLK, INPUT); 104 pinMode(DT, INPUT); 105 pinMode(SW, INPUT_PULLUP); 106 pinMode(IR_SENSOR, INPUT); 107 pinMode(BUZZER, OUTPUT); 108 digitalWrite(BUZZER, LOW); 109 110 lastEncoderState = digitalRead(CLK); 111 112 if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 113 Serial.println(F("OLED init failed")); 114 while (1); 115 } 116 117 display.clearDisplay(); 118 display.drawBitmap(0, 0, myBitmap, 128, 64, SSD1306_WHITE); 119 display.display(); 120 delay(2000); 121 122 displayMultiLine("Please", "place your", "water", "bottle"); 123} 124 125void loop() { 126 int irStatus = digitalRead(IR_SENSOR); 127 128 if (inQuestion) { 129 handleQuestionMenu(); 130 return; 131 } 132 133 if (irStatus == LOW) { // Bottle placed 134 if (!bottlePresent) { 135 bottlePresent = true; 136 beep(); // ✅ Beep on bottle placed 137 Serial.println("[INFO] Bottle placed."); 138 139 if (!timerRunning && timeRemaining > 0) { 140 Serial.println("[INFO] Resuming paused timer..."); 141 timerStart = millis(); 142 timerDuration = timeRemaining; 143 timerRunning = true; 144 timeRemaining = 0; 145 } else if (!timerRunning && timeRemaining == 0) { 146 if (waitingAfterDrink) { 147 Serial.println("[INFO] Restarting timer after drinking..."); 148 timerDuration = setTime * 60 * 1000UL; 149 timerStart = millis(); 150 timerRunning = true; 151 waitingAfterDrink = false; 152 sessionCompleted = false; 153 } else if (!sessionCompleted) { 154 displayTimer(setTime); 155 } 156 } 157 } 158 159 if (!timerRunning) { 160 handleEncoder(); 161 162 if (digitalRead(SW) == LOW) { 163 timerDuration = setTime * 60 * 1000UL; 164 timerStart = millis(); 165 timerRunning = true; 166 sessionCompleted = false; 167 Serial.print("[INFO] Timer started: "); 168 Serial.print(setTime); 169 Serial.println(" minutes"); 170 delay(500); 171 } 172 173 } else { 174 unsigned long elapsed = millis() - timerStart; 175 176 if (elapsed >= timerDuration) { 177 Serial.println("[INFO] Drinking Time!"); 178 179 for (int i = 0; i < 3; i++) { 180 beep(); 181 delay(200); 182 } 183 184 displayMessage("Drinking\nTime ", 2); 185 186 while (digitalRead(IR_SENSOR) == LOW) { 187 delay(100); 188 } 189 190 timerRunning = false; 191 sessionCompleted = true; 192 waitingAfterDrink = true; 193 displayMultiLine("Please", "place your", "water", "bottle"); 194 bottlePresent = false; 195 } else { 196 unsigned long remaining = (timerDuration - elapsed) / 1000; 197 int min = remaining / 60; 198 int sec = remaining % 60; 199 char buf[20]; 200 sprintf(buf, "%02d:%02d", min, sec); 201 displayMessage(String("Next sip in:\n") + buf, 2); 202 Serial.print("[INFO] Time left: "); 203 Serial.println(buf); 204 delay(1000); 205 } 206 } 207 208 } else { // Bottle removed 209 if (bottlePresent && timerRunning) { 210 timeRemaining = timerDuration - (millis() - timerStart); 211 timerRunning = false; 212 inQuestion = true; 213 menuOption = 0; 214 displayQuestionMenu(); 215 Serial.println("[INFO] Bottle removed during timer. Asking reason..."); 216 } 217 218 if (!bottlePresent) { 219 displayMultiLine("Please", "place your", "water", "bottle"); 220 } 221 222 bottlePresent = false; 223 } 224} 225 226// ------------------ Question Menu ------------------ 227void handleQuestionMenu() { 228 int currentState = digitalRead(CLK); 229 if (currentState != lastEncoderState) { 230 if (digitalRead(DT) != currentState) { 231 menuOption++; 232 } else { 233 menuOption--; 234 } 235 menuOption = constrain(menuOption, 0, 1); 236 displayQuestionMenu(); 237 delay(100); 238 } 239 lastEncoderState = currentState; 240 241 if (digitalRead(SW) == LOW) { 242 delay(300); 243 Serial.println(menuOption == 0 ? "[SELECTED] Bottle Fell" : "[SELECTED] Drank Water"); 244 displayMultiLine("Resume", "when", "bottle is", "placed"); 245 waitForBottleReplacement(menuOption == 0); 246 inQuestion = false; 247 } 248} 249 250void displayQuestionMenu() { 251 display.clearDisplay(); 252 display.setTextSize(1); 253 display.setTextColor(SSD1306_WHITE); 254 display.setCursor(0, 0); 255 display.println("Why removed?"); 256 display.setCursor(0, 20); 257 if (menuOption == 0) display.print("> "); 258 else display.print(" "); 259 display.println("Bottle fell"); 260 display.setCursor(0, 35); 261 if (menuOption == 1) display.print("> "); 262 else display.print(" "); 263 display.println("I drank water"); 264 display.display(); 265} 266 267// ------------------ Helper Functions ------------------ 268void handleEncoder() { 269 int currentState = digitalRead(CLK); 270 if (currentState != lastEncoderState) { 271 if (digitalRead(DT) != currentState) { 272 setTime++; 273 } else { 274 setTime--; 275 } 276 setTime = constrain(setTime, 1, 20); 277 beep(); 278 displayTimer(setTime); 279 delay(100); 280 } 281 lastEncoderState = currentState; 282} 283 284void beep() { 285 digitalWrite(BUZZER, HIGH); 286 delay(50); 287 digitalWrite(BUZZER, LOW); 288} 289 290void displayMessage(String msg, int textSize) { 291 display.clearDisplay(); 292 display.setTextSize(textSize); 293 display.setTextColor(SSD1306_WHITE); 294 display.setCursor(0, 0); 295 display.println(msg); 296 display.display(); 297} 298 299void displayTimer(int time) { 300 display.clearDisplay(); 301 display.setTextSize(2); 302 display.setTextColor(SSD1306_WHITE); 303 display.setCursor(0, 0); 304 display.println("Set Time:"); 305 display.setTextSize(3); 306 display.setCursor(20, 30); 307 display.print(time); 308 display.println(" min"); 309 display.display(); 310} 311 312void displayMultiLine(String l1, String l2, String l3, String l4) { 313 display.clearDisplay(); 314 display.setTextSize(2); 315 display.setTextColor(SSD1306_WHITE); 316 display.setCursor(0, 0); 317 display.println(l1); 318 display.println(l2); 319 display.println(l3); 320 display.println(l4); 321 display.display(); 322} 323 324void waitForBottleRemoval() { 325 while (digitalRead(IR_SENSOR) == LOW) delay(100); 326 while (digitalRead(IR_SENSOR) == HIGH) delay(100); 327} 328 329void waitForBottleReplacement(bool resumePrevious) { 330 while (digitalRead(IR_SENSOR) == HIGH) delay(100); 331 332 if (resumePrevious) { 333 timerStart = millis(); 334 timerDuration = timeRemaining; 335 Serial.print("[INFO] Resuming from: "); 336 Serial.print(timerDuration / 1000); 337 Serial.println(" seconds"); 338 } else { 339 timerStart = millis(); 340 timerDuration = setTime * 60 * 1000UL; 341 Serial.println("[INFO] Starting new timer."); 342 } 343 344 timerRunning = true; 345 timeRemaining = 0; 346} 347 348void loop(){ 349 digitalWrite(10,HIGH); 350 dleay(1000); 351}
Downloadable files
Code and Schematics
https://github.com/RohanBarnwal/Arduino-Projects/tree/master/Water_reminder_copy_20250520103016
Comments
Only logged in users can leave comments