Grid Frequency Monitor with E-Paper Display
Posted by Matthew Little on
I've been wanting to build a grid frequency monitor for a while now. The national electricity grid frequency is a good indicator of the state of the supply and demand within the grid. If the frequency is high then there is more supply than demand (so it's OK to switch on some loads), if the frequency is low then there is more demand than supply (so, if possible, switch off loads). The grid frequency does not vary by much (typically from 49.8Hz to 50.2Hz here in the UK where the nominal frequency is 50Hz).

There are quite a few plans and ideas to build your own, including a couple of designs I had seen in Elektor Electronics:
- https://www.elektormagazine.com/magazine/elektor-461/64462
- https://www.elektormagazine.com/labs/electricity-grid-frequency-meter
Typically these projects actually measure the frequency from the AC power supply at the plug socket. This is a simple hardware option, but it does need an AC power supply, transformer and some conversion circuitry. As I wanted other people to be able to build this project, I was very wary of providing information on circuitry to connect to the mains. So I thought this frequency information must be available on the web. If I can do a call to some kind of API which can return the UK grid frequency then I can use that information without any connection to mains (although an internet connection is still required).
I decided to use the E-Paper Display kit which I sell here. This shows the data even with no power, so maybe the unit can wake up, get the data then go back to sleep at regular intervals to show the grid frequency throughout the day. Maybe I can even get historic data and display that without waking up.
I found this UK grid frequency data website (which has the graph already): https://bmrs.elexon.co.uk/rolling-system-frequency
More details about the API and documentation is available here: https://bmrs.elexon.co.uk/api-documentation
As a quick demo I put in the URL "https://data.elexon.co.uk/bmrs/api/v1/system/frequency?format=json" into my chrome browser and saw that I got a whole load of frequency data back:

This is JSON response data format. I tried getting data from between two timestamps, with a timestamp in the format "2026-04-16T15:00:00Z". Getting 1 hour of data worked, but the data is a frequency point for every 15 seconds within the hour, so lots of data! 1 hour of data will give 240 data points. I don't need that many and cannot display to that resolution. So really I'd like to know the 10 min averaged data, along with the most recent instantaneous grid frequency....
There does not seem to be any option for obtaining the data as different averages. So maybe I need to do this myself? I can perform requests to get the 10 min data, average that and store the datapoint, then get the 10 mins before that. If I do that lots of times then I can build up the graph, but it seems not very efficient. I tested this with 24 calls to get hourly data. This actually did not take very long, so maybe this is the way to go.
In order to find the system frequency data I need to know the date/time now to then call for the most recent information. I followed this guide to get date and time:
https://randomnerdtutorials.com/esp32-date-time-ntp-client-server-arduino/
Note: While installing this code I ran out of program memory on the ESP32. The board has a ESP32-D0WDQ6 microcontroller IC, which apparently has 448kB ROM & 520kB SRAM. I changed the ESP32 'Partition Scheme' within the Arduino IDE from "Default" to "Huge App", which gives space, but removes the ability to do over the air uploads. This changed from filling 100% of the program space to just 41%. I presume this is due to the code required for the libraries I have installed (mainly the graphics and JSON?). But it meant I could fit the code onto the device.
With the simple code from the above link I managed to get the date/time from the NTP server which can then be used to obtains the correct grid frequency data.
I needed to be able to find time in the past to use as the 'from' value. This is much harder than you would think - you cant just take the minute value and subtract 5 as this could give you a negative number and it could roll back over midnight to give a different date. I found the simplest way is to convert the time into UTC (Universal Coordinated Time) which is seconds since 1st Jan 1970. Then subtract the seconds value, then re-convert into the date/time. My little function to do this is here:
String returnTimeNow(int _sec_offset) {// Create output looking like:"2026-04-16T13%3A00%3A00Z";// Need to convert time into UTC, then remove offset, then re-create the time:struct tm timeinfo;if (!getLocalTime(&timeinfo)) {Serial.println(F("Failed to obtain time"));return ("NO TIME");}time_t _time_unix;_time_unix = mktime(&timeinfo);time_t _time_past = _time_unix - _sec_offset;// Serial.print("Time unix in seconds:\t");// Serial.println(_time_unix);// Serial.print("Time unix minus offset:\t");// Serial.println(_time_past);struct tm *returntimeinfo;returntimeinfo = localtime(&_time_past);char timeReturned[50];strftime(timeReturned, sizeof(timeReturned), "%Y-%m-%dT%H:%M:%SZ", returntimeinfo);return ((String)timeReturned);}
So now I can find different DateTime stamps and use them to get the data I want.
One thing I did realise is that the Elexon data is in GMT and does not use daylight savings, so BST is not needed. So when finding the data from the NTP server we can set the daylight savings offset to zero, which will return GMT.
I sorted out using ArduinoJson to process the json data from Elexon. I perform multiple calls to get sets of 10 min data for the past 24 hours. This is 144 calls in total. For each call we get 10 mins of data, which is 40 data points at 15 seconds data. For each 10 mins I average the frequency to find the 10 min average freq. A bit crazy, maybe. But it works and is an easy way of getting the averaged data. I might look at getting the max and min within each 10min period as well.
So after a couple of seconds of getting the data I have the most recent grid frequency value, the time now and an array of 144 data points with the previous 24hrs as 10 min averaged data.
I plot these along the e-paper screen. The screen is 250 px wide, so I adjust the scale of the lines being draw to stretch the 144 items of data to cover the full 250 pixels width.
The height is scaled using a constant. This was set to convert 0.1Hz into 30 pixels, using a scale factor of 300. So value in pixel height is (Hz - 50.0) * 300. This could be positive or negative. Data is drawn around the mid point of the paper (which is the 50Hz line).

Playing around with the GxEPD2 graphics library I managed to make a graph of the data and the overlay the horizontal lines (showing the frequency bands in 0.1Hz steps). I also added vertical lines to show 6 hour time bands. The most recent values are on the right.
I added the most recent instantaneous frequency and an arrow in the middle of the screen to show the last 10 min trend. This can be a big or small arrow up (which means the frequency is above 50Hz so you can increase your load) or a big or small arrow down (which means frequency is below 50Hz so reduce your load). If the frequency is around 50Hz (+/- 0.03Hz) then an '=' sign is shown to say about balanced.
Here is a video on the unit in action:
The github repository for this information and the example code is here:
Share this post
- 0 comment
- Tags: citizen science, display, e-ink, education, educational, ESP32, experiment, makers
0 comment