Drink Safety System - HackViolet 2026
A cross-platform IoT solution to protect drinks from tampering. When the system detects unauthorized access to a protected drink, it immediately alerts the user and their emergency contacts via push notifications and SMS.
SipSafe consists of three components that work together:
- ESP32 Device - Hardware that detects when a drink container lid is removed
- Mobile Apps - iOS and Android apps for device control and alerts
- Supabase Backend - Database, authentication, and notification delivery
See Alternatives to see the thought process/design choices/things we tried.
┌─────────────────┐ BLE ┌─────────────────┐
│ ESP32 Device │◄────────────►│ Mobile App │
│ (Capacitive │ │ (iOS/Android) │
│ Touch + BLE) │ └────────┬────────┘
└─────────────────┘ │
│ HTTPS
▼
┌───────────────────────┐
│ Supabase Backend │
├───────────────────────┤
│ • PostgreSQL Database │
│ • Auth (Email/Apple) │
│ • Edge Functions │
│ - Push Notifications│
│ - SMS via Vonage │
└───────────────────────┘
- Setup: User pairs ESP32 device with mobile app via Bluetooth
- Protection: User places drink under device and taps "Arm" in app
- Detection: ESP32 monitors capacitive touch sensor for lid removal
- Alert: If lid removed while armed:
- ESP32 sounds buzzer alarm
- BLE notification sent to app
- App logs incident to Supabase
- Edge function sends iOS push notification
- Edge function sends SMS to emergency contacts
- Review: User can view alert history and drink tracking in app
SipSafe/
├── SipSafe/ # iOS App (SwiftUI)
│ ├── SipSafeApp.swift # App entry point
│ ├── MainTabView.swift # Tab navigation
│ ├── SupabaseClient.swift # Supabase singleton
│ ├── Env.swift # Environment config
│ ├── AppDelegate.swift # Push notification handling
│ ├── auth/ # Authentication views
│ ├── bluetooth/ # BLE manager
│ ├── device/ # Device pairing UI
│ ├── home/ # Emergency contacts
│ ├── friends/ # Friend management
│ ├── drinks/ # Drink tracking
│ ├── notifications/ # Alert history
│ ├── account/ # User settings
│ └── location/ # GPS for alerts
│
├── app/ # Android App (Kotlin/Compose)
│ └── src/main/java/com/sipsafe/app/
│ ├── MainActivity.kt # App entry point
│ ├── MainTabView.kt # Tab navigation
│ ├── SipSafeApp.kt # Application class
│ ├── SupabaseClient.kt # Supabase singleton
│ ├── auth/ # Authentication
│ ├── bluetooth/ # BLE manager
│ ├── device/ # Device pairing UI
│ ├── home/ # Home screen
│ └── account/ # User settings
│
└── Esp32Files/ # ESP32 Firmware
└── drinkguard/
└── drinkguard.ino # Main firmware
- Xcode 15+ (iOS)
- Android Studio Hedgehog+ (Android)
- Arduino IDE with ESP32 board support
- Supabase project with Edge Functions enabled
-
Open
SipSafe/SipSafe.xcodeprojin Xcode -
Configure Supabase credentials in scheme environment variables:
- Product > Scheme > Edit Scheme > Run > Arguments > Environment Variables
- Add
SUPABASE_URL= your Supabase project URL - Add
SUPABASE_KEY= your Supabase anon key
-
Configure push notifications:
- Enable Push Notifications capability
- Create APNs key in Apple Developer portal
- Upload key to Supabase project settings
-
Build and run on device (BLE requires physical device)
-
Copy
local.properties.exampletolocal.properties -
Add Supabase credentials:
SUPABASE_URL=https://your-project.supabase.co SUPABASE_KEY=your-anon-key
-
Open project in Android Studio
-
Build and run:
./gradlew installDebug
-
Install Arduino IDE with ESP32 board support
-
Open
Esp32Files/drinkguard/drinkguard.ino -
Wire hardware:
- GPIO 4: Capacitive touch sensor (aluminum foil)
- GPIO 5: Buzzer
- GPIO 15: Physical button (INPUT_PULLUP)
-
Upload to ESP32 DevKit board
-
Device will advertise as "SipSafe" via BLE
Detailed Documentation:
- Hardware Guide - Wiring diagram, components, calibration
- Product Assembly - Physical build (scrunchie + foil cover)
- Wiring Diagram (SVG) - Visual wiring reference
- Product Design (SVG) - Product visualization
The ESP32 exposes a BLE GATT service with three characteristics:
| Characteristic | UUID | Properties | Description |
|---|---|---|---|
| Service | 12345678-1234-5678-1234-56789abcdef0 |
- | SipSafe service |
| Armed | 12345678-1234-5678-1234-56789abcdef1 |
R/W/N | Arm state (0x00/0x01) |
| Lid | 12345678-1234-5678-1234-56789abcdef2 |
R/N | Lid state (0x01=on, 0x00=off) |
| Status | 12345678-1234-5678-1234-56789abcdef3 |
R/N | Combined bitmask |
Status byte format:
- Bit 0: Armed (1=armed)
- Bit 1: Lid on (1=lid present)
Alert condition: Armed=1 AND Lid=0 (lid removed while armed)
-- User profiles (linked to Supabase Auth)
users
├── userId (uuid, PK) -- Same as auth.users.id
├── auth_userId (uuid) -- Foreign key to auth.users
├── email (text)
├── first_name (text)
├── last_name (text)
├── device_token (text) -- APNs/FCM token for push
└── platform (text) -- 'ios' or 'android'
-- Emergency contacts for SMS alerts
emergency_contacts
├── id (serial, PK)
├── user (uuid, FK) -- Owner's userId
└── contact_number (text) -- Phone number
-- Incident log (all state changes)
incident_table
├── incident_id (uuid, PK)
├── userId (uuid, FK)
├── armed (boolean)
├── covered (boolean)
├── battery (text) -- Device battery level
├── latitude (text) -- GPS if available
├── longitude (text)
└── created_at (timestamptz)
-- Friend relationships for alert sharing
friends_table
├── friend_id (uuid, PK)
├── friender_id (uuid, FK) -- User who added friend
├── friendee_id (uuid, FK) -- User being added
└── created_at (timestamptz)
-- Notification log
notification_table
├── notification_id (uuid, PK)
├── incident_id (uuid, FK)
├── victim_id (uuid, FK)
├── sent_id (uuid, FK)
└── created_at (timestamptz)Triggered by database webhook on incident_table INSERT when armed=true AND covered=false.
Actions:
- Fetches user details and device token
- Sends APNs push notification to user
- Invokes Twillio-Test for SMS to emergency contacts
- Logs notification to notification_table
- Notifies user's friends
Sends SMS alerts via Vonage API.
Request body:
{
"number": "XXXXXXXXXXX",
"userName": "John Doe"
}Triggered on auth.users INSERT. Creates corresponding record in public users table.
SUPABASE_URL
SUPABASE_SERVICE_ROLE_KEY
APNS_KEY_B64 # Base64 .p8 key
APNS_KEY_ID # Apple key ID
APNS_TEAM_ID # Apple team ID
APNS_TOPIC # Bundle ID
VONAGE_API_KEY
VONAGE_API_SECRET
VONAGE_FROM_NUMBER
Inside of the repo you will need to update the corresponding keys to match your own supabase instance.
- BLE device pairing and control (iOS/Android)
- Email/password authentication
- Apple Sign In (iOS)
- Emergency contacts management (iOS)
- Push notifications (iOS)
- SMS alerts via Vonage
- Friend alert sharing
- Drink tracking
- Alert history
- Offline event queue (ESP32)
- Auto-reconnection
- Android push notifications
- Location sharing in alerts
- Multiple device support
- Drink type categorization
- ultrasonic addition to determne fluid level
- BAC estimator with drink level/quantity of drinks
- multiple levels of capacitive touch
- can/drink guesser based off diameter (can/glass/etc.)
- iOS: SwiftUI with MVVM pattern
- Android: Jetpack Compose with MVI pattern
- ESP32: Arduino with state machine
- Singleton BLE managers - Ensures single connection across app
- StateFlow/Published - Reactive UI updates
- Offline queue - ESP32 stores alerts when disconnected
- Edge functions - Server-side notification logic
Go to: (Devpost)[https://devpost.com/software/sipsafe?ref_content=user-portfolio&ref_feature=in_progress]
Or see Devpost.md
GPL-2 License. See the License tab.