|
| 1 | +""" |
| 2 | +Module for interacting with the weather API service for fetching historical forecast data. |
| 3 | +
|
| 4 | +The module provides a client for the weather API service. The client can be used |
| 5 | +to retrieve historical weather forecast data for multiple locations and a given |
| 6 | +time range. |
| 7 | +
|
| 8 | +License: MIT |
| 9 | +Copyright © 2024 Frequenz Energy-as-a-Service GmbH |
| 10 | +""" |
| 11 | + |
| 12 | +from datetime import datetime |
| 13 | + |
| 14 | +import grpc.aio as grpcaio |
| 15 | +import pandas as pd |
| 16 | +from frequenz.client.weather._client import Client |
| 17 | +from frequenz.client.weather._types import ForecastFeature, Location |
| 18 | + |
| 19 | + |
| 20 | +async def fetch_historical_weather_forecasts( # pylint: disable=too-many-arguments |
| 21 | + *, |
| 22 | + service_address: str, |
| 23 | + feature_names: list[str], |
| 24 | + locations: list[tuple[float, float]], |
| 25 | + start_time: datetime, |
| 26 | + end_time: datetime, |
| 27 | + file_to_store: str = "", |
| 28 | +) -> pd.DataFrame: |
| 29 | + """Fetch historical weather forecast data and return a pandas dataframe. |
| 30 | +
|
| 31 | + Args: |
| 32 | + service_address: The address of the service to connect to given in a |
| 33 | + form of a host followed by a colon and a port. |
| 34 | + feature_names: The list of forecast feature names. Each feature is a |
| 35 | + string representing a ForecastFeature enum value. |
| 36 | + locations: The list of locations to retrieve the forecast data for. |
| 37 | + Expects location as a tuple of (latitude, longitude) in this order. |
| 38 | + start_time: Start of the time range to get weather forecasts for. |
| 39 | + end_time: End of the time range to get weather forecasts for. |
| 40 | + file_to_store: The filename to optionally store the data. The data |
| 41 | + will be stored in the specified file format. Supported formats |
| 42 | + are 'csv' and 'parquet'. |
| 43 | +
|
| 44 | + Returns: |
| 45 | + A pandas dataframe containing the historical weather forecast data. |
| 46 | +
|
| 47 | + Raises: |
| 48 | + ValueError: If the file format is not supported. |
| 49 | + """ |
| 50 | + client = Client(service_address) |
| 51 | + |
| 52 | + features = [ForecastFeature[fn] for fn in feature_names] |
| 53 | + locations_in = [ |
| 54 | + Location(latitude=lat, longitude=lon, country_code="") |
| 55 | + for (lat, lon) in locations |
| 56 | + ] |
| 57 | + |
| 58 | + location_forecast_iterator = client.hist_forecast_iterator( |
| 59 | + features=features, locations=locations_in, start=start_time, end=end_time |
| 60 | + ) |
| 61 | + |
| 62 | + # The try and except block was added as a work-around until fixed in the service. |
| 63 | + # NOTE: Remove when fixed and uncomment the code block below. |
| 64 | + rows = [] |
| 65 | + try: |
| 66 | + async for forecasts in location_forecast_iterator: |
| 67 | + rows.extend(forecasts.flatten()) |
| 68 | + except grpcaio.AioRpcError: |
| 69 | + # this error occurs when forecasts for multiple locations are requested |
| 70 | + # can be ignored |
| 71 | + pass |
| 72 | + # rows = [ |
| 73 | + # item |
| 74 | + # async for forecasts in location_forecast_iterator |
| 75 | + # for item in forecasts.flatten() |
| 76 | + # ] |
| 77 | + |
| 78 | + df = pd.DataFrame(rows) |
| 79 | + valid_file_formats = ["csv", "parquet"] |
| 80 | + if file_to_store: |
| 81 | + file_format = file_to_store.split(".")[-1].lower() |
| 82 | + if file_format == "parquet": |
| 83 | + df.to_parquet(file_to_store) |
| 84 | + elif file_format == "csv": |
| 85 | + df.to_csv(file_to_store) |
| 86 | + else: |
| 87 | + raise ValueError( |
| 88 | + f"Unsupported file format: {file_format}. " |
| 89 | + f"Supported formats are: {', '.join(valid_file_formats)}." |
| 90 | + ) |
| 91 | + return df |
0 commit comments