LD2412 Human Presence Sensor
The LD2412 is a wide-angle 24GHz mmWave radar sensor that detects human presence via FMCW. It supports both UART and digital output and is ideal for real-time occupancy monitoring in smart environments.

On this page
LD2412 pinout
The LD2412 is a 6-pin 24GHz mmWave radar with wide-angle detection and flexible power:
| Pin | Type | Description | Notes |
|---|---|---|---|
| OUT | Communication | Digital presence output | 3.3V HIGH when presence detected |
| TX | Communication | UART transmit | Sends data from sensor (connect to ESP32 RX) |
| RX | Communication | UART receive | Receives commands (connect to ESP32 TX) |
| 5V | Power | 5V power input | Use either 5V OR 3V3 (not both) |
| 3V3 | Power | 3.3V power input | Use either 5V OR 3V3 (not both) |
| GND | Power | Ground connection |
Interface: UART (115200 baud)
Technology: 24GHz FMCW radar
Detection: Human presence (stationary and moving targets)
Range: Up to 9 meters (longest in LD series)
Field of View: ±75° (widest in LD series)
Power: Flexible - choose 5V or 3.3V (do NOT power both simultaneously)
Pin Spacing: 2.54mm (standard breadboard-compatible)
OUT Logic: 3.3V compatible, safe for ESP32 GPIO
Applications: Wide-area occupancy detection, smart lighting, security systems
Power Warning: Only connect ONE power source (5V or 3V3), never both
Wiring the LD2412 to ESP32
To interface the LD2412 with an ESP32 for wide-angle presence detection via UART:
| LD2412 pin | ESP32 pin | Purpose |
|---|---|---|
| 5V (or 3V3) | 5V (or 3.3V) | Power supply (choose one voltage) |
| GND | GND | Ground |
| TX | GPIO16 (RX2) | Sensor transmit to ESP32 receive |
| RX | GPIO17 (TX2) | Sensor receive from ESP32 transmit |
| OUT | GPIO18 | Digital presence output (optional) · optional |
UART2: Use UART2 on ESP32 (GPIO16/17 are default UART2 pins)
Baud Rate: 115200 bps - must match in firmware configuration
Power: Choose either 5V or 3.3V (do NOT connect both)
TX/RX: Connect sensor TX to ESP32 RX, sensor RX to ESP32 TX
OUT Pin: 3.3V logic level, safe for direct ESP32 GPIO connection
Wide Angle: ±75° field of view provides excellent room coverage
Long Range: 9-meter detection range ideal for large spaces
Breadboard: 2.54mm pitch allows easy prototyping
LD2412 code examples
LD2412 Arduino example
Copy// Requires library: "LD2412"
#include <LD2412.h>
// UART2: sensor TX -> GPIO16 (RX2), sensor RX -> GPIO17 (TX2)
LD2412 radar(Serial2);
void setup() {
Serial.begin(115200);
Serial2.begin(115200, SERIAL_8N1, 16, 17);
}
void loop() {
int state = radar.targetState(); // 0 none, 1 moving, 2 stationary, 3 both
if (state > 0) {
Serial.print("Presence detected (");
Serial.print(state == 1 ? "moving" : state == 2 ? "stationary" : "moving + stationary");
Serial.print("), moving at ");
Serial.print(radar.movingDistance());
Serial.print(" cm, static at ");
Serial.print(radar.staticDistance());
Serial.println(" cm");
} else {
Serial.println("No presence");
}
delay(1000);
}This example uses the "LD2412" Arduino library (by Trent Tobias, tobiastl/LD2412 on GitHub) over UART2 - sensor TX to GPIO16, RX to GPIO17 at 115200 baud. The library parses the radar frames internally: targetState() reports 0 (no one), 1 (moving), 2 (stationary) or 3 (both), and movingDistance()/staticDistance() return the target distances in centimeters. The same library also exposes sensitivity and gate configuration if you need to tune detection.
LD2412 ESP-IDF example
Copy#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
// LD2412 on UART2: radar TX -> GPIO16 (RX2), RX -> GPIO17 (TX2), 115200 baud
#define RADAR_UART UART_NUM_2
#define RADAR_RX_PIN 16
#define RADAR_TX_PIN 17
static const uint8_t FRAME_HEAD[4] = {0xF4, 0xF3, 0xF2, 0xF1};
void app_main(void)
{
uart_config_t config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
ESP_ERROR_CHECK(uart_param_config(RADAR_UART, &config));
ESP_ERROR_CHECK(uart_set_pin(RADAR_UART, RADAR_TX_PIN, RADAR_RX_PIN,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
ESP_ERROR_CHECK(uart_driver_install(RADAR_UART, 1024, 0, 0, NULL, 0));
uint8_t buf[64];
int matched = 0;
while (1) {
uint8_t byte;
if (uart_read_bytes(RADAR_UART, &byte, 1, pdMS_TO_TICKS(100)) != 1)
continue;
// Sync on the F4 F3 F2 F1 data-frame header
if (matched < 4) {
matched = (byte == FRAME_HEAD[matched]) ? matched + 1 : (byte == FRAME_HEAD[0]);
continue;
}
// Read length (2 bytes, little-endian), then the payload + 4-byte tail
uint8_t len_bytes[2];
len_bytes[0] = byte;
uart_read_bytes(RADAR_UART, &len_bytes[1], 1, pdMS_TO_TICKS(100));
int length = len_bytes[0] | (len_bytes[1] << 8);
matched = 0;
if (length < 11 || length > (int)sizeof(buf))
continue; // implausible - resync
if (uart_read_bytes(RADAR_UART, buf, length + 4, pdMS_TO_TICKS(100)) != length + 4)
continue;
// Basic-mode report: [0]=0x02, [1]=0xAA, [2]=state, then little-endian values
if (buf[0] != 0x02 || buf[1] != 0xAA)
continue; // engineering-mode or config frame - ignore here
uint8_t state = buf[2]; // 0 none, 1 moving, 2 still, 3 both
int moving_cm = buf[3] | (buf[4] << 8);
int still_cm = buf[6] | (buf[7] << 8);
int detect_cm = buf[9] | (buf[10] << 8);
static const char *STATES[] = {"no target", "moving", "still", "moving + still"};
printf("%s | moving %d cm (energy %d) | still %d cm (energy %d) | detect %d cm\n",
STATES[state & 0x03], moving_cm, buf[5], still_cm, buf[8], detect_cm);
}
}ESP-IDF has no LD2412 component, but the radar's basic data reports use the same framing family as the LD2410 - header F4 F3 F2 F1, little-endian length, a type-0x02/0xAA payload with target state, moving/still distances and energies - at the LD2412's 115200 baud default. The example syncs on the header and prints each report; configuration uses the separate FD FC FB FA command framing in the vendor's protocol manual.
LD2412 ESPHome example
Copyexternal_components:
- source: github://Rihan9/LD2412
components: [ld2412]
uart:
id: uart_bus
tx_pin: GPIO17
rx_pin: GPIO16
baud_rate: 115200
parity: NONE
stop_bits: 1
ld2412:
id: ld2412_radar
binary_sensor:
- platform: ld2412
has_target:
name: "Presence"
has_moving_target:
name: "Moving Target"
has_still_target:
name: "Still Target"
sensor:
- platform: ld2412
moving_distance:
name: "Moving Distance"
still_distance:
name: "Still Distance"Core ESPHome does not support the LD2412 (its frame format differs from the LD2410), so this pins the maintained Rihan9/LD2412 external component, which mirrors the ld2410 configuration style: presence and moving/still target binary sensors plus distance sensors over UART2 at 115200 baud.
LD2412 PlatformIO example
Copy[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
build_unflags = -std=gnu++11
build_flags = -std=gnu++17 ; the LD2412 library requires C++17
lib_deps =
tobiastl/LD2412 @ ^1.0.2#include <Arduino.h>
#include <LD2412.h>
// UART2: sensor TX -> GPIO16 (RX2), sensor RX -> GPIO17 (TX2)
LD2412 radar(Serial2);
void setup() {
Serial.begin(115200);
Serial2.begin(115200, SERIAL_8N1, 16, 17);
}
void loop() {
int state = radar.targetState(); // 0 none, 1 moving, 2 stationary, 3 both
if (state > 0) {
Serial.print("Presence detected (");
Serial.print(state == 1 ? "moving" : state == 2 ? "stationary" : "moving + stationary");
Serial.print("), moving at ");
Serial.print(radar.movingDistance());
Serial.print(" cm, static at ");
Serial.print(radar.staticDistance());
Serial.println(" cm");
} else {
Serial.println("No presence");
}
delay(1000);
}This PlatformIO example communicates with the LD2412 radar using the LD2412 library. It initializes UART2, polls the sensor for presence detection, and logs results via Serial. Use GPIO16/17 for UART2, and install the library via PlatformIO Registry at tobiastl/LD2412.
LD2412 MicroPython example
Copyfrom machine import UART
import time
# LD2412: radar TX -> GPIO16 (RX2), RX -> GPIO17 (TX2), 115200 baud
uart = UART(2, baudrate=115200, tx=17, rx=16)
STATES = ("no target", "moving", "still", "moving + still")
buf = b""
while True:
data = uart.read()
if data:
buf += data
while True:
i = buf.find(b"\xf4\xf3\xf2\xf1") # data-frame header
if i < 0 or len(buf) < i + 6:
break
length = buf[i + 4] | (buf[i + 5] << 8)
if len(buf) < i + 6 + length + 4:
break
payload = buf[i + 6 : i + 6 + length]
buf = buf[i + 6 + length + 4 :]
if length >= 11 and payload[0] == 0x02 and payload[1] == 0xAA:
state = payload[2] & 0x03
moving = payload[3] | (payload[4] << 8)
still = payload[6] | (payload[7] << 8)
print("{} | moving {} cm | still {} cm".format(STATES[state], moving, still))
time.sleep(0.1)No MicroPython driver exists for the LD2412, but its data stream parses easily: reports start with F4 F3 F2 F1, a little-endian length, and a basic-mode payload carrying the target state and the moving/still distances in centimeters. The example buffers UART2 (115200 baud), syncs on the header and prints each report.
LD2412 specifications
About the LD2412
The LD2412 is Hi-Link’s actual successor to the original LD2410, not just a variant: it widens the field of view from ±60 degrees to ±75 degrees, extends detection range from roughly 5-6 meters out to about 9 meters, and adds finer gate-resolution options for zone tuning beyond the LD2410’s 0.2 m or 0.75 m choice. It also drops the LD2410’s fixed 5V requirement - the LD2412 runs on either 3.3V or 5V - and includes Bluetooth Low Energy for configuration through the HLKRadarTool app, the same way the LD2410B and LD2410C do.
Software support caught up with the hardware in August 2025: ESPHome merged a native ld2412 component in release 2025.8.0, so new projects no longer need the community Rihan9/LD2412 external component that many existing guides still reference - worth switching to the core component for new builds. On the UART side the LD2412 talks 115200 baud rather than the LD2410’s 256000 baud, so wiring code between the two families is not drop-in compatible even though both speak a similarly framed packet protocol.
For a new design with no existing LD2410 code to reuse, the LD2412 is the stronger buy: wider coverage, longer range, and Bluetooth setup built in, all natively supported in ESPHome. Stick with the plain LD2410 only if compatibility with its larger existing library and tutorial base matters more than the extra range and field of view.
LD2412 troubleshooting
No UART Response
›
Issue: The ESP32 receives no data from the LD2412 sensor.
Ensure TX/RX lines are correctly wired. Check that only one power source (either 5V or 3V3) is connected. Confirm UART baud is 115200 and no conflicting components use the same UART.
Digital OUT Stuck LOW
›
Issue: The OUT pin never changes even when motion is detected.
Check power supply voltage. Try reinitializing the sensor with a UART command. Ensure OUT is not floating and that detection parameters are configured properly via UART.
Where to buy the LD2412

Resources
Similar sensors





