Simple Python Web Service Client

Data Delivery Web service (the API for retrieving time series data)

if __name__ == '__main__': import requests import xmltodict # https://pypi.org/project/xmltodict/ import pandas as pd api_key = 'demo' dateFrom = '2024-05-01' dateTo = '2024-05-01' latitude = 48.61259 longitude = 20.827079 tilt = 40 azimuth = 180 request_xml = f'''<ws:dataDeliveryRequest dateFrom="{dateFrom}" dateTo="{dateTo}" xmlns="http://geomodel.eu/schema/data/request" xmlns:ws="http://geomodel.eu/schema/ws/data" xmlns:geo="http://geomodel.eu/schema/common/geo" xmlns:pv="http://geomodel.eu/schema/common/pv" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <site id="demo" lat="{latitude}" lng="{longitude}"> <pv:geometry xsi:type="pv:GeometryFixedOneAngle" tilt="{tilt}" azimuth="{azimuth}"/> <pv:system installedPower="1" installationType="ROOF_MOUNTED"> <pv:module type="CSI"/> <pv:inverter/> <pv:losses/> </pv:system> </site> <processing key="GHI DNI DIF GTI TEMP WS WD RH" summarization="HOURLY"> <timeZone>GMT+02</timeZone> <timestampType>START</timestampType> </processing> </ws:dataDeliveryRequest>''' url = f'https://solargis.info/ws/rest/datadelivery/request?key={api_key}' headers = {'Content-Type': 'application/xml'} with requests.post(url, data=request_xml, headers=headers) as response: if not response.ok: print(f'Failed API request with code {response.status_code}:\n{response.text}') else: datadict = xmltodict.parse(response.text) # transform XML document into Python dictionary columns = datadict['dataDeliveryResponse']['site']['columns'].split() # get names of columns (GHI, DNI, etc.) rows = datadict['dataDeliveryResponse']['site']['row'] # get rows or records from XML rows = rows if isinstance(rows, list) else [rows] timestamps = [r['@dateTime'] for r in rows] # use '@dateTime' for sub/hourly data, '@date' for daily data, '@yearMonth' for monthly data data_values = [r['@values'].split() for r in rows] # create pandas dataframe from the response data: df = pd.DataFrame(data_values, index=pd.to_datetime(timestamps), columns=columns) df = df.apply(pd.to_numeric, errors='coerce') # make numbers from original strings in XML print(df) print(df.describe()) # plot the response: # import matplotlib.pyplot as plt # df.plot() # plt.savefig('solargi_api_response.png')

LTA Web service (the API for retrieving long-term average data)

if __name__ == '__main__': import requests import xmltodict # https://pypi.org/project/xmltodict/ api_key = 'demo' latitude = 48.61259 longitude = 20.827079 tilt = 40 azimuth = 180 request_xml = f'''<calculateRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:geo="http://geomodel.eu/schema/common/geo" xmlns:pv="http://geomodel.eu/schema/common/pv" xmlns="http://geomodel.eu/schema/ws/pvplanner"> <site lat="{latitude}" lng="{longitude}"> <!-- optional terrain data --> <geo:terrain elevation="246" azimuth="176" tilt="3.1" /> <!-- optional custom horizon data can override the natural terrain horizon --> <!--<geo:horizon>11.11:18.0 7.5:15.53 15.0:10.94 352.5:17.29</geo:horizon>--> <pv:geometry xsi:type="pv:GeometryFixedOneAngle" azimuth="{azimuth}" tilt="{tilt}"/> <pv:system installedPower="1" installationType="ROOF_MOUNTED" availability="99"> <pv:module type="CSI"> </pv:module> <pv:inverter> <pv:efficiency xsi:type="pv:EfficiencyConstant" percent="97.5"/> </pv:inverter> <pv:losses dc="5.5" ac="1.5"/> </pv:system> </site> </calculateRequest>''' url = f'https://solargis.info/ws/rest/pvplanner/calculate?key={api_key}' headers = {'Content-Type': 'application/xml'} with requests.post(url, data=request_xml, headers=headers) as response: if not response.ok: print(f'Failed API request with code {response.status_code}:\n{response.text}') else: datadict = xmltodict.parse(response.text) # transform XML document into Python dictionary response_dict = datadict['ns3:calculateResponse'] # explore solar and climate data in the response: climate_data = response_dict['ns3:irradiation'] climate_data_reference = climate_data['ns3:reference'] # general climate data solar_data_inplane = climate_data['ns3:inplane'] # POA irradiance components geometry_comparison = climate_data['ns3:comparison'] # comparison of the various geometry options with selected one optimum_angle = climate_data.get('ns3:optimum') # optimum fixed angle for the selected location # get PV calculation data: pv_data = response_dict['ns3:calculation'] pv_data_output = pv_data['ns3:output'] # PV system output total and specific pv_data_losses = pv_data['ns3:losses'] # PV system losses breakdown print('Climate data reference:', climate_data_reference) print('Solar data in-plane:', solar_data_inplane) print('Geometry comparison:', geometry_comparison) print('Optimum angle:', optimum_angle) print('PV data output:', pv_data_output) print('PV data losses:', pv_data_losses)