515 lines
10 KiB
Markdown
515 lines
10 KiB
Markdown
# Wetterstation API
|
||
|
||
REST API zum Abrufen von Wetterdaten aus der PostgreSQL-Datenbank.
|
||
|
||
## Übersicht
|
||
|
||
Die API basiert auf **FastAPI** und bietet Endpunkte für aktuelle Wetterdaten, historische Zeitreihen, Statistiken und aggregierte Daten.
|
||
|
||
- **Version:** 1.0.0
|
||
- **Framework:** FastAPI mit Uvicorn
|
||
- **Datenbank:** PostgreSQL
|
||
- **Interaktive API-Dokumentation:** `/docs` (Swagger UI) oder `/redoc` (ReDoc)
|
||
|
||
## Starten der API
|
||
|
||
### Lokal (Development)
|
||
|
||
```bash
|
||
cd api
|
||
python main.py
|
||
```
|
||
|
||
Die API läuft dann auf `http://localhost:8000`
|
||
|
||
### Docker (Production)
|
||
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
## Umgebungsvariablen
|
||
|
||
Die API benötigt folgende Umgebungsvariablen (definiert in `.env`):
|
||
|
||
```env
|
||
DB_HOST=localhost
|
||
DB_PORT=5432
|
||
DB_NAME=wetterstation
|
||
DB_USER=wetterstation_user
|
||
DB_PASSWORD=<passwort>
|
||
```
|
||
|
||
## Endpunkte
|
||
|
||
### 📋 General
|
||
|
||
#### `GET /`
|
||
**Root-Endpunkt mit API-Informationen**
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"message": "Wetterstation API",
|
||
"version": "1.0.0",
|
||
"docs": "/docs"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### `GET /health`
|
||
**Health Check - Prüft API- und Datenbankstatus**
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"status": "ok",
|
||
"database": "connected",
|
||
"timestamp": "2026-03-23T14:30:00"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 🌡️ Weather Data
|
||
|
||
#### `GET /weather/latest`
|
||
**Gibt die neuesten Wetterdaten zurück**
|
||
|
||
**Response Model:** `WeatherData`
|
||
|
||
**Beispiel:**
|
||
```json
|
||
{
|
||
"id": 123456,
|
||
"datetime": "2026-03-23T14:30:00Z",
|
||
"temperature": 15.5,
|
||
"humidity": 65,
|
||
"pressure": 1013.2,
|
||
"wind_speed": 12.5,
|
||
"wind_gust": 18.7,
|
||
"wind_dir": 225.0,
|
||
"rain": 0.0,
|
||
"rain_rate": 0.0,
|
||
"received_at": "2026-03-23T14:30:05"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### `GET /weather/current`
|
||
**Alias für `/weather/latest` - gibt aktuelle Wetterdaten zurück**
|
||
|
||
---
|
||
|
||
#### `GET /weather/history`
|
||
**Gibt historische Wetterdaten der letzten X Stunden zurück**
|
||
|
||
**Query Parameter:**
|
||
- `hours` (optional): Anzahl Stunden zurück (1-168, default: 24)
|
||
- `limit` (optional): Maximale Anzahl Datensätze (1-10000, default: 1000)
|
||
|
||
**Beispiel:**
|
||
```bash
|
||
GET /weather/history?hours=48&limit=500
|
||
```
|
||
|
||
**Response:** Array von `WeatherData`
|
||
|
||
---
|
||
|
||
#### `GET /weather/range`
|
||
**Gibt Wetterdaten für einen bestimmten Zeitraum zurück**
|
||
|
||
**Query Parameter:**
|
||
- `start` (erforderlich): Startdatum (ISO 8601)
|
||
- `end` (erforderlich): Enddatum (ISO 8601)
|
||
- `limit` (optional): Maximale Anzahl Datensätze (1-50000, default: 10000)
|
||
|
||
**Beispiel:**
|
||
```bash
|
||
GET /weather/range?start=2026-03-01T00:00:00Z&end=2026-03-23T23:59:59Z&limit=5000
|
||
```
|
||
|
||
**Response:** Array von `WeatherData`
|
||
|
||
---
|
||
|
||
#### `GET /weather/temperature`
|
||
**Gibt nur Temperatur-Zeitreihen zurück (optimiert für Diagramme)**
|
||
|
||
**Query Parameter:**
|
||
- `hours` (optional): Anzahl Stunden zurück (1-168, default: 24)
|
||
|
||
**Response:**
|
||
```json
|
||
[
|
||
{
|
||
"datetime": "2026-03-23T14:00:00Z",
|
||
"temperature": 15.3
|
||
},
|
||
{
|
||
"datetime": "2026-03-23T14:05:00Z",
|
||
"temperature": 15.5
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
#### `GET /weather/wind`
|
||
**Gibt nur Wind-Daten zurück (Geschwindigkeit, Richtung, Böen)**
|
||
|
||
**Query Parameter:**
|
||
- `hours` (optional): Anzahl Stunden zurück (1-168, default: 24)
|
||
|
||
**Response:**
|
||
```json
|
||
[
|
||
{
|
||
"datetime": "2026-03-23T14:00:00Z",
|
||
"wind_speed": 12.5,
|
||
"wind_gust": 18.7,
|
||
"wind_dir": 225.0
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
#### `GET /weather/rain`
|
||
**Gibt nur Regen-Daten zurück**
|
||
|
||
**Query Parameter:**
|
||
- `hours` (optional): Anzahl Stunden zurück (1-168, default: 24)
|
||
|
||
**Response:**
|
||
```json
|
||
[
|
||
{
|
||
"datetime": "2026-03-23T14:00:00Z",
|
||
"rain": 0.5,
|
||
"rain_rate": 2.3
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### 📊 Statistics
|
||
|
||
#### `GET /weather/stats`
|
||
**Gibt aggregierte Statistiken für den angegebenen Zeitraum zurück**
|
||
|
||
**Query Parameter:**
|
||
- `hours` (optional): Zeitraum in Stunden (1-168, default: 24)
|
||
|
||
**Response Model:** `WeatherStats`
|
||
|
||
**Beispiel:**
|
||
```json
|
||
{
|
||
"avg_temperature": 15.2,
|
||
"min_temperature": 8.5,
|
||
"max_temperature": 22.1,
|
||
"avg_humidity": 65.3,
|
||
"avg_pressure": 1013.5,
|
||
"avg_wind_speed": 10.2,
|
||
"max_wind_gust": 28.5,
|
||
"total_rain": 3.2,
|
||
"data_points": 288
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### `GET /weather/daily`
|
||
**Gibt tägliche Statistiken für die letzten X Tage zurück**
|
||
|
||
**Query Parameter:**
|
||
- `days` (optional): Anzahl Tage zurück (1-90, default: 7)
|
||
|
||
**Response:** Array von `WeatherStats` mit `date` Feld
|
||
|
||
---
|
||
|
||
### 📈 Aggregated Data
|
||
|
||
Die aggregierten Endpunkte sind optimiert für Langzeit-Visualisierungen und reduzieren die Datenmenge durch Mittelwertbildung.
|
||
|
||
#### `GET /weather/hourly-aggregated`
|
||
**Gibt stündlich aggregierte Wetterdaten zurück (Stundenmittel)**
|
||
|
||
**Query Parameter:**
|
||
- `days` (optional): Anzahl Tage zurück (1-60, default: 7)
|
||
|
||
**Response:** Array von `WeatherData` (stündlich aggregiert)
|
||
|
||
**Verwendung:** Ideal für 7-Tage- und 30-Tage-Ansichten
|
||
|
||
---
|
||
|
||
#### `GET /weather/daily-aggregated`
|
||
**Gibt täglich aggregierte Wetterdaten zurück (Tagesmittel)**
|
||
|
||
**Query Parameter:**
|
||
- `days` (optional): Anzahl Tage zurück (1-730, default: 365)
|
||
|
||
**Response:** Array von `WeatherData` (täglich aggregiert)
|
||
|
||
**Besonderheit:** Bei `days >= 365` werden automatisch **alle verfügbaren Daten** zurückgegeben (nicht nur die letzten 365 Tage).
|
||
|
||
**Verwendung:** Ideal für Jahresübersicht (365-Tage-Ansicht)
|
||
|
||
---
|
||
|
||
#### `GET /weather/rain-daily`
|
||
**Gibt tägliche Regensummen zurück**
|
||
|
||
**Query Parameter:**
|
||
- `days` (optional): Anzahl Tage zurück (1-365, default: 30)
|
||
|
||
**Response:**
|
||
```json
|
||
[
|
||
{
|
||
"date": "2026-03-23T00:00:00Z",
|
||
"total_rain": 5.2
|
||
},
|
||
{
|
||
"date": "2026-03-22T00:00:00Z",
|
||
"total_rain": 0.0
|
||
}
|
||
]
|
||
```
|
||
|
||
**Verwendung:** Ideal für 7-Tage- und 30-Tage-Regen-Diagramme
|
||
|
||
---
|
||
|
||
#### `GET /weather/rain-weekly`
|
||
**Gibt wöchentliche Regensummen zurück (Woche = Mo-So)**
|
||
|
||
**Query Parameter:**
|
||
- `days` (optional): Anzahl Tage zurück (1-730, default: 365)
|
||
|
||
**Response:**
|
||
```json
|
||
[
|
||
{
|
||
"week_start": "2026-03-17T00:00:00Z",
|
||
"total_rain": 12.5
|
||
}
|
||
]
|
||
```
|
||
|
||
**Besonderheit:** Bei `days >= 365` werden automatisch **alle verfügbaren Daten** zurückgegeben.
|
||
|
||
**Verwendung:** Ideal für Jahresübersicht (365-Tage-Ansicht)
|
||
|
||
---
|
||
|
||
## Datenmodelle
|
||
|
||
### WeatherData
|
||
|
||
```typescript
|
||
{
|
||
id: number
|
||
datetime: string (ISO 8601)
|
||
temperature: number | null // °C
|
||
humidity: number | null // %
|
||
pressure: number | null // hPa
|
||
wind_speed: number | null // km/h (konvertiert von mph)
|
||
wind_gust: number | null // km/h (konvertiert von mph)
|
||
wind_dir: number | null // Grad (0-360)
|
||
rain: number | null // mm
|
||
rain_rate: number | null // mm/h
|
||
received_at: string (ISO 8601)
|
||
}
|
||
```
|
||
|
||
### WeatherStats
|
||
|
||
```typescript
|
||
{
|
||
avg_temperature: number | null
|
||
min_temperature: number | null
|
||
max_temperature: number | null
|
||
avg_humidity: number | null
|
||
avg_pressure: number | null
|
||
avg_wind_speed: number | null
|
||
max_wind_gust: number | null
|
||
total_rain: number | null
|
||
data_points: number
|
||
}
|
||
```
|
||
|
||
### HealthResponse
|
||
|
||
```typescript
|
||
{
|
||
status: string // "ok" | "error"
|
||
database: string // "connected" | "disconnected"
|
||
timestamp: string (ISO 8601)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Einheitenkonvertierung
|
||
|
||
Die API konvertiert automatisch folgende Einheiten aus der Datenbank:
|
||
|
||
| Wert | Datenbank | API-Ausgabe |
|
||
|------|-----------|-------------|
|
||
| Windgeschwindigkeit | mph | km/h (× 1.60934) |
|
||
| Windböen | mph | km/h (× 1.60934) |
|
||
| Temperatur | °C | °C (unverändert) |
|
||
| Luftdruck | hPa | hPa (unverändert) |
|
||
| Regen | mm | mm (unverändert) |
|
||
|
||
---
|
||
|
||
## CORS
|
||
|
||
Die API erlaubt CORS-Anfragen von allen Origins (`allow_origins=["*"]`). In Production sollte dies auf spezifische Domains eingeschränkt werden.
|
||
|
||
---
|
||
|
||
## Fehlerbehandlung
|
||
|
||
### HTTP Status Codes
|
||
|
||
- `200 OK` - Erfolgreiche Anfrage
|
||
- `400 Bad Request` - Ungültige Parameter
|
||
- `404 Not Found` - Keine Daten gefunden
|
||
- `500 Internal Server Error` - Datenbankfehler
|
||
|
||
### Fehler-Response
|
||
|
||
```json
|
||
{
|
||
"detail": "Keine Daten verfügbar"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Interaktive Dokumentation
|
||
|
||
FastAPI generiert automatisch eine interaktive API-Dokumentation:
|
||
|
||
- **Swagger UI:** [http://localhost:8000/docs](http://localhost:8000/docs)
|
||
- **ReDoc:** [http://localhost:8000/redoc](http://localhost:8000/redoc)
|
||
|
||
Dort können alle Endpunkte direkt getestet werden.
|
||
|
||
---
|
||
|
||
## Beispiele
|
||
|
||
### cURL
|
||
|
||
```bash
|
||
# Aktuelle Wetterdaten abrufen
|
||
curl http://localhost:8000/weather/current
|
||
|
||
# Letzte 48 Stunden
|
||
curl "http://localhost:8000/weather/history?hours=48"
|
||
|
||
# Jahresübersicht (alle verfügbaren Daten)
|
||
curl "http://localhost:8000/weather/daily-aggregated?days=365"
|
||
|
||
# Statistiken für letzte 7 Tage
|
||
curl "http://localhost:8000/weather/stats?hours=168"
|
||
```
|
||
|
||
### JavaScript (Fetch)
|
||
|
||
```javascript
|
||
// Aktuelle Wetterdaten
|
||
const response = await fetch('http://localhost:8000/weather/current')
|
||
const data = await response.json()
|
||
console.log(`Temperatur: ${data.temperature}°C`)
|
||
|
||
// Tägliche Aggregation für 365 Tage
|
||
const yearData = await fetch('http://localhost:8000/weather/daily-aggregated?days=365')
|
||
const year = await yearData.json()
|
||
console.log(`${year.length} Tage verfügbar`)
|
||
```
|
||
|
||
### Python (requests)
|
||
|
||
```python
|
||
import requests
|
||
|
||
# Aktuelle Daten
|
||
response = requests.get('http://localhost:8000/weather/current')
|
||
data = response.json()
|
||
print(f"Temperatur: {data['temperature']}°C")
|
||
|
||
# Statistiken
|
||
stats = requests.get('http://localhost:8000/weather/stats?hours=24')
|
||
print(f"Durchschnittstemperatur: {stats.json()['avg_temperature']}°C")
|
||
```
|
||
|
||
---
|
||
|
||
## Entwicklung
|
||
|
||
### Abhängigkeiten installieren
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
### Server starten (Development mit Auto-Reload)
|
||
|
||
```bash
|
||
uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
||
```
|
||
|
||
### Logging
|
||
|
||
Die API verwendet Python's `logging`-Modul. Log-Level: `INFO`
|
||
|
||
---
|
||
|
||
## Deployment
|
||
|
||
Die API wird als Docker-Container deployed. Siehe `Dockerfile` und `docker-compose.yml` im Hauptverzeichnis.
|
||
|
||
### Docker Image bauen
|
||
|
||
```bash
|
||
docker build -t wetterstation-api ./api
|
||
```
|
||
|
||
### Container starten
|
||
|
||
```bash
|
||
docker run -d \
|
||
-p 8000:8000 \
|
||
-e DB_HOST=db \
|
||
-e DB_USER=wetterstation_user \
|
||
-e DB_PASSWORD=<passwort> \
|
||
wetterstation-api
|
||
```
|
||
|
||
---
|
||
|
||
## Performance-Tipps
|
||
|
||
1. **Aggregierte Endpunkte verwenden** für Langzeit-Visualisierungen (reduziert Datenmenge)
|
||
2. **Limit-Parameter** nutzen, um nur benötigte Datenmenge abzurufen
|
||
3. **Spezifische Endpunkte** verwenden (`/weather/temperature` statt `/weather/history` wenn nur Temperatur benötigt wird)
|
||
4. **Caching** auf Client-Seite implementieren für historische Daten
|
||
|
||
---
|
||
|
||
## Lizenz
|
||
|
||
Siehe Hauptprojekt-Repository.
|