Skip to content

Instantly share code, notes, and snippets.

@pakdev
Last active January 20, 2023 15:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pakdev/2faf62302c831e8f180dc458d4266818 to your computer and use it in GitHub Desktop.
Save pakdev/2faf62302c831e8f180dc458d4266818 to your computer and use it in GitHub Desktop.
Calculates projected yearly power costs for all the providers on powertochoose.org using historical usage
import sys
from collections import namedtuple
from datetime import datetime
from operator import attrgetter
import numpy
import requests
Option = namedtuple('Option', 'plan price')
def get_plans(include_tiered):
url = 'http://powertochoose.org/en-us/service/v1/'
r = requests.post(url, json={
'method': 'plans',
'zip_code': '78728',
'estimated_use': 1000,
'include_details': True,
'min_usage_plan': '' if include_tiered else 'off',
'plan_type': '1,2' # 1: Fixed, 0: Variable, 2: Indexed
})
return r.json()
def get_options(plans, tiered):
options = []
incomplete_options = []
for plan in plans:
x = [500, 1000, 2000]
y = [
plan['price_kwh500'],
plan['price_kwh1000'],
plan['price_kwh2000']
]
plan['tiered'] = tiered
term_length = int(plan['term_value'])
if term_length == 0:
incomplete_options.append(Option(plan=plan, price='???'))
continue
cur_month = datetime.now().month - 1 # Make January start at 0
months_in_term = [mo % 12 for mo in range(
cur_month, term_length + cur_month)]
term_price = 0
if not tiered:
# Note: 2nd order polynomial will always fit 3 points exactly
best_fit = numpy.poly1d(numpy.polyfit(x, y, 2))
for month in months_in_term:
usage = my_usage[month]
month_price = (best_fit(usage) / 100.0) * usage
term_price += month_price
else:
for month in months_in_term:
usage = my_usage[month]
if usage >= 500 and usage < 1000:
month_price = usage * y[0] / 100.0
elif usage >= 1000 and usage < 1500:
month_price = usage * y[1] / 100.0
elif usage >= 1500 and usage < 2000:
month_price = usage * y[2] / 100.0
elif usage < 500:
# TODO: improve?
month_price = usage * y[0] / 100.0 + 5 # Assume $5 fee
else:
# TODO: improve?
month_price = usage * y[2] / 100.0
term_price += month_price
# Price is the average price we'll pay for this plan over its term months
options.append(Option(plan=plan, price=term_price / term_length))
return options + incomplete_options
def print_options(options):
def get_plan_row(plan):
return str.join(',', map(lambda x: str(x), [
plan['company_name'],
plan['plan_name'],
plan['term_value'],
plan['price_kwh500'],
plan['price_kwh1000'],
plan['price_kwh2000'],
plan['renewable_energy_id'],
plan['tiered']
]))
# Sort by price ascending
sorted_options = sorted(options, key=attrgetter('price'))
print('Avg Price per Month,Company,Plan,Months,500 Price,1000 Price,1500 Price,% Renewable,Tiered')
for option in sorted_options:
row = str.join(',', [f"{option.price:.2f}", get_plan_row(option.plan)])
print(row)
if __name__ == '__main__':
# 2 years
my_usage = [
754,
687,
724,
942,
1489,
1247,
1666,
1414,
1011,
657,
643,
664,
718,
555,
674,
761,
813,
1494,
1845,
1991,
1700,
1009,
645,
623
]
if len(my_usage) % 12 != 0:
raise Exception('Usage data must be multiples of 12 (months)')
non_tiered_plans = get_plans(False)
non_tiered_plan_ids = [x['plan_id'] for x in non_tiered_plans]
all_plans = get_plans(True)
tiered_plans = [x for x in all_plans if x['plan_id']
not in non_tiered_plan_ids]
optionsA = get_options(non_tiered_plans, False)
optionsB = get_options(tiered_plans, True)
print_options(optionsA + optionsB)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment