Skip to content

Protocol Overview

This page explains the conceptual architecture of the Huepar S120 Bluetooth Low Energy (BLE) protocol.

The S120 uses a simple request-response protocol over BLE GATT:

┌─────────────┐ BLE ┌─────────────┐
│ Mobile App │ ◄──────────────────► │ S120 │
│ (Client) │ │ (Server) │
└─────────────┘ └─────────────┘
│ │
│ 1. Write command to 0xAE01 │
│ ───────────────────────────────────►
│ │
│ 2. Receive response on 0xAE02 │
│ ◄───────────────────────────────────
│ (notify) or 0xAE05 (indicate) │

The device exposes a custom GATT service (0xAE30) with three characteristics:

CharacteristicDirectionPurpose
0xAE01App → DeviceCommand transmission (write-without-response)
0xAE02Device → AppMeasurement data (notify)
0xAE05Device → AppStatus/errors (indicate)

All commands follow the LDMv1 (Laser Distance Meter version 1) format:

┌────────┬──────────┬──────────┬──────────┐
│ Header │ Command │ Payload │ Checksum │
│ 0xF1 │ 1 byte │ 0-N bytes│ 1 byte │
└────────┴──────────┴──────────┴──────────┘

Checksum calculation:

checksum = sum(packet[1:]) % 256 # Skip the F1 header
  1. No pairing required - Reduces friction for connecting
  2. Simple checksum - Easy to implement on microcontrollers
  3. Notification-based responses - Allows async measurement updates
  4. Separate channels - Data (0xAE02) vs status (0xAE05) isolation
1. Scan for "LDM-S120 *" devices
2. Trust the device (required on Linux/BlueZ)
3. Connect to GATT
4. Enable notifications on 0xAE02 and 0xAE05
5. Send commands to 0xAE01
6. Process responses from notifications

When you trigger a measurement:

1. App sends: F1 00 00 F1 (CLICK_MEASURE_BUTTON)
2. Device laser activates
3. Device measures distance
4. Device sends response on 0xAE02:
F1 01 00 <length> <mode> <unit> <flags> <value...> <checksum>
5. App parses value and displays to user

Distances are encoded as 16-bit big-endian integers in millimeters:

Value bytes: 0x01 0x2C
────────
│ │
│ └─ Low byte: 0x2C = 44
└────── High byte: 0x01 = 256
Result: 256 + 44 = 300 mm = 0.300 m

Strings (like MAC addresses, firmware versions) are ASCII-encoded with a length prefix:

Response: F1 03 00 0C 35 62 61 36 ...
── ─────────────
│ │
│ └─ ASCII: "5ba6..."
└───── Length: 12 bytes

Errors are reported on the indicate characteristic (0xAE05):

ErrorMeaning
Err 1Target too far
Err 2Target too close
Err 3Excessive ambient light
Err 4Out of measurement range

The app should always subscribe to both 0xAE02 (data) and 0xAE05 (errors) to handle all device responses.

The “LDMv1” designation comes from the APK code. The app also contains code for:

  • LaserLevelV1/V2/V3 - Cross-line laser protocols
  • LDMv2 - Potentially future devices

Each protocol variant uses different service UUIDs, allowing the app to auto-detect device types during scanning.