Adding LD2415H Components

This commit is contained in:
CptSkippy 2024-05-26 22:45:26 -07:00
parent e285196709
commit 41f73a8086
24 changed files with 1214 additions and 0 deletions

View file

@ -0,0 +1,38 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import uart
from esphome.const import CONF_ID
CODEOWNERS = ["@cptskippy"]
DEPENDENCIES = ["uart"]
MULTI_CONF = True
ld2415h_ns = cg.esphome_ns.namespace("ld2415h")
LD2415HComponent = ld2415h_ns.class_("LD2415HComponent", cg.Component, uart.UARTDevice)
CONF_LD2415H_ID = "ld2415h_id"
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(LD2415HComponent),
}
)
.extend(uart.UART_DEVICE_SCHEMA)
.extend(cv.COMPONENT_SCHEMA)
)
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
"ld2415h_uart",
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)

View file

@ -0,0 +1,473 @@
#include "ld2415h.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ld2415h {
static const char *const TAG = "ld2415h";
static const uint8_t LD2415H_CMD_SET_SPEED_ANGLE_SENSE[] = {0x43, 0x46, 0x01, 0x01, 0x00, 0x05, 0x0d, 0x0a};
static const uint8_t LD2415H_CMD_SET_MODE_RATE_UOM[] = {0x43, 0x46, 0x02, 0x01, 0x01, 0x00, 0x0d, 0x0a};
static const uint8_t LD2415H_CMD_SET_ANTI_VIB_COMP[] = {0x43, 0x46, 0x03, 0x05, 0x00, 0x00, 0x0d, 0x0a};
static const uint8_t LD2415H_CMD_SET_RELAY_DURATION_SPEED[] = {0x43, 0x46, 0x04, 0x03, 0x01, 0x00, 0x0d, 0x0a};
static const uint8_t LD2415H_CMD_GET_CONFIG[] = {0x43, 0x46, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* TODO ::
* Create controls that expose settings
*/
LD2415HComponent::LD2415HComponent()
: cmd_speed_angle_sense_ {0x43, 0x46, 0x01, 0x01, 0x00, 0x05, 0x0d, 0x0a},
cmd_mode_rate_uom_ {0x43, 0x46, 0x02, 0x01, 0x01, 0x00, 0x0d, 0x0a},
cmd_anti_vib_comp_ {0x43, 0x46, 0x03, 0x05, 0x00, 0x00, 0x0d, 0x0a},
cmd_relay_duration_speed_ {0x43, 0x46, 0x04, 0x03, 0x01, 0x00, 0x0d, 0x0a},
cmd_config_ {0x43, 0x46, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} {}
void LD2415HComponent::setup() {
// This triggers current sensor configurations to be dumped
//this->issue_command_(LD2415H_CMD_GET_CONFIG, sizeof(LD2415H_CMD_GET_CONFIG));
this->update_config_ = true;
#ifdef USE_NUMBER
this->min_speed_threshold_number_->publish_state(this->min_speed_threshold_);
this->compensation_angle_number_->publish_state(this->compensation_angle_);
this->sensitivity_number_->publish_state(this->sensitivity_);
this->vibration_correction_number_->publish_state(this->vibration_correction_);
this->relay_trigger_duration_number_->publish_state(this->relay_trigger_duration_);
this->relay_trigger_speed_number_->publish_state(this->relay_trigger_speed_);
#endif
#ifdef USE_SELECT
this->sample_rate_selector_->publish_state(i_to_s_(SAMPLE_RATE_STR_TO_INT, this->sample_rate_));
this->tracking_mode_selector_->publish_state(i_to_s_(TRACKING_MODE_STR_TO_INT, this->tracking_mode_));
#endif
}
void LD2415HComponent::dump_config() {
ESP_LOGCONFIG(TAG, "LD2415H:");
ESP_LOGCONFIG(TAG, " Firmware: %s", this->firmware_);
ESP_LOGCONFIG(TAG, " Minimum Speed Threshold: %u KPH", this->min_speed_threshold_);
ESP_LOGCONFIG(TAG, " Compensation Angle: %u", this->compensation_angle_);
ESP_LOGCONFIG(TAG, " Sensitivity: %u", this->sensitivity_);
ESP_LOGCONFIG(TAG, " Tracking Mode: %s", TrackingMode_to_s_(this->tracking_mode_));
ESP_LOGCONFIG(TAG, " Sampling Rate: %u", this->sample_rate_);
ESP_LOGCONFIG(TAG, " Unit of Measure: %s", UnitOfMeasure_to_s_(this->unit_of_measure_));
ESP_LOGCONFIG(TAG, " Vibration Correction: %u", this->vibration_correction_);
ESP_LOGCONFIG(TAG, " Relay Trigger Duration: %u", this->relay_trigger_duration_);
ESP_LOGCONFIG(TAG, " Relay Trigger Speed: %u KPH", this->relay_trigger_speed_);
ESP_LOGCONFIG(TAG, " Negotiation Mode: %s", NegotiationMode_to_s_(this->negotiation_mode_));
//LOG_SELECT(TAG, " Sample Rate", this->sample_rate_);
//LOG_SELECT(TAG, " Tracking Mode", this->tracking_mode_);
}
void LD2415HComponent::loop() {
// Process the stream from the sensor UART
while (this->available()) {
if (this->fill_buffer_(this->read())) {
this->parse_buffer_();
}
}
if(this->update_speed_angle_sense_) {
ESP_LOGD(TAG, "LD2415H_CMD_SET_SPEED_ANGLE_SENSE: ");
this->cmd_speed_angle_sense_[3] = this->min_speed_threshold_;
this->cmd_speed_angle_sense_[4] = this->compensation_angle_;
this->cmd_speed_angle_sense_[5] = this->sensitivity_;
this->issue_command_(this->cmd_speed_angle_sense_, sizeof(this->cmd_speed_angle_sense_));
this->update_speed_angle_sense_ = false;
return;
}
if(this->update_mode_rate_uom_) {
ESP_LOGD(TAG, "LD2415H_CMD_SET_MODE_RATE_UOM: ");
this->cmd_mode_rate_uom_[3] = static_cast<uint8_t>(this->tracking_mode_);
this->cmd_mode_rate_uom_[4] = this->sample_rate_;
this->issue_command_(this->cmd_mode_rate_uom_, sizeof(this->cmd_mode_rate_uom_));
this->update_mode_rate_uom_ = false;
return;
}
if(this->update_anti_vib_comp_) {
ESP_LOGD(TAG, "LD2415H_CMD_SET_ANTI_VIB_COMP: ");
this->cmd_anti_vib_comp_[3] = this->vibration_correction_;
this->issue_command_(this->cmd_anti_vib_comp_, sizeof(this->cmd_anti_vib_comp_));
this->update_anti_vib_comp_ = false;
return;
}
if(this->update_relay_duration_speed_) {
ESP_LOGD(TAG, "LD2415H_CMD_SET_RELAY_DURATION_SPEED: ");
this->cmd_relay_duration_speed_[3] = this->relay_trigger_duration_;
this->cmd_relay_duration_speed_[4] = this->relay_trigger_speed_;
this->issue_command_(this->cmd_relay_duration_speed_, sizeof(this->cmd_relay_duration_speed_));
this->update_relay_duration_speed_ = false;
return;
}
if(this->update_config_) {
ESP_LOGD(TAG, "LD2415H_CMD_GET_CONFIG: ");
this->issue_command_(this->cmd_config_, sizeof(this->cmd_config_));
this->update_config_ = false;
return;
}
}
void LD2415HComponent::set_min_speed_threshold(uint8_t speed) {
this->min_speed_threshold_ = speed;
this->update_speed_angle_sense_ = true;
}
void LD2415HComponent::set_compensation_angle(uint8_t angle) {
this->compensation_angle_ = angle;
this->update_speed_angle_sense_ = true;
}
void LD2415HComponent::set_sensitivity(uint8_t sensitivity) {
this->sensitivity_ = sensitivity;
this->update_speed_angle_sense_ = true;
}
void LD2415HComponent::set_tracking_mode(const std::string &state) {
uint8_t mode = TRACKING_MODE_STR_TO_INT.at(state);
this->set_tracking_mode(mode);
this->tracking_mode_selector_->publish_state(state);
}
void LD2415HComponent::set_tracking_mode(TrackingMode mode) {
this->tracking_mode_ = mode;
this->update_mode_rate_uom_ = true;
}
void LD2415HComponent::set_tracking_mode(uint8_t mode) {
this->set_tracking_mode(i_to_TrackingMode_(mode));
}
void LD2415HComponent::set_sample_rate(const std::string &state) {
uint8_t rate = SAMPLE_RATE_STR_TO_INT.at(state);
this->set_sample_rate(rate);
this->sample_rate_selector_->publish_state(state);
}
void LD2415HComponent::set_sample_rate(uint8_t rate) {
ESP_LOGD(TAG, "set_sample_rate: %i", rate);
this->sample_rate_ = rate;
this->update_mode_rate_uom_ = true;
}
void LD2415HComponent::set_vibration_correction(uint8_t correction) {
this->vibration_correction_ = correction;
this->update_anti_vib_comp_ = true;
}
void LD2415HComponent::set_relay_trigger_duration(uint8_t duration) {
this->relay_trigger_duration_ = duration;
this->update_relay_duration_speed_ = true;
}
void LD2415HComponent::set_relay_trigger_speed(uint8_t speed) {
this->relay_trigger_speed_ = speed;
this->update_relay_duration_speed_ = true;
}
void LD2415HComponent::issue_command_(const uint8_t cmd[], const uint8_t size) {
for(uint8_t i = 0; i < size; i++)
ESP_LOGD(TAG, " 0x%02x", cmd[i]);
// Don't assume the response buffer is empty, clear it before issuing a command.
clear_remaining_buffer_(0);
this->write_array(cmd, size);
}
bool LD2415HComponent::fill_buffer_(char c) {
switch(c) {
case 0x00:
case 0xFF:
case '\r':
// Ignore these characters
break;
case '\n':
// End of response
if(this->response_buffer_index_ == 0)
break;
clear_remaining_buffer_(this->response_buffer_index_);
ESP_LOGV(TAG, "Response Received:: %s", this->response_buffer_);
return true;
default:
// Append to response
this->response_buffer_[this->response_buffer_index_] = c;
this->response_buffer_index_++;
break;
}
return false;
}
void LD2415HComponent::clear_remaining_buffer_(uint8_t pos) {
while(pos < sizeof(this->response_buffer_)) {
this->response_buffer_[pos] = 0x00;
pos++;
}
this->response_buffer_index_ = 0;
}
void LD2415HComponent::parse_buffer_() {
char c = this->response_buffer_[0];
switch(c) {
case 'N':
// Firmware Version
this->parse_firmware_();
break;
case 'X':
// Config Response
this->parse_config_();
break;
case 'V':
// Speed
this->parse_speed_();
break;
default:
ESP_LOGE(TAG, "Unknown Response: %s", this->response_buffer_);
break;
}
}
void LD2415HComponent::parse_config_() {
// Example: "X1:01 X2:00 X3:05 X4:01 X5:00 X6:00 X7:05 X8:03 X9:01 X0:01"
const char* delim = ": ";
uint8_t token_len = 2;
char* key;
char* val;
char* token = strtok(this->response_buffer_, delim);
while (token != NULL)
{
if(std::strlen(token) != token_len) {
ESP_LOGE(TAG, "Configuration key length invalid.");
break;
}
key = token;
token = strtok(NULL, delim);
if(std::strlen(token) != token_len) {
ESP_LOGE(TAG, "Configuration value length invalid.");
break;
}
val = token;
this->parse_config_param_(key, val);
token = strtok(NULL, delim);
}
ESP_LOGD(TAG, "Configuration received:");
ESP_LOGCONFIG(TAG, "LD2415H:");
ESP_LOGCONFIG(TAG, " Firmware: %s", this->firmware_);
ESP_LOGCONFIG(TAG, " Minimum Speed Threshold: %u KPH", this->min_speed_threshold_);
ESP_LOGCONFIG(TAG, " Compensation Angle: %u", this->compensation_angle_);
ESP_LOGCONFIG(TAG, " Sensitivity: %u", this->sensitivity_);
ESP_LOGCONFIG(TAG, " Tracking Mode: %s", TrackingMode_to_s_(this->tracking_mode_));
ESP_LOGCONFIG(TAG, " Sampling Rate: %u", this->sample_rate_);
ESP_LOGCONFIG(TAG, " Unit of Measure: %s", UnitOfMeasure_to_s_(this->unit_of_measure_));
ESP_LOGCONFIG(TAG, " Vibration Correction: %u", this->vibration_correction_);
ESP_LOGCONFIG(TAG, " Relay Trigger Duration: %u", this->relay_trigger_duration_);
ESP_LOGCONFIG(TAG, " Relay Trigger Speed: %u KPH", this->relay_trigger_speed_);
ESP_LOGCONFIG(TAG, " Negotiation Mode: %s", NegotiationMode_to_s_(this->negotiation_mode_));
}
void LD2415HComponent::parse_firmware_() {
// Example: "No.:20230801E v5.0"
const char* fw = strchr(this->response_buffer_, ':');
if (fw != nullptr) {
// Move p to the character after ':'
++fw;
// Copy string into firmware
std::strcpy(this->firmware_, fw);
} else {
ESP_LOGE(TAG, "Firmware value invalid.");
}
}
void LD2415HComponent::parse_speed_() {
// Example: "V+001.9"
const char* p = strchr(this->response_buffer_, 'V');
if (p != nullptr) {
++p;
this->approaching_ = (*p == '+');
++p;
this->speed_ = atof(p);
ESP_LOGV(TAG, "Speed updated: %f KPH", this->speed_);
for (auto &listener : this->listeners_) {
listener->on_speed(this->speed_);
//listener->on_approaching(this->approaching_);
}
if (this->speed_sensor_ != nullptr)
this->speed_sensor_->publish_state(this->speed_);
} else {
ESP_LOGE(TAG, "Firmware value invalid.");
}
}
void LD2415HComponent::parse_config_param_(char* key, char* value) {
if(std::strlen(key) != 2 || std::strlen(value) != 2 || key[0] != 'X') {
ESP_LOGE(TAG, "Invalid Parameter %s:%s", key, value);
return;
}
uint8_t v = std::stoi(value, nullptr, 16);
switch(key[1]) {
case '1':
this->min_speed_threshold_ = v;
break;
case '2':
this->compensation_angle_ = std::stoi(value, nullptr, 16);
break;
case '3':
this->sensitivity_ = std::stoi(value, nullptr, 16);
break;
case '4':
this->tracking_mode_ = this->i_to_TrackingMode_(v);
break;
case '5':
this->sample_rate_ = v;
break;
case '6':
this->unit_of_measure_ = this->i_to_UnitOfMeasure_(v);
break;
case '7':
this->vibration_correction_ = v;
break;
case '8':
this->relay_trigger_duration_ = v;
break;
case '9':
this->relay_trigger_speed_ = v;
break;
case '0':
this->negotiation_mode_ = this->i_to_NegotiationMode_(v);
break;
default:
ESP_LOGD(TAG, "Unknown Parameter %s:%s", key, value);
break;
}
}
TrackingMode LD2415HComponent::i_to_TrackingMode_(uint8_t value) {
TrackingMode u = TrackingMode(value);
ESP_LOGD(TAG, "i_to_TrackingMode_: %i, %i", value, static_cast<uint8_t>(u));
switch (u)
{
case TrackingMode::APPROACHING_AND_RETREATING:
return TrackingMode::APPROACHING_AND_RETREATING;
case TrackingMode::APPROACHING:
return TrackingMode::APPROACHING;
case TrackingMode::RETREATING:
return TrackingMode::RETREATING;
default:
ESP_LOGE(TAG, "Invalid TrackingMode:%u", value);
return TrackingMode::APPROACHING_AND_RETREATING;
}
}
UnitOfMeasure LD2415HComponent::i_to_UnitOfMeasure_(uint8_t value) {
UnitOfMeasure u = UnitOfMeasure(value);
switch (u)
{
case UnitOfMeasure::MPS:
return UnitOfMeasure::MPS;
case UnitOfMeasure::MPH:
return UnitOfMeasure::MPH;
case UnitOfMeasure::KPH:
return UnitOfMeasure::KPH;
default:
ESP_LOGE(TAG, "Invalid UnitOfMeasure:%u", value);
return UnitOfMeasure::KPH;
}
}
NegotiationMode LD2415HComponent::i_to_NegotiationMode_(uint8_t value) {
NegotiationMode u = NegotiationMode(value);
switch (u)
{
case NegotiationMode::CUSTOM_AGREEMENT:
return NegotiationMode::CUSTOM_AGREEMENT;
case NegotiationMode::STANDARD_PROTOCOL:
return NegotiationMode::STANDARD_PROTOCOL;
default:
ESP_LOGE(TAG, "Invalid UnitOfMeasure:%u", value);
return NegotiationMode::CUSTOM_AGREEMENT;
}
}
const char* LD2415HComponent::TrackingMode_to_s_(TrackingMode value) {
switch (value)
{
case TrackingMode::APPROACHING_AND_RETREATING:
return "APPROACHING_AND_RETREATING";
case TrackingMode::APPROACHING:
return "APPROACHING";
case TrackingMode::RETREATING:
default:
return "RETREATING";
}
}
const char* LD2415HComponent::UnitOfMeasure_to_s_(UnitOfMeasure value) {
switch (value)
{
case UnitOfMeasure::MPS:
return "MPS";
case UnitOfMeasure::MPH:
return "MPH";
case UnitOfMeasure::KPH:
default:
return "KPH";
}
}
const char* LD2415HComponent::NegotiationMode_to_s_(NegotiationMode value) {
switch (value)
{
case NegotiationMode::CUSTOM_AGREEMENT:
return "CUSTOM_AGREEMENT";
case NegotiationMode::STANDARD_PROTOCOL:
default:
return "STANDARD_PROTOCOL";
}
}
const char* i_to_s_(std::map<std::string, uint8_t> map, uint8_t i) {
for (const auto& pair : map) {
if (pair.second == i) {
return pair.first;
}
}
return "Unknown";
}
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,163 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/uart/uart.h"
#include "esphome/components/sensor/sensor.h"
#ifdef USE_NUMBER
#include "esphome/components/number/number.h"
#endif
#ifdef USE_SELECT
#include "esphome/components/select/select.h"
#endif
#include <map>
namespace esphome {
namespace ld2415h {
enum NegotiationMode : uint8_t{
CUSTOM_AGREEMENT = 0x01,
STANDARD_PROTOCOL = 0x02
};
enum SampleRateStructure : uint8_t {
SAMPLE_RATE_22FPS = 0x00,
SAMPLE_RATE_11FPS = 0x01,
SAMPLE_RATE_6FPS = 0x02
};
static const std::map<std::string, uint8_t> SAMPLE_RATE_STR_TO_INT{
{"~22 fps", SAMPLE_RATE_22FPS},
{"~11 fps", SAMPLE_RATE_11FPS},
{"~6 fps", SAMPLE_RATE_6FPS}
};
enum TrackingMode : uint8_t {
APPROACHING_AND_RETREATING = 0x00,
APPROACHING = 0x01,
RETREATING = 0x02
};
static const std::map<std::string, uint8_t> TRACKING_MODE_STR_TO_INT{
{"Approaching and Restreating", APPROACHING_AND_RETREATING},
{"Approaching", APPROACHING},
{"Restreating", RETREATING}
};
enum UnitOfMeasure : uint8_t {
KPH = 0x00,
MPH = 0x01,
MPS = 0x02
};
class LD2415HListener {
public:
virtual void on_speed(uint8_t speed){};
};
class LD2415HComponent : public Component, public uart::UARTDevice {
public:
// Constructor declaration
LD2415HComponent();
void setup() override;
void dump_config() override;
void loop() override;
#ifdef USE_NUMBER
void set_min_speed_threshold_number(number::Number *number) { this->min_speed_threshold_number_ = number; };
void set_compensation_angle_number(number::Number *number) { this->compensation_angle_number_ = number; };
void set_sensitivity_number(number::Number *number) { this->sensitivity_number_ = number; };
void set_vibration_correction_number(number::Number *number) { this->vibration_correction_number_ = number; };
void set_relay_trigger_duration_number(number::Number *number) { this->relay_trigger_duration_number_ = number; };
void set_relay_trigger_speed_number(number::Number *number) { this->relay_trigger_speed_number_ = number; };
#endif
#ifdef USE_SELECT
void set_sample_rate_select(select::Select *selector) { this->sample_rate_selector_ = selector; };
void set_tracking_mode_select(select::Select *selector) { this->tracking_mode_selector_ = selector; };
#endif
float get_setup_priority() const override { return setup_priority::HARDWARE; }
//void set_speed_sensor(sensor::Sensor *speed_sensor) { this->speed_sensor_ = speed_sensor; }
void register_listener(LD2415HListener *listener) { this->listeners_.push_back(listener); }
void set_min_speed_threshold(uint8_t speed);
void set_compensation_angle(uint8_t angle);
void set_sensitivity(uint8_t sensitivity);
void set_tracking_mode(const std::string &state);
void set_tracking_mode(TrackingMode mode);
void set_tracking_mode(uint8_t mode);
void set_sample_rate(const std::string &state);
void set_sample_rate(uint8_t rate);
void set_vibration_correction(uint8_t correction);
void set_relay_trigger_duration(uint8_t duration);
void set_relay_trigger_speed(uint8_t speed);
#ifdef USE_NUMBER
number::Number *min_speed_threshold_number_{nullptr};
number::Number *compensation_angle_number_{nullptr};
number::Number *sensitivity_number_{nullptr};
number::Number *vibration_correction_number_{nullptr};
number::Number *relay_trigger_duration_number_{nullptr};
number::Number *relay_trigger_speed_number_{nullptr};
#endif
#ifdef USE_SELECT
select::Select *sample_rate_selector_{nullptr};
select::Select *tracking_mode_selector_{nullptr};
#endif
protected:
sensor::Sensor *speed_sensor_{nullptr};
// Configuration
uint8_t min_speed_threshold_ = 0;
uint8_t compensation_angle_ = 0;
uint8_t sensitivity_ = 0;
TrackingMode tracking_mode_ = TrackingMode::APPROACHING_AND_RETREATING;
uint8_t sample_rate_ = 0;
UnitOfMeasure unit_of_measure_ = UnitOfMeasure::KPH;
uint8_t vibration_correction_ = 0;
uint8_t relay_trigger_duration_ = 0;
uint8_t relay_trigger_speed_ = 0;
NegotiationMode negotiation_mode_ = NegotiationMode::CUSTOM_AGREEMENT;
// State
uint8_t cmd_speed_angle_sense_[8];
uint8_t cmd_mode_rate_uom_[8];
uint8_t cmd_anti_vib_comp_[8];
uint8_t cmd_relay_duration_speed_[8];
uint8_t cmd_config_[13];
bool update_speed_angle_sense_ = false;
bool update_mode_rate_uom_ = false;
bool update_anti_vib_comp_ = false;
bool update_relay_duration_speed_ = false;
bool update_config_ = false;
char firmware_[20] = "";
float speed_ = 0;
bool approaching_ = 1;
char response_buffer_[64];
uint8_t response_buffer_index_ = 0;
// Processing
void issue_command_(const uint8_t cmd[], const uint8_t size);
bool fill_buffer_(char c);
void clear_remaining_buffer_(uint8_t pos);
void parse_buffer_();
void parse_config_();
void parse_firmware_();
void parse_speed_();
void parse_config_param_(char* key, char* value);
// Helpers
TrackingMode i_to_TrackingMode_(uint8_t value);
UnitOfMeasure i_to_UnitOfMeasure_(uint8_t value);
NegotiationMode i_to_NegotiationMode_(uint8_t value);
const char* TrackingMode_to_s_(TrackingMode value);
const char* UnitOfMeasure_to_s_(UnitOfMeasure value);
const char* NegotiationMode_to_s_(NegotiationMode value);
const char* i_to_s_(std::map<std::string, uint8_t> map, uint8_t i);
std::vector<LD2415HListener *> listeners_{};
};
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,129 @@
import esphome.codegen as cg
from esphome.components import number
import esphome.config_validation as cv
from esphome.const import (
ENTITY_CATEGORY_CONFIG,
UNIT_DEGREES,
UNIT_EMPTY,
UNIT_KILOMETER_PER_HOUR,
UNIT_SECOND,
)
from .. import CONF_LD2415H_ID, LD2415HComponent, ld2415h_ns
ICON_COMPENSATION_ANGLE = "mdi:angle-acute"
ICON_SENSITIVITY = "mdi:ear-hearing"
ICON_SPEEDOMETER = "mdi:speedometer"
ICON_TIMELAPSE = "mdi:timelapse"
ICON_VIBRATE = "mdi:vibrate"
CONF_MIN_SPEED_THRESHOLD = "min_speed_threshold"
CONF_COMPENSATION_ANGLE = "compensation_angle"
CONF_SENSITIVITY = "sensitivity"
CONF_VIBRATION_CORRECTION = "vibration_correction"
CONF_RELAY_TRIGGER_DURATION = "relay_trigger_duration"
CONF_RELAY_TRIGGER_SPEED = "relay_trigger_speed"
MinSpeedThresholdNumber = ld2415h_ns.class_("MinSpeedThresholdNumber" , number.Number)
CompensationAngleNumber = ld2415h_ns.class_("CompensationAngleNumber" , number.Number)
SensitivityNumber = ld2415h_ns.class_("SensitivityNumber" , number.Number)
VibrationCorrectionNumber = ld2415h_ns.class_("VibrationCorrectionNumber" , number.Number)
RelayTriggerDurationNumber = ld2415h_ns.class_("RelayTriggerDurationNumber", number.Number)
RelayTriggerSpeedNumber = ld2415h_ns.class_("RelayTriggerSpeedNumber" , number.Number)
CONFIG_SCHEMA = {
cv.GenerateID(CONF_LD2415H_ID): cv.use_id(LD2415HComponent),
cv.Optional(CONF_MIN_SPEED_THRESHOLD): number.number_schema(
MinSpeedThresholdNumber,
unit_of_measurement=UNIT_KILOMETER_PER_HOUR,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_SPEEDOMETER,
),
cv.Optional(CONF_COMPENSATION_ANGLE): number.number_schema(
CompensationAngleNumber,
unit_of_measurement=UNIT_DEGREES,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_COMPENSATION_ANGLE,
),
cv.Optional(CONF_SENSITIVITY): number.number_schema(
SensitivityNumber,
unit_of_measurement=UNIT_EMPTY,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_SENSITIVITY,
),
cv.Optional(CONF_VIBRATION_CORRECTION): number.number_schema(
VibrationCorrectionNumber,
unit_of_measurement=UNIT_EMPTY,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_VIBRATE,
),
cv.Optional(CONF_RELAY_TRIGGER_DURATION): number.number_schema(
RelayTriggerDurationNumber,
unit_of_measurement=UNIT_SECOND,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_TIMELAPSE,
),
cv.Optional(CONF_RELAY_TRIGGER_SPEED): number.number_schema(
RelayTriggerSpeedNumber,
unit_of_measurement=UNIT_KILOMETER_PER_HOUR,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_SPEEDOMETER,
),
}
async def to_code(config):
ld2415h_component = await cg.get_variable(config[CONF_LD2415H_ID])
if min_speed_threshold_config := config.get(CONF_MIN_SPEED_THRESHOLD):
num = await number.new_number(
min_speed_threshold_config,
min_value=1,
max_value=60,
step=1,
)
await cg.register_parented(num, config[CONF_LD2415H_ID])
cg.add(ld2415h_component.set_min_speed_threshold_number(num))
if compensation_angle_config := config.get(CONF_COMPENSATION_ANGLE):
num = await number.new_number(
compensation_angle_config,
min_value=0,
max_value=90,
step=1,
)
await cg.register_parented(num, config[CONF_LD2415H_ID])
cg.add(ld2415h_component.set_compensation_angle_number(num))
if sensitivity_config := config.get(CONF_SENSITIVITY):
num = await number.new_number(
sensitivity_config,
min_value=0,
max_value=15,
step=1,
)
await cg.register_parented(num, config[CONF_LD2415H_ID])
cg.add(ld2415h_component.set_sensitivity_number(num))
if vibration_correction_config := config.get(CONF_VIBRATION_CORRECTION):
num = await number.new_number(
vibration_correction_config,
min_value=0,
max_value=112,
step=1,
)
await cg.register_parented(num, config[CONF_LD2415H_ID])
cg.add(ld2415h_component.set_vibration_correction_number(num))
if relay_trigger_duration_config := config.get(CONF_RELAY_TRIGGER_DURATION):
num = await number.new_number(
relay_trigger_duration_config,
min_value=0,
max_value=255,
step=1,
)
await cg.register_parented(num, config[CONF_LD2415H_ID])
cg.add(ld2415h_component.set_relay_trigger_duration_number(num))
if relay_trigger_speed_config := config.get(CONF_RELAY_TRIGGER_SPEED):
num = await number.new_number(
relay_trigger_speed_config,
min_value=0,
max_value=255,
step=1,
)
await cg.register_parented(num, config[CONF_LD2415H_ID])
cg.add(ld2415h_component.set_relay_trigger_speed_number(num))

View file

@ -0,0 +1,16 @@
#include "compensation_angle_number.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ld2415h {
static const char *const TAG = "LD2415H.compensation_angle_number";
void CompensationAngleNumber::control(float angle) {
this->publish_state(angle);
this->parent_->set_compensation_angle(angle);
}
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../ld2415h.h"
namespace esphome {
namespace ld2415h {
class CompensationAngleNumber : public number::Number, public Parented<LD2415HComponent> {
public:
CompensationAngleNumber() = default;
protected:
void control(float angle) override;
};
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,16 @@
#include "min_speed_threshold_number.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ld2415h {
static const char *const TAG = "LD2415H.min_speed_threshold_number";
void MinSpeedThresholdNumber::control(float speed) {
this->publish_state(speed);
this->parent_->set_min_speed_threshold(speed);
}
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../ld2415h.h"
namespace esphome {
namespace ld2415h {
class MinSpeedThresholdNumber : public number::Number, public Parented<LD2415HComponent> {
public:
MinSpeedThresholdNumber() = default;
protected:
void control(float speed) override;
};
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,16 @@
#include "relay_trigger_duration_number.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ld2415h {
static const char *const TAG = "LD2415H.relay_trigger_duration_number";
void RelayTriggerDurationNumber::control(float duration) {
this->publish_state(duration);
this->parent_->set_relay_trigger_duration(duration);
}
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../ld2415h.h"
namespace esphome {
namespace ld2415h {
class RelayTriggerDurationNumber : public number::Number, public Parented<LD2415HComponent> {
public:
RelayTriggerDurationNumber() = default;
protected:
void control(float duration) override;
};
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,16 @@
#include "relay_trigger_speed_number.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ld2415h {
static const char *const TAG = "LD2415H.relay_trigger_speed_number";
void RelayTriggerSpeedNumber::control(float speed) {
this->publish_state(speed);
this->parent_->set_relay_trigger_speed(speed);
}
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../ld2415h.h"
namespace esphome {
namespace ld2415h {
class RelayTriggerSpeedNumber : public number::Number, public Parented<LD2415HComponent> {
public:
RelayTriggerSpeedNumber() = default;
protected:
void control(float speed) override;
};
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,16 @@
#include "sensitivity_number.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ld2415h {
static const char *const TAG = "LD2415H.sensitivity_number";
void SensitivityNumber::control(float sensitivity) {
this->publish_state(sensitivity);
this->parent_->set_sensitivity(sensitivity);
}
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../ld2415h.h"
namespace esphome {
namespace ld2415h {
class SensitivityNumber : public number::Number, public Parented<LD2415HComponent> {
public:
SensitivityNumber() = default;
protected:
void control(float sensitivity) override;
};
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,16 @@
#include "vibration_correction_number.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ld2415h {
static const char *const TAG = "LD2415H.vibration_correction_number";
void VibrationCorrectionNumber::control(float correction) {
this->publish_state(correction);
this->parent_->set_vibration_correction(correction);
}
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../ld2415h.h"
namespace esphome {
namespace ld2415h {
class VibrationCorrectionNumber : public number::Number, public Parented<LD2415HComponent> {
public:
VibrationCorrectionNumber() = default;
protected:
void control(float correction) override;
};
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,56 @@
import esphome.codegen as cg
from esphome.components import select
import esphome.config_validation as cv
from esphome.const import ENTITY_CATEGORY_CONFIG
from .. import CONF_LD2415H_ID, LD2415HComponent, ld2415h_ns
CONF_SAMPLE_RATE = "sample_rate"
CONF_SAMPLE_RATE_SELECTS = [
"~22 fps",
"~11 fps",
"~6 fps",
]
ICON_CLOCK_FAST = "mdi:clock-fast"
CONF_TRACKING_MODE = "tracking_mode"
CONF_TRACKING_MODE_SELECTS = [
"Approaching and Restreating",
"Approaching",
"Restreating",
]
ICON_RADAR = "mdi:radar"
SampleRateSelect = ld2415h_ns.class_("SampleRateSelect", select.Select)
TrackingModeSelect = ld2415h_ns.class_("TrackingModeSelect", select.Select)
CONFIG_SCHEMA = {
cv.GenerateID(CONF_LD2415H_ID): cv.use_id(LD2415HComponent),
cv.Optional(CONF_SAMPLE_RATE, default=1): select.select_schema(
SampleRateSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_CLOCK_FAST,
),
cv.Optional(CONF_TRACKING_MODE, default=0): select.select_schema(
TrackingModeSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RADAR,
),
}
async def to_code(config):
ld2415h_component = await cg.get_variable(config[CONF_LD2415H_ID])
if sample_rate_config := config.get(CONF_SAMPLE_RATE):
sel = await select.new_select(
sample_rate_config,
options=[CONF_SAMPLE_RATE_SELECTS],
)
await cg.register_parented(sel, config[CONF_LD2415H_ID])
cg.add(ld2415h_component.set_sample_rate_select(sel))
if tracking_mode_config := config.get(CONF_TRACKING_MODE):
sel = await select.new_select(
tracking_mode_config,
options=[CONF_TRACKING_MODE_SELECTS],
)
await cg.register_parented(sel, config[CONF_LD2415H_ID])
cg.add(ld2415h_component.set_tracking_mode_select(sel))

View file

@ -0,0 +1,16 @@
#include "sample_rate_select.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ld2415h {
static const char *const TAG = "LD2415H.sample_rate_select";
void SampleRateSelect::control(const std::string &value) {
this->publish_state(value);
this->parent_->set_sample_rate(state);
}
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "../ld2415h.h"
#include "esphome/components/select/select.h"
namespace esphome {
namespace ld2415h {
class SampleRateSelect : public Component, public select::Select, public Parented<LD2415HComponent> {
public:
SampleRateSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,16 @@
#include "tracking_mode_select.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ld2415h {
static const char *const TAG = "LD2415H.tracking_mode_select";
void TrackingModeSelect::control(const std::string &value) {
this->publish_state(value);
this->parent_->set_tracking_mode(state);
}
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "../ld2415h.h"
#include "esphome/components/select/select.h"
namespace esphome {
namespace ld2415h {
class TrackingModeSelect : public Component, public select::Select, public Parented<LD2415HComponent> {
public:
TrackingModeSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace ld2415h
} // namespace esphome

View file

@ -0,0 +1,41 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import (
CONF_ID,
CONF_SPEED,
DEVICE_CLASS_SPEED,
STATE_CLASS_MEASUREMENT,
UNIT_KILOMETER_PER_HOUR,
)
from .. import ld2415h_ns, LD2415HComponent, CONF_LD2415H_ID
LD2415HSensor = ld2415h_ns.class_("LD2415HSensor", sensor.Sensor, cg.Component)
ICON_SPEEDOMETER = "mdi:speedometer"
CONFIG_SCHEMA = cv.All(
cv.COMPONENT_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(LD2415HSensor),
cv.GenerateID(CONF_LD2415H_ID): cv.use_id(LD2415HComponent),
cv.Optional(CONF_SPEED): sensor.sensor_schema(
device_class=DEVICE_CLASS_SPEED,
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=UNIT_KILOMETER_PER_HOUR,
icon=ICON_SPEEDOMETER,
accuracy_decimals=1,
),
}
),
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
if speed := config.get(CONF_SPEED):
sens = await sensor.new_sensor(speed)
cg.add(var.set_speed_sensor(sens))
ld2415h = await cg.get_variable(config[CONF_LD2415H_ID])
cg.add(ld2415h.register_listener(var))

View file

@ -0,0 +1,16 @@
#include "ld2415h_sensor.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ld2415h {
static const char *const TAG = "LD2415H.sensor";
void LD2415HSensor::dump_config() {
ESP_LOGCONFIG(TAG, "LD2415H Sensor:");
LOG_SENSOR(" ", "Speed", this->speed_sensor_);
}
} // namespace ld2415H
} // namespace esphome

View file

@ -0,0 +1,26 @@
#pragma once
#include "../ld2415h.h"
#include "esphome/components/sensor/sensor.h"
namespace esphome {
namespace ld2415h {
class LD2415HSensor : public LD2415HListener, public Component, sensor::Sensor {
public:
void dump_config() override;
void set_speed_sensor(sensor::Sensor *sensor) { this->speed_sensor_ = sensor; }
void on_speed(uint8_t speed) override {
if (this->speed_sensor_ != nullptr) {
if (this->speed_sensor_->get_state() != speed) {
this->speed_sensor_->publish_state(speed);
}
}
}
protected:
sensor::Sensor *speed_sensor_{nullptr};
};
} // namespace ld2415h
} // namespace esphome