mirror of
https://github.com/esphome/esphome.git
synced 2026-10-21 21:36:14 +00:00
[ld2420][ld2450] Use Apply numbers for hub forwarding numbers (#21146)
This commit is contained in:
@@ -917,6 +917,17 @@ void LD2420Component::init_gate_config_numbers() {
|
||||
}
|
||||
}
|
||||
|
||||
void LD2420Component::set_gate_threshold_value(number::Number *n, float value) {
|
||||
for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) {
|
||||
const bool move = this->gate_move_threshold_numbers_[gate] == n;
|
||||
if (!move && this->gate_still_threshold_numbers_[gate] != n)
|
||||
continue;
|
||||
const uint8_t target = this->is_gate_select() ? this->get_gate_select_value() : gate;
|
||||
(move ? this->new_config.move_thresh : this->new_config.still_thresh)[target] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void LD2420Component::refresh_gate_config_numbers() {
|
||||
this->gate_timeout_number_->publish_state(this->new_config.timeout);
|
||||
this->min_gate_distance_number_->publish_state(this->new_config.min_gate);
|
||||
|
||||
@@ -89,6 +89,8 @@ class LD2420Component final : public Component, public uart::UARTDevice {
|
||||
void publish_gate_still_threshold(uint8_t gate) {
|
||||
this->gate_still_threshold_numbers_[0]->publish_state(this->new_config.still_thresh[gate]);
|
||||
};
|
||||
// Stores a threshold number's value for its gate, or for the selected gate with gate_select
|
||||
void set_gate_threshold_value(number::Number *n, float value);
|
||||
void init_gate_config_numbers();
|
||||
void refresh_gate_config_numbers();
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from functools import partial
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import number
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_MOVE_THRESHOLD,
|
||||
CONF_STILL_THRESHOLD,
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
@@ -16,22 +17,9 @@ from esphome.types import ConfigType
|
||||
|
||||
from .. import CONF_LD2420_ID, LD2420Component, ld2420_ns
|
||||
|
||||
LD2420TimeoutNumber = ld2420_ns.class_("LD2420TimeoutNumber", number.Number)
|
||||
LD2420MoveSensFactorNumber = ld2420_ns.class_(
|
||||
"LD2420MoveSensFactorNumber", number.Number
|
||||
)
|
||||
LD2420StillSensFactorNumber = ld2420_ns.class_(
|
||||
"LD2420StillSensFactorNumber", number.Number
|
||||
)
|
||||
LD2420MinDistanceNumber = ld2420_ns.class_("LD2420MinDistanceNumber", number.Number)
|
||||
LD2420MaxDistanceNumber = ld2420_ns.class_("LD2420MaxDistanceNumber", number.Number)
|
||||
LD2420GateSelectNumber = ld2420_ns.class_("LD2420GateSelectNumber", number.Number)
|
||||
LD2420MoveThresholdNumbers = ld2420_ns.class_(
|
||||
"LD2420MoveThresholdNumbers", number.Number
|
||||
)
|
||||
LD2420StillThresholdNumbers = ld2420_ns.class_(
|
||||
"LD2420StillThresholdNumbers", number.Number
|
||||
)
|
||||
CONF_MIN_GATE_DISTANCE = "min_gate_distance"
|
||||
CONF_MAX_GATE_DISTANCE = "max_gate_distance"
|
||||
CONF_GATE_MOVE_SENSITIVITY = "gate_move_sensitivity"
|
||||
@@ -46,7 +34,7 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_LD2420_ID): cv.use_id(LD2420Component),
|
||||
cv.Inclusive(CONF_PRESENCE_TIMEOUT, TIMEOUT_GROUP): number.number_schema(
|
||||
LD2420TimeoutNumber,
|
||||
number.ApplyNumber,
|
||||
unit_of_measurement=UNIT_SECOND,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon=ICON_TIMELAPSE,
|
||||
@@ -70,23 +58,23 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
icon=ICON_MOTION_SENSOR,
|
||||
),
|
||||
cv.Inclusive(CONF_STILL_THRESHOLD, GATE_GROUP): number.number_schema(
|
||||
LD2420StillThresholdNumbers,
|
||||
number.ApplyNumber,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon=ICON_MOTION_SENSOR,
|
||||
),
|
||||
cv.Inclusive(CONF_MOVE_THRESHOLD, GATE_GROUP): number.number_schema(
|
||||
LD2420MoveThresholdNumbers,
|
||||
number.ApplyNumber,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon=ICON_MOTION_SENSOR,
|
||||
),
|
||||
cv.Optional(CONF_GATE_MOVE_SENSITIVITY): number.number_schema(
|
||||
LD2420MoveSensFactorNumber,
|
||||
number.ApplyNumber,
|
||||
device_class=DEVICE_CLASS_DISTANCE,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon=ICON_SCALE,
|
||||
),
|
||||
cv.Optional(CONF_GATE_STILL_SENSITIVITY): number.number_schema(
|
||||
LD2420StillSensFactorNumber,
|
||||
number.ApplyNumber,
|
||||
device_class=DEVICE_CLASS_DISTANCE,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon=ICON_SCALE,
|
||||
@@ -98,12 +86,12 @@ CONFIG_SCHEMA = CONFIG_SCHEMA.extend(
|
||||
cv.Optional(f"gate_{x}"): (
|
||||
{
|
||||
cv.Required(CONF_MOVE_THRESHOLD): number.number_schema(
|
||||
LD2420MoveThresholdNumbers,
|
||||
number.ApplyNumber,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon=ICON_MOTION_SENSOR,
|
||||
),
|
||||
cv.Required(CONF_STILL_THRESHOLD): number.number_schema(
|
||||
LD2420StillThresholdNumbers,
|
||||
number.ApplyNumber,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon=ICON_MOTION_SENSOR,
|
||||
),
|
||||
@@ -123,6 +111,8 @@ async def to_code(config: ConfigType) -> None:
|
||||
min_value=0,
|
||||
max_value=255,
|
||||
step=5,
|
||||
apply="new_config.timeout = value",
|
||||
publish="before",
|
||||
)
|
||||
await numbers(
|
||||
CONF_MIN_GATE_DISTANCE,
|
||||
@@ -144,6 +134,8 @@ async def to_code(config: ConfigType) -> None:
|
||||
min_value=0.05,
|
||||
max_value=1,
|
||||
step=0.025,
|
||||
apply="gate_move_sensitivity_factor = value",
|
||||
publish="before",
|
||||
)
|
||||
await numbers(
|
||||
CONF_GATE_STILL_SENSITIVITY,
|
||||
@@ -151,7 +143,16 @@ async def to_code(config: ConfigType) -> None:
|
||||
min_value=0.05,
|
||||
max_value=1,
|
||||
step=0.025,
|
||||
apply="gate_still_sensitivity_factor = value",
|
||||
publish="before",
|
||||
)
|
||||
threshold = {
|
||||
"min_value": 0,
|
||||
"max_value": 65535,
|
||||
"step": 25,
|
||||
"apply": "set_gate_threshold_value(entity, value)",
|
||||
"publish": "before",
|
||||
}
|
||||
if config.get(CONF_GATE_SELECT):
|
||||
await numbers(
|
||||
CONF_GATE_SELECT,
|
||||
@@ -160,35 +161,27 @@ async def to_code(config: ConfigType) -> None:
|
||||
max_value=15,
|
||||
step=1,
|
||||
)
|
||||
if gate_still_threshold := config.get(CONF_STILL_THRESHOLD):
|
||||
n = cg.new_Pvariable(gate_still_threshold[CONF_ID])
|
||||
await number.register_number(
|
||||
n, gate_still_threshold, min_value=0, max_value=65535, step=25
|
||||
)
|
||||
await cg.register_parented(n, hub)
|
||||
cg.add(hub.set_gate_still_threshold_numbers(0, n))
|
||||
if gate_move_threshold := config.get(CONF_MOVE_THRESHOLD):
|
||||
n = cg.new_Pvariable(gate_move_threshold[CONF_ID])
|
||||
await number.register_number(
|
||||
n, gate_move_threshold, min_value=0, max_value=65535, step=25
|
||||
)
|
||||
await cg.register_parented(n, hub)
|
||||
cg.add(hub.set_gate_move_threshold_numbers(0, n))
|
||||
# With gate_select one pair of numbers sits at index 0 and edits the selected gate
|
||||
await numbers(
|
||||
CONF_STILL_THRESHOLD,
|
||||
partial(hub.set_gate_still_threshold_numbers, 0),
|
||||
**threshold,
|
||||
)
|
||||
await numbers(
|
||||
CONF_MOVE_THRESHOLD,
|
||||
partial(hub.set_gate_move_threshold_numbers, 0),
|
||||
**threshold,
|
||||
)
|
||||
else:
|
||||
for x in range(16):
|
||||
if gate_conf := config.get(f"gate_{x}"):
|
||||
move_config = gate_conf[CONF_MOVE_THRESHOLD]
|
||||
n = cg.new_Pvariable(move_config[CONF_ID], x)
|
||||
await number.register_number(
|
||||
n, move_config, min_value=0, max_value=65535, step=25
|
||||
await numbers.create(
|
||||
gate_conf[CONF_MOVE_THRESHOLD],
|
||||
partial(hub.set_gate_move_threshold_numbers, x),
|
||||
**threshold,
|
||||
)
|
||||
await cg.register_parented(n, hub)
|
||||
cg.add(hub.set_gate_move_threshold_numbers(x, n))
|
||||
|
||||
still_config = gate_conf[CONF_STILL_THRESHOLD]
|
||||
n = cg.new_Pvariable(still_config[CONF_ID], x)
|
||||
await number.register_number(
|
||||
n, still_config, min_value=0, max_value=65535, step=25
|
||||
await numbers.create(
|
||||
gate_conf[CONF_STILL_THRESHOLD],
|
||||
partial(hub.set_gate_still_threshold_numbers, x),
|
||||
**threshold,
|
||||
)
|
||||
await cg.register_parented(n, hub)
|
||||
cg.add(hub.set_gate_still_threshold_numbers(x, n))
|
||||
|
||||
@@ -6,11 +6,6 @@ ESPHOME_LOG_TAG(TAG, "ld2420.number");
|
||||
|
||||
namespace esphome::ld2420 {
|
||||
|
||||
void LD2420TimeoutNumber::control(float timeout) {
|
||||
this->publish_state(timeout);
|
||||
this->parent_->new_config.timeout = timeout;
|
||||
}
|
||||
|
||||
void LD2420MinDistanceNumber::control(float min_gate) {
|
||||
if ((uint16_t) min_gate > this->parent_->new_config.max_gate) {
|
||||
min_gate = this->parent_->get_min_gate_distance_value();
|
||||
@@ -36,36 +31,4 @@ void LD2420GateSelectNumber::control(float gate_select) {
|
||||
this->parent_->publish_gate_still_threshold(gate);
|
||||
}
|
||||
|
||||
void LD2420MoveSensFactorNumber::control(float move_factor) {
|
||||
this->publish_state(move_factor);
|
||||
this->parent_->gate_move_sensitivity_factor = move_factor;
|
||||
}
|
||||
|
||||
void LD2420StillSensFactorNumber::control(float still_factor) {
|
||||
this->publish_state(still_factor);
|
||||
this->parent_->gate_still_sensitivity_factor = still_factor;
|
||||
}
|
||||
|
||||
LD2420MoveThresholdNumbers::LD2420MoveThresholdNumbers(uint8_t gate) : gate_(gate) {}
|
||||
|
||||
void LD2420MoveThresholdNumbers::control(float move_threshold) {
|
||||
this->publish_state(move_threshold);
|
||||
if (!this->parent_->is_gate_select()) {
|
||||
this->parent_->new_config.move_thresh[this->gate_] = move_threshold;
|
||||
} else {
|
||||
this->parent_->new_config.move_thresh[this->parent_->get_gate_select_value()] = move_threshold;
|
||||
}
|
||||
}
|
||||
|
||||
LD2420StillThresholdNumbers::LD2420StillThresholdNumbers(uint8_t gate) : gate_(gate) {}
|
||||
|
||||
void LD2420StillThresholdNumbers::control(float still_threshold) {
|
||||
this->publish_state(still_threshold);
|
||||
if (!this->parent_->is_gate_select()) {
|
||||
this->parent_->new_config.still_thresh[this->gate_] = still_threshold;
|
||||
} else {
|
||||
this->parent_->new_config.still_thresh[this->parent_->get_gate_select_value()] = still_threshold;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::ld2420
|
||||
|
||||
@@ -5,14 +5,6 @@
|
||||
|
||||
namespace esphome::ld2420 {
|
||||
|
||||
class LD2420TimeoutNumber final : public number::Number, public Parented<LD2420Component> {
|
||||
public:
|
||||
LD2420TimeoutNumber() = default;
|
||||
|
||||
protected:
|
||||
void control(float timeout) override;
|
||||
};
|
||||
|
||||
class LD2420MinDistanceNumber final : public number::Number, public Parented<LD2420Component> {
|
||||
public:
|
||||
LD2420MinDistanceNumber() = default;
|
||||
@@ -37,40 +29,4 @@ class LD2420GateSelectNumber final : public number::Number, public Parented<LD24
|
||||
void control(float gate_select) override;
|
||||
};
|
||||
|
||||
class LD2420MoveSensFactorNumber final : public number::Number, public Parented<LD2420Component> {
|
||||
public:
|
||||
LD2420MoveSensFactorNumber() = default;
|
||||
|
||||
protected:
|
||||
void control(float move_factor) override;
|
||||
};
|
||||
|
||||
class LD2420StillSensFactorNumber final : public number::Number, public Parented<LD2420Component> {
|
||||
public:
|
||||
LD2420StillSensFactorNumber() = default;
|
||||
|
||||
protected:
|
||||
void control(float still_factor) override;
|
||||
};
|
||||
|
||||
class LD2420StillThresholdNumbers final : public number::Number, public Parented<LD2420Component> {
|
||||
public:
|
||||
LD2420StillThresholdNumbers() = default;
|
||||
LD2420StillThresholdNumbers(uint8_t gate);
|
||||
|
||||
protected:
|
||||
uint8_t gate_;
|
||||
void control(float still_threshold) override;
|
||||
};
|
||||
|
||||
class LD2420MoveThresholdNumbers final : public number::Number, public Parented<LD2420Component> {
|
||||
public:
|
||||
LD2420MoveThresholdNumbers() = default;
|
||||
LD2420MoveThresholdNumbers(uint8_t gate);
|
||||
|
||||
protected:
|
||||
uint8_t gate_;
|
||||
void control(float move_threshold) override;
|
||||
};
|
||||
|
||||
} // namespace esphome::ld2420
|
||||
|
||||
@@ -957,7 +957,13 @@ void LD2450Component::set_direction_text_sensor(uint8_t target, text_sensor::Tex
|
||||
|
||||
// Send Zone coordinates data to LD2450
|
||||
#ifdef USE_NUMBER
|
||||
void LD2450Component::set_zone_coordinate(uint8_t zone) {
|
||||
void LD2450Component::set_zone_coordinate(number::Number *n) {
|
||||
uint8_t zone = 0;
|
||||
while (zone < MAX_ZONES && this->zone_numbers_[zone].x1 != n && this->zone_numbers_[zone].y1 != n &&
|
||||
this->zone_numbers_[zone].x2 != n && this->zone_numbers_[zone].y2 != n)
|
||||
zone++;
|
||||
if (zone == MAX_ZONES)
|
||||
return;
|
||||
number::Number *x1sens = this->zone_numbers_[zone].x1;
|
||||
number::Number *y1sens = this->zone_numbers_[zone].y1;
|
||||
number::Number *x2sens = this->zone_numbers_[zone].x2;
|
||||
|
||||
@@ -128,7 +128,7 @@ class LD2450Component : public Component, public uart::UARTDevice {
|
||||
void set_direction_text_sensor(uint8_t target, text_sensor::TextSensor *s);
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
void set_zone_coordinate(uint8_t zone);
|
||||
void set_zone_coordinate(number::Number *n);
|
||||
void set_zone_numbers(uint8_t zone, number::Number *x1, number::Number *y1, number::Number *x2, number::Number *y2);
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
|
||||
@@ -25,7 +25,6 @@ ICON_ARROW_TOP_LEFT_BOLD_BOX_OUTLINE = "mdi:arrow-top-left-bold-box-outline"
|
||||
MAX_ZONES = 3
|
||||
|
||||
PresenceTimeoutNumber = ld2450_ns.class_("PresenceTimeoutNumber", number.Number)
|
||||
ZoneCoordinateNumber = ld2450_ns.class_("ZoneCoordinateNumber", number.Number)
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
@@ -45,28 +44,28 @@ CONFIG_SCHEMA = CONFIG_SCHEMA.extend(
|
||||
cv.Optional(f"zone_{n + 1}"): cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_X1): number.number_schema(
|
||||
ZoneCoordinateNumber,
|
||||
number.ApplyNumber,
|
||||
device_class=DEVICE_CLASS_DISTANCE,
|
||||
unit_of_measurement=UNIT_MILLIMETER,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon=ICON_ARROW_TOP_LEFT_BOLD_BOX_OUTLINE,
|
||||
),
|
||||
cv.Required(CONF_Y1): number.number_schema(
|
||||
ZoneCoordinateNumber,
|
||||
number.ApplyNumber,
|
||||
device_class=DEVICE_CLASS_DISTANCE,
|
||||
unit_of_measurement=UNIT_MILLIMETER,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon=ICON_ARROW_TOP_LEFT,
|
||||
),
|
||||
cv.Required(CONF_X2): number.number_schema(
|
||||
ZoneCoordinateNumber,
|
||||
number.ApplyNumber,
|
||||
device_class=DEVICE_CLASS_DISTANCE,
|
||||
unit_of_measurement=UNIT_MILLIMETER,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon=ICON_ARROW_BOTTOM_RIGHT_BOLD_BOX_OUTLINE,
|
||||
),
|
||||
cv.Required(CONF_Y2): number.number_schema(
|
||||
ZoneCoordinateNumber,
|
||||
number.ApplyNumber,
|
||||
device_class=DEVICE_CLASS_DISTANCE,
|
||||
unit_of_measurement=UNIT_MILLIMETER,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
@@ -91,32 +90,21 @@ async def to_code(config: ConfigType) -> None:
|
||||
)
|
||||
for zone_num in range(MAX_ZONES):
|
||||
if zone_conf := config.get(f"zone_{zone_num + 1}"):
|
||||
zone_x1_config = zone_conf.get(CONF_X1)
|
||||
x1 = cg.new_Pvariable(zone_x1_config[CONF_ID], zone_num)
|
||||
await number.register_number(
|
||||
x1, zone_x1_config, min_value=-4860, max_value=4860, step=1
|
||||
)
|
||||
await cg.register_parented(x1, hub)
|
||||
|
||||
zone_y1_config = zone_conf.get(CONF_Y1)
|
||||
y1 = cg.new_Pvariable(zone_y1_config[CONF_ID], zone_num)
|
||||
await number.register_number(
|
||||
y1, zone_y1_config, min_value=0, max_value=7560, step=1
|
||||
)
|
||||
await cg.register_parented(y1, hub)
|
||||
|
||||
zone_x2_config = zone_conf.get(CONF_X2)
|
||||
x2 = cg.new_Pvariable(zone_x2_config[CONF_ID], zone_num)
|
||||
await number.register_number(
|
||||
x2, zone_x2_config, min_value=-4860, max_value=4860, step=1
|
||||
)
|
||||
await cg.register_parented(x2, hub)
|
||||
|
||||
zone_y2_config = zone_conf.get(CONF_Y2)
|
||||
y2 = cg.new_Pvariable(zone_y2_config[CONF_ID], zone_num)
|
||||
await number.register_number(
|
||||
y2, zone_y2_config, min_value=0, max_value=7560, step=1
|
||||
)
|
||||
await cg.register_parented(y2, hub)
|
||||
|
||||
x1, y1, x2, y2 = [
|
||||
await numbers.create(
|
||||
zone_conf[key],
|
||||
None,
|
||||
min_value=lo,
|
||||
max_value=hi,
|
||||
step=1,
|
||||
apply="set_zone_coordinate(entity)",
|
||||
publish="before",
|
||||
)
|
||||
for key, lo, hi in (
|
||||
(CONF_X1, -4860, 4860),
|
||||
(CONF_Y1, 0, 7560),
|
||||
(CONF_X2, -4860, 4860),
|
||||
(CONF_Y2, 0, 7560),
|
||||
)
|
||||
]
|
||||
cg.add(hub.set_zone_numbers(zone_num, x1, y1, x2, y2))
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#include "zone_coordinate_number.h"
|
||||
|
||||
namespace esphome::ld2450 {
|
||||
|
||||
ZoneCoordinateNumber::ZoneCoordinateNumber(uint8_t zone) : zone_(zone) {}
|
||||
|
||||
void ZoneCoordinateNumber::control(float value) {
|
||||
this->publish_state(value);
|
||||
this->parent_->set_zone_coordinate(this->zone_);
|
||||
}
|
||||
|
||||
} // namespace esphome::ld2450
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/number/number.h"
|
||||
#include "../ld2450.h"
|
||||
|
||||
namespace esphome::ld2450 {
|
||||
|
||||
class ZoneCoordinateNumber : public number::Number, public Parented<LD2450Component> {
|
||||
public:
|
||||
ZoneCoordinateNumber(uint8_t zone);
|
||||
|
||||
protected:
|
||||
uint8_t zone_;
|
||||
void control(float value) override;
|
||||
};
|
||||
|
||||
} // namespace esphome::ld2450
|
||||
@@ -0,0 +1,71 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "esphome/components/ld2420/ld2420.h"
|
||||
|
||||
namespace esphome::ld2420::testing {
|
||||
|
||||
class TestNumber : public number::Number {
|
||||
protected:
|
||||
void control(float value) override {}
|
||||
};
|
||||
|
||||
class LD2420GateThresholdTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) {
|
||||
this->ld2420_.new_config.move_thresh[gate] = 1000 + gate;
|
||||
this->ld2420_.new_config.still_thresh[gate] = 2000 + gate;
|
||||
}
|
||||
}
|
||||
void expect_untouched_except_(const uint32_t *thresh, uint32_t base, int skip) {
|
||||
for (int gate = 0; gate < TOTAL_GATES; gate++) {
|
||||
if (gate != skip)
|
||||
EXPECT_EQ(thresh[gate], base + gate) << "gate " << gate;
|
||||
}
|
||||
}
|
||||
|
||||
LD2420Component ld2420_;
|
||||
TestNumber move_;
|
||||
TestNumber still_;
|
||||
};
|
||||
|
||||
TEST_F(LD2420GateThresholdTest, PerGateNumbersWriteTheirOwnGate) {
|
||||
this->ld2420_.set_gate_move_threshold_numbers(3, &this->move_);
|
||||
this->ld2420_.set_gate_still_threshold_numbers(3, &this->still_);
|
||||
|
||||
this->ld2420_.set_gate_threshold_value(&this->move_, 500);
|
||||
EXPECT_EQ(this->ld2420_.new_config.move_thresh[3], 500u);
|
||||
this->expect_untouched_except_(this->ld2420_.new_config.move_thresh, 1000, 3);
|
||||
this->expect_untouched_except_(this->ld2420_.new_config.still_thresh, 2000, -1);
|
||||
|
||||
this->ld2420_.set_gate_threshold_value(&this->still_, 750);
|
||||
EXPECT_EQ(this->ld2420_.new_config.still_thresh[3], 750u);
|
||||
EXPECT_EQ(this->ld2420_.new_config.move_thresh[3], 500u);
|
||||
this->expect_untouched_except_(this->ld2420_.new_config.still_thresh, 2000, 3);
|
||||
}
|
||||
|
||||
TEST_F(LD2420GateThresholdTest, GateSelectWritesTheSelectedGate) {
|
||||
TestNumber select;
|
||||
this->ld2420_.set_gate_select_number(&select);
|
||||
this->ld2420_.set_gate_move_threshold_numbers(0, &this->move_);
|
||||
this->ld2420_.set_gate_still_threshold_numbers(0, &this->still_);
|
||||
select.publish_state(5);
|
||||
|
||||
this->ld2420_.set_gate_threshold_value(&this->move_, 300);
|
||||
this->ld2420_.set_gate_threshold_value(&this->still_, 400);
|
||||
EXPECT_EQ(this->ld2420_.new_config.move_thresh[5], 300u);
|
||||
EXPECT_EQ(this->ld2420_.new_config.still_thresh[5], 400u);
|
||||
this->expect_untouched_except_(this->ld2420_.new_config.move_thresh, 1000, 5);
|
||||
this->expect_untouched_except_(this->ld2420_.new_config.still_thresh, 2000, 5);
|
||||
}
|
||||
|
||||
TEST_F(LD2420GateThresholdTest, UnregisteredNumberChangesNothing) {
|
||||
this->ld2420_.set_gate_move_threshold_numbers(3, &this->move_);
|
||||
this->ld2420_.set_gate_still_threshold_numbers(3, &this->still_);
|
||||
TestNumber other;
|
||||
|
||||
this->ld2420_.set_gate_threshold_value(&other, 123);
|
||||
this->expect_untouched_except_(this->ld2420_.new_config.move_thresh, 1000, -1);
|
||||
this->expect_untouched_except_(this->ld2420_.new_config.still_thresh, 2000, -1);
|
||||
}
|
||||
|
||||
} // 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_NUMBER so the hub's number forwarding code is in the host test build
|
||||
async def to_code_testing(config: ConfigType) -> None:
|
||||
CORE.testing_ensure_platform_registered("number")
|
||||
|
||||
manifest.to_code = to_code_testing
|
||||
manifest.dependencies = manifest.dependencies + ["number"]
|
||||
@@ -0,0 +1,83 @@
|
||||
#include <algorithm>
|
||||
#include "common.h"
|
||||
|
||||
namespace esphome::ld2450::testing {
|
||||
|
||||
namespace {
|
||||
class CapturingUARTComponent : public MockUARTComponent {
|
||||
public:
|
||||
void write_array(const uint8_t *data, size_t len) override {
|
||||
this->written.insert(this->written.end(), data, data + len);
|
||||
}
|
||||
std::vector<uint8_t> written;
|
||||
};
|
||||
|
||||
class TestNumber : public number::Number {
|
||||
protected:
|
||||
void control(float value) override {}
|
||||
};
|
||||
|
||||
// Header, length 28, command 0xC2 (set zone): the coordinate payload follows two zone type bytes.
|
||||
constexpr uint8_t SET_ZONE_PREFIX[] = {0xFD, 0xFC, 0xFB, 0xFA, 0x1C, 0x00, 0xC2, 0x00};
|
||||
} // namespace
|
||||
|
||||
class LD2450ZoneNumberTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
this->ld2450_.set_uart_parent(&this->uart_);
|
||||
for (auto &zone : this->ld2450_.zone_config_) {
|
||||
zone = {1, 2, 3, 4};
|
||||
}
|
||||
// Only the third zone has numbers, so the lookup must walk past the empty slots.
|
||||
this->ld2450_.set_zone_numbers(2, &this->x1_, &this->y1_, &this->x2_, &this->y2_);
|
||||
this->x1_.publish_state(-100);
|
||||
this->y1_.publish_state(200);
|
||||
this->x2_.publish_state(1500);
|
||||
this->y2_.publish_state(3000);
|
||||
}
|
||||
|
||||
CapturingUARTComponent uart_;
|
||||
TestableLD2450 ld2450_;
|
||||
TestNumber x1_, y1_, x2_, y2_;
|
||||
};
|
||||
|
||||
TEST_F(LD2450ZoneNumberTest, EachCoordinateNumberUpdatesItsZoneAndSendsCommand) {
|
||||
for (TestNumber *n : {&this->x1_, &this->y1_, &this->x2_, &this->y2_}) {
|
||||
this->uart_.written.clear();
|
||||
this->ld2450_.zone_config_[2] = {0, 0, 0, 0};
|
||||
this->ld2450_.set_zone_coordinate(n);
|
||||
|
||||
EXPECT_EQ(this->ld2450_.zone_config_[2].x1, -100);
|
||||
EXPECT_EQ(this->ld2450_.zone_config_[2].y1, 200);
|
||||
EXPECT_EQ(this->ld2450_.zone_config_[2].x2, 1500);
|
||||
EXPECT_EQ(this->ld2450_.zone_config_[2].y2, 3000);
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
EXPECT_EQ(this->ld2450_.zone_config_[i].x1, 1) << "zone " << i;
|
||||
EXPECT_EQ(this->ld2450_.zone_config_[i].y2, 4) << "zone " << i;
|
||||
}
|
||||
|
||||
const auto &w = this->uart_.written;
|
||||
auto it = std::search(w.begin(), w.end(), std::begin(SET_ZONE_PREFIX), std::end(SET_ZONE_PREFIX));
|
||||
ASSERT_NE(it, w.end());
|
||||
ASSERT_GE(static_cast<size_t>(w.end() - it), sizeof(SET_ZONE_PREFIX) + 26 + 4);
|
||||
const uint8_t *zone2 = &*it + sizeof(SET_ZONE_PREFIX) + 2 + 2 * 8;
|
||||
const std::vector<uint8_t> expected = {0x9C, 0xFF, 0xC8, 0x00, 0xDC, 0x05, 0xB8, 0x0B};
|
||||
EXPECT_EQ(std::vector<uint8_t>(zone2, zone2 + 8), expected);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(LD2450ZoneNumberTest, UnregisteredNumberChangesNothing) {
|
||||
TestNumber other;
|
||||
other.publish_state(42);
|
||||
this->ld2450_.set_zone_coordinate(&other);
|
||||
|
||||
for (size_t i = 0; i < MAX_ZONES; i++) {
|
||||
EXPECT_EQ(this->ld2450_.zone_config_[i].x1, 1) << "zone " << i;
|
||||
EXPECT_EQ(this->ld2450_.zone_config_[i].y1, 2) << "zone " << i;
|
||||
EXPECT_EQ(this->ld2450_.zone_config_[i].x2, 3) << "zone " << i;
|
||||
EXPECT_EQ(this->ld2450_.zone_config_[i].y2, 4) << "zone " << i;
|
||||
}
|
||||
EXPECT_TRUE(this->uart_.written.empty());
|
||||
}
|
||||
|
||||
} // namespace esphome::ld2450::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_NUMBER so the hub's number forwarding code is in the host test build
|
||||
async def to_code_testing(config: ConfigType) -> None:
|
||||
CORE.testing_ensure_platform_registered("number")
|
||||
|
||||
manifest.to_code = to_code_testing
|
||||
manifest.dependencies = manifest.dependencies + ["number"]
|
||||
Reference in New Issue
Block a user