A self-hosted weather display for Raspberry Pi, Synology NAS or any Linux box — with your choice of forecast provider and first-class Netatmo weather-station support. Designed for wall-mounted tablets, kiosk screens and old iPads given a second life.
🌐 English · Svenska · Norsk · Dansk · Suomi · Deutsch · Français · Español
🧑🔧 This is a personal hobby project, shared as-is. I mostly built it for the weather screen on my own wall. I'm putting it on GitHub in case someone else wants a clean, good-looking weather display — especially one with real Netatmo support — but I may not have time to answer bug reports or review pull requests. You're very welcome to fork it and make it your own. See Support & contributing for the friendly details.
📖 A note on its Swedish origins: this started life as a Sweden-only project built around SMHI (the Swedish meteorological institute), and that heritage still shows in the code — SMHI is the base class the other providers extend, coordinates live in a
smhiconfig block, the internal weather-symbol scale is SMHI's 1–27, humidity can come from SMHI observation stations, and outdoor air quality uses SMHI's national reference network. Global YR/met.no and Open-Meteo support was added later, so wherever you see "SMHI" in the code or config it's usually the shared mechanism the other providers build on — not a hard dependency. The dashboard works anywhere in the world.
Live from my own wall display: the measured temperature, humidity, pressure and CO₂ from a Netatmo station (green, “FAKTISK”) shown right next to the forecast (blue, “PROGNOS”), with UV index and a five-day outlook.
A small Flask web app that turns any spare screen into an elegant, always-on weather dashboard. One low-power device (a Raspberry Pi, a Synology NAS, or any Linux machine) runs the server; any tablet, phone or dedicated monitor displays it in a browser. It works out of the box with just a location, and grows with you if you own a Netatmo weather station.
Why you might want it:
- 🌍 Pick your forecast source — SMHI (Nordics), or YR/met.no and Open-Meteo for global coverage. No API key required, and every provider is normalised to the same icons and animations.
- 🏠 Real measurements, not just forecasts — with a Netatmo weather station you see your actual temperature, humidity, air pressure and indoor CO₂/air quality beside the forecast. This is the feature most weather dashboards don't have.
- 🎨 Looks the part — a glassmorphism dark theme, a circular LED clock, colour-coded temperatures/wind/UV, six swappable icon packs and animated rain & snow effects that follow the real forecast.
- 🌐 Speaks your language — eight UI languages with wind terminology taken from each country's national weather service.
- 📟 Built for kiosks — tuned for 1920×1080 wall panels and iPad/Android home-screen web apps, with performance options for Raspberry Pi and Safari/WebKit.
Everything is configured in one commented config.py file — no database, no build step, no account required for the basics.
Eight UI languages (wind terms, weekdays, barometer words and compass letters all localise):
Six swappable icon packs (same dashboard, different weather icons — set ui.icon_pack, or let them rotate automatically):
🖥️ Server (runs the dashboard):
- Raspberry Pi, Linux computer or Synology NAS
- Python 3.8+ and an internet connection
- No screen or browser needed
📱 Client (displays the dashboard):
- iPad, Android tablet, phone or computer
- Modern browser (Safari, Chrome, Firefox)
- WiFi connection to the same network
📺 Dedicated display:
- Raspberry Pi 3B or better (Pi5 recommended for Weather Effects)
- 15.6" IPS screen (optimized for N156HCA-E5B @ 1920×1080, works with other sizes)
- Chromium for kiosk mode
- Keyboard/mouse for configuration
Linux/Ubuntu/Raspberry Pi:
sudo apt update && sudo apt install python3 python3-pip git libeccodes-dev -y
cd ~ && git clone https://github.com/cgillinger/flask-weather.git && cd flask-weather
pip3 install -r requirements.txt --break-system-packages
cp reference/config_example.py reference/config.py
nano reference/config.py # Configure (see guide below)
python3 app.pySynology NAS:
python3 -m pip install --user flask requests netCDF4 cdsapi
cd /var/services/homes/$(whoami) && git clone https://github.com/cgillinger/flask-weather.git && cd flask-weather
cp reference/config_example.py reference/config.py
nano reference/config.py
python3 app.py📱 Then open: http://SERVER-IP:8036 on your tablet/phone
- Overview
- Features
- Graceful fallback
- Server installation
- Client setup
- Configuration
- Weather Effects
- UV index
- Color management
- Usage
- Customization
- Troubleshooting
- Support
Flask Weather Dashboard is an elegant weather dashboard that combines a national weather institute forecast with optional integration of a Netatmo weather station. The system uses a server/client architecture - the server can run on any Linux device (Raspberry Pi, Synology NAS, Ubuntu computer) while the dashboard is displayed on tablets, phones or dedicated screens.
📊 Forecast-only (for users without Netatmo equipment)
- ✅ Works immediately without extra configuration
- ✅ Shows the weather forecast from the selected provider
- ✅ Humidity from the provider forecast — or SMHI observation stations when the provider is SMHI
- ✅ Simple pressure trend based on forecast data
- ✅ Outdoor air quality (European AQI): the nearest SMHI air-quality station in Sweden, or a global Open-Meteo/CAMS model everywhere else — no API key
- ✅ UV index from CAMS (optional, requires API key)
🏠 Forecast + Netatmo (for users with a Netatmo weather station)
- ✅ Everything from forecast-only mode PLUS:
- ✅ Actual temperature from your Netatmo weather station
- ✅ Indoor CO₂/air quality measurement — shown next to the outdoor value (choose indoor, outdoor or both)
- ✅ Advanced pressure trend based on historical data
- 🔧 Noise level measurement (backend support exists, frontend not enabled)
- Selectable weather provider (
weather_provider): SMHI, YR/met.no or Open-Meteo (the shipped example config uses YR) — 12-hour and 5-day forecasts with color-coded temperatures. All providers are normalized to SMHI's symbol scale so icons and effects work identically; YR and Open-Meteo have global coverage (SMHI only covers the Nordics) - Current temperature: From the selected provider or Netatmo, with color coding (freezing → hot)
- Humidity: Netatmo, the provider forecast (YR/Open-Meteo), or SMHI observation stations when the provider is SMHI
- Air pressure: Five-step pressure trend (falling fast · falling · steady · rising · rising fast) with color-coded indicators and a double arrow for rapid weather changes. Optional word mode (
pressure_display: 'words') that shows descriptive level words like a physical barometer. - 🍃 Air quality (
air_quality.mode): indoor CO₂ (Netatmo), outdoor European AQI, or both side by side. Outdoor data comes from the nearest SMHI air-quality station — Sweden's national network, so inside Sweden the outdoor tile shows how far away the station is — falling back to a global Open-Meteo/CAMS model anywhere else in the world — no API key. Color-coded by the EEA index (good → extremely poor); in both mode the leaf takes the worse of the two levels. - Wind data: Beaufort color-coded wind icons (green → yellow → orange → red) with several unit options
- Precipitation: Forecasts with rain intensity
- ☀️ UV index: Real-time UV data from CAMS with WHO/WMO color coding (low → extreme)
- Eight UI languages (
ui.language): Swedish, Norwegian, Danish, Finnish, German, French, Spanish and English — wind terminology per language follows each country's weather institute (SMHI/YR/DMI/FMI/DWD/Météo-France/AEMET/Met Office)
- Circular clock: 60 LED dots showing seconds
- Responsive design: Optimized for all screen sizes (1920×1080 IPS is the primary target resolution)
- Themes: Dark (production-ready) and light theme
- Six icon packs with optional automatic rotation (day/week/month)
- Glassmorphism: Modern glass-effect design
- 🎨 ColorManager: Centralized color management with 80+ CSS variables
- 🌧️ Rain animations: Realistic raindrops with wind influence and color coding
- ❄️ Snow effects: Falling snowflakes with sparkle effects
- ⚡ Symbol-driven: Weather symbols decide the effect type, precipitation decides intensity — fully language- and provider-independent
- 🎛️ Configurable intensity: Light, medium, heavy or auto detection
- 🚀 GPU acceleration: Pi5-optimized for smooth performance
- Sun times: Sunrise/sunset via the ipgeolocation API or fallback calculation
- Air quality: outdoor European AQI (SMHI station in Sweden → global CAMS fallback) and/or indoor CO₂ (Netatmo), configurable via
air_quality.mode— see Features - Auto refresh: Configurable update intervals
A wall-mounted dashboard is only trustworthy if it never quietly shows a made-up number. This app follows one rule: every value on screen is real data from a source, or it isn't shown at all. When a source is missing it degrades honestly rather than filling in zeros or placeholders.
Here is exactly what happens when each source is unavailable:
| Data | Primary source | Fallback | If nothing is available |
|---|---|---|---|
| Forecast (temp, wind, symbols, precipitation) | Selected weather_provider (SMHI/YR/Open-Meteo) |
— (mandatory) | The last successful forecast stays on screen; the status line reports the failure and the "updated" time stops advancing, so stale data is visible as stale — never blanked or zeroed |
| Actual temperature, CO₂, noise | Netatmo station | — | Automatically switched off (forecast-only mode). These tiles are omitted, not shown as 0 |
| Pressure trend | Netatmo's own ≥3 h measured history (five-step, high precision) | Provider forecast tendency — the real pressure change over the next 3 h from the forecast (works with any provider) | Only if even the forecast pressure is missing does it show n/a / collecting |
| Outdoor air quality | Nearest SMHI air-quality station — Sweden's national network, tried first regardless of your forecast provider (so it only applies in Sweden) | Global Open-Meteo/CAMS model, used everywhere outside Sweden — no API key | Tile hidden |
| UV index | CAMS (requires API config) | — | Tile hidden — never a fake "0 / low" |
| Rain (Netatmo module) | Netatmo rain gauge | — | Tile hidden — a silent gauge is not reported as "0 mm" |
| Humidity | Netatmo | Provider forecast (or an SMHI observation station when the provider is SMHI) | Tile hidden |
| Sun times | ipgeolocation API | Built-in astronomical calculation | — |
Netatmo's trend is measured from the station's own pressure history, which is the most accurate source once it holds a continuous 3-hour window. Right after a restart or a longer outage that window is empty. Instead of guessing, the app fills the gap with the forecast pressure tendency (the provider's predicted pressure change over the coming 3 hours) — a genuine value, classified on the same thresholds as the measured trend, and available from the very first update. The app switches back to the measured Netatmo trend automatically as soon as enough history has accumulated. This is provider-independent: SMHI, YR and Open-Meteo all supply the forecast pressure used here.
The server runs the Flask application and handles all weather data. No screen or browser is needed on the server.
- Linux distribution (Ubuntu, Debian, Raspberry Pi OS, Synology DSM)
- Python 3.8+
- 2GB+ RAM, 1GB storage
- Internet connection for the weather API, CAMS UV API (optional), ipgeolocation (optional)
sudo apt update && sudo apt upgrade -y
sudo apt install python3 python3-pip git curl nano libeccodes-dev -yUpdates the system and installs base tooling plus libeccodes for the UV feature.
cd ~
git clone https://github.com/cgillinger/flask-weather.git
cd flask-weather
pip3 install -r requirements.txt --break-system-packagescp reference/config_example.py reference/config.py
nano reference/config.pyMinimal configuration (works out of the box):
CONFIG = {
'smhi': {
'latitude': 59.3293, # Stockholm (change to your coordinates)
'longitude': 18.0686
},
'display': {
'location_name': 'Stockholm' # Display name
}
}Weather provider:
'weather_provider': 'yr', # 'yr' (default, global) | 'smhi' (Nordics only) | 'open-meteo' (global)The shipped example config defaults to YR/met.no (global coverage), English UI and forecast-only mode (no Netatmo).
The coordinates in the smhi block are used regardless of provider — with yr (met.no) or open-meteo the dashboard works anywhere in the world. No provider requires an API key; humidity then comes from the forecast instead of SMHI's observation stations, and the provider's symbol codes (YR symbol_code or WMO codes) are automatically translated to the SMHI 1-27 scale, so icon packs and weather effects work identically.
UV index (optional, requires .cdsapirc setup):
IMPORTANT: The UV feature requires two steps:
- API account at https://ads.atmosphere.copernicus.eu/
- ~/.cdsapirc file with your credentials (see the detailed guide in the UV index section)
In config.py:
'cams_uv': {
'enabled': True
}NOTE: The API key does NOT go into config.py - it is read from ~/.cdsapirc automatically by the cdsapi library.
Netatmo (optional): See Configuration.
python3 app.pyStarts the server on port 8036.
sudo tee /etc/systemd/system/weather-dashboard.service > /dev/null <<EOF
[Unit]
Description=Weather Dashboard
After=network.target
[Service]
Type=simple
User=$USER
WorkingDirectory=$HOME/flask-weather
ExecStart=/usr/bin/python3 app.py
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable weather-dashboard
sudo systemctl start weather-dashboard- DSM → Package Center → Install Python 3
- Control Panel → Terminal & SNMP → Enable SSH service
- Connect via SSH:
ssh admin@SYNOLOGY-IP
python3 -m pip install --user flask requests netCDF4 cdsapi
cd /var/services/homes/$(whoami)
git clone https://github.com/cgillinger/flask-weather.git
cd flask-weather
cp reference/config_example.py reference/config.py
nano reference/config.pyNote: libeccodes can be hard to install on Synology - the UV feature is optional.
python3 app.pyOpen http://SYNOLOGY-IP:8036 on another device to verify.
- DSM → Control Panel → Task Scheduler
- Create → User-defined script
- User: your username
- Script:
cd /var/services/homes/$(whoami)/flask-weather && python3 app.py
- Schedule: On boot
The server now runs at: http://SERVER-IP:8036
Clients display the dashboard from the server. Works on any device with a modern browser.
- 🌐 Open Safari on the iPad
- 📍 Navigate to
http://SERVER-IP:8036 - 📤 Tap the share button
- ➕ Choose "Add to Home Screen"
- ✅ Tap "Add"
iPad tips:
- 🔄 Landscape orientation gives the best experience
- 🔒 Disable Auto-Lock: Settings → Display & Brightness → Auto-Lock → Never
- 🎯 Guided Access for kiosk behavior (Settings → Accessibility → Guided Access)
- ⚡ Weather Effects run smoothly on iPad Pro and newer; animated SVG icon packs are automatically limited to the hero icon on iPad (see
icon_animations)
- 🌐 Open Chrome
- 📍 Navigate to
http://SERVER-IP:8036 - ⋮ Open the menu → "Add to Home screen" / "Install app"
Android tips:
- 🔋 Disable battery saver while the dashboard is running
- 🎮 Kiosk mode: use apps like "Kiosk Browser Lockdown" for public installs
sudo apt update && sudo apt upgrade -y
sudo apt install python3 python3-pip git curl nano chromium-browser xorg libeccodes-dev -y
cd ~
git clone https://github.com/cgillinger/flask-weather.git
cd flask-weather
pip3 install -r requirements.txt --break-system-packages
cp reference/config_example.py reference/config.pyKiosk mode (Pi5, optimized for Weather Effects):
chromium-browser --kiosk --disable-infobars --enable-gpu-rasterization --enable-zero-copy http://localhost:8036Autostart:
mkdir -p ~/.config/autostart
cat > ~/.config/autostart/weather-dashboard.desktop << 'EOF'
[Desktop Entry]
Type=Application
Name=Weather Dashboard
Exec=/bin/bash -c 'cd ~/flask-weather && python3 app.py & sleep 10 && chromium-browser --kiosk --disable-infobars http://localhost:8036'
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
EOFip addr show | grep 'inet 192' | awk '{print $2}' | cut -d'/' -f1The main configuration lives in reference/config.py.
Weather provider (mandatory, no key required):
'weather_provider': 'yr', # 'yr' | 'smhi' | 'open-meteo'
'smhi': {
'latitude': 59.3293, # Your coordinates (used by all providers)
'longitude': 18.0686
}☀️ UV index via CAMS (optional, free API key): see the UV index section.
🏠 Netatmo (optional): requires client_id/client_secret/refresh_token from https://dev.netatmo.com/apps — see reference/config_example.py for details.
🌅 Sun times via ipgeolocation (optional, fallback exists):
'ipgeolocation': {
'api_key': 'YOUR_API_KEY', # Free from https://ipgeolocation.io/
}'display': {
'location_name': 'Stockholm', # Location label shown on screen
}
'ui': {
'fullscreen': True,
'refresh_interval_minutes': 15,
'netatmo_refresh_interval_minutes': 10,
'wind_unit': 'land', # Options: 'sjo', 'beaufort', 'ms', 'kmh'
'pressure_display': 'words', # 'words' = barometer words, 'numeric' = numbers
'icon_pack': 'weather-icons', # Weather icon set, see below
'icon_animations': 'auto', # Icon animation mode for SVG packs, see below
'icon_pack_rotation': { # Automatic pack rotation, see below
'enabled': False,
'interval': 'week', # 'day' | 'week' | 'month'
'exclude': [],
},
'language': 'en', # UI language, see Languages below
'theme': 'dark' # Only 'dark' is production-ready
}
'air_quality': {
# 'indoor' = Netatmo CO₂ only (requires use_netatmo=True)
# 'outdoor' = outdoor European AQI only (nearest SMHI station → global CAMS fallback, no key)
# 'both' = show both; without Netatmo it automatically shows outdoor only
'mode': 'both',
}The dashboard UI language is set with ui.language. Eight languages are included:
| Code | Language | Wind terminology follows |
|---|---|---|
sv |
Swedish | SMHI |
nb / no |
Norwegian (bokmål) | YR / Norwegian Meteorological Institute |
da |
Danish | DMI |
fi |
Finnish | Finnish Meteorological Institute (FMI) |
de |
German | DWD |
fr |
French | Météo-France (Beaufort) |
es |
Spanish | AEMET (Beaufort) |
en |
English (install default) | Met Office (Beaufort) |
All user-facing text is looked up via translation keys with Swedish as fallback. Dates, weekdays and month names follow the language automatically via the browser's Intl API, and even the compass letters for wind direction are localized (Swedish V = English W, east is O/E/Ø depending on language). The barometer's level words follow each language's classic barometer dial (e.g. German Sturm/Regen/Veränderlich/Schön/Sehr trocken).
Adding a language: copy static/translations/sv.js to <code>.js, translate the values, add the <script> tag in templates/index.html and set 'language': '<code>'. Weather effects, icon choice and color coding are unaffected by language — they are driven by language-neutral symbol codes (the SMHI 1-27 scale).
The weather icon set is switched with ui.icon_pack:
| Pack | Look | License |
|---|---|---|
weather-icons |
Weather Icons font (Erik Flowers) - monochrome, auto color-coded by weather type (default) | SIL OFL 1.1 (via CDN) |
amcharts |
Animated color SVGs with day/night variants | Free (amCharts/ammap.com) |
meteocons |
Animated color SVGs, fill style (Bas Milius) - most modern, smoothest animations, complete day/night | MIT |
amedia-meteo |
Static color SVGs (Amedia Utvikling) - complete day/night, all precipitation intensities | CC BY-NC-SA 4.0 - non-commercial use only! |
open-weather-icons |
Font (Ivan Vilanculo) - monochrome, OpenWeatherMap symbols with day/night, auto color-coded | MIT |
kickstand-weather |
Font (KickstandApps) - minimalist Climacons style, 12 glyphs, auto color-coded | SIL OFL 1.1 |
After switching: restart the server (Docker: docker compose up -d --build).
Automatic pack rotation (ui.icon_pack_rotation): with enabled: True the dashboard rotates between icon packs per day, week or month (interval). The rotation covers all packs registered in icon-packs.js — the list is never hardcoded, so new packs join automatically. Skip packs with exclude, e.g. 'exclude': ['kickstand-weather']. The pack is chosen deterministically from the date (switching at local midnight, Monday, or the turn of the month), so all clients show the same pack without synchronization; ui.icon_pack acts as fallback when rotation is off or all packs are excluded.
Per-pack notes:
meteoconsis animated and interacts withui.icon_animationsjust likeamcharts- static variants are ready inmeteocons-svg-static/. The animations are lightweight (SMIL without filters).amedia-meteoand the font packs are static and unaffected byui.icon_animations.open-weather-iconshas no sleet symbol (snow icon is used) and does not distinguish precipitation intensities.kickstand-weatherhas only 12 glyphs: sleet shows as rain and intensity levels look identical.
The icon files under static/assets/icons/ come from third parties and have their own licenses - they are not covered by the project's MIT license. Each pack folder contains its license file, which must accompany redistribution:
| Folder | Author | License |
|---|---|---|
amcharts-svg/, amcharts-svg-static/ |
amCharts (ammap.com) | Free to use with attribution (kept in the SVG file comments) |
meteocons-svg/, meteocons-svg-static/ |
Bas Milius | MIT (LICENSE in folder) |
amedia-meteo/ |
Amedia Utvikling | CC BY-NC-SA 4.0 (LICENSE.md in folder) |
open-weather-icons/ |
Ivan Vilanculo | MIT (LICENSE.md in folder) |
kickstand-weather/ |
KickstandApps | SIL OFL 1.1 (License.txt in folder) |
⚠️ Important aboutamedia-meteo: CC BY-NC-SA 4.0 allows non-commercial use only, and derivatives must be shared under the same license. Fine for a private weather display, but for commercial use you must pick another icon pack or remove the folder.
Icon animations (ui.icon_animations):
The animated SVG packs (e.g. amcharts) can lag on Safari and on iPad/iPhone (every browser there is WebKit under the hood): the icon animations are CPU-rasterized through a built-in shadow filter, and with ~10 icons on screen it gets heavy. ui.icon_animations therefore controls which icons animate:
| Mode | Behavior |
|---|---|
auto |
Animate everything — except on Safari/iPad, which only animates the hero icon (default, recommended) |
all |
Animate all icons on all clients |
hero |
Animate only the hero icon (current weather); forecast icons are static |
none |
All icons static |
Chromium kiosks (e.g. a Pi5 setup) handle full animation and are unaffected by auto. The setting has no effect on the weather-icons font pack, which is not animated.
The static icon variants live in static/assets/icons/amcharts-svg-static/ and are generated with python3 scripts/generate_static_icons.py (only needed when the icon pack is updated — the result is committed).
Adding your own pack:
- Put the icon files under
static/assets/icons/<packname>/— plus the pack's license file - Add an entry in
ICON_PACKSinstatic/js/utils/icon-packs.js— map the semantic keys (clear,rain,snow, …) to your icons with day/night variants. For animated SVG packs: pointstaticBasePathto a folder of non-animated copies. For font packs: setbaseClassand link the pack's CSS intemplates/index.html - Select the pack with
'icon_pack': '<packname>'
The views never need changes — all symbol interpretation happens in the canonical mapping in the same file.
Default configuration (works on most devices):
'weather_effects': {
'enabled': True,
'intensity': 'auto', # Determined automatically from forecast precipitation
'rain_config': {
'droplet_count': 50,
'min_speed': 15,
'max_speed': 25
},
'snow_config': {
'flake_count': 25,
'min_speed': 2,
'max_speed': 5
}
}Weather Effects creates realistic weather animations synchronized with the forecast data.
| Intensity | Description |
|---|---|
'auto' |
Determined automatically from precipitation (recommended) |
'light' |
Light effects with fewer particles |
'medium' |
Default intensity |
'heavy' |
Intense effects with many particles |
| Symbols (1-27) | Effect |
|---|---|
| 1-7 | None (clear/cloudy) |
| 8-10, 18-20 | 🌧️ Rain |
| 11, 21 | ⚡ Thunder (treated as intense rain) |
| 12-14, 22-24 | 🌨️ Sleet (snow effects at rain speed) |
| 15-17, 25-27 | ❄️ Snow |
📱 Mobile devices (iPad/Android):
'rain_config': {'droplet_count': 35},
'snow_config': {'flake_count': 20},🖥️ Raspberry Pi 5:
'rain_config': {'droplet_count': 75},
'snow_config': {'flake_count': 40},UV index integration via CAMS (Copernicus Atmosphere Monitoring Service) provides real-time UV data. The UV location follows the same coordinates as the weather provider.
| UV value | Risk level | Color | Advice |
|---|---|---|---|
| 0-2 | Low | 🟢 Green | No special measures |
| 3-5 | Moderate | 🟡 Yellow | Sun protection recommended |
| 6-7 | High | 🟠 Orange | Sun protection required |
| 8-10 | Very high | 🔴 Red | Extra caution |
| 11+ | Extreme | 🟣 Purple | Avoid exposure |
-
Register an account:
- Go to https://ads.atmosphere.copernicus.eu/ and create a free account
-
Accept the license:
- Log in, go to https://ads.atmosphere.copernicus.eu/datasets/cams-global-atmospheric-composition-forecasts
- Click "Download data" and accept the "Terms of Use"
- IMPORTANT: Without this acceptance the API will not work!
-
Get the API key:
- Go to https://ads.atmosphere.copernicus.eu/how-to-api
- Your UID and API key are shown on the page
-
Create the ~/.cdsapirc file:
nano ~/.cdsapirc # Contents (replace with YOUR values): url: https://ads.atmosphere.copernicus.eu/api key: 12345:abc123-def456-ghi789 chmod 600 ~/.cdsapirc
Key format:
UID:API-KEY(colon in between, no spaces) -
Test the configuration:
cat ~/.cdsapirc python3 -c "import cdsapi; c = cdsapi.Client(); print('✅ CAMS API OK')"
Then enable in config.py:
'cams_uv': {
'enabled': True
}Common errors:
- "Invalid API key" → check the UID:API-KEY format (colon, no spaces)
- "License not accepted" → accept the Terms of Use on the dataset page
- "~/.cdsapirc not found" → the file must be in the home directory
curl http://SERVER-IP:8036/api/uvColorManager v1.0.0 provides centralized color management for the whole application.
1. Temperature scale (5 levels): Freezing (< 0°C) blue · Cold (0-10°C) light blue · Cool (10-20°C) yellow · Warm (20-30°C) orange · Hot (> 30°C) red
2. UV scale (WHO/WMO): Low green · Moderate yellow · High orange · Very high red · Extreme purple
3. Beaufort wind scale: Calm green · Moderate yellow · Strong orange · Storm red
4. Weather icon colors: Sun gold · Partly cloudy orange · Clouds gray · Rain cyan · Snow light blue · Thunder yellow
ColorManager.getTemperatureColor(25); // "#fb923c" (orange)
ColorManager.getWindColor(8.5); // "#f59e0b" (yellow, Beaufort 5)
ColorManager.getUVColor('high'); // "#FB8C00" (orange)
ColorManager.getWeatherIconColor(1); // "#FFD700" (gold sun)Edit static/css/colors.css — all components update automatically:
:root {
--temp-freezing: #3b82f6;
--weather-sun: #FFD700;
/* ... */
}| Endpoint | Description |
|---|---|
/ |
Main page |
/api/current |
Current weather (provider + Netatmo) |
/api/uv |
UV index |
/api/forecast |
12-hour forecast |
/api/daily |
5-day forecast |
/api/weather-effects-config |
Weather Effects status |
/api/pressure_trend |
Pressure trend |
/api/status |
System status |
'ui': {
'wind_unit': 'land', # Options: 'sjo', 'beaufort', 'ms', 'kmh'
}- 'land': land terminology in the active language (e.g. "Moderate wind")
- 'sjo': sea terminology (e.g. "Gale")
- 'beaufort': Beaufort number
- 'ms': meters per second
- 'kmh': kilometers per hour
Edit the bottom of app.py (default 8036).
python3 --version # Requires 3.8+
python3 -c "import flask, requests; print('✅ Modules OK')"
python3 -c "from reference.config import CONFIG; print('✅ Config OK')"libeccodes problems (UV feature):
sudo apt install libeccodes-dev
pip3 install netCDF4 cdsapi --break-system-packages --force-reinstall# On the server
ip addr show | grep 'inet 192'
netstat -tulpn | grep :8036
# On the client
ping SERVER-IP
curl http://SERVER-IP:8036/api/status- Verify the ~/.cdsapirc file
- Check libeccodes:
ldconfig -p | grep eccodes - Accept the CAMS license at https://ads.atmosphere.copernicus.eu/
Reduce particles on mobile devices (droplet_count/flake_count), and on a Pi give the GPU more memory:
echo "gpu_mem=128" | sudo tee -a /boot/config.txt
sudo rebootA friendly heads-up: this is a hobby project I maintain in my spare time, mainly for my own weather screen. I'm sharing it because it might be useful to someone else who wants a nice self-hosted weather display — not as a supported product. So please:
- 🙂 Feel free to open an issue, but know that I may not get to it (or reply) quickly, if at all.
- 🍴 Forking is encouraged. If you want changes, the fastest path is to fork and adapt it to your setup — the code is MIT-licensed exactly so you can.
- 🔀 Pull requests are welcome to exist, but I can't promise reviews or merges. No hard feelings either way.
- 📖 Most answers are already written down:
reference/config_example.pyhas detailed inline comments, and this README covers installation, configuration and troubleshooting in depth.
Thanks for understanding — and enjoy the dashboard! 🌤️
- Issues: github.com/cgillinger/flask-weather/issues
- Configuration reference:
reference/config_example.py - Development history: CHANGELOG.md · DEVELOPMENT_HISTORY.md
cd ~/flask-weather
cp reference/config.py reference/config.backup
git pull
pip3 install -r requirements.txt --break-system-packages --upgrade
cp reference/config.backup reference/config.py
python3 app.pyThis project is open source under the MIT license. See the LICENSE file for details.
Exception: the vendored icon packs under static/assets/icons/ have their own licenses from their respective authors — see Icon pack licenses. Note in particular that amedia-meteo/ is CC BY-NC-SA 4.0 (non-commercial use only).
- SMHI: for the open weather API
- YR / Norwegian Meteorological Institute and Open-Meteo: for global forecast APIs
- CAMS/Copernicus: for UV index data
- Netatmo: for the weather station API
- Weather Icons: professional weather icons (Erik Flowers)
- Flask: robust web framework
- MagicMirror Community: inspiration for Weather Effects, the provider architecture and the translation system
Backend (Python/Flask):
app.py: Flask server and routingreference/data/smhi_client.py: SMHI API client (base class for all providers)reference/data/yr_client.py: YR/met.no providerreference/data/open_meteo_client.py: Open-Meteo providerreference/data/netatmo_client.py: Netatmo API clientcams_uv_client.py: CAMS UV API client
Frontend (HTML/CSS/vanilla JavaScript):
templates/index.html: main templatestatic/js/utils/i18n.js+static/translations/: language engine and catalogsstatic/js/utils/icon-packs.js: icon pack registry and rotationstatic/js/utils/color-manager.js: color management APIstatic/js/dashboard-views/,static/js/dashboard-components/: views and componentsstatic/js/weather-effects.js: Weather Effects engine
🌤️ Good luck with your weather dashboard!

