def bm_generation_type(args): """ BMReport Generation Type """ gdd = GenerationData() gdd.get_data() data = gdd.as_dict() fmt = StdoutFormatter("8s", "40s", "5s", "10d", "12.3f") row_titles = fmt.titles('Code', 'Generation Type', 'Intcr', 'Output', 'Percentage') print(data) for sect in data.keys(): if 'start' in data[sect]: print("{} - started {}".format(sect.title(), data[sect]['start'])) if 'finish' in data[sect]: print("{} - finished {}".format(" " * len(sect.title()), data[sect]['finish'])) else: print(sect.title()) print("\n" + row_titles) for typ in data[sect]['data']: print( fmt.row(typ['code'], typ['name'], ' Y' if typ['interconnector'] else ' N', typ['value'], typ['percent'])) print("\n") return gdd
def elexon_b1320(args): """ Congestion Management Measures Countertrading """ if not check_api_key(args): return None print("This report has *VERY* sparse data.") api = B1320(args.apikey) if args.date is None: print("You MUST supply a date for this report.") return None if args.period is None: print("You MUST supply a period for this report, from 1 to 50") return None params = {'SettlementDate': args.date, 'Period': args.period} if get_check_data(api, params) is False: return None fmt = StdoutFormatter("12s", "8s", "10.4f", "9s", "6s", "20s", "10s") print("\n" + fmt.titles('Date', 'Period', 'Quantity', 'Direction', 'Active', 'Reason', 'Resolution')) for item in api.items: print(fmt.row(item['settlementdate'], item['settlementperiod'], item['quantity'], item['flowdirection'], str(item['activeflag']), item['reasoncode'], item['resolution'])) return api
def elexon_b1630(args): """ Actual or forecast Wind & Solar Generation """ if not check_api_key(args): return None api = B1630(args.apikey) if args.settlement_period is None: print("A settlement period should be supplied using the --settlement-period flag (range 1 to 50)." "Defaulting to 1") if args.date is None: print("A date should be supplied using the --date flag. Format is YYYY-MM-DD. Defaulting to today") if not api.get_data(**{'SettlementDate': args.date or date.today().strftime("%Y-%m-%d"), 'Period': args.settlement_period or 1}): print("No data returned.") return None fmt = StdoutFormatter("10s", "6s", "6s", "10.1f", "20s", "30s") print("\n" + fmt.titles('Date', 'Period', 'Active', 'Output', 'Type', 'Reference')) for item in sorted(api.items, key=lambda xxx: xxx['documentid']): print(fmt.row(item['settlementdate'], str(item['settlementperiod']), str(item['activeflag']), float(item['quantity']), item.get('powersystemresourcetype', 'n/a'), item['documentid'] + " - " + item['documentrevnum'])) return api
def elexon_sbp(args): """ Derived System Prices from Elexon """ if not check_api_key(args): return None api = DERSYSDATA(args.apikey) params = { 'FromSettlementDate': args.fromdate or date.today() - timedelta(days=1), 'ToSettlementDate': args.todate or args.fromdate or (date.today()) - timedelta(days=1) } if args.period is not None: params['SettlementPeriod'] = args.period if args.all_periods: params['SettlementPeriod'] = '*' if get_check_data(api, params) is False: return None fmt = StdoutFormatter("15s", "^20d", "15.4f", "15.4f", "4s") print("\nSystem adjustments are included in the figures shown below where '*' is shown.\n") print("\n" + fmt.titles('Date', 'Settlement Period', 'Sell Price', 'Buy Price', 'Adj?')) for item in api.items: print(fmt.row(item['settlementdate'].strftime("%Y %b %d"), item['settlementperiod'], item['systemsellprice'] + item['sellpriceadjustment'], item['systembuyprice'] + item['buypriceadjustment'], "*" if item['sellpriceadjustment'] + item['buypriceadjustment'] > 0 else '' )) return api
def power_pack_units(args): """ National Grid Power Pack Units """ ppu = PowerPackUnits() if ppu.get_list() is False: print("Unable to get an updated list of power pack units") sys.exit(0) print("Total of {} units".format(len(ppu))) fmt = StdoutFormatter('12s', '12s', '35s', '>10f', '12s', '8s', '>12f') print( fmt.titles("NGC Id", "Sett ID", "Station Name", "Reg Cap", "Date Added", "BM Unit?", "Capacity")) for unit in ppu.units: vals = [ unit.get('ngc_id'), unit.get('sett_id', 'n/a'), unit.get('name'), unit.get('reg_capacity', ''), unit.get('date_added'), "Yes" if unit.get('bmunit') else "No", unit.get('cap', 0.0) ] if vals[4] is not None: vals[4] = vals[4].strftime("%d %b %Y") else: vals[4] = 'Unknown' print(fmt.row(*vals)) return ppu
def elexon_bm_unit(args): """ Balancing Mechanism Unit information from Elexon """ if not check_api_key(args): return None api = BMUNITSEARCH(args.apikey) params = { 'BMUnitType': args.unit_type or '*' } if not get_check_data(api, params): return None print("Total of {} units\n".format(len(api.items))) fmt = StdoutFormatter('12s', '12s', '^8s', '30s', '50s') print("\n" + fmt.titles('NGC ID', 'BM ID', 'Active ?', 'BM Type', 'Lead Party Name')) for item in sorted(api.items, key=lambda x: x['ngcbmunitname']): print(fmt.row(item['ngcbmunitname'], item['bmunitid'], 'Y' if item['activeflag'] else 'N', "{}, {}".format(item['bmunittype'], item['category']), item['leadpartyname'])) return api
def elexon_bm_data(args): """ Derived System Prices from Elexon """ if not check_api_key(args): return None bd = BalancingData(args.apikey) params = { 'SettlementDate': args.date or date.today() - timedelta(days=1), 'SettlementPeriod': args.period or 1 } if args.all_periods: params['SettlementPeriod'] = '*' if not bd.get_data(**params): return None fmt = StdoutFormatter('12s', '^7d', '16.4f', '16.4f', '18.4f', '18.4f', '12.4f', '12.4f') print("\n" + fmt.titles('Unit Name', 'Period', 'Bid Volume', 'Offer Volume', 'Bid Cashflow', 'Offer Cashflow', 'Bid Rate', 'Offer Rate')) for unit_name in sorted(bd.units): unit = bd.units[unit_name] for period in sorted(unit.periods): pd = unit.periods[period] print(fmt.row(unit.unit, period, pd.bid_volume, pd.offer_volume, pd.bid_cashflow, pd.offer_cashflow, pd.bid_rate, pd.offer_rate)) return bd.api
def bm_generation_type(args): """ BMReport Generation Type """ gdd = GenerationData() gdd.get_data() data = gdd.as_dict() fmt = StdoutFormatter("8s", "40s", "5s", "10d", "12.3f") row_titles = fmt.titles('Code', 'Generation Type', 'Intcr', 'Output', 'Percentage') print(data) for sect in data.keys(): if 'start' in data[sect]: print("{} - started {}".format(sect.title(), data[sect]['start'])) if 'finish' in data[sect]: print("{} - finished {}".format(" " * len(sect.title()), data[sect]['finish'])) else: print(sect.title()) print("\n" + row_titles) for typ in data[sect]['data']: print(fmt.row(typ['code'], typ['name'], ' Y' if typ['interconnector'] else ' N', typ['value'], typ['percent'])) print("\n") return gdd
def power_pack_units(args): """ National Grid Power Pack Units """ ppu = PowerPackUnits() if ppu.get_list() is False: print("Unable to get an updated list of power pack units") sys.exit(0) print("Total of {} units".format(len(ppu))) fmt = StdoutFormatter('12s', '12s', '35s', '>10f', '12s', '8s', '>12f') print(fmt.titles("NGC Id", "Sett ID", "Station Name", "Reg Cap", "Date Added", "BM Unit?", "Capacity")) for unit in ppu.units: vals = [ unit.get('ngc_id'), unit.get('sett_id', 'n/a'), unit.get('name'), unit.get('reg_capacity', ''), unit.get('date_added'), "Yes" if unit.get('bmunit') else "No", unit.get('cap', 0.0) ] if vals[4] is not None: vals[4] = vals[4].strftime("%d %b %Y") else: vals[4] = 'Unknown' print(fmt.row(*vals)) return ppu
def bm_unitlist(args): """ BMReport Unit List """ ulist = UnitList() if ulist.get_list() is False: print("There was an error getting the list from the BMReports website") sys.exit(0) print("Total of {} units\n".format(len(ulist))) fmt = StdoutFormatter('12s', '12s', '10s', '12s', '12s') print(fmt.titles('NGC ID', 'Sett Id', 'Fuel Type', 'Eff. From', 'Eff. To')) for unit in ulist.units: vals = [unit['ngc_id'], unit.get('sett_id', ''), unit['fuel_type'], unit['eff_from'].strftime("%d %b %Y")] if unit['eff_to'] is not None: vals.append(unit['eff_to'].strftime("%d %b %Y")) else: vals.append('n/a') print(fmt.row(*vals)) return ulist
def elexon_b1330(args): """ Congestion Management Measures Costs of Congestion Management Service """ if args.apikey is None: print("You MUST supply an API key to access Elexon data") return None if args.year is None: print("You MUST supply a year for this report.") return None if args.month is None: print("You MUST supply a month for this report.") return None MONTHS = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] api = B1330(args.apikey) params = {'Year': args.year or 2016, 'Month': MONTHS[args.month - 1 or 8]} if get_check_data(api, params) is False: return None fmt = StdoutFormatter("4d", "5s", "40s", "8s") print("\n" + fmt.titles('Year', 'Mon', 'Document Id', 'Rev. Num')) for item in api.items: print(fmt.row(item['year'], item['month'], item['documentid'], item['documentrevnum'])) return api
def main(): parser = commandline_parser( 'Get ofgem certificates for a given month & year') parser.add_argument('--generator', action='store', help='Generator ID to search for') args = parser.parse_args() setup_logging(args.debug, request_logging=args.request_debug) print("Contacting Ofgem and preparing to search.\n") ocs = CertificateSearch() ocs.start() print("Filtering search:") if args.station: print(" - cannot filter results based on station name") if args.scheme: if ocs.filter_scheme(args.scheme): print(" - scheme {}".format(args.scheme)) else: print("\nFailed to filter for scheme.") sys.exit(0) if args.generator: if ocs.filter_generator_id(args.generator.upper()): print(" - generator id {}".format(args.generator.upper())) else: print("\nFailed to filter by generator") sys.exit(0) if args.period: if ocs.set_period(args.period): print(' - period should be {}'.format(args.period)) else: print("\nFailed to set period") sys.exit(0) if ocs.get_data() is False: print("No data was returned from the Ofgem server") sys.exit(0) print("Total of %d records returned" % len(ocs)) fmt = StdoutFormatter("10s", "8s", "35s", "6s", "10s", "12d") print( fmt.titles("Issue Date", "Period", "Station Name", "Scheme", "Status", "Certificates")) for cert in ocs.certificates(): print( fmt.row(cert.issue_dt.strftime("%Y-%m-%d"), cert.period, cert.name, cert.scheme, cert.status, cert.certificates))
def main(): parser = commandline_parser('Get ofgem certificates for a given month & year') parser.add_argument('--generator', action='store', help='Generator ID to search for') args = parser.parse_args() setup_logging(args.debug, request_logging=args.request_debug) print("Contacting Ofgem and preparing to search.\n") ocs = CertificateSearch() ocs.start() print("Filtering search:") if args.station: print(" - cannot filter results based on station name") if args.scheme: if ocs.filter_scheme(args.scheme): print(" - scheme {}".format(args.scheme)) else: print("\nFailed to filter for scheme.") sys.exit(0) if args.generator: if ocs.filter_generator_id(args.generator.upper()): print(" - generator id {}".format(args.generator.upper())) else: print("\nFailed to filter by generator") sys.exit(0) if args.period: if ocs.set_period(args.period): print(' - period should be {}'.format(args.period)) else: print("\nFailed to set period") sys.exit(0) if ocs.get_data() is False: print("No data was returned from the Ofgem server") sys.exit(0) print("Total of %d records returned" % len(ocs)) fmt = StdoutFormatter("10s", "8s", "35s", "6s", "10s", "12d") print(fmt.titles("Issue Date", "Period", "Station Name", "Scheme", "Status", "Certificates")) for cert in ocs.certificates(): print(fmt.row(cert.issue_dt.strftime("%Y-%m-%d"), cert.period, cert.name, cert.scheme, cert.status, cert.certificates))
def roc_prices(args): """ eROC Auction Prices """ roc = EROCPrices() if not roc.get_prices(): print("Unable to get prices from eROC website.") sys.exit(0) fmt = StdoutFormatter("<12s", "11.2f") print(fmt.titles("Period", "Average Price")) for price in roc.prices(): print(fmt.row(*price)) return roc
def bm_system_prices(args): """ BMReport System Price Data """ if args.date is not None: spp = SystemPrices(dtt=args.date) else: spp = SystemPrices() print("\nNo date specified, using today.\n") if spp.get_data() is False: print("Failed to get data from remote server.") sys.exit(0) print("Date: {}".format(spp.dtt)) fmt = StdoutFormatter('6s', '>10s', '>10s') print(fmt.titles("Period", 'SBP', 'SSP')) for prc in spp.prices: print(fmt.row(str(prc['period']), prc['sbp'], prc['ssp'])) return spp
def bm_unitdata(args): """ BMReport Unit Constraint Data The data can be filtered by date and or period using the --date and --period flags. :Example: To obtain data for period 5, 1st Jan 2016 .. code-block: $ pywind bm_unitdata --date 2016-01-01 --period 5 """ if args.date is not None: udd = UnitData(date=args.date) else: udd = UnitData() print("No date supplied, getting information for yesterday, {}.\n". format(udd.date)) if args.period is not None: udd.period = args.period if udd.get_data() is False: print("Unable to get unit data.") sys.exit(0) print("Data is for period {}, {}".format(udd.period, udd.date)) fmt = StdoutFormatter('9s', '30s', '>10.4f', '>10s', '>10.4f', '>10s', '>10.4f', '>10.4f', '>10.4f', ">10.4f") print("{:43s} Bid Volume Offer Volume Cashflow". format(' ')) print( fmt.titles("NGC", 'Lead', 'Original', 'Tagged', 'Original', 'Tagged', 'Bid', 'Offer', 'Bid Rate', 'Offer Rate')) for bmu in udd.data: print( fmt.row( bmu.id, bmu.lead, bmu.bid_volume, multi_level_get(bmu.volume, 'bid_values.tagged.total.value', 'n/a'), bmu.offer_volume, multi_level_get(bmu.volume, 'offer_values.tagged.total.value', 'n/a'), bmu.bid_cashflow, bmu.offer_cashflow, bmu.rate("bid"), bmu.rate("offer"))) return udd
def elexon_generation_inst(args): """ Generation Data at 5 minute intervals from the Elexon Data Portal """ if not check_api_key(args): return None api = FUELINST(args.apikey) args_get_datetime(args) params = {} if args.fromdatetime is not None or args.todatetime is not None: params['FromDateTime'] = args.fromdatetime if args.fromdatetime else args.todatetime - timedelta(days=1) params['ToDateTime'] = args.todatetime if args.todatetime else args.fromdatetime + timedelta(days=1) else: print("Getting data for yesterday as no dates specified.") params['FromDateTime'] = datetime.combine(date.today() - timedelta(days=2), time(23, 59)) params['ToDateTime'] = datetime.combine(date.today() - timedelta(days=1), time(23, 59)) if get_check_data(api, params) is False: return None fmt = StdoutFormatter("10s", "6s", "7s", "7s", "7s", "7s", "7s", "7s", "7s", "7s", "7s", "7s", "7s", "7s", "7s", "7s") print("\n" + fmt.titles('Date', 'Time', 'Period', 'CCGT', 'Oil', 'Coal', 'Nuclear', 'Wind', 'PS', 'NPSHYD', 'OCGT', 'Other', 'Int Fr', 'Int Irl', 'Int Ned', 'Int E/W')) for item in api.items: print(fmt.row(item['date'].strftime("%Y-%m-%d"), item['time'].strftime("%H:%M"), item['settlementperiod'], item['ccgt'], item['oil'], item['coal'], item['nuclear'], item['wind'], item['ps'], item['npshyd'], item['ocgt'], item['other'], item['intfr'], item['intirl'], item['intned'], item['intew'], )) return api
def elexon_b1420(args): """ Installed Generation Capacity per Unit """ if not check_api_key(args): return None api = B1420(args.apikey) if not api.get_data(**{'Year': args.year or 2016}): print("No data returned.") return None fmt = StdoutFormatter("30s", "8s", "10s", "6s", "10.1f", "20s") print("\n" + fmt.titles('Resource Name', 'NGC Id', 'BM Unit Id', 'Active', 'Output', 'Type')) for item in sorted(api.items, key=lambda xxx: xxx['ngcbmunitid']): print(fmt.row(item['registeredresourcename'], item['ngcbmunitid'], item['bmunitid'], str(item['activeflag']), float(item['nominal']), item.get('powersystemresourcetype', 'n/a'))) return api
def bm_unitdata(args): """ BMReport Unit Constraint Data The data can be filtered by date and or period using the --date and --period flags. :Example: To obtain data for period 5, 1st Jan 2016 .. code-block: $ pywind bm_unitdata --date 2016-01-01 --period 5 """ if args.date is not None: udd = UnitData(date=args.date) else: udd = UnitData() print("No date supplied, getting information for yesterday, {}.\n".format(udd.date)) if args.period is not None: udd.period = args.period if udd.get_data() is False: print("Unable to get unit data.") sys.exit(0) print("Data is for period {}, {}".format(udd.period, udd.date)) fmt = StdoutFormatter('9s', '30s', '>10.4f', '>10s', '>10.4f', '>10s', '>10.4f', '>10.4f', '>10.4f', ">10.4f") print("{:43s} Bid Volume Offer Volume Cashflow".format(' ')) print(fmt.titles("NGC", 'Lead', 'Original', 'Tagged', 'Original', 'Tagged', 'Bid', 'Offer', 'Bid Rate', 'Offer Rate')) for bmu in udd.data: print(fmt.row(bmu.id, bmu.lead, bmu.bid_volume, multi_level_get(bmu.volume, 'bid_values.tagged.total.value', 'n/a'), bmu.offer_volume, multi_level_get(bmu.volume, 'offer_values.tagged.total.value', 'n/a'), bmu.bid_cashflow, bmu.offer_cashflow, bmu.rate("bid"), bmu.rate("offer"))) return udd
def test_stdout_formatter(self): """ Test StdoutFormatter class """ for case in [ (('5s', '5s'), ('abcde', 'abcde'), 2, " abcde abcde\n ----- -----", ('hello', 'world'), ' hello world'), (('5s', '5.1f'), ('abcde', 'abcde'), 2, " abcde abcde\n ----- -----", ('world', 1.1), ' world 1.1'), ]: fmt = StdoutFormatter(*case[0]) self.assertIsInstance(fmt, StdoutFormatter) self.assertEqual(len(fmt.columns), case[2]) self.assertEqual(fmt.titles(*case[1]), case[3]) self.assertEqual(fmt.row(*case[4]), case[5]) fmt2 = StdoutFormatter("5.2f") with self.assertRaises(ValueError): fmt2.row("hello") fmt2.row(123) fmt2.row(None) self.assertEqual(fmt2.row(123.45), " 123.45")
def main(): parser = commandline_parser('Search ofgem database for matching stations') parser.add_argument('--generator', action='store', help='Generator ID to search for') parser.add_argument('--organisation', action='store', help='Organisation to search for') args = parser.parse_args() if args.station is None and \ args.generator is None and \ args.organisation is None: print("You must specify either a name, generator id or organisation") sys.exit(0) setup_logging(args.debug, request_logging=args.request_debug) print("Connecting with Ofgem website and preparing the search...") osd = StationSearch() osd.start() print("Setting up filters:") if args.station is not None: osd.filter_name(args.station) print(" - station name contains {}".format(args.station)) if args.organisation: osd.filter_organisation(args.organisation) print(" - organisation contains {}".format(args.organisation)) if args.generator: if args.generator.upper()[0] in ['R', 'P']: osd.filter_scheme('RO') elif args.generator.upper()[0] == 'G': osd.filter_scheme('REGO') osd.filter_generator_id(args.generator.upper()) print(" - generator ID is {}".format(args.generator.upper())) print("\nGetting results from Ofgem...\n") if osd.get_data() is False: print("Search returned no data") sys.exit(0) print("Query returned {} result{}".format(len(osd), '' if len(osd) == 0 else 's')) fmt = StdoutFormatter("35s", "13s", "12.2f", "20s", "20s", "15s") print( fmt.titles("Station Name", "Commission Dt", "Capacity", "Technology", "Country", "Generator ID")) for stat in osd.rows(): # The rows() output is intended for exporting, so fields will have '@' prepended # if they are attributes. # This could also be done by using osd.stations station = stat.get('Station') if station is None: continue cdt = station.get('@commission_dt') print( fmt.row(station.get('@name'), cdt.strftime("%Y-%m-%d") if cdt else 'n/a', station.get('@capacity'), station.get('@technology'), station.get('@country'), station.get('@generator_id')))
def main(): parser = commandline_parser('Search ofgem database for matching stations') parser.add_argument('--generator', action='store', help='Generator ID to search for') parser.add_argument('--organisation', action='store', help='Organisation to search for') args = parser.parse_args() if args.station is None and \ args.generator is None and \ args.organisation is None: print("You must specify either a name, generator id or organisation") sys.exit(0) setup_logging(args.debug, request_logging=args.request_debug) print("Connecting with Ofgem website and preparing the search...") osd = StationSearch() osd.start() print("Setting up filters:") if args.station is not None: osd.filter_name(args.station) print(" - station name contains {}".format(args.station)) if args.organisation: osd.filter_organisation(args.organisation) print(" - organisation contains {}".format(args.organisation)) if args.generator: if args.generator.upper()[0] in ['R', 'P']: osd.filter_scheme('RO') elif args.generator.upper()[0] == 'G': osd.filter_scheme('REGO') osd.filter_generator_id(args.generator.upper()) print(" - generator ID is {}".format(args.generator.upper())) print("\nGetting results from Ofgem...\n") if osd.get_data() is False: print("Search returned no data") sys.exit(0) print("Query returned {} result{}".format(len(osd), '' if len(osd) == 0 else 's')) fmt = StdoutFormatter("35s", "13s", "12.2f", "20s", "20s", "15s") print(fmt.titles("Station Name", "Commission Dt", "Capacity", "Technology", "Country", "Generator ID")) for stat in osd.rows(): # The rows() output is intended for exporting, so fields will have '@' prepended # if they are attributes. # This could also be done by using osd.stations station = stat.get('Station') if station is None: continue cdt = station.get('@commission_dt') print(fmt.row(station.get('@name'), cdt.strftime("%Y-%m-%d") if cdt else 'n/a', station.get('@capacity'), station.get('@technology'), station.get('@country'), station.get('@generator_id')))