Easy-to-manage touch screens
Free, open-source touch screens. Guided USB setup, a drag-and-drop editor and local control. Made for Home Assistant.
Quando GTT devia un bus o un tram a Torino, DeviaTo ti dice se dalla tua fermata passa ancora e, se no, dove andare a prenderlo. Gratis.
Translation pending
LifestyleDart · PythonGitHub @TCdesign-devOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Trasforma gli avvisi di deviazione di GTT Torino in mappe: quali fermate saltano e dove andare al loro posto.
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Gli avvisi di deviazione di GTT (Torino) sono scritti in prosa. DeviaTo li trasforma in una mappa e risponde a una domanda sola: la mia fermata è ancora servita?Read the full README ↗
Gli avvisi di deviazione di GTT (Torino) sono scritti in prosa. DeviaTo li trasforma in una mappa e risponde a una domanda sola: la mia fermata è ancora servita?
L'avviso tipico di GTT si presenta così:
Linea 65 deviata in direzione corso Bolzano dalle 8:00 di lunedì 3 sino alle 18:00 di venerdì 7 agosto 2026. Da via Asinari di Bernezzo angolo corso Monte Grappa, per via Asinari di Bernezzo, piazza Chironi, via Medici, corso Lecce, via Lessona, segue percorso normale.
È un elenco di vie. Ma chi aspetta il bus sta a una fermata, non su una via, e per sapere se quella fermata è ancora servita dovrebbe ricostruire il percorso a mente su una mappa che non ha davanti.
L'app fa quel lavoro: geocodifica i toponimi, calcola il percorso deviato sulla rete stradale reale, lo confronta con il percorso ufficiale del GTFS e determina quali fermate restano fuori.
[!NOTE] DeviaTo — da «devia» e «To», che a Torino è come si scrive Torino. Progetto personale, non affiliato a GTT né approvato da GTT.
DeviaTo è gratuita, senza pubblicità e senza account. Arriva a breve su App Store e Google Play: i link compariranno qui e sul sito.
Aggiungi le linee che usi con +: si cercano per numero o per via. Poi apri una linea, tocca la tua fermata sulla mappa e salvala: la home ti dice subito se è servita.
[!IMPORTANT] Privacy. Nessun account, nessuna statistica d'uso, nessuna pubblicità. La posizione, se la attivi, serve solo a mostrarti sulla mappa: non viene salvata e non esce dal telefono. Il permesso si chiede quando tocchi il pulsante, non all'apertura. Informativa completa.
L'output più utile, e quello che GTT non fornisce quasi mai. Le fermate chiuse sono riassunte per tratti e non avviso per avviso: quando GTT pubblica un avviso per ogni fermata, sedici avvisi diventano «nove fermate chiuse di fila, sali a Vibò o a Statuto Nord». Le alternative privilegiano le fermate ancora servite dalla stessa linea, così da non richiedere un cambio di mezzo, ed escludono quelle chiuse da qualunque altro avviso della linea.
Percorso normale di entrambe le direzioni con tonalità distinte, tratto deviato in rosso, fermate toccabili per il nome, fermate saltate cerchiate, e la tua posizione su richiesta. Si apre anche a tutto schermo, con una direzione sola se le due si sovrappongono e un pannello che si trascina dal basso: le fermate non servite per tratti, e quella che tocchi.
In tempo reale, finché non la interrompi, con i mezzi che si aggiornano sulla mappa: ognuno ha una punta verso dove sta andando e il colore della direzione che sta facendo. Continua mentre guardi altre linee — una alla volta, per non raddoppiare le richieste al feed di GTT. Risponde a una domanda che nessun'altra fonte copre — la deviazione è già finita? — e a una che il testo non sa rispondere bene: dove escono e dove rientrano davvero. L'app lo dice con i nomi delle fermate, e disegna il tratto realmente percorso. È l'unico dato del sistema che non viene da un testo di GTT.
Il 19 % delle variazioni pubblicate non è ancora in vigore. L'app le tiene separate — «comincia dopodomani» — invece di segnalarle come attive.
Salvi la fermata che usi — linea, direzione, palo — e la home ti risponde per quella: servita, non servita fino al…, e dove salire invece.
In fondo a ogni scheda, così che il dato grezzo resti disponibile anche quando il sistema sbaglia.
Il passaggio da testo a geometria è il punto in cui questi progetti si fermano. Un geocoder interrogato liberamente con «via Roma» restituisce decine di risultati in tutto il Piemonte, e la polilinea che ne esce non ha alcun rapporto con il percorso reale della linea.
La soluzione è il geocoding vincolato: i toponimi si cercano esclusivamente entro un chilometro dal percorso ufficiale di quella linea. È questo vincolo — non il modello linguistico, non l'euristica — a rendere affidabile l'intera catena.
| Grandezza | Valore |
|---|---|
| Toponimi risolti correttamente | 150 / 150 entro 2 km |
| Distanza massima di un toponimo corretto dal percorso | 800 m |
| Distanza minima di una via estranea alla linea | 1342 m |
| Estrazione strutturata dal testo (LLM) | 34 / 34, zero toponimi inventati |
| Copertura della tabella alias dei nomi di linea | 98,4 % (63/64) |
Il margine fra 800 m e 1342 m è ciò che rende il filtro possibile: un toponimo corretto e uno estraneo si separano nettamente, e il buffer di 1 km cade in mezzo. Un buffer da 2 km lascia entrare rumore; uno da 500 m scarta vie legittime, perché una deviazione per definizione si allontana.
avvisi GTT (due fonti)
│
▼
unione dei doppioni ......... 31 coppie su 189 avvisi
│
▼
estrazione LLM .............. testo → JSON (vie, direzione, tipo)
│
▼
geocoding VINCOLATO ......... toponimi → coordinate, entro 1 km dalla linea
│
▼
routing bus (Valhalla) ...... coordinate → polilinea sulla rete reale
│
▼
cinque validazioni .......... o si dichiara l'incertezza
│
▼
impatto sulle fermate ....... quali saltano, dove andare al loro posto
Il percorso ricostruito supera cinque validazioni prima di essere disegnato. Se una fallisce, l'app dichiara l'incertezza e mostra il testo di GTT. La regola è esplicita:
⚠️ Meglio nessuna mappa che una mappa sbagliata. Un falso positivo fa camminare l'utente ottocento metri inutilmente, e distrugge la fiducia nello strumento.
Il sistema è organizzato attorno a un vincolo strutturale:
app/lib/core/è Dart puro. Nessunimport 'package:flutter/…'.
Da questo discende il resto: la logica si esegue e si testa in millisecondi
senza simulatore, si può invocare da riga di comando, e l'interfaccia è
sostituibile — con un'altra UI, con uno script, con un'implementazione
nativa — senza toccare il calcolo. Se un file di core/ avesse bisogno di
Flutter, quel file sarebbe nel posto sbagliato.
Il calcolo gira in un posto solo: il job su GitHub. L'app legge i risultati.
avvisi GTT ─► job su GitHub Actions (ogni 30 min) ─► gh-pages: indice.json,
percorsi/, stato/
│
app ◄────────────┘ (qualche KB)
app/tool/pubblica.dart ← il giro del job: scarica, calcola, scrive
app/lib/
├── core/ ← Dart puro, zero dipendenze da Flutter
│ ├── config.dart ← tutte le soglie tarabili, in un posto solo
│ ├── models/ ← tipi di dominio, senza comportamento di rete
│ ├── geo/
│ │ ├── projection.dart ← gradi ↔ metri
│ │ ├── geometry.dart ← distanze, proiezioni, Fréchet, densify
│ │ └── polyline.dart ← codifica Google polyline
│ ├── gtfs/ ← scarico e indicizzazione del GTFS statico
│ ├── sources/ ← una classe per fonte GTT, intercambiabili
│ ├── llm/ ← client OpenAI-compatibile, con tetto di spesa
│ ├── io/formato_pubblicato.dart ← il formato dei file fra job e app
│ ├── publish/pubblicatore.dart ← lo stato di tutte le linee, in un giro
│ └── pipeline/ ← un passaggio del calcolo per file
│ ├── notice_merge.dart ← le due fonti → un avviso solo
│ ├── line_resolver.dart ← «55» → 55U (tabella alias)
│ ├── extractor.dart ← testo → JSON strutturato (LLM)
│ ├── geocoder.dart ← toponimo → coordinate, VINCOLATO
│ ├── route_builder.dart ← vie → polilinea (Valhalla) + validazioni
│ ├── rejoin_inference.dart ← dove rientra, quando GTT non lo dice
│ ├── stop_impact.dart ← quali fermate saltano, e le alternative
│ ├── closure_summary.dart ← le fermate chiuse lette per tratti
│ └── vehicle_watch.dart ← osservazione dei mezzi in tempo reale
├── data/ ← dati pubblicati con copia locale, preferenze, posizione
└── ui/ ← schermate e mappa
Perché è diviso così. Ogni file di pipeline/ è un passaggio del
ragionamento ed è sostituibile isolatamente: se Photon cessa il servizio si
riscrive geocoder.dart; se Valhalla pubblico sparisce, route_builder.dart;
per cambiare modello linguistico, extractor.dart. Nessun altro file se ne
accorge.
config.dart esiste perché quasi tutte le soglie vanno tarate sul campo. I
valori marcati MISURATO vengono da rilevazioni reali, e in sette casi
contraddicono le stime del progetto originale — fra cui la soglia di
fuori-rotta (50 m misurati contro 80 stimati) e il buffer del geocoding
(1 km contro 2).
| Fonte | Uso | Nota |
|---|---|---|
| GTFS statico GTT | percorsi, fermate, orari | rigenerato ogni giorno alle 04:00, CC-BY |
alerts.aspx (GTFS-RT) | avvisi | porta il route_id canonico nel 96,7 % dei casi |
/cms/variazioni (HTML) | avvisi | unica fonte con le date d'inizio reali; spenta nel job finché GTT non ne autorizza l'uso |
vehicle_position.aspx | posizioni dei mezzi | si spegne di notte, il servizio no |
| Photon | geocoding | nessuna chiave richiesta |
| Valhalla (FOSSGIS) | routing costing: bus | polilinee a precisione 6 |
| Overpass (FOSSGIS, riserva VK Maps) | forma intera delle vie degli avvisi, per gli incroci (algoritmo 2) | nessuna chiave; può essere lento |
| OpenRouter | estrazione dal testo | chiave del job, segreto di GitHub Actions |
L'OTP di GTT — che il progetto originale indicava come fonte primaria — è
stato scartato dopo verifica: espone un build più vecchio, i cui trip_id
non esistono nel feed corrente, e a cui mancano sette linee.
Il job su GitHub calcola ogni mezz'ora, ma l'app non manda notifiche: i dati si vedono aprendola. Le notifiche sono il passo naturale successivo, ora che il calcolo non sta più sul telefono.
Quando una fermata salta, l'app ti propone quelle vicine e ti dice quanto distano — ma in linea retta, come vola un uccello, non come cammini tu. A Torino un fiume, una ferrovia o un muro possono raddoppiare il percorso reale. L'app scrive «in linea d'aria» ogni volta, così il numero non si scambia per una distanza a piedi.
La stessa linea ha spesso più percorsi leggermente diversi: alcune corse si fermano prima, altre passano da una via invece che da un'altra. L'app usa quello più frequente. Se una deviazione riguardasse soltanto una di quelle corse minori, l'app la calcolerebbe come se valesse per tutte.
GTT pubblica gli avvisi in due posti, e nel feed dei dati aperti la data di inizio non è quella vera: è l'ora in cui l'avviso è stato scritto (verificato su 161 avvisi su 161). Le date vere stanno nella tabella del sito di GTT, che però non è pubblicata come dato aperto: il job non la usa finché GTT non lo autorizza. Nel frattempo una variazione annunciata in anticipo può comparire come già in corso.
Serve Flutter con Dart ≥ 3.12.
Il codice è lo stesso per iOS e Android: lib/core/ è Dart puro e non sa
su cosa sta girando.
cd app && flutter test # 409 test
cd app && flutter analyze
cd app && flutter run # legge i dati pubblicati, nessuna chiave
Per provare l'app contro un giro del job lanciato sul computer:
cd app && dart run tool/pubblica.dart --uscita ../sito/v1 --gtfs ../.gtfs
python3 -m http.server 8765 --directory ../sito &
flutter run --dart-define=DATI_URL=http://localhost:8765/v1/
.github/workflows/pubblica.yml esegue
app/tool/pubblica.dart ogni mezz'ora di giorno,
ogni ora la sera e una volta di notte, e pubblica il risultato sul ramo
gh-pages. A lanciarlo è un servizio esterno (cron-job.org) che chiama
workflow_dispatch: gli orari programmati di GitHub saltano troppi giri, e
restano solo come riserva. Su un fork va configurato una volta:
gh-pages, cartella
/. Il ramo lo crea il primo giro.OPENROUTER_API_KEY. Senza, si pubblicano solo le fermate sospese che GTT
scrive col numero, e gli altri avvisi restano da leggere.Le richieste al modello dipendono dagli avvisi nuovi di GTT — una ventina al giorno, misurato il 26/09/2026 — e non da quante persone usano l'app: un avviso già letto e non cambiato non si rilegge.
I test sulle fonti girano offline su dati reali: il feed protobuf e la
pagina HTML di GTT del 31 luglio 2026 stanno in app/test/fixtures/. I test
sul GTFS si saltano da soli se i file non ci sono.
Strumenti di misura, che interrogano i servizi veri:
cd app && dart run tool/check_pipeline_live.dart # catena completa
cd app && dart run tool/check_merge_offline.dart # unione delle fonti
[!TIP] Prima di modificare qualcosa, leggi
CLAUDE.md. Contiene ciò che non sta nel codice: le misure e il metodo con cui sono state ottenute, il ragionamento dietro le scelte, i sette punti in cui la specifica originale è stata smentita dai dati, e le trappole già pagate — per esempio il confronto per sottostringhe che faceva scattare «lavori stradali» sul capolinea «STRADA del Drosso», mandando l'avviso sulla direzione sbagliata.
Due criteri per i contributi:
scripts/ e app/tool/
esistono per questo. Un numero rimesso in discussione va rimisurato, non
stimato.Altra documentazione: app/ARCHITETTURA.md per lo
stato dei moduli · docs/FASE-0-RISULTATI.md per
le misure sulle fonti · docs/ per la specifica originale, che va
letta sapendo che sette dei suoi assunti si sono rivelati falsi.
L'idea è mia, e nasce da una cosa che mi capitava di continuo: gli avvisi di GTT ci sono, i dati aperti pure, le posizioni dei mezzi anche — ma stanno in posti diversi e in formati diversi, e nessuno li mette insieme per rispondere alla domanda che uno si fa davvero alla fermata. Volevo aggregare quelle fonti e ricavarne delle funzioni utili.
Il passaggio da quell'idea a un'app che funziona l'ho fatto insieme a Claude (Anthropic): l'architettura, il codice, le misure sulle fonti e le verifiche sul campo sono venute da quel lavoro a quattro mani. Le decisioni su cosa dovesse fare e su come dovesse comportarsi sono rimaste mie; il mestiere per realizzarle e il rigore nel misurare invece di supporre li ha messi lui.
Buona parte di quello che c'è scritto in CLAUDE.md — le
misure che smentiscono le stime, le trappole trovate provando l'app invece
che leggendo il codice — è il residuo di quel processo, ed è la parte del
progetto che credo valga di più.
| 🚌 Dati di trasporto | GTT S.p.A. – Gruppo Torinese Trasporti, dati aperti: CC BY 4.0 sul portale del Comune, solo uso non commerciale secondo la licenza di GTT. L'attribuzione è obbligatoria, e l'app non ha pubblicità né acquisti |
| 🗺️ Cartografia | OpenStreetMap, ODbL; immagini della cartina di CARTO (Positron e Dark Matter) |
| 🧭 Routing | Valhalla ospitato da FOSSGIS |
| 📍 Geocoding | Photon di Komoot |
| 🛣️ Vie per nome | Overpass, istanze pubbliche di FOSSGIS e VK Maps, sui dati OpenStreetMap |
Photon, Valhalla e Overpass sono servizi offerti gratuitamente alla comunità. Li
chiama solo il job, per gli avvisi nuovi: qualche decina di richieste al
giorno, con pause fra le chiamate, uno User-Agent riconoscibile e
l'intestazione X-Client-Id che FOSSGIS chiede alle app pubblicate.
DeviaTo non è un'app di GTT e non è collegata a GTT.
Il codice è distribuito con licenza Apache 2.0 — vedi LICENSE —
e chi lo ridistribuisce, anche modificato, deve citare l'autore
riportando il file NOTICE. La licenza riguarda il codice, non i
dati.