Welcome to the SebaKit developer guide. This document serves as a comprehensive onboarding reference detailing the technical architecture, data model, realtime event flow, and firmware states of the Supabase & ESP32-C3 upgraded system.
| Layer | Technology | Key Libraries & SDKs |
|---|---|---|
| Microcontroller Hardware | ESP32-C3 (Super Mini) | Arduino IDE Framework, Adafruit BME280, Adafruit SSD1306, WiFiManager, ArduinoJson, NTPClient |
| Database & Backend | Supabase (Managed PostgreSQL) | PostgreSQL 15, PostgREST (Auto-REST API), Supabase Realtime Engine, PL/pgSQL functions |
| Caregiver Dashboard | React 19, TypeScript 6, Vite 8 | @supabase/supabase-js, zustand (State Management), react-router-dom (Routing), tailwindcss (Styling) |
| Communication / Alerts | Twilio Messages API (WhatsApp) | Direct HTTPS REST requests via ESP32 WiFiClientSecure |
The backend runs entirely on Supabase. The database structure is defined in two schema files under supabase-sql/.
- Custom Types:
medicine_statusENUM:'pending','taken','missed'event_typeENUM:'created','taken','missed','skipped'
medications: The master catalog of scheduled items.id(UUID, PK),device_id(TEXT),name(TEXT),dose(TEXT),notes(TEXT),created_at/updated_at.
schedules: Recurring rule definitions for medication doses.id(UUID, PK),medication_id(UUID, FK),device_id(TEXT),time_of_day(TIME),days_of_week(TEXT, e.g.,'1,2,3,4,5,6,7'),start_date(DATE),end_date(DATE),active(BOOLEAN).
medicines: Daily concrete instances generated fromschedules. The ESP32 device queries this table to know when to sound alarms.id(UUID, PK),medication_id(UUID, FK),schedule_id(UUID, FK),device_id(TEXT),name(TEXT),dose(TEXT),time(TIME),date(DATE),status(medicine_status),taken_at(TIMESTAMPTZ).
device_settings: Global configuration parameters for the pill-box device.id(UUID, PK),device_id(TEXT, Unique),patient_name(TEXT),patient_type(TEXT),alert_duration_min(INTEGER),timezone(TEXT),guardian_phone(TEXT),twilio_call_enabled(BOOLEAN).
room_monitoring: Live sensor telemetry logs uploaded by the device.id(UUID, PK),device_id(TEXT),temperature(REAL),humidity(REAL),created_at(TIMESTAMPTZ).- Note: The columns
eco2andtvocexist in the legacy database schema but are no longer active, as the CCS811 sensor has been deprecated.
events_log: Audit trail of statuses for history reports.id(UUID, PK),medicine_id(UUID, FK),device_id(TEXT),event_type(event_type),details(JSONB),created_at(TIMESTAMPTZ).
- Auto-Log Status Changes: The trigger
on_medicine_status_changeruns the functionlog_medicine_status_change()before any update onmedicines. It logs transition audits intoevents_logand setstaken_atautomatically if status becomes'taken'. - Generate Daily Medicine Instances:
generate_daily_medicines(target_date DATE, target_device TEXT)generates allmedicinesrows for a particular date by matching activeschedulesand theirdays_of_weekarray. It is triggered automatically when creating a new schedule or loading the web app. - Telemetry Cleanup:
cleanup_old_room_data()deletes entries inroom_monitoringolder than 24 hours to keep the database size optimized.
The frontend is located under frontend-supabase/ and communicates directly with your Supabase database.
frontend-supabase/src/store/useStore.ts holds all state:
interface AppState {
medications: Medication[];
schedules: Schedule[];
todayMedicines: Medicine[];
deviceSettings: DeviceSettings | null;
roomData: RoomMonitoring | null; // Live sensor telemetry (Temperature & Humidity only)
loading: boolean;
// actions...
}frontend-supabase/src/hooks/useSupabaseRealtime.ts runs on app load. It sets up two primary event listeners:
medicinesupdates: Re-fetches today's medicines if the device marks a dose astakenormissed.room_monitoringinserts: Automatically pushes new ambient sensor records into the store state, triggering immediate UI state updates inside the<RoomMonitor />card on the dashboard.
/(Dashboard): Main landing page. Features general patient stats, a 2x2 grid live Room Monitor telemetry card (displaying current temperature & humidity), and today's schedule checklist./schedule(Schedule): Form to create new medications and manage schedules. Creating schedules automatically triggers today's medicine generation./history(History): Displays historical logs fromevents_log./settings(Settings): Configures timezone, patient details, alarm duration, guardian phone numbers, and Twilio WhatsApp alerts.
The firmware (esp32_c3/sebakit_firmware.ino) uses an event-driven, cooperative non-blocking loop built around a state machine:
┌───────────────┐
│ WIFI_SETUP │ ◄─── Captive Portal Active
└───────┬───────┘
│ Connected
▼
┌───────────────┐
│ IDLE │ ◄─── Polls settings & medicines
└───────┬───────┘ Updates sensors & POSTs data
│
Time Matches │ Dose Opened
Pending Dose │ Within Window
▼
┌───────────────┐
│ ALERT ├──────────────┐
└───────┬───────┘ │
│ │ Open Duration
Box Opened │ │ Timeout Expired
(Ingested) ▼ ▼
┌───────────────┐ ┌───────────────┐
│ TAKEN │ │ MISSED │
└───────┬───────┘ └───────┬───────┘
│ │
│ Returns to Idle │ Twilio WhatsApp Message
▼ After 1.5 Seconds │ HTTPS POST Triggered
┌───────────────┐ ▼
│ IDLE │ ┌───────────────┐
└───────────────┘ │ IDLE │
└───────────────┘
STATE_WIFI_SETUP: Initiated if no WiFi credentials exist or auto-connection fails. Starts the captive portal SSID:SebaKit_Setup(Pass:12345678).STATE_IDLE: The baseline operating state. Every 30 seconds, it reads the BME280 sensor, logs values to the SSD1306 OLED, and POSTs them to the Supabase REST API. It also polls scheduled medicines.STATE_ALERT: Triggered when the current device time matches a pending medication's time. Buzzes the hardware and flashes the LED.STATE_TAKEN: Triggered if the metal switch is opened during an alert. Sounds success tones and updates status totakenon Supabase.STATE_MISSED: Triggered if the alert duration (e.g. 3 minutes) expires without the patient opening the box. Updates the dose status tomissedand initiates the Twilio WhatsApp alert.STATE_OFFLINE: Safe fallback if Wi-Fi drops.
When a missed dose event is determined:
- The device checks if
twilio_call_enabledis true andguardian_phonehas a valid number. - It generates a WhatsApp message body:
"🚨 *SebaKit Alert*\n\nThe patient has *missed* their *[Medicine Name]* dose scheduled at *[Time]*.\n\nPlease check on them immediately." - It performs a secure HTTPS POST to the Twilio Messages API Endpoint
/Accounts/[Account_SID]/Messages.jsonwith the parametersTo,From, andBody. - Authentication uses HTTP Basic Auth header (
Authorization: Basic BASE64(SID:TOKEN)).
If the device status update fails (e.g., local Wi-Fi drops), the firmware saves the pending update (e.g., id:taken or id:missed) to the ESP32's non-volatile flash storage using the Preferences library. On the next successful loop connection, retryPendingUpdates() reads this queue and PATCHes the records to Supabase.
Before pushing any codebase changes, verify both type-correctness and build results.
# 1. Type-check frontend project
cd frontend-supabase
npx tsc --noEmit
# 2. Build production assets
npm run build- BME280 reads temperature & humidity on the shared I2C bus.
- Read values and modify
readAndPostSensors()to append parameters to the JSON payload. - Modify the layout inside
frontend-supabase/src/components/RoomMonitor.tsxto customize display cards.
- All policies are defined in
supabase-sql/001_complete_setup.sqland002_room_monitoring_and_twilio.sql. - If adding user authentication later, replace the
"Allow anon full access"policies with authenticated checks:CREATE POLICY "Allow authenticated read" ON medications FOR SELECT TO authenticated USING (true);