Dragino LHT52 Payload Decoder

Decode Dragino LHT52 LoRaWAN payloads online: SHT temperature and humidity, external probe, Unix timestamp, and the FPort 5 device-status frame with battery. Includes payload structure, verified examples and a decodeUplink codec for ChirpStack v4 and The Things Stack.

Type: Temperature & humidity sensor with external probe LoRaWAN class: Class A FPort: 2 (sensor) / 5 (status) Payload: 11 bytes / 7 bytes Endianness: Big-endian

Example payloads

08CD02207FFF0161CD4EDD 22.53 °C · 54.4 % · probe not connected (0x7FFF) · sampled 2021-12-30 06:17:01 UTC (official manual example)
09010001000B3A FPort 5 status: LHT52 · firmware v1.0.0 · EU868 · battery 2.874 V (official manual example)

Payload structure

Bytes Field Type / scale Description
0–1 Built-in temperature (SHT) int16 ÷ 100 → °C Signed two's complement. Example: 0x08CD = 2253 → 22.53 °C; 0xF5C6 → −26.18 °C.
2–3 Built-in humidity (SHT) uint16 ÷ 10 → %RH Example: 0x0220 = 544 → 54.4 %.
4–5 External temperature int16 ÷ 100 → °C 0x7FFF is the sentinel for probe not connected (would read as 327.67 °C in a naive decoder).
6 External sensor type uint8 0x01 = AS-01 / DS18B20 temperature probe.
7–10 Timestamp uint32 → Unix epoch Sampling time in seconds since 1970 (UTC). The LHT52 timestamps readings on the device.
FPort 5 (7 bytes) Device status frame model + fw + band + battery Sent on join and every 12 h: sensor model (0x09), firmware, frequency band, sub-band, and battery in mV (bytes 5–6). Battery does NOT travel in the FPort 2 uplink.

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;
  function int16(i) { var v = (b[i] << 8) | b[i + 1]; return v >= 0x8000 ? v - 0x10000 : v; }
  if (input.fPort === 5 && b.length === 7) {
    return {
      data: {
        sensor_model: b[0] === 9 ? "LHT52" : b[0],
        firmware: "v" + b[1].toString(16) + "." + (b[2] >> 4) + "." + (b[2] & 0x0F),
        band: [null, "EU868", "US915", "IN865", "AU915", "KZ865", "RU864", "AS923", "AS923-1", "AS923-2", "AS923-3"][b[3]] || b[3],
        battery: ((b[5] << 8) | b[6]) / 1000
      }
    };
  }
  if (b.length !== 11) return { errors: ["expected 11 bytes on FPort 2"] };
  var ext = (b[4] << 8) | b[5];
  return {
    data: {
      temperature: int16(0) / 100,
      humidity: ((b[2] << 8) | b[3]) / 10,
      ext_temperature: ext === 0x7FFF ? null : int16(4) / 100,
      ext_sensor: b[6],
      timestamp: (b[7] * 16777216) + (b[8] << 16) + (b[9] << 8) + b[10]
    }
  };
}

The Dragino LHT52 is the successor of the LHT65 family: a compact indoor temperature/humidity sensor with an external probe connector. Its payload differs from the LHT65 in important ways — decoders are not interchangeable between the two:

  • Different field order. The LHT52 leads with temperature (bytes 0–1), not battery.
  • Battery is not in the sensor uplink. It travels in a separate FPort 5 device-status frame (sent on join and every 12 hours), in plain millivolts with no status bits. This tool decodes both frames and tells them apart by length.
  • On-device timestamp. Bytes 7–10 carry the sampling time as a Unix epoch — the LHT52 has an RTC and can store 178 readings that can be polled later as datalog uplinks (FPort 3).
  • Same 0x7FFF sentinel as the LHT65 for a disconnected external probe: a naive decoder shows 327.67 °C.

References

  • Dragino LHT52 user manual (payload sections 2.4.1–2.4.4) — wiki.dragino.com
  • Official decoder: github.com/dragino/dragino-end-node-decoder, LHT52/