Skip to content

Case study · Connected devices

Six repositories, four benches, one system that had to behave as one

A connected-device platform for retail and facilities: battery-powered devices on a long-range radio network, a provisioning path, remote configuration, telemetry, an operator dashboard and an internal operations app. Four separate benches touched it — radio firmware, device hardware, backend, front end — and the only question that mattered was whether the chain agreed with itself at every boundary.

  • LoRaWAN
  • Multi-tenant GraphQL API
  • Realtime telemetry
  • Payload decoding
  • Operator dashboard
  • Measured authorship

The systems involved

What had to talk to what

The devicesBattery-powered sensing and signalling units, plus a gateway class of device, reporting over a long-range low-power radio network. Two firmware targets, built on the programme's own bench alongside the platform.
The network serverAn open-source LoRaWAN network server, deployed and operated rather than written. It hands up raw payloads and expects something above it to know what the bytes mean.
The platformA multi-tenant API with background jobs and realtime channels: device registry and provisioning, configuration push, zones and groups, live and historical analytics, and a service-desk path for the people who actually operate the estate.
The two front endsA customer-facing dashboard with a floor-plan builder, and an internal operations app for the staff who commission and support devices. Different users, different failure modes, one API.

The difficulty

What made them hard to connect

The failure mode of a system like this is not a crash. It is a device that silently disagrees with the server — a payload format changed on the device side, a unit scaled by ten, a field reordered — and a dashboard that keeps drawing a confident line through wrong numbers. Nothing in the stack raises an error for that.

A programme this wide is several benches at once — devices, radio, platform, two front ends — and the expensive problems live on the seams between them rather than inside any one of them. The network server was an upstream open-source project nobody could change, and the customer front end had contributors of its own, so every component had to be defensive about edges it did not control.

Multi-tenancy made the quiet bugs expensive: a device registered to the wrong tenant is not a rendering mistake, it is one customer looking at another customer's estate.

The work

What we built

Payload decoding as a first-class component

Roughly 2,700 lines whose entire job is turning bytes into values and refusing to guess: known formats decoded explicitly, unknown ones surfaced as unknown rather than coerced into a number that looks plausible on a chart.

A multi-tenant API with tests as its largest component

Device registry, provisioning, configuration push, jobs, realtime channels and analytics — and a quarter of everything written in it is test code, which on a system whose failure mode is silent disagreement is the whole argument.

An operations app for the people holding the pager

The internal app is not a cut-down dashboard. Commissioning, device health, configuration history and support calls are a different job from reporting, and it is built as one.

Now

What it does today

Devices are provisioned, configured and monitored through one platform; payloads are decoded with the unknown cases visible rather than smoothed over; operators see zones, groups and history, and support staff see the device rather than the chart. Whether and where it is installed is the operator's business to state, not ours — this page makes no deployment claim in either direction.

Repositories in the system7, of which we authored the majority of 3
API, ours147 of 171 commits — 88.1% of 104,704 lines
Of that API, test code26,692 lines — just over a quarter
Internal operations app, ours101 of 133 commits — 67.0% of the lines
Payload decoding, oursabout 2,700 lines
Customer front end, ours143 commits — 17.2% of the lines, a contribution
Device firmware and simulatorDelivered on the programme's own bench; the commit record we can read carries none of our identities, so this row is attested, not measured

The stack

What it is made of

Devices and radioLoRaWAN class-A devices, two microcontroller targets, gateway hardware — firmware and boards built on the programme's own bench
Network serverOpen-source LoRaWAN network server, self-hosted
PlatformMulti-tenant GraphQL API, background job queue, realtime channels, relational database, object storage
Front endsTypeScript single-page applications — a customer dashboard with a floor-plan builder, and an internal operations app
Integration surfacePayload decoders, device provisioning, configuration push, webhooks

Who did what

Stated as a table above rather than a footnote, because on this system the division of labour is the story. The API, the operations app and the payload decoding are ours by a measured majority — the figures are git log --all counts, not estimates. The radio network server is an upstream open-source project we deployed and operated rather than wrote. The customer front end was a contribution to somebody else's majority. The devices, their firmware and the simulator were delivered on the programme's own bench: the repositories we can read carry none of our commit identities, which is a fact about those repositories rather than about who did the work, so that row is attested here instead of counted. Where a number exists it is measured; where one does not, this page says so.

Check it

The evidence, not a description of it

Every link here opens the thing itself — a repository, a running demo, a note with the method in it.

Next step

Tell us the version, the hardware, and what it has to do.

You will get a written scope and a fixed price against it. If the honest answer is that you do not need us, you will get that instead.