forked from pvlib/pvlib-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsolcast.py
More file actions
448 lines (381 loc) · 13.7 KB
/
solcast.py
File metadata and controls
448 lines (381 loc) · 13.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
""" Functions to access data from the Solcast API.
"""
import requests
import pandas as pd
from dataclasses import dataclass
BASE_URL = "https://api.solcast.com.au/data"
@dataclass
class ParameterMap:
solcast_name: str
pvlib_name: str
conversion: callable = lambda x: x
# define the conventions between Solcast and PVLib nomenclature and units
VARIABLE_MAP = [
# air_temp -> temp_air (deg C)
ParameterMap("air_temp", "temp_air"),
# surface_pressure (hPa) -> pressure (Pa)
ParameterMap("surface_pressure", "pressure", lambda x: x*100),
# dewpoint_temp -> temp_dew (deg C)
ParameterMap("dewpoint_temp", "temp_dew"),
# gti (W/m^2) -> poa_global (W/m^2)
ParameterMap("gti", "poa_global"),
# wind_speed_10m (m/s) -> wind_speed (m/s)
ParameterMap("wind_speed_10m", "wind_speed"),
# wind_direction_10m (deg) -> wind_direction (deg)
ParameterMap("wind_direction_10m", "wind_direction"),
# azimuth -> solar_azimuth (degrees) (different convention)
ParameterMap(
"azimuth", "solar_azimuth", lambda x: -x % 360
),
# precipitable_water (kg/m2) -> precipitable_water (cm)
ParameterMap("precipitable_water", "precipitable_water", lambda x: x*10),
# zenith -> solar_zenith
ParameterMap("zenith", "solar_zenith")
]
def get_solcast_tmy(
latitude, longitude, api_key, map_variables=True, **kwargs
):
"""Get irradiance and weather for a
Typical Meteorological Year (TMY) at a requested location.
Data is derived from a multi-year time series selected to present the
unique weather phenomena with annual averages that are consistent with
long term averages. See [1]_ for details on the calculation.
Parameters
----------
latitude : float
in decimal degrees, between -90 and 90, north is positive
longitude : float
in decimal degrees, between -180 and 180, east is positive
api_key : str
To access Solcast data you will need an API key [2]_.
map_variables: bool, default: True
When true, renames columns of the DataFrame to pvlib variable names
where applicable. See variable :const:`VARIABLE_MAP`.
kwargs:
Optional parameters passed to the API.
See [3]_ for full list of parameters.
Returns
-------
data : pandas.DataFrame
containing the values for the parameters requested.The times
in the DataFrame index indicate the midpoint of each interval.
metadata: dict
latitude and longitude of the request.
Examples
--------
>>> df, meta = pvlib.iotools.solcast.get_solcast_tmy(
>>> latitude=-33.856784,
>>> longitude=151.215297,
>>> api_key="your-key"
>>> )
you can pass any of the parameters listed in the API docs,
like ``time_zone``. Here we set the value of 10 for
"10 hours ahead of UTC":
>>> df, meta = pvlib.iotools.solcast.get_solcast_tmy(
>>> latitude=-33.856784,
>>> longitude=151.215297,
>>> time_zone=10,
>>> api_key="your-key"
>>> )
References
----------
.. [1] `Solcast TMY Docs <https://solcast.com/tmy>`_
.. [2] `Solcast API Docs <https://docs.solcast.com.au/>`_
.. [3] `Get an API Key <https://toolkit.solcast.com.au/register>`_
"""
params = dict(
latitude=latitude,
longitude=longitude,
format="json",
**kwargs
)
data = _get_solcast(
endpoint="tmy/radiation_and_weather",
params=params,
api_key=api_key,
map_variables=map_variables
)
return data, {"latitude": latitude, "longitude": longitude}
def get_solcast_historic(
latitude,
longitude,
start,
api_key,
end=None,
duration=None,
map_variables=True,
**kwargs
):
"""Get historical irradiance and weather estimated actuals
for up to 31 days of data at a time for a requested location,
derived from satellite (clouds and irradiance
over non-polar continental areas) and
numerical weather models (other data).
Data is available from 2007-01-01T00:00Z up to real time estimated actuals.
Parameters
----------
latitude : float
in decimal degrees, between -90 and 90, north is positive
longitude : float
in decimal degrees, between -180 and 180, east is positive
start : datetime-like
First day of the requested period
end : optional, datetime-like
Last day of the requested period.
Must include one of ``end`` or ``duration``.
duration : optional, default is None
Must include either ``end`` or ``duration``.
ISO_8601 compliant duration for the historic data,
like "P1D" for one day of data.
Must be within 31 days of the ``start``.
map_variables: bool, default: True
When true, renames columns of the DataFrame to pvlib variable names
where applicable. See variable :const:`VARIABLE_MAP`.
api_key : str
To access Solcast data you will need an API key [1]_.
kwargs:
Optional parameters passed to the API.
See [2]_ for full list of parameters.
Returns
-------
data : pandas.DataFrame
containing the values for the parameters requested.The times
in the DataFrame index indicate the midpoint of each interval.
metadata: dict
latitude and longitude of the request.
Examples
--------
>>> df, meta = pvlib.iotools.solcast.get_solcast_historic(
>>> latitude=-33.856784,
>>> longitude=151.215297,
>>> start='2007-01-01T00:00Z',
>>> duration='P1D',
>>> api_key="your-key"
>>> )
you can pass any of the parameters listed in the API docs,
for example using the ``end`` parameter instead
>>> df, meta = pvlib.iotools.solcast.get_solcast_historic(
>>> latitude=-33.856784,
>>> longitude=151.215297,
>>> start='2007-01-01T00:00Z',
>>> end='2007-01-02T00:00Z',
>>> api_key="your-key"
>>> )
References
----------
.. [1] `Get an API Key <https://toolkit.solcast.com.au/register>`_
.. [2] `Solcast API Docs <https://docs.solcast.com.au/>`_
"""
params = dict(
latitude=latitude,
longitude=longitude,
start=start,
end=end,
duration=duration,
api_key=api_key,
format="json",
**kwargs
)
data = _get_solcast(
endpoint="historic/radiation_and_weather",
params=params,
api_key=api_key,
map_variables=map_variables
)
return data, {"latitude": latitude, "longitude": longitude}
def get_solcast_forecast(
latitude, longitude, api_key, map_variables=True, **kwargs
):
"""Get irradiance and weather forecasts from the present time
up to 14 days ahead
Parameters
----------
latitude : float
in decimal degrees, between -90 and 90, north is positive
longitude : float
in decimal degrees, between -180 and 180, east is positive
api_key : str
To access Solcast data you will need an API key [1]_.
map_variables: bool, default: True
When true, renames columns of the DataFrame to pvlib variable names
where applicable. See variable :const:`VARIABLE_MAP`.
kwargs:
Optional parameters passed to the API.
See [2]_ for full list of parameters.
Returns
-------
data : pandas.DataFrame
Contains the values for the parameters requested.The times
in the DataFrame index indicate the midpoint of each interval.
metadata: dict
latitude and longitude of the request.
Examples
--------
>>> df, meta = pvlib.iotools.solcast.get_solcast_forecast(
>>> latitude=-33.856784,
>>> longitude=151.215297,
>>> api_key="your-key"
>>> )
you can pass any of the parameters listed in the API docs,
like asking for specific variables:
>>> df, meta = pvlib.iotools.solcast.get_solcast_forecast(
>>> latitude=-33.856784,
>>> longitude=151.215297,
>>> output_parameters=['dni', 'clearsky_dni', 'snow_soiling_rooftop'],
>>> api_key="your-key"
>>> )
References
----------
.. [1] `Get an API Key <https://toolkit.solcast.com.au/register>`_
.. [2] `Solcast API Docs <https://docs.solcast.com.au/>`_
"""
params = dict(
latitude=latitude,
longitude=longitude,
format="json",
**kwargs
)
data = _get_solcast(
endpoint="forecast/radiation_and_weather",
params=params,
api_key=api_key,
map_variables=map_variables
)
return data, {"latitude": latitude, "longitude": longitude}
def get_solcast_live(
latitude, longitude, api_key, map_variables=True, **kwargs
):
"""Get irradiance and weather estimated actuals for near real-time
and past 7 days
Parameters
----------
latitude : float
in decimal degrees, between -90 and 90, north is positive
longitude : float
in decimal degrees, between -180 and 180, east is positive
api_key : str
To access Solcast data you will need an API key [1]_.
map_variables: bool, default: True
When true, renames columns of the DataFrame to pvlib variable names
where applicable. See variable :const:`VARIABLE_MAP`.
kwargs:
Optional parameters passed to the API.
See [2]_ for full list of parameters.
Returns
-------
data : pandas.DataFrame
containing the values for the parameters requested.The times
in the DataFrame index indicate the midpoint of each interval.
metadata: dict
latitude and longitude of the request.
Examples
--------
>>> df, meta = pvlib.iotools.solcast.get_solcast_live(
>>> latitude=-33.856784,
>>> longitude=151.215297,
>>> api_key="your-key"
>>> )
you can pass any of the parameters listed in the API docs, like
>>> df, meta = pvlib.iotools.solcast.get_solcast_live(
>>> latitude=-33.856784,
>>> longitude=151.215297,
>>> terrain_shading=True,
>>> output_parameters=['ghi', 'clearsky_ghi', 'snow_soiling_rooftop'],
>>> api_key="your-key"
>>> )
use ``map_variables=False`` to avoid converting the data
to PVLib's conventions.
>>> df, meta = pvlib.iotools.solcast.get_solcast_live(
>>> latitude=-33.856784,
>>> longitude=151.215297,
>>> map_variables=False,
>>> api_key="your-key"
>>> )
References
----------
.. [1] `Get an API Key <https://toolkit.solcast.com.au/register>`_
.. [2] `Solcast API Docs <https://docs.solcast.com.au/>`_
"""
params = dict(
latitude=latitude,
longitude=longitude,
format="json",
**kwargs
)
data = _get_solcast(
endpoint="live/radiation_and_weather",
params=params,
api_key=api_key,
map_variables=map_variables
)
return data, {"latitude": latitude, "longitude": longitude}
def _solcast2pvlib(data):
"""Formats the data from Solcast to PVLib's conventions.
Parameters
----------
data : pandas.DataFrame
contains the data as returned from the Solcast API
Returns
-------
a pandas.DataFrame with the data cast to PVLib's conventions
"""
# move from period_end to period_middle as per pvlib convention
data["period_mid"] = pd.to_datetime(
data.period_end) - pd.to_timedelta(data.period.values) / 2
data = data.set_index("period_mid").drop(columns=["period_end", "period"])
# rename and convert variables
for variable in VARIABLE_MAP:
if variable.solcast_name in data.columns:
data.rename(
columns={variable.solcast_name: variable.pvlib_name},
inplace=True
)
data[variable.pvlib_name] = data[
variable.pvlib_name].apply(variable.conversion)
return data
def _get_solcast(
endpoint,
params,
api_key,
map_variables
):
"""retrieves weather, irradiance and power data from the Solcast API
Parameters
----------
endpoint : str
one of Solcast API endpoint:
- live/radiation_and_weather
- forecast/radiation_and_weather
- historic/radiation_and_weather
- tmy/radiation_and_weather
params : dict
parameters to be passed to the API
api_key : str
To access Solcast data you will need an API key [1]_.
map_variables: bool, default: True
When true, renames columns of the DataFrame to PVLib's variable names
where applicable. See variable :const:`VARIABLE_MAP`.
Time is the index as midpoint of each interval
from Solcast's "period end" convention.
Returns
-------
A pandas.DataFrame with the data if the request is successful,
an error message otherwise
References
----------
.. [1] `register <https://toolkit.solcast.com.au/register>`
"""
response = requests.get(
url='/'.join([BASE_URL, endpoint]),
params=params,
headers={"Authorization": f"Bearer {api_key}"}
)
if response.status_code == 200:
j = response.json()
df = pd.DataFrame.from_dict(j[list(j.keys())[0]])
if map_variables:
return _solcast2pvlib(df)
else:
return df
else:
raise Exception(response.json())