Turning Smart Meter Data Into a Panel Count
Most online sizing tools ask for your postcode, your annual electricity use and your roof direction, then hand back a number of panels. That calculation runs on a single scalar: 3,800 kWh a year, say. The problem is that a solar array doesn’t meet your annual total, it meets whatever you happen to be using between roughly 9am and 5pm, and no annual figure contains that information. Your smart meter does. It has been recording your consumption in 30-minute buckets since the day it was commissioned, and that series is the only input that makes the question answerable.
This page walks the whole pipeline: pulling half-hourly data out of a UK smart meter, generating a matched half-hourly irradiance series, joining them without wrecking the timestamps, and reading the marginal value of each additional panel. If you want the wider framing on why consumption-led sizing beats rule-of-thumb sizing, the pillar at Sizing From Your Own Consumption Data covers the strategy. What follows is the arithmetic.
Why the annual total is the wrong input
Two households both using 3,800 kWh a year can want very different arrays. One is a couple working from home with a heat pump running a daytime setback; the other is out of the house 8am to 6pm with everything stacked into a 6pm to 10pm evening block. The first household self-consumes maybe 55% of a 4 kWp array. The second self-consumes 30% of the same array, and the difference is worth over £200 a year at current rates.
A solar panel calculator using smart meter data closes that gap because it never aggregates. You keep all 17,520 half-hourly readings and you compare each one against the generation in that same half hour. The overlap is what you save at your import rate. Everything else is export, valued at your SEG rate, which is typically less than half as much.
Getting your half-hourly data out
Three routes work in the UK, and which one you use depends mostly on your supplier.
Octopus Energy API. Generate an API key from your account dashboard, then hit the consumption endpoint for your MPAN and meter serial:
GET https://api.octopus.energy/v1/electricity-meter-points/{mpan}/meters/{serial}/consumption/
?period_from=2024-09-01T00:00Z&period_to=2025-09-01T00:00Z&page_size=25000
Basic auth, API key as the username, blank password. Results come back as {"consumption": 0.284, "interval_start": "2025-06-14T12:00:00+01:00", ...}. The consumption field is kWh already, not Wh and not average power. Note the +01:00 offset in summer, because it matters later.
n3rgy. If you’re not with Octopus, n3rgy is the free data service that reads your meter through the DCC directly. You register at n3rgy.com with your MPAN, and after authorisation you get 13 months of half-hourly history over a simple REST API. It works with SMETS2 and most migrated SMETS1 meters regardless of supplier, which makes it the general-purpose answer.
Hildebrand Glow. A Glow CAD (about £70) pairs to your meter over Zigbee and pushes both real-time power and half-hourly totals to the Bright app and an MQTT feed. This is the option worth paying for if you want higher-than-half-hourly resolution, which, as you’ll see below, changes your answer.
Home Assistant users can shortcut the lot with BottlecapDave’s Octopus Energy integration, which populates the statistics tables with half-hourly import and cost. Pull it out to CSV from there.
One trap: if you already have solar, your import readings are net of existing generation and are useless as a load profile. You’d need the generation data from the inverter to reconstruct gross demand.
Building the generation side
PVGIS is the free tool the industry quietly runs on. The seriescalc endpoint returns hourly modelled output for a 1 kWp system at your exact coordinates, using satellite-derived irradiance for real historical years:
https://re.jrc.ec.europa.eu/api/v5_2/seriescalc
?lat=52.95&lon=-1.15&startyear=2020&endyear=2020
&pvcalculation=1&peakpower=1&loss=14&angle=40&aspect=45&outputformat=csv
PVGIS aspect is measured from south, so a roof facing 225° on a compass is aspect=45. loss=14 is the default system loss assumption covering cabling, inverter efficiency and soiling; raise it to 17 or 18 if you have a partially shaded roof and don’t want to model shading properly.
Scaling is linear, which is the useful part. Run it once for 1 kWp, then multiply by n_panels × panel_watts / 1000. For the Nottingham example above, PVGIS returns 905 kWh per kWp per year. Twelve 440 W panels (an Aiko Neostar or a JA Solar JAM54, both common on UK roofs right now) is 5.28 kWp, so 4,778 kWh a year before any self-consumption analysis.
The hourly series needs splitting into half hours. Dividing each hourly value by two and duplicating it is fine for annual totals and slightly wrong at sunrise and sunset. Linear interpolation between hour midpoints is better and costs you one line of pandas.
The join, and the timezone bug that eats 4% of your answer
PVGIS timestamps are UTC. Octopus timestamps are ISO 8601 with a real offset. If you parse the Octopus string, strip the offset and treat it as naive local time, every summer half hour shifts one position relative to the generation curve. Your modelled solar now peaks an hour early, before your afternoon and evening load picks up, and self-consumption comes out low by two to four percentage points across the year.
Convert everything to UTC on ingest. In pandas that’s pd.to_datetime(col, utc=True) on both sides, then a straight index join. Verify by plotting a single clear June day and confirming your modelled peak sits at about 12:10 UTC for a south-facing array, later for a west-facing one.
Running the simulation
The core loop is three lines. For each half hour, self-consumption is the smaller of load and generation; export is whatever generation is left over.
gen_kwh = pv_1kwp * (n_panels * 0.440)
self_use = np.minimum(load_kwh, gen_kwh)
export = gen_kwh - self_use
value = self_use.sum() * 0.27 + export.sum() * 0.15
In a spreadsheet the same thing is =SUMPRODUCT(MIN(...)) over two columns of 17,520 rows, which Excel handles without complaint. Wrap the whole thing in a loop over panel counts and print the table.
panels kWp gen_kWh self_kWh self% export_kWh £@15p £@5p
4 1.76 1593 1020 64% 573 361 304
6 2.64 2389 1315 55% 1074 516 409
8 3.52 3186 1540 48% 1646 663 498
10 4.40 3982 1706 43% 2276 802 574
12 5.28 4778 1834 38% 2944 937 642
14 6.16 5575 1930 35% 3645 1068 703
16 7.04 6371 2003 31% 4368 1196 759
That run used a real 3,847 kWh import profile, evening-weighted, one occupant home two days a week. Import priced at 27p/kWh, export at 15p (Octopus Outgoing Fixed) in one column and 5p in the other.
Reading the marginal panel, not the average
The average return per panel falls steadily as you add panels, which is the fact everyone knows and the reason people repeat “don’t oversize.” Look at the marginal column instead. Going from 14 panels to 16 adds £128 a year at 15p export. Once scaffolding is up and the inverter is paid for, two extra panels cost roughly £320 to £380 installed. That’s a 2.6 to 3.0 year marginal payback, which is better than almost anything else you could do with £350.
Now read the 5p column. The same two panels add £56 a year, a marginal payback over six years, and the case gets thin. Your export tariff, not your consumption profile, is what decides whether filling the roof is right. Any calculator that doesn’t take your SEG rate as an input cannot answer this question, and that includes most of the free ones.
Worth noting what the table doesn’t show: at 16 panels you’re at 7.04 kWp. On a 3.68 kW inverter (the G98 notify-after limit for single phase), you’d clip. Estimate it from the same PVGIS series by counting half hours where modelled output exceeds 3.68 kW and summing the excess. For this roof that came to 8.2% of annual generation at 7.04 kWp, against 1.4% at 5.28 kWp. Feed that back in as a multiplier before you trust the top rows, or budget for a G99 application and a larger inverter.
Where the battery changes the shape
Add a 5.2 kWh usable battery (a GivEnergy Giv-Bat, or a Fogstar Energy 15.5 if you’re going bigger) and rerun with a state-of-charge variable: charge from surplus, discharge into deficit, respect the power limit and a round-trip efficiency of about 0.88.
For the 12-panel case, self-consumption rises from 1,834 kWh to roughly 2,780 kWh. Those extra 946 kWh are worth 27p instead of 15p, so the battery earns £113 a year from solar time-shifting alone. That number surprises people who expect more. Then model overnight charging on Intelligent Octopus Go at 7p: 5.2 kWh displaced at 27p, call it 200 usable nights across the darker months, and you’re at £208 a year from arbitrage. The battery is mostly a tariff device with a solar side hustle, and your own half-hourly data is what proves it rather than a brochure.
Corrections worth applying before you believe the output
Half-hourly averaging flatters you. A 3 kW kettle running six minutes registers as 0.3 kWh in that bucket, which your model reads as a smooth 600 W draw that solar happily covers. In reality the kettle drew 3 kW for six minutes while the array was making 2 kW. Modelling at one-minute resolution typically drops self-consumption by two to five percentage points against the half-hourly figure. If you have a Glow CAD, test it directly on a month of minute data. If you don’t, take a haircut of three points off your self-consumption percentage and move on.
Future load matters more than past load. A 7 kW EV charger arriving next spring adds 2,000 kWh of demand that your historical profile knows nothing about, and if you charge overnight it contributes nothing to solar self-consumption. Model the profile you expect to have in year three, not the one you had last year. Same for a heat pump, which adds winter load when your array is producing 15% of its summer output.
Degradation and tariff drift both belong in the payback calculation rather than the sizing one. Panels lose around 0.4% a year on a modern warranty; import prices have risen faster than export rates for four years running, which quietly strengthens the case for self-consumption over export as time passes.
Keeping the model alive after install
The same pipeline that sized the array validates it. Once the system is live, pull your import series and your export series (your export MPAN works through the identical Octopus endpoint) and compare measured self-consumption against what the model predicted. A gap of more than about 8% usually means one of three things: shading you didn’t model, an inverter that’s clipping more than you expected, or a load profile that shifted when your working pattern did.
Set that comparison to run monthly and you have something no installer’s projection gives you, which is a live, falsifiable model of your own roof.