Architecture
Architecture
Five layers, one orchestrated device. From sensor input to wireless broadcast, every signal passes through a deterministic pipeline tuned for low latency and high reliability.
Five layers, one orchestrated device. From sensor input to wireless broadcast, every signal passes through a deterministic pipeline tuned for low latency and high reliability. Nothing in the WB-1 is event-loop spaghetti — each stage has a fixed contract, a measured latency budget, and a defined failure mode. That is what lets us promise sub-8-millisecond sensor-to-broadcast and actually hit it on every cycle, not just the median one.
The pipeline at a glance
Signals flow left to right. Each layer hands the next a strictly typed frame and a timestamp drawn from the same hardware clock, so latency is additive and auditable rather than emergent.
INPUTS NORMALIZE ENGINE TRANSMIT OUTPUTS
┌───────┐ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐
│ 12 ch │ ──▶ │ unify + │──▶ │ fuse + │──▶ │ BLE/WiFi │──▶ │ actu- │
│ radios│ │ stamp │ │ decide │ │ /LoRa fan│ │ ators │
└───────┘ └─────────┘ └──────────┘ └──────────┘ └────────┘
~0.5 ms ~1.2 ms ~2.5 ms ~3 ms —
The per-layer budgets above are worst-case at full channel load; typical operation runs roughly 40% under. The Cortex-M7 owns the deterministic real-time path (normalize → engine → transmit-schedule), while the ESP32 owns the radios, the web stack, and the cloud sync. Splitting the two means a slow REST request can never stall a safety interlock.
Layer 1: Inputs
What it does: terminates every physical and wireless source the device can see — 12 channels spanning analog (0–10V, 4–20mA), digital GPIO, I²C/SPI/UART sensor buses, plus BLE and Wi-Fi scan results.
In / out: raw electrical or packet data in; a tagged sample
(channel_id, value, hw_timestamp) out.
Latency budget: ~0.5 ms. ADC sampling and bus reads are DMA-driven, so the CPU is never blocked polling.
What can go wrong: a flapping sensor, a disconnected bus, an
out-of-range analog reading. How to debug: every channel exposes a live
rssi/quality field in the dashboard; a dead channel shows as stale
with its last-good timestamp.
Layer 2: Normalization
What it does: converts the zoo of input formats into one unified wire frame. Every sample is timestamped against the shared monotonic clock, priority-tagged, and deduplicated against the last frame on that channel.
In / out: heterogeneous tagged samples in; a uniform Frame struct out.
Latency budget: ~1.2 ms including the dedup window.
What can go wrong: clock skew between input sources, or a chatty sensor
flooding its channel. How to debug: the normalize layer emits a
dropped_duplicates counter per channel — a spike there usually means a
sensor needs debounce tuning, not a device fault.
Layer 3: Bobulation Engine
What it does: the decisioning core. Multi-input fusion with weighted confidence, the YAML rule engine, deterministic conflict resolution, and context-aware routing. This is the layer worth the price of the box, and it gets its own deep-dive.
In / out: normalized frames in; routing decisions
(output_target, payload, priority) out.
Latency budget: ~2.5 ms worst-case for a 12-channel fusion with a deep rule set.
What can go wrong: a rule conflict with no defined precedence. How to debug: the engine never silently picks a winner — unresolved conflicts hit the audit log with both contending rules and the freshness scores that broke the tie.
Layer 4: Transmission
What it does: schedules and fans out decisions across BLE 5.3, Wi-Fi 6, and LoRa — one radio or all three simultaneously.
In / out: routing decisions in; framed radio packets out.
Latency budget: ~3 ms, dominated by the BLE connection interval. LoRa is fire-and-forget for range; BLE/Wi-Fi carry the low-latency traffic.
What can go wrong: RF congestion, a saturated 2.4 GHz band. How to debug: the transmit layer reports airtime utilization per radio; if BLE airtime is pegged, move bulk traffic to Wi-Fi via a one-line routing rule.
Layer 5: Outputs
What it does: the far end — actuators, downstream devices, cloud APIs, dashboards, and alerts. The Bobulator doesn’t care whether the receiver is a relay board or a Kubernetes ingress; it’s all addressable output.
In / out: radio packets in; physical actuation or API calls out.
Layer-to-layer contracts
| From → To | Frame type | Guarantee |
|---|---|---|
| Inputs → Normalize | TaggedSample | hardware timestamp, never reordered |
| Normalize → Engine | Frame | deduplicated, priority-tagged |
| Engine → Transmit | Decision | deterministic, audit-logged |
| Transmit → Outputs | RadioPacket | per-radio delivery receipts (BLE/Wi-Fi) |
Every boundary is a typed struct, not a loose dictionary. That is the whole trick: because each contract is fixed, you can reason about — and test — each layer in isolation.
Failure modes & recovery
A deterministic pipeline is only as good as its behaviour when something breaks. Every layer has a defined failure mode and a defined recovery — none of them is “the device hangs and someone reboots it.” Here is what actually happens.
The Cortex-M7 hangs. The ESP32 holds an independent hardware watchdog that the M7 must pet every tick. Miss the deadline and the ESP32 resets the M7 within 50 ms, then replays the last-good rule set from NVRAM. Because the two chips are independent, a wedged control loop cannot also wedge the watchdog that’s supposed to catch it.
A radio’s SPI bus errors out. The driver backs off with a bounded exponential retry rather than hammering a dead bus. If the fault persists past the retry budget, the transmit layer marks that radio degraded and escalates the affected traffic to mesh neighbours, so a single failed radio downgrades range and redundancy instead of dropping the link.
Power drops below threshold. At the 3.1 V brown-out point the M7 takes a hardware interrupt with reserve energy in the bulk capacitance — enough to write the last rule state and audit cursor to NVRAM before shutdown. On the next power-up the engine resumes from that checkpoint rather than cold-booting blind.
Cloud connection is lost. Nothing stops. The engine runs entirely on the last-known rule set and recent sensor history held on-device; the audit log buffers locally and hash-chains forward, then syncs when the link returns. The WB-1 was designed offline-first — the cloud is where you manage the fleet, never where you run it.
Ready to go deeper? Read about the Bobulation Engine, pick a wireless topology for your site, scan the full technical specifications, or read how it’s built.