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.
Air quality forecasts from Copernicus on a map, for every town in Italy and every city in Europe: now and for the next 48 hours.
LifestyleHTML · PythonGitHub @azuki-beansOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Air quality forecasts from Copernicus CAMS on a map: Django + DuckDB reading daily Parquet files on Cloud Run
Translation pending
Loading the full README.
Read the full README ↗Air quality forecasts from Copernicus, readable at a glance.
Coperni shows the European air quality forecast of the Copernicus Atmosphere Monitoring Service (CAMS) on a map centred on an Italian municipality, a European city or any coordinates, plus a chart of how the pollutants evolved over the past week and what is expected for the next 48 hours.
Live demo: https://coperni.azukibeans.dev
Available in English and Italian (/it/…).
Air quality data in Europe is public and free, but it usually comes as technical files (NetCDF, GRIB), expert portals or scattered monitoring stations. Coperni takes the CAMS forecast and turns it into something anyone can read: a grid of ~10 km cells around the place you care about, coloured against the European limit values.
It is a public, read-only site. There are no accounts and no tracking. The only cookie remembers the last place you looked at.
value / threshold: cyan to green below the EU
threshold, yellow at the threshold, red above it, purple above twice the threshold, drawn
as a halftone (dot size ∝ concentration) over a light basemap. Click a cell to read its value.CAMS European air quality forecasts (cams-europe-air-quality-forecasts), downloaded
daily from the Copernicus Atmosphere Data Store (ADS).
CAMS is part of the European Union's Copernicus programme and is operated by the European Centre
for Medium-Range Weather Forecasts (ECMWF).
| Model | ensemble: the median of about ten European regional air quality models |
| Resolution | 0.1° × 0.1° (~11 km N–S, ~7–9 km E–W at Italian latitudes) |
| Domain | lat 30°–72° N, lon 25° W–45° E (North Africa to Scandinavia) |
| Level | surface, i.e. the air we breathe |
| Time step | hourly, forecast run at 00 UTC, lead times 0–48 h |
| Unit | µg/m³ |
| Pollutant | Threshold (µg/m³) | Reference |
|---|---|---|
| PM2.5 | 25 | EU daily limit value from 2030 |
| PM10 | 45 | EU daily limit value from 2030 |
| NO₂ | 50 | EU daily limit value from 2030 |
| O₃ | 120 | EU target value (maximum daily 8-hour mean) |
| SO₂ | 50 | EU daily limit value from 2030 |
All thresholds are the strictest EU references of Directive 2024/2881 and apply to daily (O₃: 8-hour) means, so every pollutant is judged on the same footing. The hourly limits (NO₂ 200, SO₂ 350) are meant for acute episodes and would leave the map almost always empty: the project aims at awareness, not at signalling emergencies. Thresholds are configurable through environment variables. The map compares each hourly value with the threshold: this is intentional (the site always shows the latest hour) and the comparison is meant as indicative, not as a check of legal compliance.
These are forecasts, not measurements. They come from a numerical model of the atmosphere, not from monitoring stations. They describe the overall situation and its evolution well, but can differ from what is measured at a specific spot (a busy street, the bottom of a valley). For official data refer to your regional environmental agency.
cities15000, restricted to the
CAMS domain.Both are small CSV files versioned in luoghi/dati/ and loaded into SQLite when the image is built.
Cloud Scheduler (08:30 UTC)
└─ Cloud Run Job → manage.py cams_export
└─ 1 ADS request: all of Europe, 5 pollutants, 49 h (~275 MB NetCDF)
└─ convert → gs://<bucket>/cams/YYYY-MM-DD.parquet (~54 MB) + indice.json
Browser → Cloud Run service (Django + DuckDB)
├─ reads only the requested window of the Parquet over HTTPS range requests
└─ luoghi.sqlite3 (municipalities + cities), built into the image
No database server, no queue, no GIS stack. The whole backend is Django, DuckDB and static
files in a bucket. See docs/architecture.md for the Google Cloud setup,
the reasoning behind it and how to deploy your own copy.
This is the beginning of the README. Read the rest at the original. Read the full README ↗