Utilities · 9 months

Metering platform for a regional energy retailer

The retailer inherited three meter vendors with three protocols, and a billing team reconciling exports by hand every month.

Node.jsKafkaEMQXKubernetesReact
18kmeters reporting
9k/speak messages ingested
3 → 1protocols the billing team sees
4 dayssaved per billing cycle

The situation

Three acquisitions in five years left the retailer with three meter estates, three vendor portals and three export formats. The billing team downloaded CSVs from each, reconciled them in a spreadsheet, and manually chased the gaps.

What made it hard

Metering load is not evenly distributed. Every meter reports on the quarter hour, so the platform is idle for fourteen minutes and then receives everything at once. The inherited system was sized for the average and lost readings on every spike.

Worse, nobody could say how many were lost. There was no dead-letter path, so a malformed payload from one vendor's firmware simply vanished, and the gap was discovered by a customer complaint weeks later.

How we built it

One schema, translated at the edge

Rather than teach every downstream system three formats, translation happens once at the gateway. Each vendor's payload is mapped into a single versioned schema, and everything above that layer only ever sees one shape. Adding a fourth vendor is now a translator, not a project.

Absorbing the quarter-hour spike

EMQX accepts the burst, Kafka absorbs it, and consumers drain at their own pace into TimescaleDB. Peak throughput measured at 9,000 messages a second against a launch requirement of 2,000, so growth does not need a re-architecture.

Making loss visible

Every rejected payload lands in a dead-letter topic with the validation error attached. The console shows the dead-letter rate as a first-class metric, which surfaced a firmware bug in one vendor's estate during the pilot that had been silently dropping readings for over a year.

One console for two audiences

Field engineers commission meters from the same application the operations team monitors, so a newly commissioned meter appears in the fleet view immediately rather than after an overnight sync.

What changed

Billing moved from three manual exports to one API call, saving roughly four days of work per cycle. The dead-letter path paid for itself in the pilot by exposing a fault that had been quietly corrupting a subset of readings.

What we would tell the next team

  • The peak matters, not the average. Asking for peak message rate in discovery changed the entire architecture.
  • The dead-letter path was scoped as a nice-to-have and turned out to be the most valuable single feature.
  • Commissioning is part of the product. Treating it as an afterthought is how estates end up with untracked meters.
Figures are the client's own

Results above were measured by the client against their own baseline. We are happy to arrange a reference call where the contract allows it.

Tell us what you are trying to measure

An engineer reads every message and replies within one working day. The first call is a conversation about your problem, not a sales script.

See engagement models