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:
- Live demand (instant power draw, in Watts)
- 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:
- Create a script
- 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.