Flussi Architetturali Principali¶
Panoramica¶
Questa sezione descrive nel dettaglio l'implementazione dei tre flussi centrali dell'applicazione mobile HapGree:
- Calcolo e salvataggio delle emissioni di CO2;
- Pipeline di tracking automatico della mobilità;
- Integrazione con Health Connect e Apple Health per il contapassi.
L'architettura adotta un principio guida fondamentale: il client mobile ha la responsabilità di raccogliere, validare, bufferizzare e sincronizzare i dati grezzi, mentre il backend gestisce il calcolo canonico dei fattori di emissione e la storicizzazione delle metriche aggregate.
1. Flusso di calcolo e gestione della CO2¶
Principio architetturale¶
Il calcolo definitivo delle emissioni avviene lato backend. Il client mobile:
- costruisce e invia DTO strutturati per ciascuna categoria (viaggi, consumi energetici, prodotti alimentari);
- riceve dal backend gli aggregati storici e le metriche di breakdown pronte per il rendering;
- esegue localmente solo conversioni accessorie di presentazione (es. calcolo percentuali e indicatori grafici).
Raccolta dati per Categoria¶
sequenceDiagram
participant U as Utente / Sensori
participant V as View & ViewModel
participant A as HapGreeApiContainer
participant B as Backend HapGree
U->>V: Inserimento viaggio / bolletta / cibo
V->>A: Costruzione DTO di creazione
A->>B: Chiamata POST con payload
B->>B: Calcolo emissioni e aggiornamento metriche
V->>A: Richiesta Dashboard / Categoria
A->>B: GET aggregati (giorno, mese, anno)
B-->>A: DTO con stats e breakdown
A-->>V: Notifica stato ViewModel
V-->>U: Rendering dati e grafici
Mobilità¶
Il client compone il DTO CreateTravel includendo:
- distanza totale percorsa;
- tipologia di veicolo (vehicleType);
- motivazione dello spostamento (travelReasonType);
- velocità media e tempi (tempo totale, tempo in idle);
- driving score;
- coordinate geografiche di inizio/fine e segmenti della polyline del percorso.
I dati vengono inviati tramite ViaggiApi.createTrip.
Energia¶
L'utente registra consumi o bollette inviando:
- amountConsumed (quantità consumata);
- type (water, gas, electricity);
- periodo di riferimento (date inizio e fine bolletta).
I dati vengono trasmessi tramite EnergyApi.
Cibo e Alimentazione¶
Supportiamo tre modalità di inserimento:
1. Manuale: selezione di prodotti e quantità;
2. Barcode: scansione del codice a barre tramite mobile_scanner con ricerca metadati su OpenFoodFacts;
3. Scontrino con OCR: scansione dello scontrino con Google ML Kit Text Recognition per estrarre gli articoli acquistati.
I singoli prodotti includono il fattore di emissione (co2KgForProductKg) e la classe ecologica (a-e).
Attività Fisica e Compensazioni¶
I passi e le distanze sincronizzate dai servizi salute contribuiscono al profilo delle attività dell'utente, mentre le compensazioni effettuate riducono l'impronta complessiva nei totali stats.saved.
Consumo dei dati aggregati nella UI¶
La HomePageViewModel consuma l'endpoint aggregato UserDashboard, che fornisce:
stats.emitted: emissioni suddivise per periodo (giorno, settimana, mese, anno);stats.saved: CO2 compensata o risparmiata;weekBreakdown: ripartizione giornaliera tra le categorie (vehicle,food,energy,receipt).
2. Pipeline del Tracking Automatico della Mobilità¶
Panoramica¶
Il tracciamento automatico dei viaggi è implementato come una pipeline continua in background composta da:
- gestione permessi runtime;
- foreground service permanente (
flutter_background_service); - riconoscimento dell'attività e filtraggio GPS;
- macchina a stati (
TrackingStateMachine); - buffer locale su
SharedPreferences(driving_history) per garantire resilienza offline; - sincronizzazione asincrona verso il backend.
sequenceDiagram
participant S as Background Service
participant G as Geolocator + Activity Recognition
participant M as TrackingStateMachine
participant P as SharedPreferences (driving_history)
participant API as Backend (ViaggiApi)
S->>G: Avvio stream GPS e rilevamento attività
G-->>M: Posizioni e velocità filtrate
M->>M: Valutazione transizione di stato
alt Viaggio completato
M->>P: Bufferizzazione sessione in driving_history
S->>P: Lettura sessioni pendenti
S->>API: POST createTrip(CreateTravel)
API-->>S: Risposta 200 OK
S->>P: Rimozione sessione sincronizzata dal buffer
end
Dettaglio delle Fasi¶
1. Inizializzazione del servizio¶
Al login dell'utente, main.dart invoca InitializeAutomaticTrackingBackgroudProcess(context). AutomaticTrackingViewModel richiede i permessi necessari:
- localizzazione foreground (locationWhenInUse) e background (locationAlways);
- notifiche (notification);
- riconoscimento dell'attività (activityRecognition).
Quindi configura FlutterBackgroundService impostando autoStart e autoStartOnBoot.
2. Entrypoint di Background¶
Il servizio esegue la funzione onStart(ServiceInstance service):
- crea la notifica persistente in foreground richiesta da Android;
- avvia lo stream di coordinate tramite Geolocator.
3. Macchina a Stati e Filtraggio GPS¶
Il flusso degli eventi è gestito da TrackingStateMachine e GpsFilterUtils:
- Stati gestiti:
idle,detecting,tracking,saving,error. - Soglia di avvio movimento: velocità minima impostata a
20.0 km/hper distinguere gli spostamenti veicolari dai passi a piedi. - Filtri di pulizia del segnale:
_maxJitterDistance = 100.0 m(scarto di coordinate anomale o balzi di rete);_maxAcceleration = 8.0 m/s²(scarto di accelerazioni irrealistiche);_minMovementSpeed = 1.5 m/s.
4. Bufferizzazione e Invio a Backend¶
Al termine della sessione di guida:
1. La sessione completa (coordinate, tempi, velocità media, driving score) viene salvata in SharedPreferences sotto la chiave driving_history.
2. Il metodo _loadAllSavedSessionsToDatabase() cicla le sessioni salvate ed esegue il flush via viaggiApi.createTrip.
3. Le sessioni confermate con successo dal backend vengono rimosse dal buffer, garantendo che nessun viaggio vada perso in caso di disconnessione o riavvio improvviso del dispositivo.
3. Integrazione con Health Connect e Apple Health¶
Obiettivo del flusso¶
Rilevare i passi e la distanza percorsa quotidianamente tramite le API native del sistema operativo e sincronizzarli con il backend HapGree.
Libreria e Tipi di Dato¶
Utilizziamo il plugin health ^12.0.1:
- Android (Health Connect):
HealthDataType.STEPSHealthDataType.DISTANCE_DELTA- iOS (Apple Health / HealthKit):
HealthDataType.STEPSHealthDataType.DISTANCE_WALKING_RUNNING
Logica di Aggregazione e Deduplicazione¶
La logica centrale è implementata in lib/utils/TodayHealthValues.dart tramite la funzione fetchHealthData():
- Inizializza
Healthe richiede i permessi di lettura per le metriche supportate. - Recupera i datapoint registrati dalla mezzanotte del giorno corrente fino a
DateTime.now(). - Algoritmo di deduplicazione passi (
_calculateStepsFromSources): - Raggruppa i dati per sorgente (
sourceName); - Calcola i passi per singola fonte (valutando valori aggregati vs parziali);
- Prende il valore massimo tra le diverse fonti per evitare doppie registrazioni da app/tracker multipli.
- Calcolo della distanza (
_calculateTotalDistanceKm): - Raggruppa e somma i chilometri rilevati per la giornata.
- Restituisce l'oggetto DTO
UpdatePhysicalActivity.
sequenceDiagram
participant APP as Flutter App
participant H as Health Connect / Apple Health
participant API as Backend HapGree
APP->>H: Richiesta autorizzazioni di lettura
H-->>APP: Permessi concessi
APP->>H: Query datapoint da mezzanotte a ora
H-->>APP: HealthDataPoint[]
APP->>APP: Deduplica e aggregazione (passi + km)
APP->>API: POST /physicalActivity (UpdatePhysicalActivity)
API-->>APP: Conferma sincronizzazione
Punti di integrazione nell'app¶
- Home Screen (
HomePageViewModel): recupera i dati della giornata per mostrare il widget riepilogativo di passi e chilometri percorsi. - Schermata Connessione App (
ConnectableAppViewModel): consente all'utente di connettere/disconnettere l'integrazione e monitorare lo stato di sincronizzazione. - Sync al Login (
main.dart): invia automaticamente al backend un aggiornamento dell'attività fisica all'apertura dell'app.