Skip to content

K-deladem/WearableSensor

Repository files navigation

WearableCollector

Application Android + WearOS pour la collecte multi-capteurs haute frequence depuis un smartphone et une montre connectee, avec streaming temps reel, gestion de scenarios et export Google Drive.

Architecture

WearableSensor/
 ├── app/          # Application telephone (minSdk 23, targetSdk 35)
 ├── wear/         # Application montre WearOS (minSdk 30, targetSdk 34)
 └── shared/       # Module partage (capteurs, communication, modeles)

Les deux appareils communiquent via la Wear Data Layer API (MessageClient + DataClient).

Communication Montre ↔ Telephone

┌─────────────────────────────────────┐      ┌─────────────────────────────────────┐
│           MONTRE (WearOS)           │      │           TELEPHONE (Android)        │
│                                     │      │                                     │
│  ┌───────────────────────────────┐  │      │  ┌───────────────────────────────┐  │
│  │     Capteurs Hardware         │  │      │  │     Capteurs Hardware         │  │
│  │  Accelerometre, Gyroscope,    │  │      │  │  Accelerometre, Gyroscope,    │  │
│  │  Magnetometre, Pression...    │  │      │  │  Lumiere, Proximite...        │  │
│  └──────────┬────────────────────┘  │      │  └──────────┬────────────────────┘  │
│             │                       │      │             │                       │
│  ┌──────────┴────────────────────┐  │      │  ┌──────────┴────────────────────┐  │
│  │     Capteurs Virtuels         │  │      │  │     Capteurs Virtuels         │  │
│  │  Microphone, GPS              │  │      │  │  Microphone, GPS              │  │
│  └──────────┬────────────────────┘  │      │  └──────────┬────────────────────┘  │
│             │                       │      │             │                       │
│  ┌──────────┴────────────────────┐  │      │  ┌──────────┴────────────────────┐  │
│  │     Health Services           │  │      │  │                               │  │
│  │  MeasureClient (HR BPM)       │  │      │  │      SensorDataFlow           │  │
│  └──────────┬────────────────────┘  │      │  │      (SharedFlow)             │  │
│             │                       │      │  └──────────┬────────────────────┘  │
│  ┌──────────┴────────────────────┐  │      │             │                       │
│  │      SensorDataFlow           │  │      │  ┌──────────┴────────────────────┐  │
│  │      (SharedFlow)             │  │      │  │    SensorDataProcess          │  │
│  └──────────┬────────────────────┘  │      │  │    Queue → .gz files          │  │
│             │                       │      │  └──────────┬────────────────────┘  │
│  ┌──────────┴────────────────────┐  │      │             │                       │
│  │    SensorDataProcess          │  │      │  ┌──────────┴────────────────────┐  │
│  │    Queue → .gz files          │  │      │  │  PhoneDataProcessingWorker    │  │
│  └──────────┬────────────────────┘  │      │  │  .gz → phone_*.csv           │  │
│             │                       │      │  └──────────┬────────────────────┘  │
│             ▼                       │      │             │                       │
│  ┌───────────────────────────────┐  │      │             │                       │
│  │  WearDataProcessingWorker     │  │      │             │                       │
│  │  Envoi .gz par .gz            │  │      │             │                       │
│  └──────────┬────────────────────┘  │      │             │                       │
│             │                       │      │             │                       │
└─────────────┼───────────────────────┘      └─────────────┼──────────────────────┘
              │                                            │
              │         Wear Data Layer API                │
              │     (Bluetooth / Wi-Fi / Cloud)            │
              │                                            │
              ▼                                            │
