DRINKPAD your drink reminder
Print Profile(1)

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)











Comment & Rating (7)