diff --git a/api/api/prediction/config.py b/api/api/prediction/config.py new file mode 100644 index 0000000..51156d8 --- /dev/null +++ b/api/api/prediction/config.py @@ -0,0 +1,4 @@ +import os + +open_meteo_host = os.getenv("OPEN_METEO_HOST", "localhost") +open_meteo_port = int(os.getenv("OPEN_METEO_PORT", "8080")) diff --git a/api/api/prediction/constants.py b/api/api/prediction/constants.py index 552ac92..702ff2c 100644 --- a/api/api/prediction/constants.py +++ b/api/api/prediction/constants.py @@ -1,3 +1,4 @@ +# FIXME move features = [ "Latitude", "Longitude", @@ -13,8 +14,6 @@ OUTPUT_SIZE = 1 MODEL_STATE_DICT_FILE_NAME = "model.pth" - -OPEN_METEO_BASE_URL = "https://api.open-meteo.com" MAX_OKTAS = 8 LOGFILE_KEY = "SKY_BRIGHTNESS_LOGFILE" diff --git a/api/api/prediction/open_meteo_client.py b/api/api/prediction/open_meteo_client.py index 4d2b5c9..a60683e 100644 --- a/api/api/prediction/open_meteo_client.py +++ b/api/api/prediction/open_meteo_client.py @@ -1,6 +1,8 @@ +import logging import typing as t -from .constants import OPEN_METEO_BASE_URL, MAX_OKTAS +from .config import open_meteo_host, open_meteo_port +from .constants import MAX_OKTAS from .observer_site import ObserverSite from .utils import get_astro_time_hour @@ -8,22 +10,32 @@ class OpenMeteoClient: def __init__(self, site: ObserverSite) -> None: self.site = site + self.url_base = f"http://{open_meteo_host}:{open_meteo_port}" async def get_values_at_site(self) -> t.Tuple[int, float]: """get cloudcover and elevation values for the observer site""" import httpx lat, lon = self.site.latitude.value, self.site.longitude.value + async with httpx.AsyncClient() as client: - r = await client.get( - f"{OPEN_METEO_BASE_URL}/v1/forecast?latitude={lat}&longitude={lon}&hourly=temperature_2m,cloud_cover&forecast_days=1" - ) + params = { + "latitude": lat, + "longitude": lon, + "models": "ecmwf_ifs04", + "hourly": "temperature_2m,cloud_cover" + } + r = await client.get(f"{self.url_base}/v1/forecast", params=params) r.raise_for_status() res_json = r.json() + + elevation = float(res_json.get("elevation", 0.)) + idx = self.get_hourly_index_of_site_time() cloud_cover = res_json["hourly"]["cloud_cover"][idx] cloud_cover = self.get_cloud_cover_as_oktas(cloud_cover) - return cloud_cover, float(res_json["elevation"]) + + return cloud_cover, elevation def get_hourly_index_of_site_time(self) -> int: """pull out the relevant slice in the meteo data""" diff --git a/api/api/prediction/prediction.py b/api/api/prediction/prediction.py index 96596c0..315491e 100644 --- a/api/api/prediction/prediction.py +++ b/api/api/prediction/prediction.py @@ -19,7 +19,7 @@ path_to_logfile = (Path.home() / logfile_name) if logfile_name else None logging.basicConfig( - format="%(asctime)s -> %(levelname)s: %(message)s", + format="%(asctime)s [%(levelname)s] %(message)s", filename=path_to_logfile if bool(path_to_logfile) else None, encoding="utf-8", level=logging.DEBUG, diff --git a/api/requirements.txt b/api/requirements.txt index 5154169..f427b11 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -7,5 +7,5 @@ fastapi~=0.110.2 httpx==0.26.0 uvicorn==0.25.0 pytest==7.4.3 -Pillow~=10.1.0 +Pillow~=10.3.0 numpy~=1.26.2 diff --git a/docker-compose.yml b/docker-compose.yml index 07c5584..cd83e36 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,6 @@ version: "3" + services: - api: - build: ./api - ports: - - "8000:8000" - environment: - API_VERSION: "v1" rabbitmq: image: "rabbitmq:management" ports: @@ -19,6 +14,25 @@ services: environment: RABBITMQ_DEFAULT_USER: "guest" RABBITMQ_DEFAULT_PASS: "guest" + + openmeteo: + image: "ghcr.io/open-meteo/open-meteo" + ports: + - "8080:8080" + volumes: + - open-meteo-data:/app/data + + api: + build: ./api + ports: + - "8000:8000" + environment: + API_VERSION: "v1" + OPEN_METEO_HOST: "openmeteo" + restart: on-failure + depends_on: + - openmeteo + cpp: build: ./cpp environment: @@ -31,4 +45,8 @@ services: - api links: - rabbitmq + +volumes: + open-meteo-data: + external: true