prix-carburant / README.md
SamDNX's picture
Deeper SEO, Apache-2.0 metadata, full ADEME car scrape, chargers when zoomed out
4ccb3e1
|
Raw
History Blame Contribute Delete
5.67 kB
metadata
title: Prix des Carburants France
emoji: 
colorFrom: green
colorTo: red
sdk: docker
app_port: 7860
pinned: false
license: apache-2.0

⛽ Petrol Map — live French fuel prices (PWA)

An installable, mobile-friendly map of every petrol station in France, colour-coded by price and refreshed twice a day from the official open-data feed.

Data source: prix_des_carburants_j_7 on opendatasoft (the last 7 days of prices reported by ~9 800 stations).

Features

  • Installable PWA — add it to your phone's home screen and launch it like a native app; works offline (shows the last cached prices) via a service worker.
  • Responsive — full-screen map with touch-friendly controls and safe-area handling for notched phones.
  • One layer per fuel — Gazole, SP95, SP98, E10, E85, GPLc — via the selector.
  • Price colour scale — green = cheaper, red = pricier, scaled to each fuel's national 5th–95th percentile; the legend updates per fuel.
  • Search by postal code / city — type e.g. 75011 or Lyon to filter the map to that area and zoom to it.
  • Itinerary maker — enter a ville de départ and ville d'arrivée (with city autocomplete via the Base Adresse Nationale); the route is drawn (OSRM) and the map shows only the stations along the way, flagging the cheapest for the fuel.
  • Real vehicle picker + journey cost — choose an actual model (≈550 from the ADEME database, with their exact WLTP L/100 km, hybrids included) to estimate the trip's fuel cost from the cheapest along-route price.
  • Electric vehicles — pick an EV (WLTP range), see the number of recharge stops needed and energy used, with stops placed at real chargers along the route.
  • EV charging stations — toggle the national IRVE layer (≈224 000 points, loaded live by viewport), colour-coded by power (fast ≥ 50 kW).
  • Marker clustering keeps ~10 000 stations smooth; zoom in to split clusters.
  • Click a station for all prices, address, last-reported date, and a one-click Directions link, plus hover tooltips.

Data sources: fuel prices prix_des_carburants_j_7, vehicle consumption ADEME Car Labelling, chargers IRVE via ODRE, geocoding BAN, routing OSRM, basemap IGN Plan v2.

Run locally

pip install -r requirements.txt
python app.py            # builds, then serves http://localhost:7860

Open http://localhost:7860 — on a phone (same network or behind HTTPS) you can then "Add to Home Screen" to install it.

Other entrypoints:

python build_map.py      # build output/index.html once, no server
python scheduler.py      # rebuild twice daily without serving (for static hosting)
python scheduler.py --once

PWA note: install/offline features need a secure context — i.e. https:// or http://localhost. Opening the file directly (file://) shows the map but not the installable app.

Deploy to Hugging Face Spaces (Docker)

  1. Create a new Space → SDK: Docker.

  2. Push these files to the Space repo (the YAML header above configures it):

    git init && git add . && git commit -m "Petrol map PWA"
    git remote add origin https://huggingface.co/spaces/<user>/<space>
    git push origin main
    
  3. The Space builds the Dockerfile, serves on port 7860, and rebuilds the prices twice a day. The public Space URL is HTTPS, so the PWA is installable straight from your phone.

Run the same container anywhere else:

docker build -t petrol-map .
docker run -p 7860:7860 petrol-map      # http://localhost:7860

Files

Backend (Python, build/serve):

File Purpose
fuel_data.py Fetch + normalise fuel prices (drops implausible values)
car_data.py Fetch real vehicle models + WLTP L/100 km from ADEME
build_map.py Inject the dataset into the HTML shell, copy static assets
app.py Build + serve on $PORT + twice-daily refresh (container entrypoint)
scheduler.py Twice-daily rebuild without serving
generate_icons.py One-off PWA icon generator (needs Pillow; not used at runtime)
Dockerfile Container image for Hugging Face Spaces / anywhere

Frontend (served from static/, separated for clean architecture):

File Purpose
map_template.html Slim HTML shell; injects the build's data as window.APP_DATA
static/app.js All map logic (one IIFE, sectioned by concern)
static/styles.css All styles
static/sw.js Service worker (offline + installable)
static/manifest.webmanifest, icons PWA metadata
output/ Generated site (index.html + copied static assets + stations.json)

How the refresh works

The upstream dataset is updated continuously by the French administration. app.py re-fetches the full feed and regenerates the page twice daily (07:00 and 19:00, container local time — set TZ), so the map always reflects a recent snapshot. Change REFRESH_TIMES to refresh on a different cadence.

License

Licensed under the Apache License, Version 2.0 — see the LICENSE file for the full text. © 2026 Samuel Adone.

Open data used by this project remains under its own licences (Licence Ouverte / Etalab for the French government feeds).