eInk Display for Octopus's Agile Energy Tariff


I'm a little bit obsessed with building eInk displays. They're pretty cheap second hand. They're low energy, passive displays, with good-enough performance for occasional updates. Here's a new one which shows me what the current cost of my electricity is:

An eInk screen with a line graph on it. The graph shows the current price of power. The eInk is mounted in a wooden frame.

Background

After installing solar panels, a smart electricity meter, and a solar battery - the next obvious step was a smart energy tariff.

Octopus (join and we both get £50) have an "Agile" tariff. Unlike a normal tariff - with a set price for electricity - this tariff fluctuates every 30 minutes. Prices depend on wholesale costs which means they can go negative. That's right, you can get paid to soak up excess power.

Of course, they can also spike considerably. Unlike the failed Texas experiment, here the maximum price is capped at £1/kWh.

Every day at about 1600, the next day's prices are published on Octopus's website. And they're also made available via a simple REST API.

So, it's relatively simple to generate a line graph and display it on the eInk screen.

Code

(You can treat this code as MIT Licenced if that makes you happy.)

Calling the API for the half-houly prices is:

PHP PHP$url = "https://{$API_KEY}:@api.octopus.energy/v1/products/" .
       "AGILE-FLEX-22-11-25/electricity-tariffs/E-1R-AGILE-FLEX-22-11-25-C/standard-unit-rates/";

Your API_KEY is unique - and you'll need to check which tariff you're on.

The data is retrieved as JSON and converted:

PHP PHP$content = file_get_contents($url);
$data = json_decode($content);

The JSON is full of entries like this:

JSON JSON"results": [
{
  "value_exc_vat": 13.6,
  "value_inc_vat": 14.28,
  "valid_from": "2023-11-01T22:30:00Z",
  "valid_to": "2023-11-01T23:00:00Z",
  "payment_method": null
},
{
  "value_exc_vat": 18.4,
  "value_inc_vat": 19.32,
  "valid_from": "2023-11-01T22:00:00Z",
  "valid_to": "2023-11-01T22:30:00Z",
  "payment_method": null
},

They're newest first, so need to be reversed:

PHP PHP$tariffs = array_reverse( $data->results );

Then it's a case of looping through them and grabbing today's data:

PHP PHP$userTimeZone = new DateTimeZone('Europe/London');
$now = new DateTime('now', $userTimeZone);

$nowPosition = 0;
$datay = array();
$datax = array();

foreach ( $tariffs as $tariff ) {
    $dateStringFrom = $tariff->valid_from;
    $dateStringTo   = $tariff->valid_to;
    $dateTimeFrom = new DateTime($dateStringFrom, new DateTimeZone('UTC'));
    $dateTimeTo   = new DateTime($dateStringTo,   new DateTimeZone('UTC'));

    if ($now >= $dateTimeFrom && $now <= $dateTimeTo) {
        $costNow = $roundedInteger = (int)round( $tariff->value_inc_vat );
        $hour   = intval( $dateTimeFrom->format('G') );    //  No leading 0
        $minute = intval( $dateTimeFrom->format('i') );
        $offset = ($minute == 0) ? 0 : (($minute == 30) ? 1 : null);
        $nowPosition = (2 * $hour) + $offset + 0.5;
        $until = $dateTimeTo->format('H:i');
    }

    if ($dateTimeFrom->format('Y-m-d') == $now->format('Y-m-d')) {

        $datax[] = $dateTimeFrom->format("H:i");
        $cost = $roundedInteger = (int)round( $tariff->value_inc_vat );
        $datay[] = $cost;
    }  
}

Drawing the graph uses the venerable JPGraph:

PHP PHP$path = 'jpgraph/';
set_include_path(get_include_path() . PATH_SEPARATOR . $path);
require_once ('jpgraph/jpgraph.php');
require_once ('jpgraph/jpgraph_line.php');
require_once ('jpgraph/jpgraph_plotline.php');

// Size of graph
$width  = 600;
$height = 600;

// Setup the graph
$graph = new Graph($width,$height);
$graph->SetScale("intlin");
$graph->SetMargin(35,0,45,20); // L R T B

$graph->SetUserFont('dejavu/DejaVuSansMono.ttf');
$graph->title->SetFont(FF_USERFONT,FS_NORMAL,25);

$graph->SetBox(false);

$graph->title->Set( $now->format('l') . "'s Electricity Prices\n" . $costNow . "p / kWh until {$until}" );
$graph->title->SetColor('#000');

$graph->ygrid->Show(true);
$graph->xgrid->Show(true);

$graph->xaxis->SetTickLabels( $datax );

$graph->xaxis->SetColor('#000');
$graph->yaxis->SetColor('#000');

$graph->xaxis->SetFont(FF_USERFONT, FS_NORMAL, 10);
$graph->yaxis->SetFont(FF_USERFONT, FS_NORMAL, 14);

// Just let the maximum be autoscaled
$graph->yaxis->scale->SetAutoMin(0);

// Only show up until 23:00
$graph->xaxis->scale->SetAutoMax(46);

$graph->xaxis->SetTextLabelInterval(2);
$graph->SetTickDensity(TICKD_DENSE, TICKD_DENSE);  

// Create the line plot
$p1 = new LinePlot($datay);
$graph->Add($p1);
$p1->SetStepStyle();
$p1->SetColor('#000');

//                 Direction, position,     colour@alpha, width
$l1 = new PlotLine(VERTICAL,  $nowPosition, 'black@.8',   13);
// Add vertical highlight line to the plot
$graph->AddLine($l1);

// Output line
$graph->Stroke();

Next steps

I dunno? Add some details about carbon emissions? Battery stats? Let me know what you think in the comments.


Share this post on…

  • Mastodon
  • Facebook
  • LinkedIn
  • BlueSky
  • Threads
  • Reddit
  • HackerNews
  • Lobsters
  • WhatsApp
  • Telegram

4 thoughts on “eInk Display for Octopus's Agile Energy Tariff”

  1. says:

    It's a shame it's "authentication protected" as it doesn't give out any confidential information and it's something that could be cached either on their frontend servers or on proxy servers/CDNs: as it is, they are probably using up more computing power authenticating the API token then they would just leaving it open and catchable (especially since it changes at the same time everyday - easy enough to set cache headers).

    Turns out, that endpoint isn't actually restricted by API keys - so you can access it without authentication (although the Expires: setting is only a minute into the future so not that cachable)

    Reply
  2. Libosmackle says:

    Are you not worried about someone nicking the batteries from your porch?

    Reply

What links here from around this blog?

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.

Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">