7static const char *
const TAG =
"rd03d";
10static constexpr uint32_t SETUP_TIMEOUT_MS = 100;
13static constexpr uint8_t FRAME_HEADER[] = {0xAA, 0xFF, 0x03, 0x00};
14static constexpr uint8_t FRAME_FOOTER[] = {0x55, 0xCC};
17static constexpr uint8_t CMD_FRAME_HEADER[] = {0xFD, 0xFC, 0xFB, 0xFA};
18static constexpr uint8_t CMD_FRAME_FOOTER[] = {0x04, 0x03, 0x02, 0x01};
21static constexpr uint16_t CMD_SINGLE_TARGET = 0x0080;
22static constexpr uint16_t CMD_MULTI_TARGET = 0x0090;
26static constexpr int16_t SPEED_SENTINEL_248 = 248;
27static constexpr int16_t SPEED_SENTINEL_256 = 256;
31static constexpr int16_t decode_value(uint8_t low_byte, uint8_t high_byte) {
32 int16_t value = ((high_byte & 0x7F) << 8) | low_byte;
33 if ((high_byte & 0x80) == 0) {
41static constexpr bool is_speed_valid(int16_t
speed) {
43 return speed != 0 && abs_speed != SPEED_SENTINEL_248 && abs_speed != SPEED_SENTINEL_256;
47 ESP_LOGCONFIG(TAG,
"Setting up RD-03D...");
52 ESP_LOGCONFIG(TAG,
"RD-03D:");
54 ESP_LOGCONFIG(TAG,
" Tracking Mode: %s",
58 ESP_LOGCONFIG(TAG,
" Throttle: %ums", this->
throttle_);
63#ifdef USE_BINARY_SENSOR
66 for (uint8_t i = 0; i < MAX_TARGETS; i++) {
67 ESP_LOGCONFIG(TAG,
" Target %d:", i + 1);
69 LOG_SENSOR(
" ",
"X", this->
targets_[i].
x);
70 LOG_SENSOR(
" ",
"Y", this->
targets_[i].
y);
72 LOG_SENSOR(
" ",
"Distance", this->
targets_[i].distance);
74 LOG_SENSOR(
" ",
"Angle", this->
targets_[i].angle);
76#ifdef USE_BINARY_SENSOR
84 uint8_t
byte = this->
read();
85 ESP_LOGVV(TAG,
"Received byte: 0x%02X, buffer_pos: %d",
byte, this->
buffer_pos_);
90 this->
buffer_[this->buffer_pos_++] = byte;
91 }
else if (
byte == FRAME_HEADER[0]) {
94 this->buffer_pos_ = 1;
96 this->buffer_pos_ = 0;
107 if (this->
buffer_[FRAME_SIZE - 2] == FRAME_FOOTER[0] && this->
buffer_[FRAME_SIZE - 1] == FRAME_FOOTER[1]) {
110 ESP_LOGW(TAG,
"Invalid frame footer: 0x%02X 0x%02X (expected 0x55 0xCC)", this->
buffer_[FRAME_SIZE - 2],
111 this->
buffer_[FRAME_SIZE - 1]);
128 uint8_t target_count = 0;
130 for (uint8_t i = 0; i < MAX_TARGETS; i++) {
133 uint8_t offset = FRAME_HEADER_SIZE + (i * TARGET_DATA_SIZE);
136 uint8_t x_low = this->
buffer_[offset + 0];
137 uint8_t x_high = this->
buffer_[offset + 1];
138 uint8_t y_low = this->
buffer_[offset + 2];
139 uint8_t y_high = this->
buffer_[offset + 3];
140 uint8_t speed_low = this->
buffer_[offset + 4];
141 uint8_t speed_high = this->
buffer_[offset + 5];
142 uint8_t res_low = this->
buffer_[offset + 6];
143 uint8_t res_high = this->
buffer_[offset + 7];
146 int16_t
x = decode_value(x_low, x_high);
147 int16_t
y = decode_value(y_low, y_high);
148 int16_t
speed = decode_value(speed_low, speed_high);
149 uint16_t
resolution = (res_high << 8) | res_low;
154 bool has_position = (
x != 0 ||
y != 0);
155 bool has_valid_speed = is_speed_valid(
speed);
156 bool target_present = has_position && has_valid_speed;
157 if (target_present) {
165#ifdef USE_BINARY_SENSOR
178#ifdef USE_BINARY_SENSOR
188 bool valid = is_speed_valid(
speed);
191 if (target.
x !=
nullptr) {
196 if (target.
y !=
nullptr) {
201 if (target.
speed !=
nullptr) {
221 if (target.
angle !=
nullptr) {
223 float angle = std::atan2(
static_cast<float>(
x),
static_cast<float>(
y)) * 180.0f / M_PI;
234 this->
write_array(CMD_FRAME_HEADER,
sizeof(CMD_FRAME_HEADER));
237 uint16_t
len = 2 + data_len;
246 if (data !=
nullptr && data_len > 0) {
251 this->
write_array(CMD_FRAME_FOOTER,
sizeof(CMD_FRAME_FOOTER));
253 ESP_LOGD(TAG,
"Sent command 0x%04X with %d bytes of data", command, data_len);
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
void publish_state(bool new_state)
Publish a new state to the front-end.
optional< TrackingMode > tracking_mode_
std::array< TargetSensor, MAX_TARGETS > targets_
void dump_config() override
void send_command_(uint16_t command, const uint8_t *data=nullptr, uint8_t data_len=0)
uint32_t last_publish_time_
binary_sensor::BinarySensor * target_binary_sensor_
std::array< uint8_t, FRAME_SIZE > buffer_
void publish_target_(uint8_t target_num, int16_t x, int16_t y, int16_t speed, uint16_t resolution)
std::array< binary_sensor::BinarySensor *, MAX_TARGETS > target_presence_
sensor::Sensor * target_count_sensor_
void publish_state(float state)
Publish a new state to the front-end.
void write_byte(uint8_t data)
void write_array(const uint8_t *data, size_t len)
uint32_t IRAM_ATTR HOT millis()
sensor::Sensor * resolution
sensor::Sensor * distance