A utility bill watcher on AWS for a few dollars a month
Utility bills are the classic small-business blind spot: too small to justify attention individually, too numerous to check, and just variable enough that a bad one looks like a normal one. A cafe with three sites gets roughly a hundred and forty utility bills a year. Nobody reads a hundred and forty bills. So the tariff that rolled onto a variable rate in March gets noticed in September, and the freezer that has been running with a failing door seal since April never gets noticed at all. This post walks through a small system that reads all of them.

Key takeaways
- Bills arrive the way they already do: a PDF in an email, or a portal download in a folder.
- Three numbers are pulled from each: usage, unit rate, and standing charge.
- Each is compared separately — against the same period last year and against your contract.
- Only a bill where something moved produces a message. Most produce nothing.
- Designed on AWS for about $3 a month across a dozen sites.
The whole system on one page
Before any code, here is the shape of what we are designing.
- Machine learning
- Management
- Analytics
- People
What you set up once (the outside)
- A place for bills to land. A dedicated address that suppliers already email, or a folder that a portal download gets dropped into. Both are covered in Part 2. Nobody changes how bills arrive; that is the whole point.
- A meter list. One tab: each meter number, which site it belongs to, what it supplies, the contracted unit rate and standing charge, and when the contract ends. Most small businesses do not have this written down anywhere, and building it is genuinely the hardest part of the project — and worth doing even if you build nothing else.
- A tolerance line. How far a number has to move before it is worth mentioning. Usage swings with weather and trade, so the default is generous: twenty-five per cent against the same period last year. Rates are different — a unit rate that differs from the contract at all is worth a message, because it is either an error or a contract that rolled over.
What runs on every bill (the inside)
- The reader. Turns a PDF into three numbers plus the meter number and the period. Utility bills are visually chaotic and vary wildly between suppliers, so this is where Textract and a model earn their keep — but the meter number is matched against your list rather than trusted from the page, and a number the reader is not confident about is left null.
- The comparer. Three comparisons, each against two references. Usage against the same period last year for that meter, and against the previous period. Unit rate against the contract. Standing charge against the contract. Each comparison is a subtraction, and each carries the two numbers that produced it.
- The reporter. Builds a message only when something moved past its tolerance, and the message says which of the three moved. That distinction is the entire value: “usage up 40% on last July” sends somebody to look at a freezer, and “unit rate up 62% against contract” sends somebody to phone a supplier. Those are different days.
One bill, end to end
In plain words
The electricity bill for your Hitchin site arrives on the 12th. The reader pulls out 4,180 kWh, a unit rate of 24.1p and a standing charge of 48p a day, on meter 1200034557. That meter is on your list, it is Hitchin, and the contract says 24.1p until November. Usage last July on the same meter was 3,980 kWh, so this is five per cent up — well inside the band. Every number behaves. The bill is filed, the history row is written, and nobody hears anything.
The August bill for the same meter comes in at 6,240 kWh. Same rate, same standing charge, but usage is up fifty-seven per cent on last August. One message goes out: “Hitchin electricity: usage 6,240 kWh, up 57% on Aug 2025 (3,970). Rate and standing charge unchanged.” That sentence is doing something specific — it has already ruled out the two commercial explanations, so the person reading it knows immediately that something at the site is drawing power. It turned out to be a walk-in fridge with a door that was not sealing, which had been running flat out since the middle of July.
Design rules that shaped every decision
- Three numbers, compared separately. A total cannot distinguish an operational problem from a contract problem, and those need different people.
- The meter list is the source of truth. A bill for a meter that is not on the list is a question, not a new meter.
- Compare against the same period last year, not last month. Utilities are seasonal and month-on-month comparison generates constant noise.
- An estimated reading is compared but never becomes the baseline. A run of estimates followed by a real reading produces a catch-up that would look like a crisis.
- Rate tolerance is near zero. Usage moves for a hundred honest reasons; a unit rate that differs from the contract does not.
- Nothing is ever paid, disputed or cancelled by the system. It reads and it tells you.
Why this shape
The reason nobody checks utility bills is not laziness; it is that checking one properly requires last year’s bill for the same meter, the contract, and ten minutes. Multiply by four utilities and three sites and it is a day a month for a saving that is usually zero. So it does not happen, and the two things that would have been caught — the tariff that rolled onto a variable rate and the equipment that started drawing double — both run for months.
The shape above makes that ten minutes cost nothing and applies it to every bill. It spends most of its effort on the boring half, which is matching a bill to the right meter and reading three numbers off a page that a different supplier lays out differently every time. The interesting half — the comparison — is three subtractions.
The next four posts walk through each piece: how a bill arrives and gets read, how it gets matched to a meter, how a change gets reported, and how the history builds into something worth looking at. One diagram per post, a cost breakdown, and an engineering reference at the end.
All posts