mirror of
https://github.com/esphome/esphome.git
synced 2024-12-24 22:44:54 +01:00
Add Ld2410 Support (#3919)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
6b7b076875
commit
0bf6e21e1a
8 changed files with 747 additions and 0 deletions
|
@ -119,6 +119,7 @@ esphome/components/kalman_combinator/* @Cat-Ion
|
|||
esphome/components/key_collector/* @ssieb
|
||||
esphome/components/key_provider/* @ssieb
|
||||
esphome/components/lcd_menu/* @numo68
|
||||
esphome/components/ld2410/* @sebcaps
|
||||
esphome/components/ledc/* @OttoWinter
|
||||
esphome/components/light/* @esphome/core
|
||||
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
|
||||
|
|
158
esphome/components/ld2410/__init__.py
Normal file
158
esphome/components/ld2410/__init__.py
Normal file
|
@ -0,0 +1,158 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import uart
|
||||
from esphome.const import CONF_ID, CONF_TIMEOUT
|
||||
from esphome import automation
|
||||
from esphome.automation import maybe_simple_id
|
||||
|
||||
DEPENDENCIES = ["uart"]
|
||||
CODEOWNERS = ["@sebcaps"]
|
||||
MULTI_CONF = True
|
||||
|
||||
ld2410_ns = cg.esphome_ns.namespace("ld2410")
|
||||
LD2410Component = ld2410_ns.class_("LD2410Component", cg.Component, uart.UARTDevice)
|
||||
LD2410Restart = ld2410_ns.class_("LD2410Restart", automation.Action)
|
||||
CONF_LD2410_ID = "ld2410_id"
|
||||
CONF_MAX_MOVE_DISTANCE = "max_move_distance"
|
||||
CONF_MAX_STILL_DISTANCE = "max_still_distance"
|
||||
CONF_G0_MOVE_THRESHOLD = "g0_move_threshold"
|
||||
CONF_G0_STILL_THRESHOLD = "g0_still_threshold"
|
||||
CONF_G1_MOVE_THRESHOLD = "g1_move_threshold"
|
||||
CONF_G1_STILL_THRESHOLD = "g1_still_threshold"
|
||||
CONF_G2_MOVE_THRESHOLD = "g2_move_threshold"
|
||||
CONF_G2_STILL_THRESHOLD = "g2_still_threshold"
|
||||
CONF_G3_MOVE_THRESHOLD = "g3_move_threshold"
|
||||
CONF_G3_STILL_THRESHOLD = "g3_still_threshold"
|
||||
CONF_G4_MOVE_THRESHOLD = "g4_move_threshold"
|
||||
CONF_G4_STILL_THRESHOLD = "g4_still_threshold"
|
||||
CONF_G5_MOVE_THRESHOLD = "g5_move_threshold"
|
||||
CONF_G5_STILL_THRESHOLD = "g5_still_threshold"
|
||||
CONF_G6_MOVE_THRESHOLD = "g6_move_threshold"
|
||||
CONF_G6_STILL_THRESHOLD = "g6_still_threshold"
|
||||
CONF_G7_MOVE_THRESHOLD = "g7_move_threshold"
|
||||
CONF_G7_STILL_THRESHOLD = "g7_still_threshold"
|
||||
CONF_G8_MOVE_THRESHOLD = "g8_move_threshold"
|
||||
CONF_G8_STILL_THRESHOLD = "g8_still_threshold"
|
||||
|
||||
DISTANCES = [0.75, 1.5, 2.25, 3, 3.75, 4.5, 5.25, 6]
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(LD2410Component),
|
||||
cv.Optional(CONF_MAX_MOVE_DISTANCE, default="4.5m"): cv.All(
|
||||
cv.distance, cv.one_of(*DISTANCES, float=True)
|
||||
),
|
||||
cv.Optional(CONF_MAX_STILL_DISTANCE, default="4.5m"): cv.All(
|
||||
cv.distance, cv.one_of(*DISTANCES, float=True)
|
||||
),
|
||||
cv.Optional(CONF_TIMEOUT, default="5s"): cv.All(
|
||||
cv.positive_time_period_seconds,
|
||||
cv.Range(max=cv.TimePeriod(seconds=32767)),
|
||||
),
|
||||
cv.Optional(CONF_G0_MOVE_THRESHOLD, default=50): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G0_STILL_THRESHOLD, default=0): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G1_MOVE_THRESHOLD, default=50): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G1_STILL_THRESHOLD, default=0): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G2_MOVE_THRESHOLD, default=40): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G2_STILL_THRESHOLD, default=40): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G3_MOVE_THRESHOLD, default=40): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G3_STILL_THRESHOLD, default=40): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G4_MOVE_THRESHOLD, default=40): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G4_STILL_THRESHOLD, default=40): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G5_MOVE_THRESHOLD, default=40): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G5_STILL_THRESHOLD, default=40): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G6_MOVE_THRESHOLD, default=30): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G6_STILL_THRESHOLD, default=15): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G7_MOVE_THRESHOLD, default=30): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G7_STILL_THRESHOLD, default=15): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G8_MOVE_THRESHOLD, default=30): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
cv.Optional(CONF_G8_STILL_THRESHOLD, default=15): cv.int_range(
|
||||
min=0, max=100
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(uart.UART_DEVICE_SCHEMA)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
)
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
|
||||
"ld2410",
|
||||
baud_rate=256000,
|
||||
require_tx=True,
|
||||
require_rx=True,
|
||||
parity="NONE",
|
||||
stop_bits=1,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await uart.register_uart_device(var, config)
|
||||
cg.add(var.set_timeout(config[CONF_TIMEOUT]))
|
||||
cg.add(var.set_max_move_distance(int(config[CONF_MAX_MOVE_DISTANCE] / 0.75)))
|
||||
cg.add(var.set_max_still_distance(int(config[CONF_MAX_STILL_DISTANCE] / 0.75)))
|
||||
cg.add(
|
||||
var.set_range_config(
|
||||
config[CONF_G0_MOVE_THRESHOLD],
|
||||
config[CONF_G0_STILL_THRESHOLD],
|
||||
config[CONF_G1_MOVE_THRESHOLD],
|
||||
config[CONF_G1_STILL_THRESHOLD],
|
||||
config[CONF_G2_MOVE_THRESHOLD],
|
||||
config[CONF_G2_STILL_THRESHOLD],
|
||||
config[CONF_G3_MOVE_THRESHOLD],
|
||||
config[CONF_G3_STILL_THRESHOLD],
|
||||
config[CONF_G4_MOVE_THRESHOLD],
|
||||
config[CONF_G4_STILL_THRESHOLD],
|
||||
config[CONF_G5_MOVE_THRESHOLD],
|
||||
config[CONF_G5_STILL_THRESHOLD],
|
||||
config[CONF_G6_MOVE_THRESHOLD],
|
||||
config[CONF_G6_STILL_THRESHOLD],
|
||||
config[CONF_G7_MOVE_THRESHOLD],
|
||||
config[CONF_G7_STILL_THRESHOLD],
|
||||
config[CONF_G8_MOVE_THRESHOLD],
|
||||
config[CONF_G8_STILL_THRESHOLD],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
CALIBRATION_ACTION_SCHEMA = maybe_simple_id(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(LD2410Component),
|
||||
}
|
||||
)
|
36
esphome/components/ld2410/binary_sensor.py
Normal file
36
esphome/components/ld2410/binary_sensor.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
import esphome.codegen as cg
|
||||
from esphome.components import binary_sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import DEVICE_CLASS_MOTION, DEVICE_CLASS_OCCUPANCY
|
||||
from . import CONF_LD2410_ID, LD2410Component
|
||||
|
||||
DEPENDENCIES = ["ld2410"]
|
||||
CONF_HAS_TARGET = "has_target"
|
||||
CONF_HAS_MOVING_TARGET = "has_moving_target"
|
||||
CONF_HAS_STILL_TARGET = "has_still_target"
|
||||
|
||||
CONFIG_SCHEMA = {
|
||||
cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component),
|
||||
cv.Optional(CONF_HAS_TARGET): binary_sensor.binary_sensor_schema(
|
||||
device_class=DEVICE_CLASS_OCCUPANCY
|
||||
),
|
||||
cv.Optional(CONF_HAS_MOVING_TARGET): binary_sensor.binary_sensor_schema(
|
||||
device_class=DEVICE_CLASS_MOTION
|
||||
),
|
||||
cv.Optional(CONF_HAS_STILL_TARGET): binary_sensor.binary_sensor_schema(
|
||||
device_class=DEVICE_CLASS_OCCUPANCY
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
ld2410_component = await cg.get_variable(config[CONF_LD2410_ID])
|
||||
if CONF_HAS_TARGET in config:
|
||||
sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_TARGET])
|
||||
cg.add(ld2410_component.set_target_sensor(sens))
|
||||
if CONF_HAS_MOVING_TARGET in config:
|
||||
sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_MOVING_TARGET])
|
||||
cg.add(ld2410_component.set_moving_target_sensor(sens))
|
||||
if CONF_HAS_STILL_TARGET in config:
|
||||
sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_STILL_TARGET])
|
||||
cg.add(ld2410_component.set_still_target_sensor(sens))
|
313
esphome/components/ld2410/ld2410.cpp
Normal file
313
esphome/components/ld2410/ld2410.cpp
Normal file
|
@ -0,0 +1,313 @@
|
|||
#include "ld2410.h"
|
||||
|
||||
#define highbyte(val) (uint8_t)((val) >> 8)
|
||||
#define lowbyte(val) (uint8_t)((val) &0xff)
|
||||
|
||||
namespace esphome {
|
||||
namespace ld2410 {
|
||||
|
||||
static const char *const TAG = "ld2410";
|
||||
|
||||
void LD2410Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "LD2410:");
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
LOG_BINARY_SENSOR(" ", "HasTargetSensor", this->target_binary_sensor_);
|
||||
LOG_BINARY_SENSOR(" ", "MovingSensor", this->moving_binary_sensor_);
|
||||
LOG_BINARY_SENSOR(" ", "StillSensor", this->still_binary_sensor_);
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
LOG_SENSOR(" ", "Moving Distance", this->moving_target_distance_sensor_);
|
||||
LOG_SENSOR(" ", "Still Distance", this->still_target_distance_sensor_);
|
||||
LOG_SENSOR(" ", "Moving Energy", this->moving_target_energy_sensor_);
|
||||
LOG_SENSOR(" ", "Still Energy", this->still_target_energy_sensor_);
|
||||
LOG_SENSOR(" ", "Detection Distance", this->detection_distance_sensor_);
|
||||
#endif
|
||||
this->set_config_mode_(true);
|
||||
this->get_version_();
|
||||
this->set_config_mode_(false);
|
||||
ESP_LOGCONFIG(" ", "Firmware Version : %u.%u.%u%u%u%u", this->version_[0], this->version_[1], this->version_[2],
|
||||
this->version_[3], this->version_[4], this->version_[5]);
|
||||
}
|
||||
|
||||
void LD2410Component::setup() {
|
||||
this->set_config_mode_(true);
|
||||
this->set_max_distances_timeout_(this->max_move_distance_, this->max_still_distance_, this->timeout_);
|
||||
// Configure Gates sensitivity
|
||||
this->set_gate_threshold_(0, this->rg0_move_threshold_, this->rg0_still_threshold_);
|
||||
this->set_gate_threshold_(1, this->rg1_move_threshold_, this->rg1_still_threshold_);
|
||||
this->set_gate_threshold_(2, this->rg2_move_threshold_, this->rg2_still_threshold_);
|
||||
this->set_gate_threshold_(3, this->rg3_move_threshold_, this->rg3_still_threshold_);
|
||||
this->set_gate_threshold_(4, this->rg4_move_threshold_, this->rg4_still_threshold_);
|
||||
this->set_gate_threshold_(5, this->rg5_move_threshold_, this->rg5_still_threshold_);
|
||||
this->set_gate_threshold_(6, this->rg6_move_threshold_, this->rg6_still_threshold_);
|
||||
this->set_gate_threshold_(7, this->rg7_move_threshold_, this->rg7_still_threshold_);
|
||||
this->set_gate_threshold_(8, this->rg8_move_threshold_, this->rg8_still_threshold_);
|
||||
this->get_version_();
|
||||
this->set_config_mode_(false);
|
||||
ESP_LOGI(" ", "Firmware Version : %u.%u.%u%u%u%u", this->version_[0], this->version_[1], this->version_[2],
|
||||
this->version_[3], this->version_[4], this->version_[5]);
|
||||
}
|
||||
|
||||
void LD2410Component::loop() {
|
||||
const int max_line_length = 80;
|
||||
static uint8_t buffer[max_line_length];
|
||||
|
||||
while (available()) {
|
||||
this->readline_(read(), buffer, max_line_length);
|
||||
}
|
||||
}
|
||||
|
||||
void LD2410Component::send_command_(uint8_t command, uint8_t *command_value, int command_value_len) {
|
||||
// lastCommandSuccess->publish_state(false);
|
||||
|
||||
// frame start bytes
|
||||
this->write_array(CMD_FRAME_HEADER, 4);
|
||||
// length bytes
|
||||
int len = 2;
|
||||
if (command_value != nullptr)
|
||||
len += command_value_len;
|
||||
this->write_byte(lowbyte(len));
|
||||
this->write_byte(highbyte(len));
|
||||
|
||||
// command
|
||||
this->write_byte(lowbyte(command));
|
||||
this->write_byte(highbyte(command));
|
||||
|
||||
// command value bytes
|
||||
if (command_value != nullptr) {
|
||||
for (int i = 0; i < command_value_len; i++) {
|
||||
this->write_byte(command_value[i]);
|
||||
}
|
||||
}
|
||||
// frame end bytes
|
||||
this->write_array(CMD_FRAME_END, 4);
|
||||
// FIXME to remove
|
||||
delay(50); // NOLINT
|
||||
}
|
||||
|
||||
void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) {
|
||||
if (len < 12)
|
||||
return; // 4 frame start bytes + 2 length bytes + 1 data end byte + 1 crc byte + 4 frame end bytes
|
||||
if (buffer[0] != 0xF4 || buffer[1] != 0xF3 || buffer[2] != 0xF2 || buffer[3] != 0xF1) // check 4 frame start bytes
|
||||
return;
|
||||
if (buffer[7] != HEAD || buffer[len - 6] != END || buffer[len - 5] != CHECK) // Check constant values
|
||||
return; // data head=0xAA, data end=0x55, crc=0x00
|
||||
|
||||
/*
|
||||
Data Type: 6th
|
||||
0x01: Engineering mode
|
||||
0x02: Normal mode
|
||||
*/
|
||||
// char data_type = buffer[DATA_TYPES];
|
||||
/*
|
||||
Target states: 9th
|
||||
0x00 = No target
|
||||
0x01 = Moving targets
|
||||
0x02 = Still targets
|
||||
0x03 = Moving+Still targets
|
||||
*/
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
char target_state = buffer[TARGET_STATES];
|
||||
if (this->target_binary_sensor_ != nullptr) {
|
||||
this->target_binary_sensor_->publish_state(target_state != 0x00);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Reduce data update rate to prevent home assistant database size grow fast
|
||||
*/
|
||||
int32_t current_millis = millis();
|
||||
if (current_millis - last_periodic_millis < 1000)
|
||||
return;
|
||||
last_periodic_millis = current_millis;
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
if (this->moving_binary_sensor_ != nullptr) {
|
||||
this->moving_binary_sensor_->publish_state(CHECK_BIT(target_state, 0));
|
||||
}
|
||||
if (this->still_binary_sensor_ != nullptr) {
|
||||
this->still_binary_sensor_->publish_state(CHECK_BIT(target_state, 1));
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
Moving target distance: 10~11th bytes
|
||||
Moving target energy: 12th byte
|
||||
Still target distance: 13~14th bytes
|
||||
Still target energy: 15th byte
|
||||
Detect distance: 16~17th bytes
|
||||
*/
|
||||
#ifdef USE_SENSOR
|
||||
if (this->moving_target_distance_sensor_ != nullptr) {
|
||||
int new_moving_target_distance = this->two_byte_to_int_(buffer[MOVING_TARGET_LOW], buffer[MOVING_TARGET_HIGH]);
|
||||
if (this->moving_target_distance_sensor_->get_state() != new_moving_target_distance)
|
||||
this->moving_target_distance_sensor_->publish_state(new_moving_target_distance);
|
||||
}
|
||||
if (this->moving_target_energy_sensor_ != nullptr) {
|
||||
int new_moving_target_energy = buffer[MOVING_ENERGY];
|
||||
if (this->moving_target_energy_sensor_->get_state() != new_moving_target_energy)
|
||||
this->moving_target_energy_sensor_->publish_state(new_moving_target_energy);
|
||||
}
|
||||
if (this->still_target_distance_sensor_ != nullptr) {
|
||||
int new_still_target_distance = this->two_byte_to_int_(buffer[STILL_TARGET_LOW], buffer[STILL_TARGET_HIGH]);
|
||||
if (this->still_target_distance_sensor_->get_state() != new_still_target_distance)
|
||||
this->still_target_distance_sensor_->publish_state(new_still_target_distance);
|
||||
}
|
||||
if (this->still_target_energy_sensor_ != nullptr) {
|
||||
int new_still_target_energy = buffer[STILL_ENERGY];
|
||||
if (this->still_target_energy_sensor_->get_state() != new_still_target_energy)
|
||||
this->still_target_energy_sensor_->publish_state(new_still_target_energy);
|
||||
}
|
||||
if (this->detection_distance_sensor_ != nullptr) {
|
||||
int new_detect_distance = this->two_byte_to_int_(buffer[DETECT_DISTANCE_LOW], buffer[DETECT_DISTANCE_HIGH]);
|
||||
if (this->detection_distance_sensor_->get_state() != new_detect_distance)
|
||||
this->detection_distance_sensor_->publish_state(new_detect_distance);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LD2410Component::handle_ack_data_(uint8_t *buffer, int len) {
|
||||
ESP_LOGI(TAG, "Handling ACK DATA for COMMAND");
|
||||
if (len < 10) {
|
||||
ESP_LOGE(TAG, "Error with last command : incorrect length");
|
||||
return;
|
||||
}
|
||||
if (buffer[0] != 0xFD || buffer[1] != 0xFC || buffer[2] != 0xFB || buffer[3] != 0xFA) { // check 4 frame start bytes
|
||||
ESP_LOGE(TAG, "Error with last command : incorrect Header");
|
||||
return;
|
||||
}
|
||||
if (buffer[COMMAND_STATUS] != 0x01) {
|
||||
ESP_LOGE(TAG, "Error with last command : status != 0x01");
|
||||
return;
|
||||
}
|
||||
if (this->two_byte_to_int_(buffer[8], buffer[9]) != 0x00) {
|
||||
ESP_LOGE(TAG, "Error with last command , last buffer was: %u , %u", buffer[8], buffer[9]);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (buffer[COMMAND]) {
|
||||
case lowbyte(CMD_ENABLE_CONF):
|
||||
ESP_LOGD(TAG, "Handled Enable conf command");
|
||||
break;
|
||||
case lowbyte(CMD_DISABLE_CONF):
|
||||
ESP_LOGD(TAG, "Handled Disabled conf command");
|
||||
break;
|
||||
case lowbyte(CMD_VERSION):
|
||||
ESP_LOGD(TAG, "FW Version is: %u.%u.%u%u%u%u", buffer[13], buffer[12], buffer[17], buffer[16], buffer[15],
|
||||
buffer[14]);
|
||||
this->version_[0] = buffer[13];
|
||||
this->version_[1] = buffer[12];
|
||||
this->version_[2] = buffer[17];
|
||||
this->version_[3] = buffer[16];
|
||||
this->version_[4] = buffer[15];
|
||||
this->version_[5] = buffer[14];
|
||||
|
||||
break;
|
||||
case lowbyte(CMD_GATE_SENS):
|
||||
ESP_LOGD(TAG, "Handled sensitivity command");
|
||||
break;
|
||||
case lowbyte(CMD_QUERY): // Query parameters response
|
||||
{
|
||||
if (buffer[10] != 0xAA)
|
||||
return; // value head=0xAA
|
||||
/*
|
||||
Moving distance range: 13th byte
|
||||
Still distance range: 14th byte
|
||||
*/
|
||||
// TODO
|
||||
// maxMovingDistanceRange->publish_state(buffer[12]);
|
||||
// maxStillDistanceRange->publish_state(buffer[13]);
|
||||
/*
|
||||
Moving Sensitivities: 15~23th bytes
|
||||
Still Sensitivities: 24~32th bytes
|
||||
*/
|
||||
for (int i = 0; i < 9; i++) {
|
||||
moving_sensitivities[i] = buffer[14 + i];
|
||||
}
|
||||
for (int i = 0; i < 9; i++) {
|
||||
still_sensitivities[i] = buffer[23 + i];
|
||||
}
|
||||
/*
|
||||
None Duration: 33~34th bytes
|
||||
*/
|
||||
// noneDuration->publish_state(this->two_byte_to_int_(buffer[32], buffer[33]));
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LD2410Component::readline_(int readch, uint8_t *buffer, int len) {
|
||||
static int pos = 0;
|
||||
|
||||
if (readch >= 0) {
|
||||
if (pos < len - 1) {
|
||||
buffer[pos++] = readch;
|
||||
buffer[pos] = 0;
|
||||
} else {
|
||||
pos = 0;
|
||||
}
|
||||
if (pos >= 4) {
|
||||
if (buffer[pos - 4] == 0xF8 && buffer[pos - 3] == 0xF7 && buffer[pos - 2] == 0xF6 && buffer[pos - 1] == 0xF5) {
|
||||
ESP_LOGV(TAG, "Will handle Periodic Data");
|
||||
this->handle_periodic_data_(buffer, pos);
|
||||
pos = 0; // Reset position index ready for next time
|
||||
} else if (buffer[pos - 4] == 0x04 && buffer[pos - 3] == 0x03 && buffer[pos - 2] == 0x02 &&
|
||||
buffer[pos - 1] == 0x01) {
|
||||
ESP_LOGV(TAG, "Will handle ACK Data");
|
||||
this->handle_ack_data_(buffer, pos);
|
||||
pos = 0; // Reset position index ready for next time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LD2410Component::set_config_mode_(bool enable) {
|
||||
uint8_t cmd = enable ? CMD_ENABLE_CONF : CMD_DISABLE_CONF;
|
||||
uint8_t cmd_value[2] = {0x01, 0x00};
|
||||
this->send_command_(cmd, enable ? cmd_value : nullptr, 2);
|
||||
}
|
||||
|
||||
void LD2410Component::query_parameters_() { this->send_command_(CMD_QUERY, nullptr, 0); }
|
||||
void LD2410Component::get_version_() { this->send_command_(CMD_VERSION, nullptr, 0); }
|
||||
|
||||
void LD2410Component::set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range,
|
||||
uint16_t timeout) {
|
||||
uint8_t value[18] = {0x00,
|
||||
0x00,
|
||||
lowbyte(max_moving_distance_range),
|
||||
highbyte(max_moving_distance_range),
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
lowbyte(max_still_distance_range),
|
||||
highbyte(max_still_distance_range),
|
||||
0x00,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
lowbyte(timeout),
|
||||
highbyte(timeout),
|
||||
0x00,
|
||||
0x00};
|
||||
this->send_command_(CMD_MAXDIST_DURATION, value, 18);
|
||||
this->query_parameters_();
|
||||
}
|
||||
void LD2410Component::set_gate_threshold_(uint8_t gate, uint8_t motionsens, uint8_t stillsens) {
|
||||
// reference
|
||||
// https://drive.google.com/drive/folders/1p4dhbEJA3YubyIjIIC7wwVsSo8x29Fq-?spm=a2g0o.detail.1000023.17.93465697yFwVxH
|
||||
// Send data: configure the motion sensitivity of distance gate 3 to 40, and the static sensitivity of 40
|
||||
// 00 00 (gate)
|
||||
// 03 00 00 00 (gate number)
|
||||
// 01 00 (motion sensitivity)
|
||||
// 28 00 00 00 (value)
|
||||
// 02 00 (still sensitivtiy)
|
||||
// 28 00 00 00 (value)
|
||||
uint8_t value[18] = {0x00, 0x00, lowbyte(gate), highbyte(gate), 0x00, 0x00,
|
||||
0x01, 0x00, lowbyte(motionsens), highbyte(motionsens), 0x00, 0x00,
|
||||
0x02, 0x00, lowbyte(stillsens), highbyte(stillsens), 0x00, 0x00};
|
||||
this->send_command_(CMD_GATE_SENS, value, 18);
|
||||
}
|
||||
|
||||
} // namespace ld2410
|
||||
} // namespace esphome
|
146
esphome/components/ld2410/ld2410.h
Normal file
146
esphome/components/ld2410/ld2410.h
Normal file
|
@ -0,0 +1,146 @@
|
|||
#pragma once
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/component.h"
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#endif
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ld2410 {
|
||||
|
||||
#define CHECK_BIT(var, pos) (((var) >> (pos)) & 1)
|
||||
|
||||
// Commands
|
||||
static const uint8_t CMD_ENABLE_CONF = 0x00FF;
|
||||
static const uint8_t CMD_DISABLE_CONF = 0x00FE;
|
||||
static const uint8_t CMD_MAXDIST_DURATION = 0x0060;
|
||||
static const uint8_t CMD_QUERY = 0x0061;
|
||||
static const uint8_t CMD_GATE_SENS = 0x0064;
|
||||
static const uint8_t CMD_VERSION = 0x00A0;
|
||||
|
||||
// Commands values
|
||||
static const uint8_t CMD_MAX_MOVE_VALUE = 0x0000;
|
||||
static const uint8_t CMD_MAX_STILL_VALUE = 0x0001;
|
||||
static const uint8_t CMD_DURATION_VALUE = 0x0002;
|
||||
// Command Header & Footer
|
||||
static const uint8_t CMD_FRAME_HEADER[4] = {0xFD, 0xFC, 0xFB, 0xFA};
|
||||
static const uint8_t CMD_FRAME_END[4] = {0x04, 0x03, 0x02, 0x01};
|
||||
// Data Header & Footer
|
||||
static const uint8_t DATA_FRAME_HEADER[4] = {0xF4, 0xF3, 0xF2, 0xF1};
|
||||
static const uint8_t DATA_FRAME_END[4] = {0xF8, 0xF7, 0xF6, 0xF5};
|
||||
/*
|
||||
Data Type: 6th byte
|
||||
Target states: 9th byte
|
||||
Moving target distance: 10~11th bytes
|
||||
Moving target energy: 12th byte
|
||||
Still target distance: 13~14th bytes
|
||||
Still target energy: 15th byte
|
||||
Detect distance: 16~17th bytes
|
||||
*/
|
||||
enum PeriodicDataStructure : uint8_t {
|
||||
DATA_TYPES = 5,
|
||||
TARGET_STATES = 8,
|
||||
MOVING_TARGET_LOW = 9,
|
||||
MOVING_TARGET_HIGH = 10,
|
||||
MOVING_ENERGY = 11,
|
||||
STILL_TARGET_LOW = 12,
|
||||
STILL_TARGET_HIGH = 13,
|
||||
STILL_ENERGY = 14,
|
||||
DETECT_DISTANCE_LOW = 15,
|
||||
DETECT_DISTANCE_HIGH = 16,
|
||||
};
|
||||
enum PeriodicDataValue : uint8_t { HEAD = 0XAA, END = 0x55, CHECK = 0x00 };
|
||||
|
||||
enum AckDataStructure : uint8_t { COMMAND = 6, COMMAND_STATUS = 7 };
|
||||
|
||||
// char cmd[2] = {enable ? 0xFF : 0xFE, 0x00};
|
||||
class LD2410Component : public Component, public uart::UARTDevice {
|
||||
#ifdef USE_SENSOR
|
||||
SUB_SENSOR(moving_target_distance)
|
||||
SUB_SENSOR(still_target_distance)
|
||||
SUB_SENSOR(moving_target_energy)
|
||||
SUB_SENSOR(still_target_energy)
|
||||
SUB_SENSOR(detection_distance)
|
||||
#endif
|
||||
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void loop() override;
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
void set_target_sensor(binary_sensor::BinarySensor *sens) { this->target_binary_sensor_ = sens; };
|
||||
void set_moving_target_sensor(binary_sensor::BinarySensor *sens) { this->moving_binary_sensor_ = sens; };
|
||||
void set_still_target_sensor(binary_sensor::BinarySensor *sens) { this->still_binary_sensor_ = sens; };
|
||||
#endif
|
||||
|
||||
void set_timeout(uint16_t value) { this->timeout_ = value; };
|
||||
void set_max_move_distance(uint8_t value) { this->max_move_distance_ = value; };
|
||||
void set_max_still_distance(uint8_t value) { this->max_still_distance_ = value; };
|
||||
void set_range_config(int rg0_move, int rg0_still, int rg1_move, int rg1_still, int rg2_move, int rg2_still,
|
||||
int rg3_move, int rg3_still, int rg4_move, int rg4_still, int rg5_move, int rg5_still,
|
||||
int rg6_move, int rg6_still, int rg7_move, int rg7_still, int rg8_move, int rg8_still) {
|
||||
this->rg0_move_threshold_ = rg0_move;
|
||||
this->rg0_still_threshold_ = rg0_still;
|
||||
this->rg1_move_threshold_ = rg1_move;
|
||||
this->rg1_still_threshold_ = rg1_still;
|
||||
this->rg2_move_threshold_ = rg2_move;
|
||||
this->rg2_still_threshold_ = rg2_still;
|
||||
this->rg3_move_threshold_ = rg3_move;
|
||||
this->rg3_still_threshold_ = rg3_still;
|
||||
this->rg4_move_threshold_ = rg4_move;
|
||||
this->rg4_still_threshold_ = rg4_still;
|
||||
this->rg5_move_threshold_ = rg5_move;
|
||||
this->rg5_still_threshold_ = rg5_still;
|
||||
this->rg6_move_threshold_ = rg6_move;
|
||||
this->rg6_still_threshold_ = rg6_still;
|
||||
this->rg7_move_threshold_ = rg7_move;
|
||||
this->rg7_still_threshold_ = rg7_still;
|
||||
this->rg8_move_threshold_ = rg8_move;
|
||||
this->rg8_still_threshold_ = rg8_still;
|
||||
};
|
||||
int moving_sensitivities[9] = {0};
|
||||
int still_sensitivities[9] = {0};
|
||||
|
||||
int32_t last_periodic_millis = millis();
|
||||
|
||||
protected:
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
binary_sensor::BinarySensor *target_binary_sensor_{nullptr};
|
||||
binary_sensor::BinarySensor *moving_binary_sensor_{nullptr};
|
||||
binary_sensor::BinarySensor *still_binary_sensor_{nullptr};
|
||||
#endif
|
||||
|
||||
std::vector<uint8_t> rx_buffer_;
|
||||
int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t)(secondbyte << 8) + firstbyte; }
|
||||
void send_command_(uint8_t command_str, uint8_t *command_value, int command_value_len);
|
||||
|
||||
void set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range,
|
||||
uint16_t timeout);
|
||||
void set_gate_threshold_(uint8_t gate, uint8_t motionsens, uint8_t stillsens);
|
||||
void set_config_mode_(bool enable);
|
||||
void handle_periodic_data_(uint8_t *buffer, int len);
|
||||
void handle_ack_data_(uint8_t *buffer, int len);
|
||||
void readline_(int readch, uint8_t *buffer, int len);
|
||||
void query_parameters_();
|
||||
void get_version_();
|
||||
|
||||
uint16_t timeout_;
|
||||
uint8_t max_move_distance_;
|
||||
uint8_t max_still_distance_;
|
||||
|
||||
uint8_t version_[6];
|
||||
uint8_t rg0_move_threshold_, rg0_still_threshold_, rg1_move_threshold_, rg1_still_threshold_, rg2_move_threshold_,
|
||||
rg2_still_threshold_, rg3_move_threshold_, rg3_still_threshold_, rg4_move_threshold_, rg4_still_threshold_,
|
||||
rg5_move_threshold_, rg5_still_threshold_, rg6_move_threshold_, rg6_still_threshold_, rg7_move_threshold_,
|
||||
rg7_still_threshold_, rg8_move_threshold_, rg8_still_threshold_;
|
||||
};
|
||||
|
||||
} // namespace ld2410
|
||||
} // namespace esphome
|
55
esphome/components/ld2410/sensor.py
Normal file
55
esphome/components/ld2410/sensor.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
import esphome.codegen as cg
|
||||
from esphome.components import sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
DEVICE_CLASS_ENERGY,
|
||||
UNIT_CENTIMETER,
|
||||
UNIT_PERCENT,
|
||||
)
|
||||
from . import CONF_LD2410_ID, LD2410Component
|
||||
|
||||
DEPENDENCIES = ["ld2410"]
|
||||
CONF_MOVING_DISTANCE = "moving_distance"
|
||||
CONF_STILL_DISTANCE = "still_distance"
|
||||
CONF_MOVING_ENERGY = "moving_energy"
|
||||
CONF_STILL_ENERGY = "still_energy"
|
||||
CONF_DETECTION_DISTANCE = "detection_distance"
|
||||
|
||||
CONFIG_SCHEMA = {
|
||||
cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component),
|
||||
cv.Optional(CONF_MOVING_DISTANCE): sensor.sensor_schema(
|
||||
device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER
|
||||
),
|
||||
cv.Optional(CONF_STILL_DISTANCE): sensor.sensor_schema(
|
||||
device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER
|
||||
),
|
||||
cv.Optional(CONF_MOVING_ENERGY): sensor.sensor_schema(
|
||||
device_class=DEVICE_CLASS_ENERGY, unit_of_measurement=UNIT_PERCENT
|
||||
),
|
||||
cv.Optional(CONF_STILL_ENERGY): sensor.sensor_schema(
|
||||
device_class=DEVICE_CLASS_ENERGY, unit_of_measurement=UNIT_PERCENT
|
||||
),
|
||||
cv.Optional(CONF_DETECTION_DISTANCE): sensor.sensor_schema(
|
||||
device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
ld2410_component = await cg.get_variable(config[CONF_LD2410_ID])
|
||||
if CONF_MOVING_DISTANCE in config:
|
||||
sens = await sensor.new_sensor(config[CONF_MOVING_DISTANCE])
|
||||
cg.add(ld2410_component.set_moving_target_distance_sensor(sens))
|
||||
if CONF_STILL_DISTANCE in config:
|
||||
sens = await sensor.new_sensor(config[CONF_STILL_DISTANCE])
|
||||
cg.add(ld2410_component.set_still_target_distance_sensor(sens))
|
||||
if CONF_MOVING_ENERGY in config:
|
||||
sens = await sensor.new_sensor(config[CONF_MOVING_ENERGY])
|
||||
cg.add(ld2410_component.set_moving_target_energy_sensor(sens))
|
||||
if CONF_STILL_ENERGY in config:
|
||||
sens = await sensor.new_sensor(config[CONF_STILL_ENERGY])
|
||||
cg.add(ld2410_component.set_still_target_energy_sensor(sens))
|
||||
if CONF_DETECTION_DISTANCE in config:
|
||||
sens = await sensor.new_sensor(config[CONF_DETECTION_DISTANCE])
|
||||
cg.add(ld2410_component.set_detection_distance_sensor(sens))
|
|
@ -862,6 +862,7 @@ UNIT_AMPERE = "A"
|
|||
UNIT_BECQUEREL_PER_CUBIC_METER = "Bq/m³"
|
||||
UNIT_BYTES = "B"
|
||||
UNIT_CELSIUS = "°C"
|
||||
UNIT_CENTIMETER = "cm"
|
||||
UNIT_COUNT_DECILITRE = "/dL"
|
||||
UNIT_COUNTS_PER_CUBIC_METER = "#/m³"
|
||||
UNIT_CUBIC_METER = "m³"
|
||||
|
|
|
@ -222,6 +222,12 @@ uart:
|
|||
rx_pin: GPIO26
|
||||
baud_rate: 115200
|
||||
rx_buffer_size: 1024
|
||||
- id: ld2410_uart
|
||||
tx_pin: 18
|
||||
rx_pin: 23
|
||||
baud_rate: 256000
|
||||
parity: NONE
|
||||
stop_bits: 1
|
||||
|
||||
ota:
|
||||
safe_mode: true
|
||||
|
@ -1200,6 +1206,17 @@ sensor:
|
|||
pressure:
|
||||
name: "MPL3115A2 Pressure"
|
||||
update_interval: 10s
|
||||
- platform: ld2410
|
||||
moving_distance:
|
||||
name: "Moving distance (cm)"
|
||||
still_distance:
|
||||
name: "Still Distance (cm)"
|
||||
moving_energy:
|
||||
name: "Move Energy"
|
||||
still_energy:
|
||||
name: "Still Energy"
|
||||
detection_distance:
|
||||
name: "Distance Detection"
|
||||
|
||||
esp32_touch:
|
||||
setup_mode: false
|
||||
|
@ -1461,6 +1478,13 @@ binary_sensor:
|
|||
id: close_sensor
|
||||
- platform: template
|
||||
id: close_obstacle_sensor
|
||||
- platform: ld2410
|
||||
has_target:
|
||||
name: presence
|
||||
has_moving_target:
|
||||
name: movement
|
||||
has_still_target:
|
||||
name: still
|
||||
|
||||
pca9685:
|
||||
frequency: 500
|
||||
|
@ -3143,6 +3167,19 @@ button:
|
|||
on_press:
|
||||
midea_ac.power_toggle:
|
||||
|
||||
ld2410:
|
||||
id: my_ld2410
|
||||
uart_id: ld2410_uart
|
||||
timeout: 150s
|
||||
max_move_distance: 6m
|
||||
max_still_distance: 0.75m
|
||||
g0_move_threshold: 10
|
||||
g0_still_threshold: 20
|
||||
g2_move_threshold: 20
|
||||
g2_still_threshold: 21
|
||||
g8_move_threshold: 80
|
||||
g8_still_threshold: 81
|
||||
|
||||
lcd_menu:
|
||||
display_id: my_lcd_gpio
|
||||
mark_back: 0x5e
|
||||
|
|
Loading…
Reference in a new issue