LoRaWAN for Low-Power IoT
A soil moisture sensor in a vineyard needs to send 4 bytes every hour for five years on a pair of AA batteries. Wi-Fi would last weeks. Cellular would cost $5/month in SIM fees. LoRaWAN sends those 4 bytes over 3 km to a gateway, then to the cloud, drawing microamps between transmissions. It's not fast — 300 bps to 5.5 kbps depending on configuration — and it's not for video or firmware updates. It's for the millions of sensors that need to whisper, not shout.
LoRaWAN architecture
End Device (sensor) ──LoRa RF──► Gateway ──IP──► Network Server ──► Application Server
│ │ │
Battery powered Mains powered Manages keys,
868/915 MHz Ethernet/backhaul routing, ADR
0.3-50 kbps Multiple channels
- End devices — sensors/actuators with LoRa radio chip (SX1276, SX1262)
- Gateways — receive from many devices, forward to network server (many-to-one)
- Network server — manages device sessions, deduplicates, handles ADR
- Application server — decodes payloads, stores data, triggers alerts
Devices never talk directly to the application server. The network server handles all MAC-layer concerns.
Device classes
| Class | RX windows | Power | Use case |
|---|---|---|---|
| A | 2 short windows after TX | Lowest | Sensors, meters |
| B | Scheduled + post-TX | Medium | Actuators with predictable downlink |
| C | Always listening | Highest | Real-time control, street lighting |
99% of battery-powered sensors are Class A.
Spreading factors and range
LoRa modulation uses spreading factors (SF7-SF12) that trade data rate for range:
| SF | Data rate (EU868) | Sensitivity | Airtime (10 bytes) | Range (urban) |
|---|---|---|---|---|
| SF7 | 5.5 kbps | -126 dBm | ~50 ms | ~2 km |
| SF9 | 1.2 kbps | -131 dBm | ~180 ms | ~5 km |
| SF12 | 0.3 kbps | -137 dBm | ~1.5 s | ~10 km |
Higher SF = longer range but more airtime = more battery drain and less network capacity. Use Adaptive Data Rate (ADR) to let the network server optimize SF per device based on signal quality.
End device code (Arduino/ESP32)
#include <LoRaWAN.h>
void setup() {
LoRaWAN.begin(EU868);
LoRaWAN.setAppEUI(APP_EUI);
LoRaWAN.setDevEUI(DEV_EUI);
LoRaWAN.setAppKey(APP_KEY);
LoRaWAN.join(OTAA); // Over-the-Air Activation
}
void loop() {
float moisture = read_soil_sensor();
uint8_t payload[2];
payload[0] = (uint16_t)(moisture * 100) >> 8;
payload[1] = (uint16_t)(moisture * 100) & 0xFF;
LoRaWAN.send(1, payload, 2); // port 1, 2 bytes
LoRaWAN.sleep(); // deep sleep until next reading
// Wake every 15 minutes via RTC timer
enter_deep_sleep(15 * 60);
}
OTAA (Over-the-Air Activation) is preferred over ABP (Activation By Personalization) — session keys are negotiated, not pre-provisioned.
Payload encoding
Keep payloads compact. Use a binary format, not JSON:
# Decoder (Application Server — The Things Stack)
def decode_uplink(payload):
if len(payload) >= 2:
moisture = ((payload[0] << 8) | payload[1]) / 100.0
return {"soil_moisture_percent": moisture}
if len(payload) >= 4:
temp = struct.unpack(">h", payload[0:2])[0] / 100.0
humidity = payload[2]
battery = payload[3]
return {"temperature_c": temp, "humidity_percent": humidity, "battery_percent": battery}
Define a Cayenne LPP or custom binary schema per device type. Document it alongside the firmware.
Gateway placement
Rules of thumb:
- Urban: one gateway per 2-3 km radius, rooftop or pole mount
- Rural/open: one gateway covers 5-15 km depending on terrain
- Indoor: one gateway per large building floor
- Minimum: two gateways with overlapping coverage for redundancy
Use RF planning tools (Radio Mobile, CellMapper for LoRa) to model coverage before deploying hardware.
Duty cycle regulations
EU868 enforces 1% duty cycle per sub-band (device can transmit max 1% of the time). At SF7 with a 10-byte payload, that's roughly 140 messages per day. Plan your reporting interval accordingly:
Max messages/day ≈ (86400 seconds × 0.01) / airtime_per_message
SF7, 10 bytes: ~140/day → every 10 minutes is safe
SF12, 10 bytes: ~14/day → every 2 hours maximum
US915 has different regulations (no duty cycle limit but frequency hopping required).
Size LoRaWAN payload under 51 bytes for lowest data rate SF12 — larger payloads force faster SF and reduce range dramatically.
ADR and spreading factor selection
Higher SF = longer range, lower data rate, more airtime:
| SF | Range (suburban) | Airtime (10B payload) | Use case |
|---|---|---|---|
| SF7 | ~2 km | ~60 ms | Frequent updates, mains powered |
| SF10 | ~5 km | ~370 ms | Battery, hourly readings |
| SF12 | ~15 km | ~1.5 s | Remote sensors, daily readings |
Adaptive Data Rate (ADR) lets network server reduce SF when signal is strong — saves battery and increases network capacity.
Join procedure and security
OTAA (Over-The-Air Activation) preferred over ABP:
Device → Join-Request → Network Server → Join-Accept
Session keys derived from AppKey — never transmitted
ABP hardcodes keys in firmware — device clone attack copies keys to rogue device. OTAA rotates session keys on each join.
Downlink limitations
LoRaWAN is uplink-heavy — downlink slots are scarce:
- Class A: downlink only after uplink (smallest gateway load)
- Class C: continuous receive (high power, mains required)
- Downlink queue max ~10 messages on most network servers
Don't design command-and-control that requires frequent downlinks on Class A battery devices.
Pair with IoT OTA updates rollback for firmware delivery over constrained LoRaWAN downlinks.
Common production mistakes
Teams get lorawan low power wan wrong in predictable ways:
- Skipping failure-mode rehearsal — run a game day or fault injection exercise before peak traffic, not after the first outage.
- Missing correlation context — every error path should carry request, trace, or tenant identifiers so incidents are debuggable.
- Optimizing for demo, not steady state — load tests, cache warm-up, and cold-start paths matter more than local dev latency.
- Undocumented trade-offs — if you chose speed over strict correctness (or vice versa), write that down for the next engineer.
IoT deployments of lorawan low power wan fail in the field when firmware assumes stable Wi-Fi, OTA rollback is untested, and device certificates expire without automated renewal.
Resources
- LoRa Alliance specification — official LoRaWAN protocol specification
- The Things Network documentation — open LoRaWAN network and device onboarding
- Semtech LoRa calculator — airtime, sensitivity, and range estimation
- LoRaWAN Academy — free courses on LoRaWAN deployment
Frequently asked questions
What is LoRaWAN and how is it different from Wi-Fi or cellular?
LoRaWAN is a low-power wide-area network protocol that sends small payloads (10-250 bytes) over kilometers using unlicensed ISM bands (868 MHz EU, 915 MHz US). Devices sleep between transmissions and run on batteries for years. Wi-Fi and cellular offer higher bandwidth but consume 10-100x more power and require infrastructure LoRaWAN doesn't.
What are LoRaWAN device classes A, B, and C?
Class A devices receive only during two short windows after each uplink — lowest power, most common. Class B adds scheduled receive slots synchronized by gateway beacons — moderate power. Class C keeps the receiver always on — highest power, used for actuators that must respond immediately.
How long do LoRaWAN sensor batteries last?
5-10 years on 2x AA batteries for Class A devices sending one reading every 15 minutes, depending on spreading factor, payload size, and battery chemistry. Higher spreading factors (longer range) increase airtime and reduce battery life. SF7 at close range maximizes battery; SF12 at maximum range minimizes it.
Hiring a senior Android / Flutter engineer?
I architect and ship production mobile software — Kotlin, Jetpack Compose, Flutter — for robotics, EV infrastructure, fintech, and real-time systems. Open to remote roles in Europe and the US.
Get in touch →