┌─────────────────────────────────────────────────────────────────────────────────┐
│                     HybridCommunicationHelper                                   │
│                                                                                 │
│  ┌─────────────────────────────┐    ┌────────────────────────────────────────┐  │
│  │      MessageClient          │    │           DataClient                   │  │
│  │                             │    │                                        │  │
│  │  • Commandes (start/stop/   │    │  • Fichiers .gz (1 Asset par fichier)  │  │
│  │    pause/resume)            │    │  • ~50-200 KB par transfert            │  │
│  │  • Config capteurs          │    │  • Streaming anti-OOM                  │  │
│  │  • Stream temps reel 10Hz   │    │  • Legacy : chunks 256 KB             │  │
│  │  • Statut du service        │    │                                        │  │
│  │  • Liste des capteurs       │    │                                        │  │
│  └─────────────────────────────┘    └────────────────────────────────────────┘  │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│                     PhoneHandlerUtil (reception)                                │
│                                                                                 │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │  processGzFile()                                                          │  │
│  │  decompress .gz → parse JSON → CustomCSV.appendData(batch, WATCH)         │  │
│  │  → watch_*.csv (pipeline isole)                                           │  │
│  └──────────┬────────────────────────────────────────────────────────────────┘  │
│             │                                                                   │
│             ▼                                                                   │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │  scheduleFinalizeUpload()                                                 │  │
│  │  Timer 5s apres dernier .gz → CustomCSV.finalizeAndUpload(WATCH)          │  │
│  └──────────┬────────────────────────────────────────────────────────────────┘  │
│             │                                                                   │
└─────────────┼───────────────────────────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│                           CustomCSV (pipelines isoles)                          │
│                                                                                 │
│  ┌─────────────────────────────┐    ┌────────────────────────────────────────┐  │
│  │   Pipeline PHONE            │    │   Pipeline WATCH                       │  │
│  │   Lock propre               │    │   Lock propre                          │  │
│  │   phone_P001_session1.csv   │    │   watch_P001_session1.csv              │  │
│  │   data_source = "phone"     │    │   data_source = "watch"                │  │
│  └──────────┬──────────────────┘    └──────────┬─────────────────────────────┘  │
│             │                                   │                               │
│             └─────────────┬─────────────────────┘                               │
│                           │                                                     │
│                     UploadFileWorker                                             │
│                           │                                                     │
└───────────────────────────┼─────────────────────────────────────────────────────┘
                            │
                            ▼
                    ┌───────────────┐
                    │  Google Drive  │
                    │               │
                    │  /WearableSensor_Data/
                    │    ├── participant/
                    │    │   ├── phone_*.csv
                    │    │   └── watch_*.csv
                    │    └── wearable_backup.json
                    └───────────────┘

Flux de donnees :

  COLLECTE                ENVOI                RECEPTION           STOCKAGE
  ────────               ───────              ──────────          ─────────
  Capteurs               .gz files            /sensor_file/       CSV append
     │                      │                     │                  │
     ▼                      ▼                     ▼                  ▼
  SharedFlow ──→ Queue ──→ Worker ──→ DataClient Asset ──→ processGzFile ──→ watch_*.csv
  (tryEmit)    (50K)    (par fichier)  (~200KB)         (decompress+parse)  (session)
                                                                             │
  TELEPHONE (collecte locale)                                                ▼
  ───────────────────────                                               Google Drive
  SharedFlow ──→ Queue ──→ .gz ──→ PhoneDataProcessingWorker ──→ phone_*.csv
  (tryEmit)    (50K)    (flush)   (decompress + appendData)     (session)

  STREAMING TEMPS REEL
  ────────────────────
  onSensorChanged ──→ sendRawMessage ──→ MessageClient ──→ Broadcast ──→ UI Graph
  (watch, 10Hz)       (compact JSON)     (PATH_STREAM)    (FloatArray)   (Compose)

Paths de communication :

  /PATH_STREAM_SENSOR_START    Phone → Watch    Demarre le streaming d'un capteur
  /PATH_STREAM_SENSOR_STOP     Phone → Watch    Arrete le streaming
  /PATH_STREAM_SENSOR_DATA     Watch → Phone    Donnees temps reel (10 Hz)
  /PATH_SEND_WATCH_SENSOR_LIST Watch → Phone    Liste des capteurs de la montre
  /PATH_ASK_WATCH_SENSOR_LIST  Phone → Watch    Demande la liste des capteurs
  /PATH_SEND_WATCH_CONFIG      Phone → Watch    Configuration (settings + sensors)
  /PATH_GET_WATCH_SERVICE_STATUS Watch → Phone   Statut du service de collecte
  /sensor_file/{name}          Watch → Phone    Fichier .gz via DataClient Asset

Fonctionnalites

Collecte de donnees

  • Collecte simultanee de multiples capteurs hardware (accelerometre, gyroscope, magnetometre, pression, lumiere, etc.)
  • Capteurs virtuels : microphone (dB SPL), GPS (lat/lon/alt/precision)
  • Health Services : frequence cardiaque via MeasureClient (WearOS)
  • SensorDirectChannel : mode haute performance zero-copy pour les capteurs compatibles
  • Support des capteurs proprietaires constructeur (Samsung, Google, etc.) avec detection dynamique
  • Capteurs uncalibrated (6 axes : valeurs + biais)

