Seeed Studio S2100 Data Logger Payload Decoder
Decode Seeed SenseCAP S2100 LoRaWAN Data Logger payloads online: measurement packets 0x30/0x31/0x32/0x33, the 0x39 battery packet and the 0x80000000 sentinel, from the official big-endian frame format. Includes verified examples and a decodeUplink codec for ChirpStack v4 and The Things Stack.
Example payloads
311001000067DE80000000
One measurement: 26.59 (0x000067DE = 26590 ÷ 1000); second slot empty (0x80000000) — official manual example
311202000067DE0000C26A
Two measurements: 26.59 and 49.77 — official manual example
301202000067DE0000C2A633340205F98A8800019A28
Four measurements across first (0x30) + final (0x33) packets: 26.59 · 49.83 · 100240.008 · 105 — official manual example
39640101000200050000
Battery packet: 100 % · SW 1.1 · HW 0.2 · interval 5 min — official manual example
Payload structure
| Bytes | Field | Type / scale | Description |
|---|---|---|---|
| 0x31 (11 B) | Measurement packet (≤ 2 values) | [ID][m|n][flag][val m 4B][val n 4B] | Byte 2 nibbles select measurement numbers m and n (1–10). Values are int32 BE ÷ 1000. 0x80000000 = no measurement. |
| 0x30 / 0x32 / 0x33 | Multi-packet series (> 2 values) | first / middle / final | Each carries 2 measurements. 0x30 and 0x33 include a flag byte (11 B); 0x32 does not (10 B) — a fixed-offset decoder breaks here. |
| 0x39 (10 B) | Battery packet | [ID][%][SW 2B][HW 2B][interval 2B][rsv 2B] | Battery %, software/hardware version and measurement uplink interval in minutes. Arrives on FPort 3. |
| 0x34 (5 B) | Datalogger status | protocol / GPIO / analog config | Configuration echo; the manual says it can be ignored. This decoder parses and skips it safely. |
| value encoding | Measurement values | int32 BE ÷ 1000, signed | The physical meaning of each measurement number depends on how you configured the channel (4–20 mA current, 0–10 V voltage, Modbus register, GPIO count) and the Y = Ax + B scaling set in the SenseCAP Mate app. |
Ready-to-use codec
ChirpStack v4 and The Things Stack share the same decodeUplink(input) signature:
paste this into the device profile codec (ChirpStack) or the
payload formatter (TTN).
function decodeUplink(input) {
var b = input.bytes;
var data = {};
var i = 0;
function i32(o) { return (b[o] << 24) | (b[o + 1] << 16) | (b[o + 2] << 8) | b[o + 3]; }
function meas(ch, o) {
if (ch === 0) return;
if ((i32(o) >>> 0) === 0x80000000) return; // no measurement
data["measurement_" + ch] = i32(o) / 1000;
}
while (i < b.length) {
var id = b[i];
if (id === 0x30 || id === 0x31 || id === 0x33) { // 2 values + flag byte
meas(b[i + 1] >> 4, i + 3); meas(b[i + 1] & 0x0F, i + 7); i += 11;
} else if (id === 0x32) { // middle packet: no flag byte
meas(b[i + 1] >> 4, i + 2); meas(b[i + 1] & 0x0F, i + 6); i += 10;
} else if (id === 0x39) { // battery packet
data.battery = b[i + 1];
data.software_version = b[i + 2] + "." + b[i + 3];
data.hardware_version = b[i + 4] + "." + b[i + 5];
data.interval_min = (b[i + 6] << 8) | b[i + 7];
i += 10;
} else if (id === 0x34) { i += 5; } // datalogger status: skip
else if (id === 0x03) { data.battery = b[i + 1]; i += 2; }
else if (id === 0x06) { data.sensor_error = b[i + 1]; i += 2; }
else if (id === 0x10) { i += 10; } // sensor EUI: skip
else { break; } // unknown: stop safely
}
return { data: data };
}
S2100 vs. S210x: two different protocols
Despite the similar names, the S2100 Data Logger does not use the S210x sensor frame format. The S210x series (S2101–S2110) packs little-endian 7-byte frames with global measurement IDs like 0x1001; the S2100 uses big-endian packet-ID frames where measurements are numbered 1–10 according to how you configured the logger’s channels. Decoders are not interchangeable — that’s why this tool lists them as separate devices.
About the S2100 uplink
The S2100 is a battery-powered hub that turns industrial sensors into LoRaWAN nodes: two 4–20 mA / 0–10 V analog inputs, RS485 Modbus-RTU (up to 10 measurements) and GPIO (level or pulse counting). Points that matter when decoding:
- Values have no intrinsic unit. A “measurement” is whatever the channel reads — milliamps, a Modbus register, a pulse count — optionally transformed by the Y = Ax + B scaling configured in the SenseCAP Mate app. The decoder gives you the numbers; the meaning is in your config.
- 0x80000000 means “no measurement”, not a huge negative number. The official manual highlights it; naive decoders show −2147483.648.
- Packet 0x32 is one byte shorter than 0x30/0x31/0x33 (it has no flag byte). A decoder that assumes a fixed frame size corrupts every value after the first middle packet.
- Measurements arrive on FPort 2, battery on FPort 3 (0x39 packet, with versions and the uplink interval in minutes). A status packet 0x34 may piggyback after it and can be ignored.
References
- SenseCAP S2100 LoRaWAN Data Logger User Guide, chapter 10 “Payload Decoder” (packet tables and all worked examples) — Seeed Studio
- Official decoder: github.com/Seeed-Solution/SenseCAP-Decoder,
S2100/
More device decoders
Building your own LoRaWAN network? Get Yubox Gateway OS free, or learn hands-on in the LoRaWAN Master Training.