[OH4] Octopus Energy (UK) - real-time electricity consumption data with Home Mini

Overview

If you are a customer of Octopus Energy in the UK, and you have a Home Mini installed and working, then you are uploading your consumption data to Octopus every 10 seconds.

You are able to access this data via their GraphQL API at a refresh rate of roughly 30 seconds, providing near real-time electricity consumption data. Whilst the obvious down-side is that you are relying on a non-local third-party service to provide data, the obvious up-side is that this data is the exact data that is used to generate your bills.

Prerequisites

  • Octopus Home Mini
  • Octopus API Key

Method

1 Find meter GUID

Copied directly from Victoria Scales’s blog, first obtain a short-lived access token, replacing <API_KEY> with your API key:

curl -v \
    https://api.octopus.energy/v1/graphql/ \
    --data '{ "query": "mutation {obtainKrakenToken(input: {APIKey:\"<API_KEY>\"}) {token}}"}' \
    -H "Content-Type: application/json"

With this access token, now find the meter GUID, replacing the two <…> placeholders:

curl -v \
    https://api.octopus.energy/v1/graphql/ \
    --data '{ "query": "query MyQuery {account(accountNumber: \"<YOUR_ACCOUNT_NUMBER>\") {electricityAgreements(active: true){meterPoint {meters(includeInactive: false) {smartDevices {deviceId}}}}}}"}' \
    -H "Content-Type: application/json" \
    -H "Authorization: JWT <TOKEN_FROM_OBTAIN_TOKEN_RESPONSE>"

Extract the meter GUID value from the deviceID key. It should be 16 characters in pairs of two, each pair separated by hyphens (eg. AA-BB-CC-DD-EE-FF-GG-HH).

2 Create items

We will be importing two bits of data, for which we will need an Item each:

  1. Live demand (instant power draw, in Watts)
  2. Cumulative consumption (effectively your meter reading, in kWh)

I have created my items using Items files, which includes an Equipment item WebService so I can easily find this data in the semantic model:

//EQUIPMENT
Group gElectricityLive "Electricity consumption (Octopus)" (gElectricitySupply) ["WebService"]

//LIVE CONSUMPTION DATA
Number nElectricityDemand "Live electricity demand" (gElectricityLive) ["Measurement", "Power"]
Number nElectricityMeterReading "Live electricity meter reading" (gElectricityLive) ["Measurement", "Energy"]

3 Setup rule

We will import this data into the two Items using Javascript in a rule. (I had originally wanted to do all this via the HTTP binding, but couldn’t find a clean way of doing so.)

I have setup the rule in two steps:

  1. Create a script
  2. Create a rule which calls the script every 30 seconds.

You may wish to combine the two steps into a single rule.

Script: live_octopus_energy_data

var url = "https://api.octopus.energy/v1/graphql/"
var contentType = "application/json"

//Get token first
var content1 = '{ "query": "mutation {obtainKrakenToken(input: {APIKey:\\"<YOUR_API_KEY>\\"}) {token refreshToken refreshExpiresIn}}"}'
var json_data1 = actions.HTTP.sendHttpPostRequest(url, contentType, content1)
var token = JSON.parse(json_data1).data.obtainKrakenToken.token

//Generate header
var headers = []
headers["Authorization"] = "JWT " + token 
//Generate HTTP post content
var content2 = '{ "query": "{smartMeterTelemetry(deviceId: \\"<YOUR_METER_GUID>\\") {readAt demand consumption}}"}'

//Grab data
var json_data2 = actions.HTTP.sendHttpPostRequest(url, contentType, content2, headers, 10000)
//Convert data to JSON object
var json_obj = JSON.parse(json_data2)

if (json_obj.data.smartMeterTelemetry != null) {
  items.getItem('nElectricityDemand').postUpdate(json_obj.data.smartMeterTelemetry[0].demand)
  items.getItem('nElectricityMeterReading').postUpdate(json_obj.data.smartMeterTelemetry[0].consumption/1000)
}

Note that I divide the consumption value by 1000 to generate kWh from the returned Wh.

Rule:

configuration: {}
triggers:
  - id: "1"
    configuration:
      cronExpression: 0/30 * * * * ? *
    type: timer.GenericCronTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      considerConditions: true
      ruleUIDs:
        - live_octopus_energy_data
    type: core.RunRuleAction

I tried refresh rates faster than 30 seconds, but found I was hitting rate limits. It seems like the Octopus API is happy receiving data requests every 30 seconds.