app

Gottardo Live — Collector

Campiona ogni ~5 minuti lo stato delle code al tunnel del San Gottardo dall’API ufficiale di opentransportdata.swiss (DATEX II, dati USTRA/VMZ-CH), mantiene lo storico per il grafico dell’app iOS Gottardo Live e invia le notifiche push automatiche quando si forma una coda.

Componenti

Cosa produce (in data/)

File Contenuto Chi lo usa
history.json Finestra mobile di 48h di campioni (attesa in minuti per direzione) Il grafico 6/12/24h dell’app — unica fonte, i campioni locali sono stati aboliti (01.08.2026)
latest.json Ultimo stato completo + eventi in tutte le lingue del feed Fallback dell’app quando la chiamata diretta fallisce, e seme della tenuta anti-lampeggio all’avvio a freddo
alerts.json Archivio degli avvisi ufficiali per id, con firstSeen/lastSeen/revokedAt — finestra 48h dall’ultimo avvistamento Lista avvisi dell’app (ripiego quando il feed tace) e storico che la fonte non conserva
push-state.json Fase corrente per direzione (clear/queued/heavy) e timestamp ultimo invio Il collector stesso, per non ri-notificare

Gli URL letti dall’app sono cablati in APIConfig.swift (raw.githubusercontent.com/fbacchin/app/main/gotthard/data/…).

Tenuta anti-lampeggio (01.08.2026)

Il feed non tiene pubblicati i messaggi per tutta la loro durata: li revoca e li riemette a impulsi, e a volte svuota il corridoio per interi minuti. Preso alla lettera, il risultato è una coda che sparisce e riappare.

La scoperta che ha risolto il problema: la fonte annuncia la fine con un messaggio prefissato Revocato: / Aufgehoben: / Révoqué: — e il codice lo scartava con un continue. Lo zero non nasceva mai da un’informazione: nasceva dall’assenza, indistinguibile da un buco del feed.

hold_through_gaps() applica quindi queste regole al campione:

Situazione Esito
Coda letta dal feed osservazione diretta, si registra
Coda assente, revoca vista zero subito: la fonte ha dichiarato la fine
Coda assente, nessuna revoca, entro HOLD_WINDOW (60 min) si mantiene l’ultimo valore, campione marcato southHeld/northHeld
Coda assente oltre i 60 minuti zero

Dettagli che contano:

⚠️ Una protezione contro il lampeggio va applicata a tutti i consumatori del dato. A luglio era stata messa solo sulle notifiche e il problema è riemerso su storico, schede e lista avvisi.

Notifiche push automatiche

Inviate via Back4App (REST con Master Key, canale global) quando l’attesa di una direzione attraversa le soglie:

Cooldown di 45 minuti per direzione; l’isteresi tra le soglie (20/10) evita il ping-pong ai bordi. La fine coda è confermata nel tempo (CLEAR_CONFIRM, 20 min): all’area di dosaggio di Airolo il messaggio viene revocato e riemesso a impulsi, e un singolo buco nel feed non va scambiato per “traffico scorrevole” (altrimenti parte un falso “coda finita” mentre la coda è ancora presente). Quando il messaggio ufficiale riporta solo i km senza tempo d’attesa, l’attesa è stimata a ~10 min/km (dosaggio del Gottardo).

Workflow GitHub Actions

I cron di GitHub sono “best effort” e quelli frequenti vengono ritardati anche di ore: il */10 originale campionava ogni 1-3,5h. La strategia attuale:

Secrets richiesti (Settings → Secrets and variables → Actions): OTD_API_KEY (chiave opentransportdata.swiss), B4A_APP_ID e B4A_MASTER_KEY (Back4App — la Master Key vive solo qui, mai nell’app iOS).

Insidie del feed (già gestite in collect.py)

Test locale

OTD_API_KEY=... python3 collect.py                 # solo dati, niente push
OTD_API_KEY=... B4A_APP_ID=... B4A_MASTER_KEY=... python3 collect.py

Scrive in data/ accanto allo script.


Questo repo è l’unica copia del collector: le modifiche a collect.py, al workflow e a questo README si fanno direttamente qui (via API GitHub o interfaccia web). Non esiste più una copia locale nel progetto Xcode.