One Source of Truth
#kairair#kairair-state#code-generation#building-in-public#architecture#yaml
David Olsson
Ask a simple question about any hardware project and watch it get uncomfortable: the sensor is on pin D3 β where does it say that?
The honest answer, for most projects, is: in several places. It's in the firmware, as a #define. It's in the wiring diagram you drew. It's in the README where you told the builder how to hook it up. It's implied by the parts list. Four places. Maybe five.
Now the harder question. When those four places disagree β and given enough time they always do β which one is right?
If you can't answer that instantly, you don't have a source of truth. You have four rumors.
the rumor problem
This is the same disease as the four firmware sketches from the last post, just moved up a level.
Down in the firmware, duplication meant a bug fixed once and alive three more times. Up here, in the description of the hardware, duplication means something quieter and nastier: a builder wires their station to match the diagram, the diagram is a week out of date, the firmware expects a different pin, and the thing just⦠doesn't work. No error. No crash. Just a sensor reporting nothing, and a person in their kitchen wondering what they did wrong.
They didn't do anything wrong. The project told them two different things and shipped both.
For a network that wants strangers to build their own stations, that failure mode isn't acceptable. The pin map can't live in four documents that a human keeps in sync by hand. It has to live in exactly one, and everything else has to be generated from it.
That one place is a folder called kairair-state.
what's actually in there
kairair-state is not code that runs on a station. It's a facility β a small, versioned pile of structured definitions and the tools that read them. Nothing about a device is described anywhere else. If it's true about the hardware, it's true here first.
The definitions are plain YAML, split into the three things worth naming separately:
- Boards β a controller like the LoLin NodeMCU: its pins, its power expectations, what each pin can and can't do.
- Sensors β a part like the BME680 or the BMP180: what it measures, how it connects, what bus it speaks.
- Kits β a specific recipe: this board, these sensors, wired this way, as a named, versioned combination.
That's the source. A kit is just a small YAML file that says "this controller, these sensors, here's how they meet." Everything downstream is manufactured from it.
three things, generated
The reason this is worth the trouble is what the tools do with those definitions. There are three of them, and together they close the gap between "what the project says" and "what's real."
The first tool validates. Before a kit is allowed to exist, it's checked β not just "is this valid YAML," but the electrical questions that actually bite you. Are two devices fighting over the same pin? Is something wired to a pin that can't do what's being asked of it? Does the power budget make sense? This runs as a gate. A kit that breaks the rules doesn't get to become a station.
The second tool draws. From the same definition, it generates the wiring diagram β an actual SVG a human can follow β plus a connection table and the bill of materials. The builder's instructions aren't authored by hand and hopefully-kept-current. They're a rendering of the truth, regenerated whenever the truth changes.
The third tool stamps the firmware. Remember those two config headers from the last post β board_config.h and kit_config.h, the small files that tell the one shared firmware which pins and sensors this particular station has? Those are generated here too, from the same YAML. The firmware learns its hardware from the exact same file the diagram was drawn from.
One definition in. Validation, a diagram, a parts list, and the firmware's pin map out. All of them, by construction, agreeing.
the sentence that makes it a rule
The project spec puts it plainly, and it's the load-bearing sentence of the whole system:
Firmware pin maps, wiring diagrams, workshop docs, and backend registry records all derive from one source of truth β never hand-duplicated.
Never hand-duplicated. That's the commitment. Not "kept in sync." Not "documented carefully." Never duplicated in the first place, because the moment a fact about the hardware exists in two files that a person maintains, drift is only a matter of time.
Now go back to the uncomfortable question. The sensor is on pin D3 β where does it say that? For KAIRair, there's exactly one answer: it says so in the kit definition. The firmware header says D3 because it was generated from that definition. The diagram shows D3 because it was drawn from that definition. They can't disagree, because only one of them was ever authored. The rest are shadows of it.
what this actually buys
The payoff shows up when something changes.
Move a sensor to a different pin β because the first choice conflicted with the screen, say. You change it in one place: the kit's YAML. Re-run the tools. The validator re-checks the whole board for new conflicts. The diagram redraws itself. The BOM updates. The firmware header regenerates. A builder who downloads the instructions gets the new pin, and the firmware they flash expects that exact pin, because both came from the edit you just made.
You didn't update four documents. You updated one fact, and the four documents updated themselves.
That's the quiet superpower under the whole network. Not any single clever component β the discipline that there's only ever one of each fact, and the machinery to turn that one fact into everything the project needs to say about it.
The stations are built on firmware. The firmware is built on definitions. And the definitions are the only thing anyone actually writes by hand.
Part three of the KAIRair build series. Previous: From Four Sketches to One Firmware. Next: many boards, many sensors β how the network captures a brand-new sensor the moment its firmware reports one, without anyone teaching it the schema first.