#!/bin/python3 import os import sys import json import psycopg2 import requests import xmltodict from datetime import datetime from datetime import timedelta from tzlocal import get_localzone from dateutil import tz # variables # Getting an api-key isn't very well documented. The documentation [1] points # to a pdf [2], which says the following: # > In order to request the access to the Restful API, please register on the # > Transparency Platform and send an email to transparency@entsoe.eu with # > “Restful API access” in the subject line. Indicate the email address you # > entered during registration in the email body. We will make our best to # > respond to your request. # 1: https://transparency.entsoe.eu/content/static_content/Static%20content/web%20api/Guide.html#_authentication_and_authorisation # 2: https://transparency.entsoe.eu/content/static_content/download?path=/Static%20content/API-Token-Management.pdf apiKey = os.environ['el_entsoe_token'] # https://transparency.entsoe.eu/content/static_content/Static%20content/web%20api/Guide.html apiUrl = "https://transparency.entsoe.eu/api?securityToken=" + apiKey pg_db = os.environ['el_pg_db'] pg_host = os.environ['el_pg_host'] pg_table = "entsoe" startTime = datetime.now(get_localzone()) - timedelta(days = 7) startTime = startTime.strftime('%Y%m%d') endTime = datetime.now(get_localzone()) + timedelta(days = 1) endTime = endTime.strftime('%Y%m%d') # https://transparency.entsoe.eu/content/static_content/Static%20content/web%20api/Guide.html#_areas areas = [ {"name": "NO-0", "code": "10YNO-0--------C"}, {"name": "NO-1", "code": "10YNO-1--------2"}, {"name": "NO-2", "code": "10YNO-2--------T"}, {"name": "NO-3", "code": "10YNO-3--------J"}, {"name": "NO-4", "code": "10YNO-4--------9"} ] UTC = tz.gettz('UTC') CET = tz.gettz('Europe/Oslo') # Get the data values=[] for area in areas: try: url = apiUrl + "&documentType=A44&in_Domain=" + area["code"] + "&out_Domain=" + area["code"] + "&periodStart=" + startTime + "0000&periodEnd=" + endTime + "0000" print("Getting data for " + area["code"]) response = requests.get(url) if response.status_code != 200: print(response.status_code) print("Oh shit") response.raise_for_status() except Exception as e: print("oh lol") sys.exit(e) data_dict = xmltodict.parse(response.content) items = 0 if "Publication_MarketDocument" in data_dict: for lista in data_dict["Publication_MarketDocument"]["TimeSeries"]: utctime = datetime.strptime(lista["Period"]["timeInterval"]["start"], "%Y-%m-%dT%H:%MZ") utctime = utctime.replace(tzinfo = UTC) cettime = utctime.astimezone(CET) items += len(lista["Period"]["Point"]) for item in lista["Period"]["Point"]: # the response contains timerange, but not timestamp for every price, so we must calculate it time = str(cettime + timedelta(hours = int(item["position"]) - 1)) # append values values.append((time, area["name"], item["price.amount"])) print("Got " + str(items) + " records") # connect to db conn = psycopg2.connect(database=pg_db, host=pg_host) cur = conn.cursor() # count rows before we start cur.execute("SELECT COUNT(*) FROM " + pg_table) before = cur.fetchone() # insert data print("Inserting into database") try: cur.executemany("INSERT INTO " + pg_table + " VALUES(%s,%s,%s) ON CONFLICT (starttime, zone) DO NOTHING", values) conn.commit() except Exception as e: conn.rollback() raise e # count rows after we finnish cur.execute("SELECT COUNT(*) FROM " + pg_table) after = cur.fetchone() # count *new* rows newRows = after[0] - before[0] # close connection conn.close() print("Successfully inserted " + str(newRows) + " records into the database")