Tracking electricity usage through an API
TL;DR: Click here to skip to the code.
A few years ago, during the energy crisis, I created a tracker to report on my electricity usage in hopes that I could better understand my usage habits are cut back on superfluous spending. The smart meter installed by my provider at the time (EON) sent these exact stats to the IHD (In Home Device) but they were trapped inside that always-on display. Not good enough.
The drive to install smart meters in homes across the UK is part of our net zero goals. Smart meters allow consumers to be more aware of their usage to help encourage them to turn off what isn’t needed to save power (and money!). It’s much easier to control what you can see and measure. Enter the Data Communications Company (DCC).
In a nutshell, the DDC connects smart meters to energy suppliers and tracks how much energy is being used at specific intervals (usually every 30 mins). This data is made available to the big energy providers but also to the people through the use of brokers, glowmarkt is one such broker.
Using glowmarkt’s Bright app it’s possible to connect to DCC and download your meter data. The process is as easy as downloading the app and providing both your smart meter serial numbers and proof of ownership (they can’t be giving out this data to any Joe).
Registration can take several working days, but once registered the App will show you your usage in as finer details as your meter captures (usually 30 mins). This is great, we now have access to the same data on our phone as we do on the IHD. We can go one step further and get the raw data from their API directly.
Bright API
There’s a postman collection here. Below I’ll show the calls in Postman along with snippets of a typescript application to automate this.
Authenticate
First, authenticate with your user/pass using the static bright application id by making a POST to https://api.glowmarkt.com/api/v0-1/auth
async function getLoginToken() {
const body = {
"username": process.env.BRIGHT_USERNAME,
"password": process.env.BRIGHT_PASSWORD,
"applicationId": "b0f1b774-a586-4f72-9edd-27ead8aa7a8d"
}
const res = await fetch('https://api.glowmarkt.com/api/v0-1/auth', {
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
})
if (res.status !== 200) {
throw new Error(`Expected 200 from AUTH. Got ${res.status}`)
}
const json = await res.json()
return json.token
}
Get Virtual Entities
Request our Virtual Entities using our access token by making a GET to https://api.glowmarkt.com/api/v0-1/virtualentity/
async function getVirtualEntities(token: string) {
const res = await fetch('https://api.glowmarkt.com/api/v0-1/virtualentity/', {
headers: {
token,
applicationId: 'b0f1b774-a586-4f72-9edd-27ead8aa7a8d'
}
})
if (res.status !== 200) {
throw new Error(`Expected 200 from GET VEs. Got ${res.status}`)
}
const json: VirtualEntitiesResponse = await res.json()
return json
}
In this response, you’ll see various Virtual Entities representing each of your fuel types (ie, Gas and Electricity) and potentially an export meter if you have solar panels or a battery etc. For this example, we’re interested in “electricity consumption” as this will show us our electricity usage. Grab the resourceId
and let's move on to querying consumption.
Get Consumption
Make a GET to https://api.glowmarkt.com/api/v0-1/resource/<id>/readings
with query parameters defining the granularity and time periods. For example for 30 min intervals between 1st Jan 2023 and 7th Jan 2023, I would call.
GET https://api.glowmarkt.com/api/v0-1/resource/447c88f4-c99d-44c4-9f1d-03a767b084a6/readings?period=PT30M&function=sum&from=2023-01-01T00:00:00&to=2023-01-07T23:59:59
async function getThirtyMinuteIntervalUsage(token: string, resourceId: string, from: Date, to: Date) {
const fromStr = dateToApiFormat(from)
const toStr = dateToApiFormat(to)
const res = await fetch(`https://api.glowmarkt.com/api/v0-1/resource/${resourceId}/readings?period=PT30M&function=sum&from=${fromStr}&to=${toStr}`, {
headers: {
token,
applicationId: 'b0f1b774-a586-4f72-9edd-27ead8aa7a8d'
}
})
if (res.status !== 200) {
throw new Error(`Expected 200 from GET Readings. Got ${res.status}`)
}
return await res.json() as ResourceReadingsResponse
}
function dateToApiFormat(date: Date) {
const pad = (num: number) => num.toString().padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}
async function getCompleteHistoryReadings(token: string, resourceId: string, earliestTime = 0) {
const startTo = new Date(Date.now() + (1000 * 60))
const readingsByTime: Record<number, number> = {}
let i = 0
while (true) {
const to = new Date(startTo.getTime() - ((MILLI_IN_DAY * 10) * i++))
const from = new Date(to.getTime() - (MILLI_IN_DAY * 10) - 1)
const response = await getThirtyMinuteIntervalUsage(token, resourceId, from, to)
// If ALL readings are 0 then either we haven't used anything for 10 days or we're out of data
if (!response.data.some(o => o[1] > 0)) {
return readingsByTime
}
// Should already be sorted in response - but for sanity's sake
response.data.sort((a, b) => a[0] > b[0] ? -1 : 1)
for (const [epoch, kwh] of response.data) {
readingsByTime[epoch] = kwh
if (epoch < earliestTime) {
return readingsByTime
}
}
}
}
// Tie it altogether
export async function getMeterReadings(since?: number) {
const token = await getLoginToken()
const entities = await getVirtualEntities(token)
const resource = entities[1].resources.find(o => o.name === "electricity consumption")
if (!resource) {
throw new Error('Failed to find electricity consumption resource')
}
return await getCompleteHistoryReadings(token, resource?.resourceId, since ? (since / 1000) || 0 : 0)
}
We get an array of arrays representing the start time of that period and its usage. In the above screenshot, I used 0 kwh between 12 am — 1 am and then 0.211kwh between 1:30 am — 2:00 am. In the typescript code, we are converting this array of arrays to key/value objects by time.
Using this data
I’m reporting my daily usage on Discord in a nicely formatted graph.
I’m on Octopus’s Agile tariff where prices change every 30 minutes. Mapping these prices to the 30-minute usage gives me an accurate picture of how much my electricity is costing me throughout the day. I’m using this to keep track and evaluate whether the agile tariff saves money over the price cap. This was true during the energy crisis when the price cap was 33p but it’s becoming less so with time. Here the bot tells me how much I’ve saved/lost and my predicted monthly cost.
Version 1 Delivers One Digital Platform for Energia Group | Version 1
Conclusion
Having data accessible via the DCC increases transparency and gives more power to consumers to understand and control their energy usage. Hopefully I’ve shown just how easy it is to get your own data, there’s so much more that can be done with what’s available. We’ll be exploring this in future entries. Now go and build something cool!
About the author
Jack Reeve is a Full Stack Developer here at Version 1.