Most IoT architecture advice assumes a constant internet connection. That assumption breaks immediately on a farm two hours outside Lagos where cellular coverage drops out for hours at a time and grid power isn't guaranteed either.
Designing for absence, not presence
The core decision was to treat connectivity as something that happens occasionally, not continuously. Every sensor node buffers locally and syncs opportunistically rather than assuming an always-on link back to the cloud.
// Simplified sync logic running on each sensor node
async function syncReadings(buffer) {
if (!(await hasConnectivity())) {
return; // keep buffering, try again next cycle
}
const batch = buffer.drain(50); // send in small batches
try {
await uploadBatch(batch);
} catch {
buffer.restore(batch); // connectivity dropped mid-upload
}
}
The failure mode we designed around
The riskiest moment isn't losing connectivity — it's losing it mid-upload. Buffers need to be restorable, not just appendable, or you silently lose readings during exactly the conditions you built the system to handle.
LoRaWAN over cellular
For device-to-gateway hops we used LoRaWAN instead of cellular modems on each node. It's slower and lower-bandwidth, but a single gateway can cover several kilometers on a fraction of the power budget, and it doesn't depend on carrier coverage at all.
That's battery life on a single charge, same solar panel, same reporting frequency. The gap is almost entirely radio power draw.
What this bought Savannah Agro
Irrigation teams got soil moisture data that arrives within a few hours even during coverage gaps, instead of full days of blind irrigation on a fixed schedule. Water usage dropped 31% in the first season — not because the technology got smarter, but because the system was designed to actually work in the environment it was deployed into.
