fa4895a741fb222e9cb83c3cdcd197a24d48190b
- Protected /dashboard route with PBKDF2 password + HMAC-signed cookies - First-run setup flow at /dashboard/setup - Records Ambient station readings to daily JSONL files in app/data/station/ - Deduplicates on dateutc so 1-min polling never writes duplicate rows - Dashboard charts: temp, humidity/dew, wind+gusts, wind rose, pressure, rain rate, rain accumulation, UV, solar radiation - History range selector: 1h / 6h / 24h / 7d / 30d / 90d / 1y / 2y / 3y - Auto-downsamples to 720 points for long ranges - Cron interval changed from 10 min to 1 min (with dedup guard) - app/data/ added to .gitignore (contains keys and session secret) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Weather App
Self-hosted weather app with animated radar. No API keys required.
Data Sources
- Weather: Open-Meteo — free, no key
- Radar: RainViewer — free, no key
- Map tiles: CartoDB Dark Matter (free, no key)
Features
- Current conditions (temp, feels-like, wind, humidity, pressure, visibility, UV, clouds)
- 24-hour hourly forecast
- 7-day daily forecast
- Embedded radar panel on the conditions page
- Full-page radar tab with animated past frames + nowcast
- Animated radar timeline with play/pause controls
- City search with autocomplete + GPS geolocation
- Auto-pans radar to searched city
- Dark mode (follows system preference)
- Responsive / mobile-friendly
Quick Start
docker compose up -d
App runs at http://localhost:3000
Pull prebuilt image
docker pull ghcr.io/nmemmert/weather:latest
docker run -d --name weather-app -p 3000:3000 ghcr.io/nmemmert/weather:latest
If the package is private, log in first:
echo "<GITHUB_PAT>" | docker login ghcr.io -u nmemmert --password-stdin
Change the port
Edit docker-compose.yml:
ports:
- "8080:3000"
Run without Docker
cd app
npm install
node server.js
Project structure
weather-app/
├── docker-compose.yml
└── app/
├── Dockerfile
├── package.json
├── server.js # Express — proxies Open-Meteo, RainViewer
└── public/
├── index.html
├── style.css
└── app.js # Weather render + dual Leaflet radar
Nginx reverse proxy
server {
listen 80;
server_name weather.yourdomain.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Languages
JavaScript
55.3%
HTML
26.4%
CSS
18.3%