Inspiration
In a disaster, connectivity is the first casualty and that is exactly when conventional sensing fails. reach the cloud before the decision can be made. When the cell towers go down or saturate which is precisely what happens in a flood, a fire, or an earthquake the sample never arrives, the decision is never made, and the alert never exists. The system does not degrade gracefully; it stops working silently, at the worst possible moment. It is needed most in low-connectivity regions where a cloud dependent warning system is least likely to work.
What it does
I have measured this. On a LoRa-only link, a cloud-inference pipeline delivered 0 % of critical hazard alerts. It physically cannot push a 512-byte sample at 2 Hz through a 20-byte per second bearer, so no inference ever happens. SentinelGrid moves the intelligence to the device, so the decision exists whether or not a network does, and makes the delivery adapt to whatever link survives. A confirmed hazard is 14 bytes. Getting 14 bytes through a broken network is tractable; getting a waveform through it is not. Under the same conditions where the cloud pipeline delivered 0 %, SentinelGrid delivered 100 %, in under three seconds.
How we built it
On device ML: a multinomial softmax classifier (12 engineered features → 5 hazard classes), trained by gradient descent and quantized to int8 — 60 bytes of weights, 60 MACs, ~3 µs per inference. Deliberately not TensorFlow Lite Micro: its interpreter costs 20–40 KB of flash before performing a single multiply, and this model is 60 bytes. It reaches 96.2 % holdout accuracy, with zero accuracy lost to quantization. DSP: median-of-3 despiking, EMA low-pass filtering, least-squares slope estimation, and a first-difference high-pass for vibration energy-ratio features the feature that separates a passing lorry from a cracking structure. Networking: adaptive transmission engine — a real state machine over 5G/LTE, NB-IoT, LoRa and offline, with hysteretic bearer selection, four payload tiers (48 B features → 14 B alerts), a QoS priority queue in which critical alerts pre-empt telemetry, exponential-backoff retry, and RAM store-and-forward that drains on reconnect. MQTT (QoS 1 for alerts, retained; QoS 0 for telemetry). Firmware: ESP32 (C++/Arduino). BOM ~$100/node: MQ-2 gas, BME680, JSN-SR04T ultrasonic water level, MPU6050 IMU, SIM7600 (LTE/NB-IoT), RFM95 LoRa. Web:a real-time command center — vanilla JS + Canvas, zero dependencies, self-contained. The classifier trains itself in your browser when you open it. Testing:the firmware's DSP, model and network engine are pure C, so they compile and execute natively under a host test harness — 44 passing assertions, including verification that the firmware reproduces the browser model's prediction on 100 % of held-out samples.
Challenges we ran into
False alarms and the fact that my first three attempts to fix them were aimed at the wrong layer. An alerting system that cries wolf gets muted, and a muted system kills the person it was installed to protect. So the false-alarm rate is a safety parameter, not a UX one. My first model produced 23 false alarms in 200 seconds across a 12-node fleet. Unusable. I assumed it was noise, so I widened the temporal consensus window to smooth it out. It bought exactly zero improvement, and cost 2 seconds of detection latency. That failure was the most useful result in the project: it proved the false alarms were not flicker. The model was sustainedly, confidently wrong for many seconds at a time — and no temporal filter can fix a persistent error. So I stopped tuning and started diagnosing: what were the false alarms actually saying? Mostly FLOOD. And that exposed the real bug, which was not in the model at all — it was in my physics. I had modelled a flood as "the water goes up a bit," which is identical to rain. The two classes overlapped in the data, so no classifier could ever separate them. Once I modelled a flood as what a flood actually is — an unbounded, fast rise, distinguished from rain by rate — the class became learnable and the false alarms collapsed roughly 30×, to ~0.5 per node-hour, with detection still landing in 7–12 seconds. Runner-up: the host test harness caught a bug where a perfectly calm node classified as FIRE at 91 % confidence — the filters initialised to zero, so the first window contained a ramp climbing from 0 to the first real reading on every channel at once. The node alarmed on its own power-up. It was masked in the sketch by an unrelated sensor warm-up delay, meaning the protection was accidental and would have vanished the moment anyone shortened it.
Accomplishments that we're proud of
A confirmed hazard is 14 bytes. Getting 14 bytes through a broken network is tractable; getting a waveform through it is not. Under the same conditions where the cloud pipeline delivered 0 %, SentinelGrid delivered 100 %, in under three seconds. It reaches 96.2 % holdout accuracy, with zero accuracy lost to quantization.
What we learned
The lesson I'd take to any ML system: if two classes overlap in a dataset, its not training a model — its adding label noise .The false-alarm rate measured is then Bayes error, and no threshold, no filter, and no bigger network will ever remove it. The fix has to happen upstream of the model, in how to represent the problem.
What's next for SentinelGrid
The ESP32 firmware. It is written for the hardware in the BOM and every algorithm in it is the tested one — but it has never been flashed to a physical board. I did not have the hardware. The sensor drivers and AT-command sequences are written from datasheets and are untested; that is where the first bring-up bugs will be. This is next goal ,to hardware test it.
Built With
- c-/-c++
- esp32
- javascript
- lora
- mqtt
- nb-iot-/-lte
- tinyml
Log in or sign up for Devpost to join the conversation.