A distributed routing system for Barcelona that calculates eco-friendly vehicle routes by combining real-time traffic data (TomTom) and live air quality measurements (OpenData BCN). Built as a Bachelor's Thesis (TFG) project.
The city is split into 4 geographic zones, each managed by an independent edge server. A central orchestrator decomposes cross-zone route requests, queries the relevant edge nodes, and stitches the results into a complete route with three modes: Fastest, Greenest, and Balanced.
-
edge_server.py— FastAPI server, one instance per zone. Loads the enriched zone subgraph, snaps TomTom traffic data to graph edges, and exposes a/calcular_tramoendpoint that runs Dijkstra and returns the path, stats, and per-edge traffic levels. -
central_test.py— The central orchestrator. Queries the relevant edge servers, stitches path segments together, accumulates route statistics, and generates the interactive HTML comparison map. -
enrich_graphs.py— Offline enrichment script. Reads Barcelona air quality CSVs and injectspollution_costonto every edge in each zone GraphML. Run once, or whenever you want to refresh pollution data. -
subgraph_zone_N_enriched.graphml— Enriched road subgraph for zone N (0–3). OSM topology plus air quality attributes on every edge. Generated byenrich_graphs.py. -
tomtom_zone_fetcher.py— Fetches real-time traffic flow tiles from the TomTom API per zone. Estimatestravel_timeper segment using a BPR congestion model and saves onetraffic_zone_N.jsonper zone. -
gateways_map.csv— Defines how zones connect. Each row is a directed gateway: exit node in one zone → entry node in the adjacent zone. Used by the orchestrator to stitch cross-zone routes. -
traffic_zone_N.json— TomTom traffic segments for zone N, withtravel_time,current_speed, andtraffic_level. Generated bytomtom_zone_fetcher.py, loaded by the edge server at startup. -
comparativa_rutas_tfg.html— Interactive Leaflet map output. Toggle between the three route modes, with per-edge traffic colouring and a stats panel.
-map.py - Creates a visual HTML map with file named zone_map.html that shows the four different zones inside Barcelona
-jsonfilemaker.py - Creates barcelona_osm_tomtom.json file
-jsontodataframe.py - Creates enriched barcelona_osm_tomtom_pollution.json file. Takes as input geopackages downloaded from OpenData BCN Portal.
pip install fastapi uvicorn osmnx networkx scipy numpy pandas requests folium mapbox-vector-tileOnly needed once, or when refreshing pollution data:
python enrich_graphs.py# All 4 zones
python tomtom_zone_fetcher.py
# Single zone (faster for testing)
python tomtom_zone_fetcher.py --zone 0Open 4 terminals, one per zone:
ZONE_ID=0 uvicorn edge_server:app --port 8000
ZONE_ID=1 uvicorn edge_server:app --port 8001
ZONE_ID=2 uvicorn edge_server:app --port 8002
ZONE_ID=3 uvicorn edge_server:app --port 8003python central_test.pyPrints route statistics for all three modes and generates comparativa_rutas_tfg.html. Open it in a browser to see the map.
| Mode | Edge weight | Optimises for |
|---|---|---|
fastest |
travel_time (seconds) |
Minimum travel time, TomTom-aware |
greenest |
pollution_cost |
Minimum pollution exposure |
balanced |
0.5 × travel_time + 0.5 × pollution_cost |
Trade-off between time and air quality |
graph TD
%% Estilos
classDef user fill:#fff,stroke:#333,stroke-width:4px;
classDef script fill:#fff3e0,stroke:#e65100,stroke-width:2px;
classDef server fill:#f3e5f5,stroke:#4a148c,stroke-width:2px;
classDef data fill:#e1f5fe,stroke:#01579b,stroke-width:2px;
U((USUARIO)):::user -- "Route request (A -> B)" --> CO(central_orchestrator.py):::script
subgraph "Orchestration Level"
CO -- "Query Gateways" --> GW[(gateways_map.csv)]:::data
CO -- "Edge Computing" --> EN
end
subgraph "Edge Level (Distributed Nodes)"
EN{Edge Cluster}
EN -- "Port 8000" --> S0[Edge Server: Zone 0]:::server
EN -- "Port 8001" --> S1[Edge Server: Zone 1]:::server
EN -- "Port 8002" --> S2[Edge Server: Zone 2]:::server
EN -- "Port 8003" --> S3[Edge Server: Zone 3]:::server
end
subgraph "Local data per Node"
S0 & S1 & S2 & S3 --- G[GraphML Enriquecido]:::data
S0 & S1 & S2 & S3 --- T[Traffic JSON Real-time]:::data
end
subgraph "Data Preparation"
G --- E[enrich_graphs.py]:::data
T --- D[tomtom_zone_fetcher.py]:::data
end
subgraph "Data Extraction"
E --- F[(OpenData BCN<br/>Air Quality CSVs)]:::data
D --- H[(TomTom API<br/>Traffic Flow)]:::data
end
CO -- "Outputs the final map" --> Out{comparativa_rutas_tfg.html}
style Out fill:#deff9a,stroke:#333,stroke-width:3px
sequenceDiagram
actor User
participant C as Central Orchestrator
participant G as Gateway Map
participant Z1 as Zone 1 (Edge Server)
participant Z2 as Zone 2 (Edge Server)
participant Z3 as Zone 3 (Edge Server)
User->>C: Route request (origin, destination, mode)
C->>C: Find zone path via zone graph
C->>G: Look up gateway nodes
G-->>C: exit node / entry node per boundary
par Zone segments in sequence
C->>Z1: POST /calcular_tramo (start → gateway, mode)
Z1->>Z1: Dijkstra on local subgraph
Z1-->>C: path + stats + edge_traffic
C->>Z2: POST /calcular_tramo (gateway → gateway, mode)
Z2->>Z2: Dijkstra on local subgraph
Z2-->>C: path + stats + edge_traffic
C->>Z3: POST /calcular_tramo (gateway → end, mode)
Z3->>Z3: Dijkstra on local subgraph
Z3-->>C: path + stats + edge_traffic
end
C->>C: Stitch paths + accumulate stats
Note over C: Repeated × 3 (fastest, greenest, balanced)
C-->>User: 3 complete routes + distance + time + AQ cost
Note over User: Interactive map — toggle between modes