Seeed Studio SenseCAP S210x Payload Decoder
Decode Seeed SenseCAP S210x LoRaWAN payloads online: temperature, humidity, light, CO2, soil moisture and EC from the 7-byte measurement-ID frames shared by the whole S2101–S2110 series. Includes verified examples and a decodeUplink codec for ChirpStack v4 and The Things Stack.
Example payloads
01011098530000010210A87A0000AF51
S2101: 21.4 °C · 31.4 %RH (official TTN repository test vector)
010110B068000001021088F400008CFF
S2101: 26.8 °C · 62.6 %RH (example from the official user guide)
00070064000500010610B45F0000010710A41F00003259
S2104: battery 100 % · interval 5 min · soil 24.5 °C · moisture 8.1 % (user guide)
Payload structure
| Bytes | Field | Type / scale | Description |
|---|---|---|---|
| frame byte 0 | Channel | uint8 | 0x01 = sensor measurements; 0x00 = system frames (battery, versions, device info). |
| frame bytes 1–2 | Measurement ID | uint16 LE | 0x1001 air temperature (°C) · 0x1002 air humidity (%RH) · 0x1003 light (lux) · 0x1004 CO2 (ppm) · 0x1006 soil temperature (°C) · 0x1007 soil moisture (%) · 0x100C soil EC (dS/m). |
| frame bytes 3–6 | Value | int32 LE ÷ 1000 | Signed two's complement — negative temperatures are supported. On-wire value is the physical value × 1000. |
| ID 0x0007 | Battery + interval | 2 × uint16 LE | System frame sent roughly every 20 uplinks: battery % and upload interval in minutes. |
| last 2 bytes | CRC-16 | checksum | Packet checksum. The official decoders do not verify it; this tool displays it in the trace. |
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 names = {
4097: "air_temperature", 4098: "air_humidity", 4099: "light",
4100: "co2", 4101: "pressure", 4102: "soil_temperature",
4103: "soil_moisture", 4108: "soil_ec"
};
if (b.length < 9 || (b.length - 2) % 7 !== 0) {
return { errors: ["invalid S210x frame length"] };
}
var data = {};
for (var o = 0; o + 7 <= b.length - 2; o += 7) {
var id = b[o + 1] | (b[o + 2] << 8);
var raw = b[o + 3] | (b[o + 4] << 8) | (b[o + 5] << 16) | (b[o + 6] << 24);
if (id > 0x1000) {
data[names[id] || ("measurement_" + id)] = raw / 1000;
} else if (id === 7) {
data.battery = b[o + 3] | (b[o + 4] << 8);
data.interval_min = b[o + 5] | (b[o + 6] << 8);
} // other system IDs (versions, EUI) are ignored
}
return { data: data };
}
About the S210x frame format
All SenseCAP S210x sensors — S2101 (temperature & humidity), S2102 (light), S2103 (CO2), S2104/S2105 (soil) and the S2110 family — share one payload format, which is why a single decoder covers the whole series. Each uplink is a sequence of 7-byte frames plus a 2-byte CRC:
[channel 1B] [measurement ID 2B LE] [value 4B int32 LE] ... [CRC 2B]
Practical notes:
- Everything is little-endian, including the measurement ID: the
on-wire bytes
01 10mean ID 0x1001 (air temperature). - All values are ×1000. Divide the int32 by 1000: 26800 → 26.8 °C. Negative temperatures use standard two’s complement.
- A battery frame appears periodically (channel 0x00, ID 0x0007) about every 20 uplinks, carrying battery % and the upload interval in minutes — don’t treat it as a broken measurement.
- Device-info frames after join (IDs 0x0000–0x0009) carry versions and the sensor EUI; decoders can safely skip them.
- The trailing CRC-16 is not verified by the official decoders; it is shown in this tool’s trace for completeness.
References
- SenseCAP S210X Sensors User Guide (packet structure and worked examples) — Seeed Studio
- Official decoder: github.com/Seeed-Solution/SenseCAP-Decoder,
S210X/ - Measurement ID list: sensecap-docs.seeed.cc/measurement_list.html
More device decoders
Building your own LoRaWAN network? Get Yubox Gateway OS free, or learn hands-on in the LoRaWAN Master Training.