Search models, users, collections, and posts

DRINKPAD your drink reminder

Print Profile(1)

All
A1
A2L
H2D
H2C
H2S
H2D Pro
P2S
X2D

0.2mm layer, 2 walls, 15% infill
0.2mm layer, 2 walls, 15% infill
Designer
3.3 h
1 plate

Open in Bambu Studio
Boost
146
455
7
8
11
5
Released 

Description

DRINKPAD is a compact smart base designed to help you build better hydration habits throughout the day. Simply place your bottle on the base and AquaWave will track the time since your last drink using intuitive LED feedback.

The device features three simple states:

🟢 Base Mode
Your bottle is on the base and you've had a drink recently. Everything is normal.

🔴 Time's Up
After 20 minutes without drinking, the LED changes to red, providing a gentle visual reminder to take a sip of water.

🔵 Drinking
When the bottle is lifted, the base detects the movement and switches to blue, confirming that you're drinking and automatically resetting the timer.

 

 

REQUIRED COMPONENTS:

  • Arduino nano
  • MX switch 
  • Led strip WS2812b, 5mm x 8cm (ideally)
  • 330 Ohm resistor (or around that)
  • 3mm screws

 

 

ARDUINO CODE:

 

#include <FastLED.h>

// ── Pin ────────────────────────────────────────────────────────────────────
#define LED_PIN     7        //PIN where your led is connected
#define SWITCH_PIN  5    //PIN where your switch is connected
#define NUM_LEDS    14  //number of leds on your strip

// ── Timing ─────────────────────────────────────────────────────────────────
#define REMIND_INTERVAL  20UL * 60 * 1000 //20 minutes reminder
#define BLINK_DURATION   5UL * 1000
#define BLINK_SPEED      300
#define DEBOUNCE_MS      50

// ── LED ────────────────────────────────────────────────────────────────────
CRGB leds[NUM_LEDS];

// ── State ──────────────────────────────────────────────────────────────────
bool  cupDown         = false;
bool  lastSwitchState = HIGH;
bool  filledGreen     = false;
bool  reminding       = false;
bool  blinkOn         = false;

unsigned long cupDownAt   = 0;
unsigned long blinkStart  = 0;
unsigned long lastBlink   = 0;
unsigned long debounceAt  = 0;

// ───────────────────────────────────────────────────────────────────────────
void setup() {
 Serial.begin(9600);
 pinMode(SWITCH_PIN, INPUT_PULLUP);
 FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
 FastLED.setBrightness(80);
 ledsOff();
 Serial.println("Cup holder ready.");
}

// ───────────────────────────────────────────────────────────────────────────
void loop() {
 readSwitch();

 if (cupDown) {

   if (!filledGreen) {
     fillGreen();    // ~1 sec animation
     filledGreen = true;
     reminding   = false;
     cupDownAt   = millis();   // Timer starts AFTER the animation
     return;         // Exit immediately, it will be green on the next cycle
   }

   unsigned long now = millis();

   if (!reminding) {
     setAllColor(CRGB::Green);
     FastLED.show();

     if (now - cupDownAt >= REMIND_INTERVAL) {
       reminding  = true;
       blinkStart = now;
       lastBlink  = now;
       blinkOn    = true;
       Serial.println("Reminder: drink!");
     }

   } else {
     unsigned long blinkElapsed = now - blinkStart;

     if (blinkElapsed < BLINK_DURATION) {
       if (now - lastBlink >= BLINK_SPEED) {
         blinkOn = !blinkOn;
         blinkOn ? setAllColor(CRGB::Red) : ledsOff();
         FastLED.show();
         lastBlink = now;
       }
     } else {
       setAllColor(CRGB::Red);
       FastLED.show();
     }
   }

 } else {
   setAllColor(CRGB::Blue);
   FastLED.show();
 }

 delay(10);
}

// ── Switch reading with debounce ───────────────────────────────────────────
void readSwitch() {
 bool reading = digitalRead(SWITCH_PIN);

 if (reading != lastSwitchState) {
   debounceAt = millis();
 }

 if ((millis() - debounceAt) > DEBOUNCE_MS) {
   bool nowDown = (reading == LOW);

   if (nowDown && !cupDown) {
     cupDown     = true;
     filledGreen = false;
     Serial.println("Cup placed down.");

   } else if (!nowDown && cupDown) {
     cupDown   = false;
     reminding = false;
     Serial.println("Cup lifted.");
   }
 }

 lastSwitchState = reading;
}

// ── Animation: green LED fill-up, LED by LED in 1 sec ──────────────────────
void fillGreen() {
 int delayPerLed = 1000 / NUM_LEDS;

 for (int i = 0; i < NUM_LEDS; i++) {
   leds[i] = CRGB::Green;
   FastLED.show();
   delay(delayPerLed);
 }
}

// ── Helper ─────────────────────────────────────────────────────────────────
void setAllColor(CRGB color) {
 for (int i = 0; i < NUM_LEDS; i++) leds[i] = color;
}

void ledsOff() {
 FastLED.clear();
 FastLED.show();
}

 


Documentation (2)

Assembly Guide (1)
Screenshot 2026-06-03 182259.png
Other Files (1)
DRINKPAD_code.txt

Comment & Rating (7)

(0/1000)