The energy forecast (in kWh) is required for Solar PV power plants for the energy management system and/or to inform the TSOs. These data is stored on Meteo for Energy databases and also available for the user in case third party services require this information.
This example will show:
# First of all, import required packages
%matplotlib inline
import datetime
import requests
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
url_base = 'https://api.meteoforenergy.com/Meteo_WIND/v1'
/usr/local/lib/python3.6/dist-packages/pandas/compat/_optional.py:124: UserWarning: Pandas requires version '1.2.1' or newer of 'bottleneck' (version '1.2.0' currently installed). warnings.warn(msg, UserWarning)
Now, we can start preparing our request of energy generation for a site. Note that we will request the time series (ts) of the forecast (pred).
url = url_base + '/pred/ts/'
# Time period that we will request
datePred = datetime.datetime(2021,10,13,0,0,0)
# Define required GET parameters for the request
headers = {}
headers['X-Auth-Token-Site'] = 'Your API token' # Your site eToken
params = {}
params['market'] = 'spot' # spot / intraday / xbid
params['datetime_pred'] = datePred # datetime_pred requires ISO8601 format
params['proba'] = True # False or True if 10/25/75/90 percentile is required
params['midnight'] = True # Forecast time series starts from local midnight
# Request to the API the data defined on the parameters
r = requests.get(url, params=params, headers=headers)
print(r.text[:200])
if( r.status_code == 200 ):
df = pd.DataFrame(r.json()['data']) # or r.json().get('data')
print(df.head())
print(df.info())
{"name":"Atalaya","lat":41.8028,"lon":-1.29533,"market":"spot","datetime_pred":"2021-10-13T02:00:00+02:00","probability":true,"unit":"kWh","files":3,"data":[{"time_unix":1634076000,"datetime_iso8601": time_unix datetime_iso8601 datetime_local pred_mean \ 0 1634076000 2021-10-12T22:00:00.000Z 2021-10-13 00:00 427 1 1634079600 2021-10-12T23:00:00.000Z 2021-10-13 01:00 385 2 1634083200 2021-10-13T00:00:00.000Z 2021-10-13 02:00 333 3 1634086800 2021-10-13T01:00:00.000Z 2021-10-13 03:00 310 4 1634090400 2021-10-13T02:00:00.000Z 2021-10-13 04:00 271 pred_p10 pred_p25 pred_p75 pred_p90 0 83 282 572 651 1 74 264 528 634 2 73 237 453 581 3 65 190 449 575 4 65 190 435 531 <class 'pandas.core.frame.DataFrame'> RangeIndex: 147 entries, 0 to 146 Data columns (total 8 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 time_unix 147 non-null int64 1 datetime_iso8601 147 non-null object 2 datetime_local 147 non-null object 3 pred_mean 147 non-null int64 4 pred_p10 147 non-null int64 5 pred_p25 147 non-null int64 6 pred_p75 147 non-null int64 7 pred_p90 147 non-null int64 dtypes: int64(6), object(2) memory usage: 9.3+ KB None
The response is a JSON that is converted to a DataFrame, but all the types are not correctly parsed.
So we need to define correctly the datetime
column and define it on our desired time zone (List of tz database time zones), as it is localized in UTC
time zone.
# Convert type from object to datetime, and then localize o
df['datetime_iso8601'] = pd.to_datetime(df['datetime_iso8601']) # datetime: object -> datetime64[ns, UTC]
df['datetime_local'] = df['datetime_iso8601'].dt.tz_convert('Europe/Madrid') # datetime: datetime64[ns, UTC] -> datetime64[ns, Europe/Madrid]
print(df.head())
print(df.dtypes)
time_unix datetime_iso8601 datetime_local pred_mean \ 0 1634076000 2021-10-12 22:00:00+00:00 2021-10-13 00:00:00+02:00 427 1 1634079600 2021-10-12 23:00:00+00:00 2021-10-13 01:00:00+02:00 385 2 1634083200 2021-10-13 00:00:00+00:00 2021-10-13 02:00:00+02:00 333 3 1634086800 2021-10-13 01:00:00+00:00 2021-10-13 03:00:00+02:00 310 4 1634090400 2021-10-13 02:00:00+00:00 2021-10-13 04:00:00+02:00 271 pred_p10 pred_p25 pred_p75 pred_p90 0 83 282 572 651 1 74 264 528 634 2 73 237 453 581 3 65 190 449 575 4 65 190 435 531 time_unix int64 datetime_iso8601 datetime64[ns, UTC] datetime_local datetime64[ns, Europe/Madrid] pred_mean int64 pred_p10 int64 pred_p25 int64 pred_p75 int64 pred_p90 int64 dtype: object
Similarly, we can also use Unix Epoch Time to make the same transformation
# datetime: Unix epoch time -> datetime64[ns, Europe/Madrid]
df['datetime_local'] = pd.to_datetime(df['time_unix'], unit='s').dt.tz_localize('UTC').dt.tz_convert('Europe/Madrid')
print(df.head())
print(df.dtypes)
time_unix datetime_iso8601 datetime_local pred_mean \ 0 1634076000 2021-10-12 22:00:00+00:00 2021-10-13 00:00:00+02:00 427 1 1634079600 2021-10-12 23:00:00+00:00 2021-10-13 01:00:00+02:00 385 2 1634083200 2021-10-13 00:00:00+00:00 2021-10-13 02:00:00+02:00 333 3 1634086800 2021-10-13 01:00:00+00:00 2021-10-13 03:00:00+02:00 310 4 1634090400 2021-10-13 02:00:00+00:00 2021-10-13 04:00:00+02:00 271 pred_p10 pred_p25 pred_p75 pred_p90 0 83 282 572 651 1 74 264 528 634 2 73 237 453 581 3 65 190 449 575 4 65 190 435 531 time_unix int64 datetime_iso8601 datetime64[ns, UTC] datetime_local datetime64[ns, Europe/Madrid] pred_mean int64 pred_p10 int64 pred_p25 int64 pred_p75 int64 pred_p90 int64 dtype: object
It's time to plot the information requested
# Set `datetime` as index to show on X axis
if(df.index.name != 'datetime_local'):
df = df.set_index('datetime_local')
OX = df.index + pd.Timedelta(minutes=30) # As values are hourly averages, we centre at XX:30
fig = plt.figure(figsize=(14,6), dpi=80)
plt.plot(OX, df['pred_mean'], c='#95c11f', marker='o',lw=2, label=u'Forecast')
plt.fill_between(OX, df['pred_p25'], df['pred_p75'],alpha=0.5, fc='#95c11f', ec='None', label='25%-75%')
plt.fill_between(OX, df['pred_p10'], df['pred_p90'],alpha=0.2, fc='#95c11f', ec='None', label='10%-90%')
plt.title('Meteo for Energy forecast. %s' % (datePred.strftime('%Y-%m-%d')), fontsize=24, fontweight='bold')
plt.xlabel('datetime', fontsize=16, fontweight='bold')
plt.ylabel('Energy [$kWh$]', fontsize=16, fontweight='bold')
plt.legend(loc='upper right')
plt.grid()
plt.show()