Skip to main content

Wearable Integration

The bot collects physiological data from wearable devices through two mechanisms: webhooks for real-time data delivery, and a daily sync cron job at 00:00 UTC as a safety net to catch any missed data. All wearable data is stored in the device_data table.

Architecture

The wearable system uses a provider-based architecture with a registry pattern (PROVIDER_REGISTRY in src/wearables/). Each provider handles:

  • OAuth token management -- tokens are encrypted at rest via Fernet (cryptography package)
  • Webhook processing -- receives and parses incoming data from device APIs
  • Data sync -- periodic pull of historical data via daily_sync.py

Supported Providers

Withings

Create an app at developer.withings.com and configure the webhook callback URL to point to your server.

Data types: weight, blood_pressure, temperature, glucose, activity, sleep, ecg, bed_in/bed_out events

Required environment variables:

WITHINGS_CLIENT_ID=your_client_id
WITHINGS_CLIENT_SECRET=your_client_secret

Fitbit

Create an app at dev.fitbit.com and configure the webhook callback URL.

Data types: activity (1-min intraday), heartrate, hrv, spo2, breathing_rate, sleep, weight, temperature, nutrition

Required environment variables:

FITBIT_CLIENT_ID=your_client_id
FITBIT_CLIENT_SECRET=your_client_secret
FITBIT_SUBSCRIPTION_VERIFICATION_CODE=your_verification_code
note

Intraday access (1-minute granularity for activity and heart rate) requires Fitbit premium or explicit API approval. The provider automatically falls back to daily summaries if intraday requests return a 403 error.

Oura

Create an app at cloud.ouraring.com/v2/docs.

Data types: daily_sleep, daily_activity, daily_readiness, daily_spo2, daily_stress, heartrate (5-min intervals), workout, session

Required environment variables:

OURA_CLIENT_ID=your_client_id
OURA_CLIENT_SECRET=your_client_secret

Common Setup

1. Generate an encryption key

All OAuth tokens are encrypted at rest. Generate a Fernet key and add it to your .env:

python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
DEVICE_TOKEN_ENCRYPTION_KEY=your_generated_fernet_key

2. Set the base URL

Webhooks need to reach your API from the public internet. Set BASE_URL to your server's public URL:

BASE_URL=https://your-server.example.com

For local development, start.sh handles this automatically by creating a localtunnel.

Participants link their wearable devices by sending the /devices command in Telegram. This initiates the OAuth flow for the selected provider. Once authorized, the bot begins receiving webhook data and running daily syncs for that participant.

Rules Engine

The rules engine provides event-driven survey triggering based on incoming wearable data. Rules are evaluated after each webhook data save, allowing you to react to physiological events in near real-time.

Example use cases:

  • Send a morning survey when sleep data arrives (indicating the participant has woken up)
  • Trigger an activity survey when step count exceeds a threshold
  • Deliver a stress check-in when heart rate variability drops

Rules are defined in src/rules/models.py and evaluated by src/rules/engine.py. The engine supports cross-provider data type aliases, so a rule targeting "sleep" data will match both Withings sleep events and Oura daily_sleep events.