118 lines
3.3 KiB
Python
118 lines
3.3 KiB
Python
# meteo/config.py
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Self
|
|
|
|
import os
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class InfluxSettings:
|
|
"""
|
|
Configuration nécessaire pour communiquer avec un serveur InfluxDB 2.x.
|
|
|
|
Les valeurs sont généralement chargées depuis des variables d'environnement,
|
|
éventuellement via un fichier `.env` à la racine du projet.
|
|
"""
|
|
|
|
url: str
|
|
token: str
|
|
org: str
|
|
bucket: str
|
|
|
|
@classmethod
|
|
def from_env(cls) -> Self:
|
|
"""
|
|
Construit un objet `InfluxSettings` à partir des variables d'environnement.
|
|
|
|
Variables attendues :
|
|
- INFLUXDB_URL
|
|
- INFLUXDB_TOKEN
|
|
- INFLUXDB_ORG
|
|
- INFLUXDB_BUCKET
|
|
|
|
Lève une RuntimeError si une variable obligatoire est manquante.
|
|
"""
|
|
# Charge un éventuel fichier .env (idempotent)
|
|
load_dotenv()
|
|
|
|
url = os.getenv("INFLUXDB_URL")
|
|
token = os.getenv("INFLUXDB_TOKEN")
|
|
org = os.getenv("INFLUXDB_ORG")
|
|
bucket = os.getenv("INFLUXDB_BUCKET")
|
|
|
|
values = {
|
|
"INFLUXDB_URL": url,
|
|
"INFLUXDB_TOKEN": token,
|
|
"INFLUXDB_ORG": org,
|
|
"INFLUXDB_BUCKET": bucket,
|
|
}
|
|
|
|
missing = [name for name, value in values.items() if not value]
|
|
if missing:
|
|
missing_str = ", ".join(missing)
|
|
raise RuntimeError(
|
|
f"Les variables d'environnement suivantes sont manquantes : {missing_str}. "
|
|
"Définissez-les dans votre environnement ou dans un fichier .env."
|
|
)
|
|
|
|
return cls(
|
|
url=url, # type: ignore[arg-type]
|
|
token=token, # type: ignore[arg-type]
|
|
org=org, # type: ignore[arg-type]
|
|
bucket=bucket, # type: ignore[arg-type]
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class StationLocation:
|
|
"""
|
|
Décrit la position géographique de la station météo.
|
|
Utilisée pour les calculs astronomiques (ex: élévation du soleil).
|
|
"""
|
|
|
|
latitude: float
|
|
longitude: float
|
|
elevation_m: float = 0.0
|
|
|
|
@classmethod
|
|
def from_env(cls, *, optional: bool = False) -> Self | None:
|
|
"""
|
|
Charge les coordonnées GPS depuis les variables d'environnement :
|
|
- STATION_LATITUDE (obligatoire)
|
|
- STATION_LONGITUDE (obligatoire)
|
|
- STATION_ELEVATION (optionnelle, en mètres)
|
|
"""
|
|
load_dotenv()
|
|
|
|
lat = os.getenv("STATION_LATITUDE")
|
|
lon = os.getenv("STATION_LONGITUDE")
|
|
elev = os.getenv("STATION_ELEVATION")
|
|
|
|
if not lat or not lon:
|
|
if optional:
|
|
return None
|
|
raise RuntimeError(
|
|
"Les variables STATION_LATITUDE et STATION_LONGITUDE doivent être définies "
|
|
"pour calculer l'élévation solaire."
|
|
)
|
|
|
|
latitude = float(lat)
|
|
longitude = float(lon)
|
|
elevation = float(elev) if elev else 0.0
|
|
|
|
return cls(latitude=latitude, longitude=longitude, elevation_m=elevation)
|
|
|
|
def to_astral_observer_kwargs(self) -> dict[str, float]:
|
|
"""
|
|
Prépare les arguments attendus par astral.Observer.
|
|
"""
|
|
return {
|
|
"latitude": self.latitude,
|
|
"longitude": self.longitude,
|
|
"elevation": self.elevation_m,
|
|
}
|