Components and supplies
Arduino UNO R4 WiFi LED Matrix
0.96 OLED display
rotary encoder
IR Obstacle Sensor
10 jumper wires 150mm male
Apps and platforms
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