Slimme Arduino-waterfles – realtime monitoring & herinneringen
Onderdelen en benodigdheden
- SparkFun Arduino Pro Mini 328 – 5 V/16 MHz (1×)
- Waterdichte ultrasone sensor (1×)
- Real Time Clock (RTC) module (1×)
- Common-cathode 4-digit 7-segment display (1×)
- Buzzer (1×)
- Drukknop 12 mm (1×)
- Algemene NPN-transistor (1×)
- Li-Ion accu 1000 mAh (1×)
- Adafruit USB Li-Ion acculader (1×)
- Weerstanden: 221 Ω (8×), 1 kΩ (4×), 4,75 kΩ (2×)
Benodigde tools en machines
- Solderbout
- Lijmpistool
Apps en online diensten
- Arduino IDE
Over dit project
Inleiding
Voldoende water drinken is cruciaal voor gezondheid: betere huid, meer energie, verbeterde hersenfunctie, gewichtsverlies. In drukke dagen vergeet men er vaak aan – ongeveer 75% van Amerikanen is chronisch gedehydrateerd. Om een gezonde drinkgewoonte op te bouwen, maakte ik mijn waterfles slim met Arduino. De fles kan:
- Dagelijkse waterinname bijhouden.
- Wekelijkse gemiddelde inname berekenen.
- Herinneringen geven om te drinken.
- Laatste inname-tijd registreren.
- Meer dan een maand draaien op één oplading.
RTC-module maken
Voor tijdregistratie gebruik ik een DS1307 RTC met backup-batterij. De module is compact, gebruikt I²C (SCL/SDA) en vereist een 32,768 kHz kristal + twee pull-up weerstanden (2–10 kΩ, ik gebruikte 4,7 kΩ). VBAT-pin wordt gegrond als geen knoopcel gebruikt wordt. Alternatief: DS3231 (interne kristal) of kant-en-klaar RTC-module.

Belangrijke pinnen DS1307:
- 5 V – hoog = data uitsturen, laag = op backup-cel.
- GND – gemeenschappelijke ground.
- SCL – I²C klok (Arduino A5).
- SDA – I²C data (Arduino A4).
- VBAT – backup-batterij (3 V), ground als niet gebruikt.
7-segment displaybord maken
Compacte common-cathode module met vier 7-segment LED's. Multiplexing vermindert benodigde pinnen van 32 naar 11/12. Stroombegrenzende weerstanden (220 Ω voor Li-ion) en driver-transistors (2N2222) zijn nodig omdat een microcontroller-pin max ~40 mA kan leveren (bij cijfer 8 zijn alle 7 segmenten aan).

Segmenten a–g & dp → Arduino D10–D17. Cijfers D0–D3 → Arduino D6–D9 (via transistor-collectors). Drukknop op D2 (INT0) voor menu-navigatie en wake-up uit sleep.
Displaybord met Arduino Mini Pro verbinden
Soldeer segmentpinnen aan Arduino, gemeenschappelijke kathodes aan transistor-collectors, basisweerstanden 1 kΩ, segmentweerstanden 220 Ω. Drukknop aan D2 (INT0).

RTC-module en buzzer aansluiten
- RTC SDA → Arduino A4
- RTC SCL → Arduino A5
- Buzzer → Arduino D3

Ultrasone sensor aan flesdop bevestigen
Gat boren in dop, sensor middig aan de binnenkant monteren, vier draden door het gat halen.

Aansluitingen: VCC→VCC, GND→GND, Trigger→D4, Echo→D5.
Programma uploaden & testen
Benodigde bibliotheken: OneButton (knop), LowPower (sleep), DS1307RTC (tijd). Arduino meet 3× per minuut, gemiddelde berekenen, toont info 10 s, gaat dan 1 min in slaap. Knop (INT0) wekt direct op.

Algoritme (kort): Gemiddelde van 5 metingen → waterhoogte → volume in ounces. Dagelijks totaal reset om middernacht. Wekelijks gemiddelde = gemiddelde van afgelopen 7 dagen. Als 2 uur geen inname → dubbele beep elke 15 min tot drinken gedetecteerd.
Arduino aan flesdop vastmaken
Hecht Arduino Mini met lijmpistool aan de bovenzijde van de dop. Zorg dat alle componenten passen.

Accu en laadmodule bevestigen
Plaats Li-ion accu bovenop Arduino (let op geen kortsluiting). Monteer laadmodule met USB-poort naar buiten toe voor gemakkelijke toegang.