Multi-device avec isolation

  • Pipelines CSV separes : chaque appareil (phone/watch) ecrit dans son propre fichier CSV
  • Colonne data_source ajoutee automatiquement ("phone" ou "watch")
  • Nommage : phone_P001_session1_*.csv et watch_P001_session1_*.csv
  • Locks independants par pipeline : pas de contention inter-device
  • Finalisation independante : l'arret de la montre ne bloque pas le telephone

Scenarios et gestes

  • Creation de gestes avec photo/video/GIF associe
  • Scenarios configurables : ordre aleatoire, repetitions, durees personnalisees
  • Lecture de scenarios avec enchainement automatique des gestes
  • Assignment drag-and-drop des gestes aux scenarios

Streaming temps reel

  • Visualisation en temps reel des donnees capteurs de la montre sur le telephone
  • Bus reactif SharedFlow pour la distribution zero-allocation des donnees
  • Throttling a ~10 Hz pour le streaming watch-to-phone

Pipeline de donnees

  • Queue en memoire (50K items) avec flush periodique vers fichiers gzip
  • Envoi fichier par fichier (streaming anti-OOM) : chaque .gz (~200 KB) est envoye individuellement
  • CSV incremental avec append (1 fichier par session par device)
  • Backpressure a 70% de la capacite de la queue
  • Header rewriting en streaming (pas de chargement complet en RAM)
  • Pic memoire multi-device : ~30 MB max

Historique et export

  • Historique des fichiers de collecte (local + Google Drive)
  • Badges device source (Phone/Watch) sur chaque fichier
  • Stats : total fichiers, Drive, local, par device
  • Selection multiple avec long-press et export ZIP
  • Upload vers Drive des fichiers locaux (bouton CloudUpload)
  • Telechargement depuis Drive des fichiers distants
  • Suppression avec choix : local seul, Drive seul, ou les deux
  • Suppression multiple avec les memes options
  • Fusion de fichiers CSV avec union des colonnes

Configuration

  • Selection des capteurs par appareil (telephone + montre)
  • Reglages thread : priorite, frequence d'echantillonnage, delai
  • Installation de l'APK montre via ADB depuis le telephone
  • Sauvegarde/restauration des parametres via Google Drive

Stack technique

Composant Technologie
UI Jetpack Compose + Material 3
Navigation Navigation Compose (bottom tabs + nested graphs)
State ViewModel + StateFlow + MutableState
Base de donnees Room (KSP)
Background WorkManager
Communication Wear Data Layer API (MessageClient + DataClient)
Sante Health Services Client 1.1.0-alpha03
Cloud Google Drive API v3 + OAuth 2.0
Graphiques MPAndroidChart
Images Coil (PNG, GIF)
JSON Gson + Moshi (streaming)
Coroutines kotlinx-coroutines 1.8.1

Prerequis

  • Android Studio Hedgehog+ (AGP 8.5.1)
  • JDK 17
  • Kotlin 1.9.0
  • Un compte Google Cloud avec :
    • Google Drive API activee
    • OAuth 2.0 Client IDs (Android + Web) configures dans la console

Note : Aucun fichier google-services.json n'est necessaire. L'authentification Google Drive utilise OAuth 2.0 directement via le SDK Google Sign-In, sans Firebase.

Installation

1. Cloner le projet

git clone <repo-url>
cd WearableSensor

2. Configurer Google Drive (optionnel)

L'application utilise Google Drive API v3 via Google Sign-In (pas Firebase). Aucun fichier google-services.json n'est necessaire.

Etape 1 : Creer le projet Google Cloud

  1. Aller sur Google Cloud Console
  2. Creer un nouveau projet (ex: wearable-sensor)
  3. Dans le menu lateral : APIs & Services > Library
  4. Chercher et activer Google Drive API

Etape 2 : Configurer l'ecran de consentement OAuth

  1. Aller dans APIs & Services > OAuth consent screen
  2. Choisir External (ou Internal si compte Workspace)
  3. Remplir les champs obligatoires :
    • Nom de l'application : WearableCollector
    • Email d'assistance : votre email
    • Domaines autorises : laisser vide
  4. Ajouter le scope : https://www.googleapis.com/auth/drive.file
  5. Ajouter votre email en tant que Test user (obligatoire tant que l'app n'est pas publiee)
  6. Sauvegarder

Important : Tant que l'ecran de consentement est en mode "Testing", seuls les Test users configures peuvent se connecter. Ajoutez tous les comptes Google qui utiliseront l'app.

Etape 3 : Creer les OAuth Client IDs

Aller dans APIs & Services > Credentials > Create Credentials > OAuth client ID

Client 1 — Android (obligatoire) :

