mirror of
https://github.com/esphome/esphome.git
synced 2026-10-22 05:46:12 +00:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
643747e8cf | ||
|
|
7ea688c292 | ||
|
|
86044f64be | ||
|
|
2a1c658c54 | ||
|
|
1ba2e9ca3f | ||
|
|
af49c523d1 |
@@ -15,6 +15,15 @@ LD2420Component = ld2420_ns.class_("LD2420Component", cg.Component, uart.UARTDev
|
||||
|
||||
CONF_LD2420_ID = "ld2420_id"
|
||||
|
||||
# Each hub keeps its listeners in a fixed size list; the define is the largest count any one hub needs
|
||||
_request_listener_slot = cg.slot_counter("LD2420_LISTENER_COUNT")
|
||||
|
||||
|
||||
async def register_listener(hub: cg.MockObj, var: cg.MockObj) -> None:
|
||||
_request_listener_slot(str(hub))
|
||||
cg.add(hub.register_listener(var))
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ import esphome.config_validation as cv
|
||||
from esphome.const import CONF_HAS_TARGET, CONF_ID, DEVICE_CLASS_OCCUPANCY
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .. import CONF_LD2420_ID, LD2420Component, ld2420_ns
|
||||
from .. import CONF_LD2420_ID, LD2420Component, ld2420_ns, register_listener
|
||||
|
||||
LD2420BinarySensor = ld2420_ns.class_(
|
||||
"LD2420BinarySensor", binary_sensor.BinarySensor, cg.Component
|
||||
@@ -30,4 +30,4 @@ async def to_code(config: ConfigType) -> None:
|
||||
binary_sensors = binary_sensor.sub_binary_sensors(config)
|
||||
await binary_sensors(CONF_HAS_TARGET, var.set_presence_sensor)
|
||||
hub = await cg.get_variable(config[CONF_LD2420_ID])
|
||||
cg.add(hub.register_listener(var))
|
||||
await register_listener(hub, var)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "ld2420.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/progmem.h"
|
||||
|
||||
/*
|
||||
Configure commands - little endian
|
||||
@@ -102,16 +103,14 @@ static constexpr uint8_t LD2420_ERROR_UNKNOWN = 0x01;
|
||||
static constexpr uint16_t CMD_MIN_GATE_REG = 0x0000;
|
||||
static constexpr uint16_t CMD_MAX_GATE_REG = 0x0001;
|
||||
static constexpr uint16_t CMD_TIMEOUT_REG = 0x0004;
|
||||
static constexpr uint16_t CMD_GATE_MOVE_THRESH[TOTAL_GATES] = {0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015,
|
||||
0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B,
|
||||
0x001C, 0x001D, 0x001E, 0x001F};
|
||||
static constexpr uint16_t CMD_GATE_STILL_THRESH[TOTAL_GATES] = {0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025,
|
||||
0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B,
|
||||
0x002C, 0x002D, 0x002E, 0x002F};
|
||||
static constexpr uint32_t FACTORY_MOVE_THRESH[TOTAL_GATES] = {60000, 30000, 400, 250, 250, 250, 250, 250,
|
||||
250, 250, 250, 250, 250, 250, 250, 250};
|
||||
static constexpr uint32_t FACTORY_STILL_THRESH[TOTAL_GATES] = {40000, 20000, 200, 200, 200, 200, 200, 150,
|
||||
150, 100, 100, 100, 100, 100, 100, 100};
|
||||
// Gate n uses the base register plus n
|
||||
static constexpr uint16_t CMD_GATE_MOVE_THRESH_REG = 0x0010;
|
||||
static constexpr uint16_t CMD_GATE_STILL_THRESH_REG = 0x0020;
|
||||
// In flash on ESP8266; indexed directly since each entry is an aligned 32 bit read
|
||||
static constexpr uint32_t FACTORY_MOVE_THRESH[TOTAL_GATES] PROGMEM = {60000, 30000, 400, 250, 250, 250, 250, 250,
|
||||
250, 250, 250, 250, 250, 250, 250, 250};
|
||||
static constexpr uint32_t FACTORY_STILL_THRESH[TOTAL_GATES] PROGMEM = {40000, 20000, 200, 200, 200, 200, 200, 150,
|
||||
150, 100, 100, 100, 100, 100, 100, 100};
|
||||
static constexpr uint16_t FACTORY_TIMEOUT = 120;
|
||||
static constexpr uint16_t FACTORY_MIN_GATE = 1;
|
||||
static constexpr uint16_t FACTORY_MAX_GATE = 12;
|
||||
@@ -130,36 +129,10 @@ static constexpr uint8_t CMD_FRAME_STATUS = 7;
|
||||
static constexpr uint8_t CMD_ERROR_WORD = 8;
|
||||
static constexpr uint8_t ENERGY_SENSOR_START = 9;
|
||||
static constexpr uint8_t CALIBRATE_REPORT_INTERVAL = 4;
|
||||
static const char *const OP_NORMAL_MODE_STRING = "Normal";
|
||||
static const char *const OP_SIMPLE_MODE_STRING = "Simple";
|
||||
|
||||
// Memory-efficient lookup tables
|
||||
struct StringToUint8 {
|
||||
const char *str;
|
||||
const uint8_t value;
|
||||
};
|
||||
|
||||
static constexpr StringToUint8 OP_MODE_BY_STR[] = {
|
||||
{"Normal", OP_NORMAL_MODE},
|
||||
{"Calibrate", OP_CALIBRATE_MODE},
|
||||
{"Simple", OP_SIMPLE_MODE},
|
||||
};
|
||||
|
||||
static constexpr const char *ERR_MESSAGE[] = {
|
||||
"None",
|
||||
"Unknown",
|
||||
"Timeout",
|
||||
};
|
||||
|
||||
// Helper function for lookups
|
||||
template<size_t N> uint8_t find_uint8(const StringToUint8 (&arr)[N], const std::string &str) {
|
||||
for (const auto &entry : arr) {
|
||||
if (str == entry.str) {
|
||||
return entry.value;
|
||||
}
|
||||
}
|
||||
return 0xFF; // Not found
|
||||
}
|
||||
// Index + 1 is the OpMode value; the select options use the same order
|
||||
PROGMEM_STRING_TABLE(OpModeStrings, "Normal", "Calibrate", "Simple");
|
||||
static_assert(OP_NORMAL_MODE == 1 && OP_CALIBRATE_MODE == 2 && OP_SIMPLE_MODE == 3, "OpMode is index + 1");
|
||||
PROGMEM_STRING_TABLE(ErrMessages, "None", "Unknown", "Timeout");
|
||||
|
||||
static uint8_t calc_checksum(const void *data, size_t size) {
|
||||
return xor_bytes(static_cast<const uint8_t *>(data), size);
|
||||
@@ -221,12 +194,11 @@ void LD2420Component::setup() {
|
||||
this->init_gate_config_numbers();
|
||||
#endif
|
||||
this->get_firmware_version_();
|
||||
const char *pfw = this->firmware_ver_;
|
||||
std::string fw_str(pfw);
|
||||
|
||||
for (auto &listener : this->listeners_) {
|
||||
listener->on_fw_version(fw_str);
|
||||
#ifdef LD2420_LISTENER_COUNT
|
||||
for (auto *listener : this->listeners_) {
|
||||
listener->on_fw_version(this->firmware_ver_);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) {
|
||||
delay_microseconds_safe(125);
|
||||
@@ -235,21 +207,12 @@ void LD2420Component::setup() {
|
||||
|
||||
memcpy(&this->new_config, &this->current_config, sizeof(this->current_config));
|
||||
if (ld2420::get_firmware_int(this->firmware_ver_) < CALIBRATE_VERSION_MIN) {
|
||||
this->set_operating_mode(OP_SIMPLE_MODE_STRING);
|
||||
#ifdef USE_SELECT
|
||||
if (this->operating_selector_ != nullptr) {
|
||||
this->operating_selector_->publish_state(OP_SIMPLE_MODE_STRING);
|
||||
}
|
||||
#endif
|
||||
this->set_operating_mode(OP_SIMPLE_MODE);
|
||||
this->set_mode_(CMD_SYSTEM_MODE_SIMPLE);
|
||||
ESP_LOGW(TAG, "Firmware version %s and older supports Simple Mode only", this->firmware_ver_);
|
||||
} else {
|
||||
this->set_operating_mode(OP_NORMAL_MODE);
|
||||
this->set_mode_(CMD_SYSTEM_MODE_ENERGY);
|
||||
#ifdef USE_SELECT
|
||||
if (this->operating_selector_ != nullptr) {
|
||||
this->operating_selector_->publish_state(OP_NORMAL_MODE_STRING);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef USE_NUMBER
|
||||
this->init_gate_config_numbers();
|
||||
@@ -281,7 +244,7 @@ void LD2420Component::apply_config_action() {
|
||||
#endif
|
||||
this->set_system_mode(this->system_mode_);
|
||||
this->set_config_mode(false); // Disable config mode to save new values in LD2420 nvm
|
||||
this->set_operating_mode(OP_NORMAL_MODE_STRING);
|
||||
this->set_operating_mode(OP_NORMAL_MODE);
|
||||
}
|
||||
|
||||
void LD2420Component::factory_reset_action() {
|
||||
@@ -387,39 +350,40 @@ void LD2420Component::report_gate_data() {
|
||||
}
|
||||
|
||||
void LD2420Component::set_operating_mode(const char *state) {
|
||||
// If unsupported firmware ignore mode select
|
||||
if (ld2420::get_firmware_int(firmware_ver_) >= CALIBRATE_VERSION_MIN) {
|
||||
this->current_operating_mode = find_uint8(OP_MODE_BY_STR, state);
|
||||
// Entering Auto Calibrate we need to clear the previous data collection
|
||||
const int16_t index = progmem_string_table_find<OpModeStrings>(state, strlen(state));
|
||||
if (index >= 0) {
|
||||
this->set_operating_mode(static_cast<OpMode>(index + 1));
|
||||
}
|
||||
}
|
||||
|
||||
void LD2420Component::set_operating_mode(OpMode mode) {
|
||||
// Older firmware only supports simple mode
|
||||
if (ld2420::get_firmware_int(this->firmware_ver_) < CALIBRATE_VERSION_MIN) {
|
||||
mode = OP_SIMPLE_MODE;
|
||||
}
|
||||
this->current_operating_mode = mode;
|
||||
#ifdef USE_SELECT
|
||||
if (this->operating_selector_ != nullptr) {
|
||||
this->operating_selector_->publish_state(state);
|
||||
}
|
||||
if (this->operating_selector_ != nullptr) {
|
||||
this->operating_selector_->publish_state(static_cast<size_t>(mode - 1));
|
||||
}
|
||||
#endif
|
||||
if (current_operating_mode == OP_CALIBRATE_MODE) {
|
||||
this->set_calibration_(true);
|
||||
for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) {
|
||||
this->gate_avg[gate] = 0;
|
||||
this->gate_peak[gate] = 0;
|
||||
for (uint8_t i = 0; i < CALIBRATE_SAMPLES; i++) {
|
||||
this->radar_data[gate][i] = 0;
|
||||
}
|
||||
this->total_sample_number_counter = 0;
|
||||
if (mode == OP_CALIBRATE_MODE) {
|
||||
// Entering Auto Calibrate we need to clear the previous data collection
|
||||
this->set_calibration_(true);
|
||||
for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) {
|
||||
this->gate_avg[gate] = 0;
|
||||
this->gate_peak[gate] = 0;
|
||||
for (uint8_t i = 0; i < CALIBRATE_SAMPLES; i++) {
|
||||
this->radar_data[gate][i] = 0;
|
||||
}
|
||||
} else {
|
||||
// Set the current data back so we don't have new data that can be applied in error.
|
||||
if (this->get_calibration_()) {
|
||||
memcpy(&this->new_config, &this->current_config, sizeof(this->current_config));
|
||||
}
|
||||
this->set_calibration_(false);
|
||||
this->total_sample_number_counter = 0;
|
||||
}
|
||||
} else {
|
||||
this->current_operating_mode = OP_SIMPLE_MODE;
|
||||
#ifdef USE_SELECT
|
||||
if (this->operating_selector_ != nullptr) {
|
||||
this->operating_selector_->publish_state(OP_SIMPLE_MODE_STRING);
|
||||
// Set the current data back so we don't have new data that can be applied in error.
|
||||
if (this->get_calibration_()) {
|
||||
memcpy(&this->new_config, &this->current_config, sizeof(this->current_config));
|
||||
}
|
||||
#endif
|
||||
this->set_calibration_(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,11 +449,13 @@ void LD2420Component::handle_energy_mode_(uint8_t *buffer, int len) {
|
||||
return;
|
||||
}
|
||||
this->last_periodic_millis = current_millis;
|
||||
for (auto &listener : this->listeners_) {
|
||||
#ifdef LD2420_LISTENER_COUNT
|
||||
for (auto *listener : this->listeners_) {
|
||||
listener->on_distance(this->get_distance_());
|
||||
listener->on_presence(this->get_presence_());
|
||||
listener->on_energy(this->gate_energy_, sizeof(this->gate_energy_) / sizeof(this->gate_energy_[0]));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (this->current_operating_mode == OP_CALIBRATE_MODE) {
|
||||
this->auto_calibrate_sensitivity();
|
||||
@@ -535,10 +501,15 @@ void LD2420Component::handle_simple_mode_(const uint8_t *inbuf, int len) {
|
||||
return;
|
||||
}
|
||||
this->last_normal_periodic_millis = current_millis;
|
||||
for (auto &listener : this->listeners_)
|
||||
#ifdef LD2420_LISTENER_COUNT
|
||||
// Every listener gets the distance before any presence callback can run an automation
|
||||
for (auto *listener : this->listeners_) {
|
||||
listener->on_distance(this->get_distance_());
|
||||
for (auto &listener : this->listeners_)
|
||||
}
|
||||
for (auto *listener : this->listeners_) {
|
||||
listener->on_presence(this->get_presence_());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -742,10 +713,10 @@ void LD2420Component::set_reg_value(uint16_t reg, uint16_t value) {
|
||||
}
|
||||
|
||||
void LD2420Component::handle_cmd_error(uint16_t error) {
|
||||
if (error < std::size(ERR_MESSAGE)) {
|
||||
ESP_LOGE(TAG, "Command failed: %s", ERR_MESSAGE[error]);
|
||||
if (error < ErrMessages::COUNT) {
|
||||
ESP_LOGE(TAG, "Command failed: %s", LOG_STR_ARG(ErrMessages::get_log_str(error, ErrMessages::LAST_INDEX)));
|
||||
} else {
|
||||
// The error word comes from the device reply frame; unknown codes must not index ERR_MESSAGE
|
||||
// The error word comes from the device reply frame; unknown codes must not index the table
|
||||
ESP_LOGE(TAG, "Command failed: error 0x%04X", error);
|
||||
}
|
||||
}
|
||||
@@ -756,9 +727,11 @@ int LD2420Component::get_gate_threshold_(uint8_t gate) {
|
||||
cmd_frame.data_length = 0;
|
||||
cmd_frame.header = CMD_FRAME_HEADER;
|
||||
cmd_frame.command = CMD_READ_ABD_PARAM;
|
||||
memcpy(&cmd_frame.data[cmd_frame.data_length], &CMD_GATE_MOVE_THRESH[gate], sizeof(CMD_GATE_MOVE_THRESH[gate]));
|
||||
const uint16_t move_reg = CMD_GATE_MOVE_THRESH_REG + gate;
|
||||
const uint16_t still_reg = CMD_GATE_STILL_THRESH_REG + gate;
|
||||
memcpy(&cmd_frame.data[cmd_frame.data_length], &move_reg, sizeof(move_reg));
|
||||
cmd_frame.data_length += 2;
|
||||
memcpy(&cmd_frame.data[cmd_frame.data_length], &CMD_GATE_STILL_THRESH[gate], sizeof(CMD_GATE_STILL_THRESH[gate]));
|
||||
memcpy(&cmd_frame.data[cmd_frame.data_length], &still_reg, sizeof(still_reg));
|
||||
cmd_frame.data_length += 2;
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
ESP_LOGV(TAG, "Sending read gate %d high/low threshold command: %2X", gate, cmd_frame.command);
|
||||
@@ -864,8 +837,8 @@ void LD2420Component::set_gate_threshold(uint8_t gate) {
|
||||
// HH HH HH HH LL LL CC CC RR RR VV VV VV VV RR RR VV VV VV VV FF FF FF FF
|
||||
// FD FC FB FA 14 00 07 00 10 00 00 FF 00 00 00 01 00 0F 00 00 04 03 02 01
|
||||
|
||||
uint16_t move_threshold_gate = CMD_GATE_MOVE_THRESH[gate];
|
||||
uint16_t still_threshold_gate = CMD_GATE_STILL_THRESH[gate];
|
||||
const uint16_t move_threshold_gate = CMD_GATE_MOVE_THRESH_REG + gate;
|
||||
const uint16_t still_threshold_gate = CMD_GATE_STILL_THRESH_REG + gate;
|
||||
CmdFrameT cmd_frame;
|
||||
cmd_frame.data_length = 0;
|
||||
cmd_frame.header = CMD_FRAME_HEADER;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <array>
|
||||
#include <span>
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
@@ -20,6 +21,10 @@
|
||||
|
||||
namespace esphome::ld2420 {
|
||||
|
||||
namespace testing {
|
||||
class LD2420OperatingModeTest;
|
||||
} // namespace testing
|
||||
|
||||
static constexpr uint8_t CALIBRATE_SAMPLES = 64;
|
||||
// Energy frame is 45 bytes; +1 for null terminator, +4 so that a frame footer always lands
|
||||
// inside the buffer during footer-based resynchronization after losing sync.
|
||||
@@ -37,7 +42,7 @@ class LD2420Listener {
|
||||
virtual void on_presence(bool presence) {};
|
||||
virtual void on_distance(uint16_t distance) {};
|
||||
virtual void on_energy(uint16_t *sensor_energy, size_t size) {};
|
||||
virtual void on_fw_version(std::string &fw) {};
|
||||
virtual void on_fw_version(const char *fw) {};
|
||||
};
|
||||
|
||||
class LD2420Component final : public Component, public uart::UARTDevice {
|
||||
@@ -100,7 +105,9 @@ class LD2420Component final : public Component, public uart::UARTDevice {
|
||||
void set_restart_module_button(button::Button *button) { this->restart_module_button_ = button; };
|
||||
void set_factory_reset_button(button::Button *button) { this->factory_reset_button_ = button; };
|
||||
#endif
|
||||
#ifdef LD2420_LISTENER_COUNT
|
||||
void register_listener(LD2420Listener *listener) { this->listeners_.push_back(listener); }
|
||||
#endif
|
||||
|
||||
void send_module_restart();
|
||||
void restart_module_action();
|
||||
@@ -111,6 +118,7 @@ class LD2420Component final : public Component, public uart::UARTDevice {
|
||||
void report_gate_data();
|
||||
void handle_cmd_error(uint16_t error);
|
||||
void set_operating_mode(const char *state);
|
||||
void set_operating_mode(OpMode mode);
|
||||
void auto_calibrate_sensitivity();
|
||||
void update_radar_data(uint16_t const *gate_energy, uint8_t sample_number);
|
||||
uint8_t set_config_mode(bool enable);
|
||||
@@ -180,8 +188,8 @@ class LD2420Component final : public Component, public uart::UARTDevice {
|
||||
number::Number *max_gate_distance_number_{nullptr};
|
||||
number::Number *gate_move_sensitivity_factor_number_{nullptr};
|
||||
number::Number *gate_still_sensitivity_factor_number_{nullptr};
|
||||
std::vector<number::Number *> gate_still_threshold_numbers_ = std::vector<number::Number *>(16);
|
||||
std::vector<number::Number *> gate_move_threshold_numbers_ = std::vector<number::Number *>(16);
|
||||
std::array<number::Number *, TOTAL_GATES> gate_still_threshold_numbers_{};
|
||||
std::array<number::Number *, TOTAL_GATES> gate_move_threshold_numbers_{};
|
||||
#endif
|
||||
|
||||
uint16_t distance_{0};
|
||||
@@ -194,7 +202,12 @@ class LD2420Component final : public Component, public uart::UARTDevice {
|
||||
bool presence_{false};
|
||||
bool calibration_{false};
|
||||
CmdReplyT cmd_reply_;
|
||||
std::vector<LD2420Listener *> listeners_{};
|
||||
#ifdef LD2420_LISTENER_COUNT
|
||||
StaticVector<LD2420Listener *, LD2420_LISTENER_COUNT> listeners_;
|
||||
#endif
|
||||
|
||||
// clang-tidy compiles the host tests without USE_HOST, so the friend is unconditional
|
||||
friend class testing::LD2420OperatingModeTest;
|
||||
};
|
||||
|
||||
} // namespace esphome::ld2420
|
||||
|
||||
@@ -8,7 +8,7 @@ ESPHOME_LOG_TAG(TAG, "ld2420.select");
|
||||
|
||||
void LD2420Select::control(size_t index) {
|
||||
this->publish_state(index);
|
||||
this->parent_->set_operating_mode(this->option_at(index));
|
||||
this->parent_->set_operating_mode(static_cast<OpMode>(index + 1));
|
||||
}
|
||||
|
||||
} // namespace esphome::ld2420
|
||||
|
||||
@@ -10,7 +10,7 @@ from esphome.const import (
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .. import CONF_LD2420_ID, LD2420Component, ld2420_ns
|
||||
from .. import CONF_LD2420_ID, LD2420Component, ld2420_ns, register_listener
|
||||
|
||||
LD2420Sensor = ld2420_ns.class_("LD2420Sensor", sensor.Sensor, cg.Component)
|
||||
|
||||
@@ -38,4 +38,4 @@ async def to_code(config: ConfigType) -> None:
|
||||
await sensors(CONF_MOVING_DISTANCE, var.set_distance_sensor)
|
||||
await sensors(CONF_GATE_ENERGY, var.set_energy_sensor)
|
||||
hub = await cg.get_variable(config[CONF_LD2420_ID])
|
||||
cg.add(hub.register_listener(var))
|
||||
await register_listener(hub, var)
|
||||
|
||||
@@ -26,7 +26,7 @@ class LD2420Sensor final : public LD2420Listener, public Component, public senso
|
||||
|
||||
protected:
|
||||
sensor::Sensor *distance_sensor_{nullptr};
|
||||
std::vector<sensor::Sensor *> energy_sensors_ = std::vector<sensor::Sensor *>(TOTAL_GATES);
|
||||
std::array<sensor::Sensor *, TOTAL_GATES> energy_sensors_{};
|
||||
};
|
||||
|
||||
} // namespace esphome::ld2420
|
||||
|
||||
@@ -4,7 +4,7 @@ import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, ENTITY_CATEGORY_DIAGNOSTIC, ICON_CHIP
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .. import CONF_LD2420_ID, LD2420Component, ld2420_ns
|
||||
from .. import CONF_LD2420_ID, LD2420Component, ld2420_ns, register_listener
|
||||
|
||||
LD2420TextSensor = ld2420_ns.class_(
|
||||
"LD2420TextSensor", text_sensor.TextSensor, cg.Component
|
||||
@@ -31,4 +31,4 @@ async def to_code(config: ConfigType) -> None:
|
||||
text_sensors = text_sensor.sub_text_sensors(config)
|
||||
await text_sensors(CONF_FW_VERSION, var.set_fw_version_text_sensor)
|
||||
hub = await cg.get_variable(config[CONF_LD2420_ID])
|
||||
cg.add(hub.register_listener(var))
|
||||
await register_listener(hub, var)
|
||||
|
||||
@@ -9,7 +9,7 @@ class LD2420TextSensor final : public LD2420Listener, public Component, public t
|
||||
public:
|
||||
void dump_config() override;
|
||||
void set_fw_version_text_sensor(text_sensor::TextSensor *tsensor) { this->fw_version_text_sensor_ = tsensor; };
|
||||
void on_fw_version(std::string &fw) override {
|
||||
void on_fw_version(const char *fw) override {
|
||||
if (this->fw_version_text_sensor_ != nullptr) {
|
||||
this->fw_version_text_sensor_->publish_state(fw);
|
||||
}
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
#define MDNS_SERVICE_COUNT 3
|
||||
#define USE_MDNS_DYNAMIC_TXT
|
||||
#define MDNS_DYNAMIC_TXT_COUNT 2
|
||||
#define LD2420_LISTENER_COUNT 1
|
||||
#define LD2450_POLYGON_ZONE_COUNT 2
|
||||
#define SEN6X_STATUS_SENSOR_COUNT 1
|
||||
#define UART_BINARY_SENSOR_COUNT 2
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#include <cstring>
|
||||
#include <gtest/gtest.h>
|
||||
#include "esphome/components/ld2420/ld2420.h"
|
||||
#include "esphome/components/select/select.h"
|
||||
|
||||
namespace esphome::ld2420::testing {
|
||||
|
||||
class TestSelect : public select::Select {
|
||||
public:
|
||||
TestSelect() { this->traits.set_options({"Normal", "Calibrate", "Simple"}); }
|
||||
|
||||
protected:
|
||||
void control(size_t index) override {}
|
||||
};
|
||||
|
||||
class LD2420OperatingModeTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// 1.5.4 is the first firmware with calibration
|
||||
this->set_firmware_("v1.5.4");
|
||||
this->ld2420_.set_operating_mode_select(&this->select_);
|
||||
}
|
||||
// The fixture is a friend of the hub, so it reaches the version and calibration flag for the tests
|
||||
void set_firmware_(const char *version) {
|
||||
std::strncpy(this->ld2420_.firmware_ver_, version, sizeof(this->ld2420_.firmware_ver_));
|
||||
}
|
||||
void expect_mode_(OpMode mode, size_t index, bool calibrating) {
|
||||
EXPECT_EQ(this->ld2420_.current_operating_mode, static_cast<uint8_t>(mode));
|
||||
EXPECT_EQ(this->select_.active_index().value_or(SIZE_MAX), index);
|
||||
EXPECT_EQ(this->ld2420_.calibration_, calibrating);
|
||||
}
|
||||
|
||||
LD2420Component ld2420_;
|
||||
TestSelect select_;
|
||||
};
|
||||
|
||||
TEST_F(LD2420OperatingModeTest, NamesMapToModesAndSelectIndex) {
|
||||
this->ld2420_.set_operating_mode("Calibrate");
|
||||
this->expect_mode_(OP_CALIBRATE_MODE, 1, true);
|
||||
this->ld2420_.set_operating_mode("Simple");
|
||||
this->expect_mode_(OP_SIMPLE_MODE, 2, false);
|
||||
this->ld2420_.set_operating_mode("Normal");
|
||||
this->expect_mode_(OP_NORMAL_MODE, 0, false);
|
||||
}
|
||||
|
||||
TEST_F(LD2420OperatingModeTest, EnumEntryPointMatchesTheSelectIndex) {
|
||||
this->ld2420_.set_operating_mode(OP_CALIBRATE_MODE);
|
||||
this->expect_mode_(OP_CALIBRATE_MODE, 1, true);
|
||||
this->ld2420_.set_operating_mode(OP_NORMAL_MODE);
|
||||
this->expect_mode_(OP_NORMAL_MODE, 0, false);
|
||||
}
|
||||
|
||||
TEST_F(LD2420OperatingModeTest, UnknownNameLeavesTheModeUnchanged) {
|
||||
this->ld2420_.set_operating_mode(OP_CALIBRATE_MODE);
|
||||
this->ld2420_.set_operating_mode("Bogus");
|
||||
this->expect_mode_(OP_CALIBRATE_MODE, 1, true);
|
||||
}
|
||||
|
||||
TEST_F(LD2420OperatingModeTest, OlderFirmwareOnlySupportsSimpleMode) {
|
||||
this->set_firmware_("v1.5.3");
|
||||
this->ld2420_.set_operating_mode("Calibrate");
|
||||
this->expect_mode_(OP_SIMPLE_MODE, 2, false);
|
||||
this->ld2420_.set_operating_mode(OP_NORMAL_MODE);
|
||||
this->expect_mode_(OP_SIMPLE_MODE, 2, false);
|
||||
}
|
||||
|
||||
} // namespace esphome::ld2420::testing
|
||||
@@ -0,0 +1,12 @@
|
||||
from esphome.core import CORE
|
||||
from esphome.types import ConfigType
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
# Turns on USE_SELECT so the operating mode select is in the host test build
|
||||
async def to_code_testing(config: ConfigType) -> None:
|
||||
CORE.testing_ensure_platform_registered("select")
|
||||
|
||||
manifest.to_code = to_code_testing
|
||||
manifest.dependencies = manifest.dependencies + ["select"]
|
||||
Reference in New Issue
Block a user