Alles waterdicht maken
Dek alle buitenlandse schakelingselementen (behalve USB-poort) met voldoende lijm. Vorm de dop netjes af. Niet de dop in water dompelen!

Genieten!

Code
Arduino Sketch
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include "LowPower.h"
#include "OneButton.h"
OneButton button(2, true);
const byte interruptPin = 2;
volatile int state = 0;
const int trigPin = 4;
const int echoPin = 5;
int piezoPin = 3;
const int digit[4] = {9,6,7,8};
int digit_value[4], digit_value1[4];
int button_press_count = 1;
const int segment[8] = {16,10,12,14,15,17,11,13};
const byte number[10][8] = {
{1,1,1,1,1,1,0,0}, //0
{0,1,1,0,0,0,0,0}, //1
{1,1,0,1,1,0,1,0}, //2
{1,1,1,1,0,0,1,0}, //3
{0,1,1,0,0,1,1,0}, //4
{1,0,1,1,0,1,1,0}, //5
{1,0,1,1,1,1,1,0}, //6
{1,1,1,0,0,0,0,0}, //7
{1,1,1,1,1,1,1,0}, //8
{1,1,1,1,0,1,1,0} //9
};
const byte d[8] = {0,1,1,1,1,0,1,1};
const byte a[8] = {1,1,1,0,1,1,1,1};
const byte r[8] = {0,0,0,0,1,0,1,1};
const byte t[8] = {0,0,0,1,1,1,1,1};
int seconds, minutes, hours;
int water_in_ounch[15], water_intake_ounch[15], water_intake_days[7];
int water_intake_times = 0, previous_water_amount = 0;
int total_water_intake_today = 0, average_intake_last_week = 0;
int intake_day = 1;
float average_water_level = 0;
int water_amount_in_ounce = 0, idle_time = 0, previous_value = 0;
void setup() {
Serial.begin(9600);
pinMode(interruptPin, INPUT_PULLUP);
for (int i=6; i<=17; i++) pinMode(i, OUTPUT);
pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT);
button.attachClick(pressed);
button.attachDoubleClick(doubleclick);
button.attachLongPressStart(longPressStart);
button.attachDuringLongPress(longPress);
}
long previous_state = millis();
int count = 1, daily_intake = 0, weekly_intake = 0;
long sleep_time = millis();
void loop() {
read_time(); button.tick(); calculation();
daily_intake = total_water_intake_in_day();
weekly_intake = average_water_intake_last_week();
if (button_press_count == 1) { display_d(); display_number(daily_intake); }
else if (button_press_count == 2) { display_a(); display_number(weekly_intake); }
else if (button_press_count == 3) { display_r(); display_number(water_amount_in_ounce); }
else if (button_press_count == 4) { display_first_2(hours); display_last_2(minutes); }
if (idle_time >= 120) { alert(); alert(); }
if ((millis() - sleep_time) >= 15000) {
display_off();
attachInterrupt(digitalPinToInterrupt(interruptPin), blank, FALLING);
for (int i=0; i<6; i++) LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
detachInterrupt(digitalPinToInterrupt(interruptPin));
sleep_time = millis();
}
}
// ... (hulp-functies: display_digit, display_number, display_first_2, display_last_2,
// display_d, display_a, display_r, display_t, display_off, read_time,
// distance_in_cm, microsecondsToCentimeters, alert, blank, pressed,
// doubleclick, longPressStart, longPress, calculation,
// total_water_intake_in_day, average_water_intake_last_week) ...
Schema's


Productieproces
- Hoe Grasperspirators Werken: Ontwerp, Geschiedenis en Moderne Productie
- Vaatwastechnologie: geschiedenis, ontwerp en toekomstige innovaties
- De Evolutie van Pompactie Waterpistolen: Van Uitvinding tot Mondiale Marktleider
- De Evolutie, Materialen en Fabricage van Moderne Toilets
- Brandkranen: Ontwerp, Productie en Rol in Stedelijke Brandveiligheid
- De Evolutie en Wetenschap Achter Moderne Geïsoleerde Flessen
- Water: Geschiedenis, Typen en Moderne Behandelingsprocessen
- De Wetenschap Achter Shampoo: Ingrediënten, Productie en Toekomsttrends
- Gipsplaten: Geschiedenis, Materialen en Moderne Productie
- Geïntegreerde Schakelingen (IC's): Compacte, Krachtige Chips die Moderne Elektronica Aandrijven
- MOSMusic Project Kit: MOSFET, Arduino en meer