Add FlexMeasures plugins, USEF protocol, and Cariflex simulator
- flexmeasures-entsoe: ENTSO-E data plugin - flexmeasures-weather: Weather data plugin - USEF Flex Trading Protocol PDF (2.4MB) - Cariflex simulator (publishes to Redis) - Dashboard Grafana updated with correct InfluxDB queries - All tools extracted in /tools/
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
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
|
||||
Reference in New Issue
Block a user