I’ve put some code together that finds the cheapest “n” hour block and works out the price. It works with https://www.home-assistant.io/docs/ecosystem/appdaemon/
Once AppDaemon is installed, edit /config/appdaemon/apps.yaml - the module and class sections need to remain as below, but the title, and number of hours can be set as you like.
It is only coded to work with whole hours, not halves, i.e. not 2.5, but you can have as many different ones as you need. Also I haven’t considered daylight savings changes, so I’m not sure how that will work at the end of the month.
octo_block_2hour:
module: octoblock
class: OctoBlock
auth: <your Octopus API key>
hour: 2
octo_block_3hour:
module: octoblock
class: OctoBlock
auth: <your Octopus API key>
hour: 3
Create the file /config/appdaemon/apps/octoblock.py with the following in, if you are not in region “H” you will need to update the “E-1R-AGILE-18-02-21-H” part of the url that is pulled back with the prices.
import appdaemon.plugins.hass.hassapi as hass
import requests
import json
import datetime
class OctoBlock(hass.Hass):
def initialize(self):
time = datetime.datetime.now()
time = time + datetime.timedelta(seconds=5)
self.run_every(self.get_best_period_and_cost, time, 30 * 60)
def get_best_period_and_cost(self, kwargs):
hours = self.args['hour']
auth = self.args['auth']
d = datetime.datetime.now().isoformat()
r = requests.get('https://api.octopus.energy/v1/products/AGILE-18-02-21/electricity-tariffs/E-1R-AGILE-18-02-21-H/standard-unit-rates/?period_from=' + d, auth=(auth, ''))
tariff = json.loads(r.text)
tariffresults = tariff[u'results']
tariffresults.reverse()
blocks = hours * 2
for period in tariffresults:
curridx = tariffresults.index(period)
l = len(tariffresults)
if curridx >= l-blocks:
period[str(hours) + '_hour_average'] = 99
continue
cost = 0
for block in range(blocks):
cost = cost + (tariffresults[curridx+block][u'value_inc_vat'])
cost = cost / blocks
period[str(hours) + '_hour_average'] = cost
self.minprice = min(period[str(hours) + '_hour_average'] for period in tariffresults)
self.log('Lowest average price for a {} hour block is: {} p/kWh'.format(str(hours), self.minprice))
for period in tariffresults:
if period[str(hours) + '_hour_average'] == self.minprice:
self.time = period[u'valid_from']
self.log('Lowest priced {} hour period starts at: {}'.format(str(hours), self.time))
self.set_state('sensor.octopus_' + str(hours) + 'hour_time', state = self.time)
self.set_state('sensor.octopus_' + str(hours) + 'hour_price', state = round(self.minprice,4))
This updates every half hour and creates/populates sensor entities for the time and price for each block specified in the apps.yaml file. For example, using the apps.yaml file above, I end up with the following entities:
sensor.octopus_2hour_time
sensor.octopus_2hour_cost
sensor.octopus_3hour_time
sensor.octopus_3hour_cost
The sensors can then be used in the front end, for example, I have entity cards set up…
type: entities
entities:
- entity: sensor.octopus_2hour_price
name: Price (p/kWh)
icon: 'mdi:flash'
- entity: sensor.octopus_2hour_time
name: Time
icon: 'mdi:flash'
title: Best 2hr Price
show_header_toggle: false
Hope this is useful.