from packaging import version from flask import current_app from flexmeasures.data.models.generic_assets import GenericAsset, GenericAssetType from flexmeasures import Source, __version__ as flexmeasures_version from flexmeasures.data import db from flexmeasures.data.services.data_sources import get_or_create_source from flexmeasures_weather import DEFAULT_DATA_SOURCE_NAME from flexmeasures_weather import WEATHER_STATION_TYPE_NAME from flexmeasures_weather import DEFAULT_WEATHER_STATION_NAME if version.parse(flexmeasures_version) < version.parse("0.13"): SOURCE_TYPE = "forecasting script" else: SOURCE_TYPE = "forecaster" FM_SUPPORTS_ACCOUNT_LINKED_SOURCES = version.parse( flexmeasures_version ) >= version.parse("0.32") if FM_SUPPORTS_ACCOUNT_LINKED_SOURCES: from flexmeasures import Account else: Account = None def get_or_create_weather_account(): """Make sure we have an account for the weather provider service.""" if Account is None: raise RuntimeError( "FlexMeasures Account model is unavailable before FlexMeasures 0.32." ) account_name = current_app.config.get( "WEATHER_DATA_SOURCE_NAME", DEFAULT_DATA_SOURCE_NAME ) weather_account = Account.query.filter( Account.name == account_name, ).one_or_none() if weather_account is None: weather_account = Account(name=account_name) db.session.add(weather_account) db.session.flush() return weather_account def get_or_create_owm_data_source() -> Source: """Make sure we have a weather provider data source of the configured type.""" source_kwargs = dict( source=current_app.config.get( "WEATHER_DATA_SOURCE_NAME", DEFAULT_DATA_SOURCE_NAME ), source_type=SOURCE_TYPE, flush=False, ) if FM_SUPPORTS_ACCOUNT_LINKED_SOURCES: source_kwargs["account"] = get_or_create_weather_account() return get_or_create_source(**source_kwargs) def get_or_create_owm_data_source_for_derived_data() -> Source: owm_source_name = current_app.config.get( "WEATHER_DATA_SOURCE_NAME", DEFAULT_DATA_SOURCE_NAME ) source_kwargs = dict( source=f"FlexMeasures {owm_source_name}", source_type=SOURCE_TYPE, flush=False, ) if FM_SUPPORTS_ACCOUNT_LINKED_SOURCES: source_kwargs["account"] = get_or_create_weather_account() return get_or_create_source(**source_kwargs) def get_or_create_weather_station_type() -> GenericAssetType: """Make sure a weather station type exists""" weather_station_type = GenericAssetType.query.filter( GenericAssetType.name == WEATHER_STATION_TYPE_NAME, ).one_or_none() if weather_station_type is None: weather_station_type = GenericAssetType( name=WEATHER_STATION_TYPE_NAME, description="A weather station with various sensors.", ) db.session.add(weather_station_type) return weather_station_type def get_or_create_weather_station(latitude: float, longitude: float) -> GenericAsset: """Make sure a weather station exists at this location.""" station_name = current_app.config.get( "WEATHER_STATION_NAME", DEFAULT_WEATHER_STATION_NAME ) weather_station = GenericAsset.query.filter( GenericAsset.latitude == latitude, GenericAsset.longitude == longitude ).one_or_none() if weather_station is None: weather_station_type = get_or_create_weather_station_type() weather_station = GenericAsset( name=station_name, generic_asset_type=weather_station_type, latitude=latitude, longitude=longitude, ) db.session.add(weather_station) return weather_station def get_weather_station_by_asset_id(asset_id: int) -> GenericAsset: weather_station = GenericAsset.query.filter( GenericAsset.generic_asset_type_id == asset_id ).one_or_none() if weather_station is None: raise Exception( f"[FLEXMEASURES-WEATHER] Weather station is not present for the given asset id '{asset_id}'." ) if weather_station.latitude is None or weather_station.longitude is None: raise Exception( f"[FLEXMEASURES-WEATHER] Weather station {weather_station} is missing location information [Latitude, Longitude]." ) return weather_station