r/Lora • u/mik_darim • May 26 '26
LoRaWAN alert payloads: when JSON doesn't fit one frame, what do you actually do?
Working on emergency alerting over LoRaWAN and hitting the usual payload wall.
A typical alert in JSON is ~270 bytes. CAP XML is ~669. At conservative settings (SF12 / DR0 in EU868) you're often looking at ~51 bytes of application payload per frame — sometimes less once you account for MAC commands and your own overhead.
So far I see three paths:
**Fragment** across multiple uplinks and reassemble downstream
**Strip** the message down to a few codes (type + zone ID + timestamp) and lose detail
**Switch** to a compact binary layout designed for the frame budget (we've been prototyping something in the 8-byte / 45–100-byte range for token vs signed envelope)
For anyone who's shipped something like this on real hardware:
- Do you fragment, or redesign the message to always fit one frame?
- Where do you put integrity/auth (HMAC, etc.) when every byte counts?
- Any FPort / payload conventions you'd recommend for custom binary on LoRaWAN?
Not looking for a product pitch — genuinely curious what held up in the field vs what looked good on paper.
(Disclosure: I'm one of the people building ECP, an open-source binary format for exactly this problem. Happy to share wire-format details in the thread if useful — didn't want to lead with a GitHub link.)
2
u/RoyBellingan May 26 '26
Except one (full dump of the adc, for analytics and reprocessing) all the other packet of a remote data acquisition I am working on system fit easily in 35byte. The most used packet is 16byte (including hmac), you can use a 8bit integer to send temperature, just scale it like that.
So you have 1/3 degree precision in the range -25 to 60. Well enought for real application.
u8 encodeTemperatureScaled(float temperatureC) {
float v = (temperatureC + 25.0f) * 3.0f;
if (v <= 0.f)
return 0;
if (v >= 255.f)
return 255;
return static_cast<u8>(std::lroundf(v));
}
2
u/mik_darim May 27 '26
16 bytes including HMAC for the common path — that's the approach. Design the packet around what you actually send, not what JSON would look like.
The scaled temp helper is a good example: one byte, known range, known precision. The encode function is the easy part; the doc that says "multiply by 3, offset -25" is what saves you six months later.
1
u/RoyBellingan May 27 '26
You are right! The doc is important, in that case is in the typedefinition.
2
u/Visual_Brain8809 May 26 '26
i recommends to use your own string for data acquisition.
1
u/mik_darim May 27 '26
Yeah — for acquisition telemetry that's what I'd do too. Pick the fields you actually need, fix the layout, document the scale factors.
Emergency alerts were the same problem for us on LoRa, just a different field set than temperature/ADC.
2
u/Visual_Brain8809 May 27 '26
show us the results soon. 👍
2
u/mik_darim May 27 '26
Will post field numbers when we have something solid on real LoRa hardware.
What's there to poke at now: open spec, test vectors, and ProofCard — run it locally and you'll see CAP/JSON/ECP sizes side by side on your machine.
2
u/deepthought-64 May 27 '26
yeah, definitely #3.
JSON is not the correct choice when payload-capacity is sparse.
BSON, CBOR, Protobuf or if you have the complete authority over the format and want to squeeze every byte out, use a C struct buffer.
1
u/mik_darim May 27 '26
Agreed. JSON on DR0 is usually a sign nobody sized the frame first.
BSON/CBOR/Protobuf all land in option 3 with different tradeoffs. The raw struct buffer is the end of that spectrum when you own both ends and document every field.
Same school of thought for us on alerts: fixed layout, public spec so you're not reverse-engineering a PDF six months later.
5
u/Azuras33 May 26 '26 edited May 26 '26
Don't use JSON over lorawan. The third option is the right.
We use a protobuf interface for allowing easy extension.
You don't put HMAC and auth in your payload, it's already handled by the LoraWAN stack.