Champ Valeur
Type Android
Package name com.deladem.wearablecollector
SHA-1 fingerprint Voir ci-dessous

Pour obtenir le SHA-1 :

# Debug keystore
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android

# Release keystore
keytool -list -v -keystore /chemin/vers/votre/keystore.jks

Creer un client Android par SHA-1 (un pour debug, un pour release si differents).

Client 2 — Web application (obligatoire) :

Champ Valeur
Type Web application
Name WearableCollector Web
Authorized redirect URIs Laisser vide

Le client Web est necessaire pour que le flow OAuth Android fonctionne. Il n'y a pas besoin de copier le client ID dans le code.

Etape 4 : Verifier

  • Aucun fichier a telecharger ni a placer dans le projet
  • La configuration se fait uniquement dans la Google Cloud Console
  • L'app detecte automatiquement les credentials via le package name + SHA-1
  • Dans l'app : Parametres > Google Drive > Se connecter pour tester

Depannage

Probleme Solution
"Sign in failed" Verifier que le SHA-1 correspond au keystore utilise (debug vs release)
"Access denied" Ajouter le compte Google en Test user dans l'ecran de consentement
"Drive upload failed - user may not be signed in" Se reconnecter dans Parametres > Google Drive
Pas de popup de connexion Verifier que le client Android est cree avec le bon package name
"Error 403: access_denied" L'app est en mode Testing et le compte n'est pas dans les Test users

3. Configurer la signature release

Creer gradle.properties a la racine :

storePassword=votre_mot_de_passe
keyAlias=votre_alias
keyPassword=votre_mot_de_passe

4. Build

# Debug
./gradlew assembleDebug

# Release
./gradlew assembleRelease

5. Deployer sur la montre

L'application telephone inclut un guide d'installation de l'APK montre via ADB (Parametres > Guide d'installation).

Permissions

Telephone

Permission Usage
BODY_SENSORS Capteurs corporels
RECORD_AUDIO Microphone (niveau sonore dB)
ACCESS_FINE_LOCATION GPS
ACTIVITY_RECOGNITION Capteurs d'activite (step detector, etc.)
FOREGROUND_SERVICE Services de collecte
INTERNET Google Drive, communication
POST_NOTIFICATIONS Notifications de collecte

Montre (additionnel)

Permission Usage
BODY_SENSORS_BACKGROUND Capteurs en arriere-plan
HIGH_SAMPLING_RATE_SENSORS Echantillonnage haute frequence
ACTIVITY_RECOGNITION Reconnaissance d'activite

Structure des donnees

Format CSV

Delimiter : ; (point-virgule), valeurs entre guillemets doubles.

Colonnes principales :

  • data_source : source de l'appareil ("phone" ou "watch")
  • take_id : identifiant unique de la session
  • participant_id, session_id : identification du participant
  • device_brand, device_model, device_types : appareil source
  • deviceId : identifiant unique de l'appareil
  • sensor_name, sensor_type, sensor_vendor : metadata capteur
  • gestureCode, scenarioCode : contexte de collecte
  • z_timestamp : horodatage en millisecondes
  • value-1 a value-N : valeurs du capteur

Nommage des fichiers

phone_P001_session1_1711612800000.csv   # Donnees du telephone
watch_P001_session1_1711612800000.csv   # Donnees de la montre
upload_phone_P001_*.csv                  # En cours d'upload
P001_merged_1711612800000.csv           # Fusion de fichiers
P001_1711612800000.zip                  # Export ZIP

Fichiers intermediaires

  • .gz : batches compresses (~2000 records, ~50-200 KB)
  • .csv : fichiers de session (1 par device par session)
  • .zip : export groupe de fichiers selectionnes

Organisation Google Drive

WearableSensor_Data/
 ├── participant_001/
 │   ├── phone_P001_session1_*.csv
 │   └── watch_P001_session1_*.csv
 ├── participant_002/
 │   └── ...
 └── wearable_backup.json

Ecrans

Ecran Description
Collecte Lecture de scenarios ou collecte continue
Historique Fichiers collectes avec badges device, selection multiple, export ZIP, upload Drive
Parametres > Telephone Liste des capteurs du telephone
Parametres > Montre Configuration des capteurs de la montre
Parametres > Google Drive Connexion, sauvegarde, synchronisation
Parametres > Threads Priorite, frequence, delai d'echantillonnage
Gestes CRUD gestes avec media (photo/video/GIF)
Scenarios CRUD scenarios avec assignation de gestes

Licence

Projet prive.

About

Data collection project for phone and smart watch ideal for research

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages