mirror of
https://github.com/esphome/esphome.git
synced 2026-08-30 01:26:43 +00:00
[ld6002b] Add select and button platforms (4/5) (#17822)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
co-authored by
Jonathan Swoboda
parent
715b14aeba
commit
950cfc4da3
@@ -0,0 +1,101 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import button
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_WAKEUP_PIN,
|
||||
ENTITY_CATEGORY_CONFIG,
|
||||
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
)
|
||||
import esphome.final_validate as fv
|
||||
|
||||
from .. import LD6002BComponent, ld6002b_ns
|
||||
from ..const import (
|
||||
CONF_GET_DELAY,
|
||||
CONF_GET_INSTALLATION,
|
||||
CONF_GET_LOW_POWER_MODE,
|
||||
CONF_GET_LOW_POWER_SLEEP_TIME,
|
||||
CONF_GET_SENSITIVITY,
|
||||
CONF_GET_TRIGGER_SPEED,
|
||||
CONF_GET_Z_RANGE,
|
||||
CONF_LD6002B_ID,
|
||||
CONF_RESET_UNATTENDED,
|
||||
CONF_WAKE,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["ld6002b"]
|
||||
|
||||
LD6002BButton = ld6002b_ns.class_("LD6002BButton", button.Button)
|
||||
ButtonType = ld6002b_ns.enum("ButtonType", is_class=True)
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_LD6002B_ID): cv.use_id(LD6002BComponent),
|
||||
cv.Optional(CONF_GET_DELAY): button.button_schema(
|
||||
LD6002BButton, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||
),
|
||||
cv.Optional(CONF_GET_SENSITIVITY): button.button_schema(
|
||||
LD6002BButton, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||
),
|
||||
cv.Optional(CONF_GET_TRIGGER_SPEED): button.button_schema(
|
||||
LD6002BButton, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||
),
|
||||
cv.Optional(CONF_GET_Z_RANGE): button.button_schema(
|
||||
LD6002BButton, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||
),
|
||||
cv.Optional(CONF_GET_INSTALLATION): button.button_schema(
|
||||
LD6002BButton, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||
),
|
||||
cv.Optional(CONF_GET_LOW_POWER_MODE): button.button_schema(
|
||||
LD6002BButton, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||
),
|
||||
cv.Optional(CONF_GET_LOW_POWER_SLEEP_TIME): button.button_schema(
|
||||
LD6002BButton, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||
),
|
||||
cv.Optional(CONF_RESET_UNATTENDED): button.button_schema(
|
||||
LD6002BButton, entity_category=ENTITY_CATEGORY_CONFIG
|
||||
),
|
||||
cv.Optional(CONF_WAKE): button.button_schema(
|
||||
LD6002BButton, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def final_validate(config):
|
||||
full_config = fv.full_config.get()
|
||||
hub_id = config[CONF_LD6002B_ID]
|
||||
|
||||
if config.get(CONF_WAKE):
|
||||
hub_path = full_config.get_path_for_id(hub_id)
|
||||
hub_config = full_config.get_config_for_path(hub_path[:-1])
|
||||
if hub_config.get(CONF_WAKEUP_PIN) is None:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_WAKE} requires {CONF_WAKEUP_PIN} on the parent ld6002b component",
|
||||
path=[CONF_WAKE],
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = final_validate
|
||||
|
||||
BUTTON_MAP = {
|
||||
CONF_GET_DELAY: ButtonType.GET_DELAY,
|
||||
CONF_GET_SENSITIVITY: ButtonType.GET_SENSITIVITY,
|
||||
CONF_GET_TRIGGER_SPEED: ButtonType.GET_TRIGGER_SPEED,
|
||||
CONF_GET_Z_RANGE: ButtonType.GET_Z_RANGE,
|
||||
CONF_GET_INSTALLATION: ButtonType.GET_INSTALLATION,
|
||||
CONF_GET_LOW_POWER_MODE: ButtonType.GET_LOW_POWER_MODE,
|
||||
CONF_GET_LOW_POWER_SLEEP_TIME: ButtonType.GET_LOW_POWER_SLEEP_TIME,
|
||||
CONF_RESET_UNATTENDED: ButtonType.RESET_UNATTENDED,
|
||||
CONF_WAKE: ButtonType.WAKE,
|
||||
}
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
for key, button_type in BUTTON_MAP.items():
|
||||
if button_config := config.get(key):
|
||||
b = cg.new_Pvariable(button_config[CONF_ID], button_type)
|
||||
await button.register_button(b, button_config)
|
||||
await cg.register_parented(b, config[CONF_LD6002B_ID])
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "ld6002b_button.h"
|
||||
|
||||
namespace esphome::ld6002b {
|
||||
|
||||
void LD6002BButton::press_action() { this->parent_->press_button(this->type_); }
|
||||
|
||||
} // namespace esphome::ld6002b
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/button/button.h"
|
||||
#include "../ld6002b.h"
|
||||
|
||||
namespace esphome::ld6002b {
|
||||
|
||||
class LD6002BButton : public button::Button, public Parented<LD6002BComponent> {
|
||||
public:
|
||||
explicit LD6002BButton(ButtonType type) : type_(type) {}
|
||||
|
||||
protected:
|
||||
void press_action() override;
|
||||
|
||||
ButtonType type_;
|
||||
};
|
||||
|
||||
} // namespace esphome::ld6002b
|
||||
@@ -1,14 +1,25 @@
|
||||
CONF_AUTO_WAKE = "auto_wake"
|
||||
CONF_CLUSTER_ID = "cluster_id"
|
||||
CONF_DOPPLER_INDEX = "doppler_index"
|
||||
CONF_GET_DELAY = "get_delay"
|
||||
CONF_GET_INSTALLATION = "get_installation"
|
||||
CONF_GET_LOW_POWER_MODE = "get_low_power_mode"
|
||||
CONF_GET_LOW_POWER_SLEEP_TIME = "get_low_power_sleep_time"
|
||||
CONF_GET_SENSITIVITY = "get_sensitivity"
|
||||
CONF_GET_TRIGGER_SPEED = "get_trigger_speed"
|
||||
CONF_GET_Z_RANGE = "get_z_range"
|
||||
CONF_HOLD_DELAY = "hold_delay"
|
||||
CONF_INSTALLATION_MODE = "installation_mode"
|
||||
CONF_LD6002B_ID = "ld6002b_id"
|
||||
CONF_LOW_POWER = "low_power"
|
||||
CONF_LOW_POWER_SLEEP_TIME = "low_power_sleep_time"
|
||||
CONF_OTA_VERSION = "ota_version"
|
||||
CONF_POINT_CLOUD = "point_cloud"
|
||||
CONF_POINT_COUNT = "point_count"
|
||||
CONF_RESET_UNATTENDED = "reset_unattended"
|
||||
CONF_TARGET_DISPLAY = "target_display"
|
||||
CONF_TRIGGER_SPEED = "trigger_speed"
|
||||
CONF_WAKE = "wake"
|
||||
CONF_WAKEUP_PULSE = "wakeup_pulse"
|
||||
CONF_WORK_MODE = "work_mode"
|
||||
CONF_Z = "z"
|
||||
|
||||
@@ -22,7 +22,10 @@ static constexpr uint16_t TYPE_SET_LOW_POWER_SLEEP = 0x0205;
|
||||
static constexpr uint16_t TYPE_REPORT_TARGET = 0x0A04;
|
||||
static constexpr uint16_t TYPE_REPORT_POINT_CLOUD = 0x0A08;
|
||||
static constexpr uint16_t TYPE_REPORT_DELAY = 0x0A0D;
|
||||
static constexpr uint16_t TYPE_REPORT_SENSITIVITY = 0x0A0E;
|
||||
static constexpr uint16_t TYPE_REPORT_TRIGGER = 0x0A0F;
|
||||
static constexpr uint16_t TYPE_REPORT_Z_RANGE = 0x0A10;
|
||||
static constexpr uint16_t TYPE_REPORT_INSTALLATION = 0x0A11;
|
||||
static constexpr uint16_t TYPE_REPORT_LOW_POWER = 0x0A12;
|
||||
static constexpr uint16_t TYPE_REPORT_LOW_POWER_SLEEP = 0x0A13;
|
||||
static constexpr uint16_t TYPE_REPORT_WORK_MODE = 0x0A14;
|
||||
@@ -34,11 +37,23 @@ static constexpr uint32_t CMD_POINT_CLOUD_ON = 0x06;
|
||||
static constexpr uint32_t CMD_POINT_CLOUD_OFF = 0x07;
|
||||
static constexpr uint32_t CMD_TARGET_DISPLAY_ON = 0x08;
|
||||
static constexpr uint32_t CMD_TARGET_DISPLAY_OFF = 0x09;
|
||||
static constexpr uint32_t CMD_SENSITIVITY_LOW = 0x0A;
|
||||
static constexpr uint32_t CMD_SENSITIVITY_MEDIUM = 0x0B;
|
||||
static constexpr uint32_t CMD_SENSITIVITY_HIGH = 0x0C;
|
||||
static constexpr uint32_t CMD_GET_SENSITIVITY = 0x0D;
|
||||
static constexpr uint32_t CMD_TRIGGER_SLOW = 0x0E;
|
||||
static constexpr uint32_t CMD_TRIGGER_MEDIUM = 0x0F;
|
||||
static constexpr uint32_t CMD_TRIGGER_FAST = 0x10;
|
||||
static constexpr uint32_t CMD_GET_TRIGGER = 0x11;
|
||||
static constexpr uint32_t CMD_GET_Z_RANGE = 0x12;
|
||||
static constexpr uint32_t CMD_INSTALL_TOP = 0x13;
|
||||
static constexpr uint32_t CMD_INSTALL_SIDE = 0x14;
|
||||
static constexpr uint32_t CMD_GET_INSTALLATION = 0x15;
|
||||
static constexpr uint32_t CMD_LOW_POWER_ON = 0x16;
|
||||
static constexpr uint32_t CMD_LOW_POWER_OFF = 0x17;
|
||||
static constexpr uint32_t CMD_GET_LOW_POWER = 0x18;
|
||||
static constexpr uint32_t CMD_GET_LOW_POWER_SLEEP = 0x19;
|
||||
static constexpr uint32_t CMD_RESET_UNATTENDED = 0x1A;
|
||||
|
||||
static constexpr uint16_t TARGET_DATA_LEN = 20; // x,y,z,dop_idx,cluster_id
|
||||
|
||||
@@ -57,8 +72,30 @@ static const char *control_command_name(uint32_t command) {
|
||||
return "target_display_on";
|
||||
case CMD_TARGET_DISPLAY_OFF:
|
||||
return "target_display_off";
|
||||
case CMD_SENSITIVITY_LOW:
|
||||
return "sensitivity_low";
|
||||
case CMD_SENSITIVITY_MEDIUM:
|
||||
return "sensitivity_medium";
|
||||
case CMD_SENSITIVITY_HIGH:
|
||||
return "sensitivity_high";
|
||||
case CMD_GET_SENSITIVITY:
|
||||
return "get_sensitivity";
|
||||
case CMD_TRIGGER_SLOW:
|
||||
return "trigger_slow";
|
||||
case CMD_TRIGGER_MEDIUM:
|
||||
return "trigger_medium";
|
||||
case CMD_TRIGGER_FAST:
|
||||
return "trigger_fast";
|
||||
case CMD_GET_TRIGGER:
|
||||
return "get_trigger";
|
||||
case CMD_GET_Z_RANGE:
|
||||
return "get_z_range";
|
||||
case CMD_INSTALL_TOP:
|
||||
return "install_top";
|
||||
case CMD_INSTALL_SIDE:
|
||||
return "install_side";
|
||||
case CMD_GET_INSTALLATION:
|
||||
return "get_installation";
|
||||
case CMD_LOW_POWER_ON:
|
||||
return "low_power_on";
|
||||
case CMD_LOW_POWER_OFF:
|
||||
@@ -67,6 +104,8 @@ static const char *control_command_name(uint32_t command) {
|
||||
return "get_low_power";
|
||||
case CMD_GET_LOW_POWER_SLEEP:
|
||||
return "get_low_power_sleep";
|
||||
case CMD_RESET_UNATTENDED:
|
||||
return "reset_unattended";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
@@ -88,8 +127,14 @@ static const char *frame_type_name(uint16_t type) {
|
||||
return "report_point_cloud";
|
||||
case TYPE_REPORT_DELAY:
|
||||
return "report_delay";
|
||||
case TYPE_REPORT_SENSITIVITY:
|
||||
return "report_sensitivity";
|
||||
case TYPE_REPORT_TRIGGER:
|
||||
return "report_trigger";
|
||||
case TYPE_REPORT_Z_RANGE:
|
||||
return "report_z_range";
|
||||
case TYPE_REPORT_INSTALLATION:
|
||||
return "report_installation";
|
||||
case TYPE_REPORT_LOW_POWER:
|
||||
return "report_low_power";
|
||||
case TYPE_REPORT_LOW_POWER_SLEEP:
|
||||
@@ -107,8 +152,14 @@ static bool is_expected_control_report(uint32_t command, uint16_t type) {
|
||||
switch (command) {
|
||||
case CMD_GET_DELAY:
|
||||
return type == TYPE_REPORT_DELAY;
|
||||
case CMD_GET_SENSITIVITY:
|
||||
return type == TYPE_REPORT_SENSITIVITY;
|
||||
case CMD_GET_TRIGGER:
|
||||
return type == TYPE_REPORT_TRIGGER;
|
||||
case CMD_GET_Z_RANGE:
|
||||
return type == TYPE_REPORT_Z_RANGE;
|
||||
case CMD_GET_INSTALLATION:
|
||||
return type == TYPE_REPORT_INSTALLATION;
|
||||
case CMD_GET_LOW_POWER:
|
||||
case CMD_LOW_POWER_ON:
|
||||
case CMD_LOW_POWER_OFF:
|
||||
@@ -259,6 +310,18 @@ void LD6002BComponent::setup() {
|
||||
this->send_control_command_(want_point_cloud ? CMD_POINT_CLOUD_ON : CMD_POINT_CLOUD_OFF);
|
||||
this->point_cloud_enabled_ = want_point_cloud;
|
||||
}
|
||||
|
||||
#ifdef USE_SELECT
|
||||
if (this->sensitivity_select_ != nullptr) {
|
||||
this->send_control_command_(CMD_GET_SENSITIVITY);
|
||||
}
|
||||
if (this->trigger_speed_select_ != nullptr) {
|
||||
this->send_control_command_(CMD_GET_TRIGGER);
|
||||
}
|
||||
if (this->installation_select_ != nullptr) {
|
||||
this->send_control_command_(CMD_GET_INSTALLATION);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
if (this->z_min_number_ != nullptr || this->z_max_number_ != nullptr) {
|
||||
this->send_control_command_(CMD_GET_Z_RANGE);
|
||||
@@ -345,6 +408,11 @@ void LD6002BComponent::dump_config() {
|
||||
LOG_SWITCH(" ", "Point Cloud", this->point_cloud_switch_);
|
||||
LOG_SWITCH(" ", "Target Display", this->target_display_switch_);
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
LOG_SELECT(" ", "Sensitivity", this->sensitivity_select_);
|
||||
LOG_SELECT(" ", "Trigger Speed", this->trigger_speed_select_);
|
||||
LOG_SELECT(" ", "Installation Mode", this->installation_select_);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LD6002BComponent::loop() {
|
||||
@@ -492,9 +560,18 @@ void LD6002BComponent::handle_frame_(uint16_t type, const uint8_t *data, uint16_
|
||||
case TYPE_REPORT_DELAY:
|
||||
this->handle_delay_report_(data, len);
|
||||
break;
|
||||
case TYPE_REPORT_SENSITIVITY:
|
||||
this->handle_sensitivity_report_(data, len);
|
||||
break;
|
||||
case TYPE_REPORT_TRIGGER:
|
||||
this->handle_trigger_speed_report_(data, len);
|
||||
break;
|
||||
case TYPE_REPORT_Z_RANGE:
|
||||
this->handle_z_range_report_(data, len);
|
||||
break;
|
||||
case TYPE_REPORT_INSTALLATION:
|
||||
this->handle_installation_report_(data, len);
|
||||
break;
|
||||
case TYPE_REPORT_LOW_POWER:
|
||||
this->handle_low_power_report_(data, len);
|
||||
break;
|
||||
@@ -660,6 +737,32 @@ void LD6002BComponent::handle_delay_report_(const uint8_t *data, uint16_t len) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void LD6002BComponent::handle_sensitivity_report_(const uint8_t *data, uint16_t len) {
|
||||
if (len < 1)
|
||||
return;
|
||||
#ifdef USE_SELECT
|
||||
if (this->sensitivity_select_ == nullptr)
|
||||
return;
|
||||
uint8_t value = data[0];
|
||||
if (value <= 2) {
|
||||
this->sensitivity_select_->publish_state(value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LD6002BComponent::handle_trigger_speed_report_(const uint8_t *data, uint16_t len) {
|
||||
if (len < 1)
|
||||
return;
|
||||
#ifdef USE_SELECT
|
||||
if (this->trigger_speed_select_ == nullptr)
|
||||
return;
|
||||
uint8_t value = data[0];
|
||||
if (value <= 2) {
|
||||
this->trigger_speed_select_->publish_state(value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LD6002BComponent::handle_z_range_report_(const uint8_t *data, uint16_t len) {
|
||||
if (len < 8)
|
||||
return;
|
||||
@@ -673,6 +776,19 @@ void LD6002BComponent::handle_z_range_report_(const uint8_t *data, uint16_t len)
|
||||
#endif
|
||||
}
|
||||
|
||||
void LD6002BComponent::handle_installation_report_(const uint8_t *data, uint16_t len) {
|
||||
if (len < 1)
|
||||
return;
|
||||
#ifdef USE_SELECT
|
||||
if (this->installation_select_ == nullptr)
|
||||
return;
|
||||
uint8_t value = data[0];
|
||||
if (value <= 1) {
|
||||
this->installation_select_->publish_state(value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LD6002BComponent::handle_low_power_report_(const uint8_t *data, uint16_t len) {
|
||||
if (len < 1)
|
||||
return;
|
||||
@@ -889,6 +1005,8 @@ void LD6002BComponent::send_command_internal_(uint16_t type, const uint8_t *data
|
||||
if (len > 0 && data != nullptr) {
|
||||
std::memcpy(this->wake_scratch_.data(), data, len);
|
||||
}
|
||||
// A button pulse must not raise the pin in the middle of this one.
|
||||
this->cancel_timeout(WAKE_BUTTON_TIMEOUT);
|
||||
this->wake_pulse_pending_ = true;
|
||||
this->wakeup_pin_->digital_write(false);
|
||||
const uint8_t generation = this->send_generation_;
|
||||
@@ -972,6 +1090,16 @@ void LD6002BComponent::send_z_range_() {
|
||||
this->queue_command_(TYPE_SET_Z_RANGE, data, sizeof(data));
|
||||
}
|
||||
|
||||
void LD6002BComponent::wake_() {
|
||||
// A command's own pulse raises the pin and writes after it, so ride along instead of
|
||||
// claiming the flag: claiming it would send that command down the immediate-write path
|
||||
// with the pin still low.
|
||||
if (this->wakeup_pin_ == nullptr || this->wake_pulse_pending_)
|
||||
return;
|
||||
this->wakeup_pin_->digital_write(false);
|
||||
this->set_timeout(WAKE_BUTTON_TIMEOUT, this->wakeup_pulse_ms_, [this]() { this->wakeup_pin_->digital_write(true); });
|
||||
}
|
||||
|
||||
void LD6002BComponent::set_number_value(NumberType type, float value) {
|
||||
switch (type) {
|
||||
case NumberType::HOLD_DELAY: {
|
||||
@@ -999,6 +1127,36 @@ void LD6002BComponent::set_number_value(NumberType type, float value) {
|
||||
}
|
||||
}
|
||||
|
||||
void LD6002BComponent::set_select_value(SelectType type, size_t index) {
|
||||
switch (type) {
|
||||
case SelectType::SENSITIVITY:
|
||||
if (index == 0) {
|
||||
this->send_control_command_(CMD_SENSITIVITY_LOW);
|
||||
} else if (index == 1) {
|
||||
this->send_control_command_(CMD_SENSITIVITY_MEDIUM);
|
||||
} else if (index == 2) {
|
||||
this->send_control_command_(CMD_SENSITIVITY_HIGH);
|
||||
}
|
||||
break;
|
||||
case SelectType::TRIGGER_SPEED:
|
||||
if (index == 0) {
|
||||
this->send_control_command_(CMD_TRIGGER_SLOW);
|
||||
} else if (index == 1) {
|
||||
this->send_control_command_(CMD_TRIGGER_MEDIUM);
|
||||
} else if (index == 2) {
|
||||
this->send_control_command_(CMD_TRIGGER_FAST);
|
||||
}
|
||||
break;
|
||||
case SelectType::INSTALLATION_MODE:
|
||||
if (index == 0) {
|
||||
this->send_control_command_(CMD_INSTALL_TOP);
|
||||
} else if (index == 1) {
|
||||
this->send_control_command_(CMD_INSTALL_SIDE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LD6002BComponent::init_version_pref_() {
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (this->ota_version_text_sensor_ == nullptr) {
|
||||
@@ -1124,4 +1282,36 @@ void LD6002BComponent::set_switch_state(SwitchType type, bool state) {
|
||||
}
|
||||
}
|
||||
|
||||
void LD6002BComponent::press_button(ButtonType type) {
|
||||
switch (type) {
|
||||
case ButtonType::GET_DELAY:
|
||||
this->send_control_command_(CMD_GET_DELAY);
|
||||
break;
|
||||
case ButtonType::GET_SENSITIVITY:
|
||||
this->send_control_command_(CMD_GET_SENSITIVITY);
|
||||
break;
|
||||
case ButtonType::GET_TRIGGER_SPEED:
|
||||
this->send_control_command_(CMD_GET_TRIGGER);
|
||||
break;
|
||||
case ButtonType::GET_Z_RANGE:
|
||||
this->send_control_command_(CMD_GET_Z_RANGE);
|
||||
break;
|
||||
case ButtonType::GET_INSTALLATION:
|
||||
this->send_control_command_(CMD_GET_INSTALLATION);
|
||||
break;
|
||||
case ButtonType::GET_LOW_POWER_MODE:
|
||||
this->send_control_command_(CMD_GET_LOW_POWER);
|
||||
break;
|
||||
case ButtonType::GET_LOW_POWER_SLEEP_TIME:
|
||||
this->send_control_command_(CMD_GET_LOW_POWER_SLEEP);
|
||||
break;
|
||||
case ButtonType::RESET_UNATTENDED:
|
||||
this->send_control_command_(CMD_RESET_UNATTENDED);
|
||||
break;
|
||||
case ButtonType::WAKE:
|
||||
this->wake_();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::ld6002b
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/gpio.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#ifdef USE_SENSOR
|
||||
@@ -12,12 +13,14 @@
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
#include "esphome/components/number/number.h"
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
#include "esphome/components/select/select.h"
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
#include "esphome/components/switch/switch.h"
|
||||
#endif
|
||||
@@ -40,12 +43,30 @@ enum class NumberType : uint8_t {
|
||||
LOW_POWER_SLEEP,
|
||||
};
|
||||
|
||||
enum class SelectType : uint8_t {
|
||||
SENSITIVITY,
|
||||
TRIGGER_SPEED,
|
||||
INSTALLATION_MODE,
|
||||
};
|
||||
|
||||
enum class SwitchType : uint8_t {
|
||||
LOW_POWER,
|
||||
POINT_CLOUD,
|
||||
TARGET_DISPLAY,
|
||||
};
|
||||
|
||||
enum class ButtonType : uint8_t {
|
||||
GET_DELAY,
|
||||
GET_SENSITIVITY,
|
||||
GET_TRIGGER_SPEED,
|
||||
GET_Z_RANGE,
|
||||
GET_INSTALLATION,
|
||||
GET_LOW_POWER_MODE,
|
||||
GET_LOW_POWER_SLEEP_TIME,
|
||||
RESET_UNATTENDED,
|
||||
WAKE,
|
||||
};
|
||||
|
||||
#ifdef USE_SENSOR
|
||||
struct TargetSensors {
|
||||
sensor::Sensor *x{nullptr};
|
||||
@@ -124,6 +145,12 @@ class LD6002BComponent : public Component, public uart::UARTDevice {
|
||||
void set_low_power_sleep_number(number::Number *number) { this->low_power_sleep_number_ = number; }
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
void set_sensitivity_select(select::Select *select) { this->sensitivity_select_ = select; }
|
||||
void set_trigger_speed_select(select::Select *select) { this->trigger_speed_select_ = select; }
|
||||
void set_installation_select(select::Select *select) { this->installation_select_ = select; }
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
void set_low_power_switch(switch_::Switch *sw) { this->low_power_switch_ = sw; }
|
||||
void set_point_cloud_switch(switch_::Switch *sw) { this->point_cloud_switch_ = sw; }
|
||||
@@ -131,7 +158,9 @@ class LD6002BComponent : public Component, public uart::UARTDevice {
|
||||
#endif
|
||||
|
||||
void set_number_value(NumberType type, float value);
|
||||
void set_select_value(SelectType type, size_t index);
|
||||
void set_switch_state(SwitchType type, bool state);
|
||||
void press_button(ButtonType type);
|
||||
|
||||
protected:
|
||||
enum class ParseState : uint8_t { SOF, HEADER, HCK, DATA, DCK, DISCARD };
|
||||
@@ -148,7 +177,10 @@ class LD6002BComponent : public Component, public uart::UARTDevice {
|
||||
void handle_target_report_(const uint8_t *data, uint16_t len);
|
||||
void handle_point_cloud_(const uint8_t *data, uint16_t len);
|
||||
void handle_delay_report_(const uint8_t *data, uint16_t len);
|
||||
void handle_sensitivity_report_(const uint8_t *data, uint16_t len);
|
||||
void handle_trigger_speed_report_(const uint8_t *data, uint16_t len);
|
||||
void handle_z_range_report_(const uint8_t *data, uint16_t len);
|
||||
void handle_installation_report_(const uint8_t *data, uint16_t len);
|
||||
void handle_low_power_report_(const uint8_t *data, uint16_t len);
|
||||
void handle_low_power_sleep_report_(const uint8_t *data, uint16_t len);
|
||||
void handle_work_mode_report_(const uint8_t *data, uint16_t len);
|
||||
@@ -173,6 +205,7 @@ class LD6002BComponent : public Component, public uart::UARTDevice {
|
||||
void write_frame_(uint16_t type, const uint8_t *data, uint8_t len, bool track);
|
||||
void send_control_command_(uint32_t command);
|
||||
void send_z_range_();
|
||||
void wake_();
|
||||
|
||||
static uint16_t read_u16_be(const uint8_t *data);
|
||||
static uint32_t read_u32_le(const uint8_t *data);
|
||||
@@ -202,6 +235,11 @@ class LD6002BComponent : public Component, public uart::UARTDevice {
|
||||
number::Number *z_max_number_{nullptr};
|
||||
number::Number *low_power_sleep_number_{nullptr};
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
select::Select *sensitivity_select_{nullptr};
|
||||
select::Select *trigger_speed_select_{nullptr};
|
||||
select::Select *installation_select_{nullptr};
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
switch_::Switch *low_power_switch_{nullptr};
|
||||
switch_::Switch *point_cloud_switch_{nullptr};
|
||||
@@ -235,6 +273,9 @@ class LD6002BComponent : public Component, public uart::UARTDevice {
|
||||
// How long the module stays awake after any frame, and so still answers the next one.
|
||||
static constexpr uint32_t MODULE_AWAKE_MS = 10000;
|
||||
static constexpr uint8_t CMD_MAX_RETRIES = 3;
|
||||
// Named so a repeated press replaces its own pending timeout instead of stacking
|
||||
// another, and so the command path can cancel it when it takes the pin over.
|
||||
static constexpr const char *WAKE_BUTTON_TIMEOUT = "wake_button";
|
||||
// A reply cannot trail the frame that earned it for longer than this; the field worst case is ~726ms.
|
||||
static constexpr uint32_t STALE_ACK_MAX_AGE_MS = 1000;
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import select
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_SENSITIVITY, ENTITY_CATEGORY_CONFIG
|
||||
|
||||
from .. import LD6002BComponent, ld6002b_ns
|
||||
from ..const import CONF_INSTALLATION_MODE, CONF_LD6002B_ID, CONF_TRIGGER_SPEED
|
||||
|
||||
DEPENDENCIES = ["ld6002b"]
|
||||
|
||||
LD6002BSelect = ld6002b_ns.class_("LD6002BSelect", select.Select)
|
||||
SelectType = ld6002b_ns.enum("SelectType", is_class=True)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_LD6002B_ID): cv.use_id(LD6002BComponent),
|
||||
cv.Optional(CONF_SENSITIVITY): select.select_schema(
|
||||
LD6002BSelect, entity_category=ENTITY_CATEGORY_CONFIG
|
||||
),
|
||||
cv.Optional(CONF_TRIGGER_SPEED): select.select_schema(
|
||||
LD6002BSelect, entity_category=ENTITY_CATEGORY_CONFIG
|
||||
),
|
||||
cv.Optional(CONF_INSTALLATION_MODE): select.select_schema(
|
||||
LD6002BSelect, entity_category=ENTITY_CATEGORY_CONFIG
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
SELECT_MAP = (
|
||||
(
|
||||
CONF_SENSITIVITY,
|
||||
SelectType.SENSITIVITY,
|
||||
"set_sensitivity_select",
|
||||
["low", "medium", "high"],
|
||||
),
|
||||
(
|
||||
CONF_TRIGGER_SPEED,
|
||||
SelectType.TRIGGER_SPEED,
|
||||
"set_trigger_speed_select",
|
||||
["slow", "medium", "fast"],
|
||||
),
|
||||
(
|
||||
CONF_INSTALLATION_MODE,
|
||||
SelectType.INSTALLATION_MODE,
|
||||
"set_installation_select",
|
||||
["top", "side"],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
hub = await cg.get_variable(config[CONF_LD6002B_ID])
|
||||
|
||||
for key, select_type, setter, options in SELECT_MAP:
|
||||
if conf := config.get(key):
|
||||
s = await select.new_select(conf, select_type, options=options)
|
||||
await cg.register_parented(s, config[CONF_LD6002B_ID])
|
||||
cg.add(getattr(hub, setter)(s))
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "ld6002b_select.h"
|
||||
|
||||
namespace esphome::ld6002b {
|
||||
|
||||
void LD6002BSelect::control(size_t index) {
|
||||
this->publish_state(index);
|
||||
this->parent_->set_select_value(this->type_, index);
|
||||
}
|
||||
|
||||
} // namespace esphome::ld6002b
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/select/select.h"
|
||||
#include "../ld6002b.h"
|
||||
|
||||
namespace esphome::ld6002b {
|
||||
|
||||
class LD6002BSelect : public select::Select, public Parented<LD6002BComponent> {
|
||||
public:
|
||||
explicit LD6002BSelect(SelectType type) : type_(type) {}
|
||||
|
||||
protected:
|
||||
void control(size_t index) override;
|
||||
|
||||
SelectType type_;
|
||||
};
|
||||
|
||||
} // namespace esphome::ld6002b
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Tests for the wake button's wakeup_pin requirement in ld6002b."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.components.ld6002b.button import CONFIG_SCHEMA, FINAL_VALIDATE_SCHEMA
|
||||
from esphome.config import Config
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_WAKEUP_PIN, PlatformFramework
|
||||
from esphome.core import ID
|
||||
from esphome.types import ConfigType
|
||||
from tests.component_tests.types import SetCoreConfigCallable
|
||||
|
||||
HUB_ID = "ld6002b_hub"
|
||||
|
||||
|
||||
def _full_config(hub: ConfigType) -> Config:
|
||||
"""A full config carrying one ld6002b hub, as the ID pass leaves it.
|
||||
|
||||
final_validate resolves the hub through get_path_for_id, so the declaring
|
||||
path has to be registered the way validate_config registers it: the path of
|
||||
the id value itself, whose parent is the hub's own config.
|
||||
"""
|
||||
full = Config()
|
||||
full["ld6002b"] = [hub]
|
||||
full.declare_ids.append((hub[CONF_ID], ["ld6002b", 0, CONF_ID]))
|
||||
return full
|
||||
|
||||
|
||||
def _hub(*, wakeup_pin: bool) -> ConfigType:
|
||||
hub: ConfigType = {CONF_ID: ID(HUB_ID, is_declaration=True, type="ld6002b")}
|
||||
if wakeup_pin:
|
||||
hub[CONF_WAKEUP_PIN] = {"number": 4}
|
||||
return hub
|
||||
|
||||
|
||||
def _buttons(**buttons: str) -> ConfigType:
|
||||
"""A button platform config naming the given buttons on the shared hub."""
|
||||
config: ConfigType = {
|
||||
"ld6002b_id": ID(HUB_ID, is_declaration=False, type="ld6002b")
|
||||
}
|
||||
config.update({key: {"name": name} for key, name in buttons.items()})
|
||||
return config
|
||||
|
||||
|
||||
def _validated(config: ConfigType) -> ConfigType:
|
||||
"""Run the button schema, then the final validation the hub is checked in."""
|
||||
config = CONFIG_SCHEMA(config)
|
||||
FINAL_VALIDATE_SCHEMA(config)
|
||||
return config
|
||||
|
||||
|
||||
def test_wake_without_wakeup_pin_is_rejected(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
) -> None:
|
||||
"""The wake button drives the pin directly, so a hub without one cannot serve it."""
|
||||
set_core_config(
|
||||
PlatformFramework.ESP32_IDF, full_config=_full_config(_hub(wakeup_pin=False))
|
||||
)
|
||||
|
||||
with pytest.raises(cv.Invalid, match="wake requires wakeup_pin"):
|
||||
_validated(_buttons(wake="Wake"))
|
||||
|
||||
|
||||
def test_wake_with_wakeup_pin_passes(set_core_config: SetCoreConfigCallable) -> None:
|
||||
set_core_config(
|
||||
PlatformFramework.ESP32_IDF, full_config=_full_config(_hub(wakeup_pin=True))
|
||||
)
|
||||
|
||||
_validated(_buttons(wake="Wake"))
|
||||
|
||||
|
||||
def test_other_buttons_do_not_need_the_pin(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
) -> None:
|
||||
"""Only wake drives the pin; the query buttons stay usable without one."""
|
||||
set_core_config(
|
||||
PlatformFramework.ESP32_IDF, full_config=_full_config(_hub(wakeup_pin=False))
|
||||
)
|
||||
|
||||
_validated(_buttons(get_delay="Get Delay"))
|
||||
@@ -71,6 +71,16 @@ number:
|
||||
low_power_sleep_time:
|
||||
name: Low Power Sleep
|
||||
|
||||
select:
|
||||
- platform: ld6002b
|
||||
ld6002b_id: ld6002b_radar
|
||||
sensitivity:
|
||||
name: Sensitivity
|
||||
trigger_speed:
|
||||
name: Trigger Speed
|
||||
installation_mode:
|
||||
name: Installation
|
||||
|
||||
switch:
|
||||
- platform: ld6002b
|
||||
ld6002b_id: ld6002b_radar
|
||||
@@ -80,3 +90,25 @@ switch:
|
||||
name: Point Cloud
|
||||
target_display:
|
||||
name: Target Display
|
||||
|
||||
button:
|
||||
- platform: ld6002b
|
||||
ld6002b_id: ld6002b_radar
|
||||
get_delay:
|
||||
name: Get Delay
|
||||
get_sensitivity:
|
||||
name: Get Sensitivity
|
||||
get_trigger_speed:
|
||||
name: Get Trigger Speed
|
||||
get_z_range:
|
||||
name: Get Z Range
|
||||
get_installation:
|
||||
name: Get Installation
|
||||
get_low_power_mode:
|
||||
name: Get Low Power Mode
|
||||
get_low_power_sleep_time:
|
||||
name: Get Low Power Sleep
|
||||
reset_unattended:
|
||||
name: Reset Unattended
|
||||
wake:
|
||||
name: Wake
|
||||
|
||||
Reference in New Issue
Block a user