A small daily dashboard of weather, pollen and air quality for Castellón de la Plana (Spain).
Why it exists: it helps people with pollen allergies (hay fever / поллиноз) know when to be careful — which pollens are high in the air on a given day, so they can plan outdoor time, ventilate when levels are low, and start doctor-prescribed medication before exposure. The page includes a short guide on what the data means and what to do if you notice an allergic reaction to a specific pollen.
Live:
Local (development) Server (Time4VPS)
───────────────────── ──────────────────
80_pollen_monitor/ /opt/pollen_monitor/
├── fetch_pollen.py ── deploy ──→ └── fetch_pollen.py (cron, writes data.json)
├── index.html ── deploy ──→
├── plot_yearly.py /var/www/smart-shelf-ai/meteo/
├── palabras.json (Spanish word-of-the-day) ├── index.html
└── pollen_yearly.png (yearly chart) ├── data.json (generated by fetch_pollen.py)
└── palabras.json
fetch_pollen.pyruns by cron on the server, pulls 5 sources and writesdata.json.index.htmlis a self-contained SPA (inline CSS/JS, no external assets); it readsdata.jsonand renders everything client-side. Dark, monospace, mobile-friendly.meteo_api.pyis a small Flask service (behind/meteo/api/) for other cities: search a city (/api/geocode) and get a live forecast for any coordinates (/api/data?lat=&lon=), using the global sources only. The default Castellón view keeps using the precomputeddata.json(with REA).
The page defaults to Castellón, the only location with real REA station measurements (served from
the daily data.json). Use the search box to pick any other city: the choice is stored in
localStorage (no login) and its forecast is fetched on demand from /meteo/api/ — weather, air
quality, CAMS/Google pollen and, for French cities, the Atmo France commune-level pollen index.
build_data(lat, lon, include_rea, include_atmo_france, name) in fetch_pollen.py is shared by both
the cron job and the API.
| # | Source | What it gives |
|---|---|---|
| 1 | REA / SEAIC (polenes.com) | Real Hirst-sampler measurements, station Castellón #13, 22 pollen types, ~1 week delay. Fetched over a DDP WebSocket (wss://www.polenes.com/sockjs/websocket). This is the highest-quality local source. |
| 2 | Atmo France / AtmoSud (France) | Real commune-level pollen index (grains/m³), 7 taxa incl. cypress. Fetched from https://api.atmosud.org/pollens/commune. Updated daily around 13:00 CET. |
| 3 | Google Pollen API | Universal Pollen Index (0–5), 11 plants + 3 categories, 1 km. Needs an API key (see below). |
| 4 | CAMS / Copernicus (via Open-Meteo) | Forecast grains/m³, 6 types, 11 km. |
| 5 | Open-Meteo Weather | Temperature, precipitation, wind, UV. |
| 6 | Open-Meteo Air Quality | European AQI, PM10, PM2.5, UV. |
Coordinates: 39.9864, -0.0513 (Castellón de la Plana).
The page works even if some sources are unavailable; REA/Atmo + CAMS + Open-Meteo cover pollen, weather and air quality without the Google key.
How the pollen sources actually work (real vs forecast, why REA is Spain-only, France/RNSA, level thresholds, how the three are merged): see POLLEN_SOURCES.md.
- Day tabs (5-day forecast)
- Pollen: Google UPI + CAMS grains/m³ + REA real measurements (Spain) + Atmo France commune index (France), unified per plant
- Weather: temperature, precipitation, wind, UV
- Air quality: EAQI, PM10, PM2.5
- Alerts on high pollen levels
- Favourites (star your own pollen types)
- "Word of the day" in Spanish
- Built-in help: "How does this information help me?" + what to do about an allergic reaction
No credentials live in this repo.
- The Google Pollen key is read from the environment:
GOOGLE_POLLEN_API_KEY(optionalGOOGLE_POLLEN_REFERER). Without it, the Google source is simply skipped. - Server access, API keys and hosting logins are kept outside the repo, in
../80_pollen_monitor_SECRETS.md(not committed).
On the server the key is provided via /opt/pollen_monitor/pollen.env, sourced by the cron entry.
Files on the server: static in /var/www/smart-shelf-ai/meteo/, script in /opt/pollen_monitor/.
Both smart-shelf.ai and fungeneering.com serve the same static directory via their nginx configs
(location block /meteo/). See the secrets file for host/SSH details.
# static page
scp -i ~/.ssh/<key> index.html palabras.json root@<server>:/var/www/smart-shelf-ai/meteo/
# fetch script
scp -i ~/.ssh/<key> fetch_pollen.py root@<server>:/opt/pollen_monitor/Cron (server): fetch_pollen.py runs daily at 07:00 CET →
0 7 * * * /usr/bin/python3 /opt/pollen_monitor/fetch_pollen.py >> /var/log/pollen_monitor.log 2>&1
nginx note: the
smart-shelf.aisite is a Next.js proxy; the/meteo/location block must be preserved when that config is edited, or the page 404s (the static files stay intact). Config backups live in/root/nginx-backups/on the server.
pip install websocket-client # REA WebSocket
# matplotlib — only for plot_yearly.py (local yearly chart)
plot_yearly.py— yearly REA data, top-9 allergens chart →pollen_yearly.pngpalabras.json— Spanish word-of-the-day dictionary
This is a personal, informational tool. It is not medical advice and not a diagnosis. For testing, diagnosis and treatment of allergies, consult a doctor / allergist.