Many Boards, Many Sensors, One Network
#kairair#sensors#data-model#building-in-public#architecture#extensibility
David OlssonMost weather platforms ask you a question the moment you arrive: what kind of station do you have? Pick from the list. Temperature, humidity, pressure, wind, rain. The list is the product. If your sensor measures something the list didn't anticipate, that reading has nowhere to go.
That design makes sense if you're a company shipping one product to a million people. It's exactly wrong for a network that wants to grow sideways — more kinds of station, more kinds of sensor, measuring more of what's actually in the air.
So KAIRair inverts it. There is no list to pick from. A station reports whatever it measures, and the network's job is to catch it — including things nobody defined in advance.
the trap of a fixed schema
The tidy way to store sensor data is a table with a column per measurement. temperature, humidity, pressure. Clean. Fast. Obvious.
And rigid. The day a station shows up carrying a particulate sensor — PM2.5, PM10 — you don't have a column for it. So you stop, you write a database migration, you add the columns, you redeploy, and only then can that reading be stored. Every new kind of sensor is a code change. The network can only ever measure what its schema already knew about.
For a platform whose whole ambition is to keep absorbing new sensors, that's a ceiling built into the foundation. Every future sensor would have to wait in line behind a developer.
I didn't want a network where adding a sensor means editing the database.
catalog and readings
The shape that fixes this is older than any of us: instead of a column per measurement, you keep two tables.
One is a catalog of metrics — a running list of every kind of thing the network has ever seen measured. Temperature is a row. Humidity is a row. The first time a particulate sensor reports, PM2.5 becomes a row. The catalog isn't defined up front; it accretes. It's a list of what the network has learned exists.
The other is the readings themselves — and crucially, each reading names its metric rather than living in a named column. A reading is, in effect, "station 43, at this timestamp, measured this metric, value that number." The measurement's identity is data, not schema.
Put those two together and something nice happens. To store a reading, you don't need a column that matches it. You need a row that references it. And rows are cheap. Rows are the thing databases make infinitely.
what happens when an unknown sensor reports
Here's the moment the design earns its keep.
A station in the field gets a new sensor and a firmware update. It boots, reads its hardware, and POSTs its telemetry to the server like always — except this time the payload includes a key the backend has never seen before. Call it a gas-resistance reading from a BME680, or particulates, or UV.
The server doesn't reject it. It doesn't need a migration. It looks at the key, notices the catalog has no entry for it, and adds one — automatically, on first sight. Then it stores the reading against that freshly minted metric. The measurement is captured on the very first report, before any human has weighed in.
The sensor didn't wait for permission. It just started reporting, and the network started remembering. That's what I mean when I say the system is dynamic by construction — not that it has a lot of features, but that it doesn't need to be taught a new sensor to accept one.
the human touch comes after, not before
There's a subtlety worth being honest about. Auto-capturing a raw key means the network's first understanding of a new metric is thin — it knows the key and the numbers, not necessarily a friendly label or the right units to show a person.
So the ordering is deliberate: capture first, curate second. The reading is safely stored the instant it arrives. Later, in the admin view, a newly discovered metric can be given a proper name, a unit, a bit of annotation — turned from a raw key into something a station page can display nicely.
That's the right order. The expensive, irreversible thing is losing a reading you can never take again, because the air that produced it is already gone. The cheap, deferrable thing is labelling it. So the network never drops data waiting for a human, and the human never has to predict every sensor in advance.
many boards, too
The same philosophy runs one level down, in the hardware. A station's identity isn't "the weather-station product." It's a specific board and a specific set of sensors, described in a kit definition — the source-of-truth YAML from the last post. Different controller, different sensors, different measurements. The network doesn't flatten them all to a lowest common denominator; it lets each station be exactly what it is and report exactly what it carries.
So "many boards, many sensors, one network" isn't a slogan. It's the data model. The boards vary. The sensors vary. What they measure varies. The one thing that stays fixed is the network's willingness to catch whatever comes in.
Which is the quiet precondition for everything the series gets to later. A network that can absorb an unknown sensor on first report is a network that can grow past weather without being rebuilt — because to it, the next kind of measurement was never special in the first place.
Part four of the KAIRair build series. Previous: One Source of Truth. Next: updating a fleet you can't reach — signed over-the-air firmware, and the day we had to rotate a key we could not afford to lose.