From 9645e6d6de40e1cb1e45efe424ae6d0759d22d82 Mon Sep 17 00:00:00 2001 From: Ahmad Wahid <59763365+Ahmad-Wahid@users.noreply.github.com> Date: Wed, 26 Jul 2023 16:12:11 +0500 Subject: [PATCH] Forecasts can be limited to only the registered sensors (#13) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * check on sensors * Update OWM API version to 3 and auto version checker (#12) * change owm version to 3 and add version checker * rais a warning * try black only * make API_VERSION a module constant and add tested versions to the warning Signed-off-by: Nicolas Höning --------- Signed-off-by: Nicolas Höning Co-authored-by: Nicolas Höning * check on sensors * refactoring * refactoring --------- Signed-off-by: Nicolas Höning Co-authored-by: Nicolas Höning --- flexmeasures_openweathermap/utils/locating.py | 9 +-- flexmeasures_openweathermap/utils/owm.py | 67 +++++++++++-------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/flexmeasures_openweathermap/utils/locating.py b/flexmeasures_openweathermap/utils/locating.py index 35181ad..4506ce5 100644 --- a/flexmeasures_openweathermap/utils/locating.py +++ b/flexmeasures_openweathermap/utils/locating.py @@ -1,6 +1,7 @@ from typing import Tuple, List, Optional import click +from flask import current_app from flexmeasures.utils.grid_cells import LatLngGrid, get_cell_nums from flexmeasures import Asset, Sensor @@ -72,11 +73,11 @@ def get_locations( return locations -def find_weather_sensor_by_location_or_fail( +def find_weather_sensor_by_location( location: Tuple[float, float], max_degree_difference_for_nearest_weather_sensor: int, sensor_name: str, -) -> Sensor: +) -> Sensor | None: """ Try to find a weather sensor of fitting type close by. Complain if the nearest weather sensor is further away than some minimum degrees. @@ -96,11 +97,11 @@ def find_weather_sensor_by_location_or_fail( location[1] - weather_station.location[1] > max_degree_difference_for_nearest_weather_sensor ): - raise Exception( + current_app.logger.warning( f"[FLEXMEASURES-OWM] No sufficiently close weather sensor found (within {max_degree_difference_for_nearest_weather_sensor} {flexmeasures_inflection.pluralize('degree', max_degree_difference_for_nearest_weather_sensor)} distance) for measuring {sensor_name}! We're looking for: {location}, closest available: ({weather_station.location})" ) else: - raise Exception( + current_app.logger.warning( "[FLEXMEASURES-OWM] No weather sensor set up yet for measuring %s. Try the register-weather-sensor CLI task." % sensor_name ) diff --git a/flexmeasures_openweathermap/utils/owm.py b/flexmeasures_openweathermap/utils/owm.py index ba593c2..a35cf33 100644 --- a/flexmeasures_openweathermap/utils/owm.py +++ b/flexmeasures_openweathermap/utils/owm.py @@ -12,7 +12,7 @@ from flexmeasures.data.models.time_series import Sensor, TimedBelief from flexmeasures.data.utils import save_to_db -from .locating import find_weather_sensor_by_location_or_fail +from .locating import find_weather_sensor_by_location from ..sensor_specs import mapping from .modeling import ( get_or_create_owm_data_source, @@ -20,7 +20,7 @@ ) from .radiating import compute_irradiance - + API_VERSION = "3.0" @@ -103,8 +103,8 @@ def save_forecasts_in_db( datetime.fromtimestamp(fc["dt"], get_timezone()) ) click.echo(f"[FLEXMEASURES-OWM] Processing forecast for {fc_datetime} ...") + data_source = get_or_create_owm_data_source() for sensor_specs in mapping: - data_source = get_or_create_owm_data_source() sensor_name = str(sensor_specs["fm_sensor_name"]) owm_response_label = sensor_specs["owm_sensor_name"] if owm_response_label in fc: @@ -114,31 +114,37 @@ def save_forecasts_in_db( weather_sensors, max_degree_difference_for_nearest_weather_sensor, ) - if weather_sensor not in db_forecasts.keys(): - db_forecasts[weather_sensor] = [] - - fc_value = fc[owm_response_label] - - # the irradiance is not available in OWM -> we compute it ourselves - if sensor_name == "irradiance": - fc_value = compute_irradiance( - location[0], - location[1], - fc_datetime, - # OWM sends cloud cover in percent, we need a ratio - fc_value / 100.0, + if weather_sensor is not None: + click.echo( + f"Found pre-configured weather sensor {weather_sensor.name} ..." ) - data_source = get_or_create_owm_data_source_for_derived_data() - - db_forecasts[weather_sensor].append( - TimedBelief( - event_start=fc_datetime, - belief_time=now, - event_value=fc_value, - sensor=weather_sensor, - source=data_source, + if weather_sensor not in db_forecasts.keys(): + db_forecasts[weather_sensor] = [] + + fc_value = fc[owm_response_label] + + # the irradiance is not available in OWM -> we compute it ourselves + if sensor_name == "irradiance": + fc_value = compute_irradiance( + location[0], + location[1], + fc_datetime, + # OWM sends cloud cover in percent, we need a ratio + fc_value / 100.0, + ) + data_source = ( + get_or_create_owm_data_source_for_derived_data() + ) + + db_forecasts[weather_sensor].append( + TimedBelief( + event_start=fc_datetime, + belief_time=now, + event_value=fc_value, + sensor=weather_sensor, + source=data_source, + ) ) - ) else: # we will not fail here, but issue a warning msg = "No label '%s' in response data for time %s" % ( @@ -170,19 +176,22 @@ def get_weather_sensor( location: Tuple[float, float], weather_sensors: Dict[str, Sensor], max_degree_difference_for_nearest_weather_sensor: int, -) -> Sensor: +) -> Sensor | None: """Get the weather sensor for this own response label and location, if we haven't retrieved it already.""" sensor_name = str(sensor_specs["fm_sensor_name"]) if sensor_name in weather_sensors: weather_sensor = weather_sensors[sensor_name] else: - weather_sensor = find_weather_sensor_by_location_or_fail( + weather_sensor = find_weather_sensor_by_location( location, max_degree_difference_for_nearest_weather_sensor, sensor_name=sensor_name, ) weather_sensors[sensor_name] = weather_sensor - if weather_sensor.event_resolution != sensor_specs["event_resolution"]: + if ( + weather_sensor is not None + and weather_sensor.event_resolution != sensor_specs["event_resolution"] + ): raise Exception( f"[FLEXMEASURES-OWM] The weather sensor found for {sensor_name} has an unfitting event resolution (should be {sensor_specs['event_resolution']}, but is {weather_sensor.event_resolution}." )