[ld6002b] Branch on the entity directly and drop the setting enums

The setters run each setting's code in its pointer branch, so the number, select
and switch type enums go. The buttons read the public APPLY_ENTITY and the unique
setting check is a partial.
This commit is contained in:
J. Nick Koston
2026-10-16 13:44:52 -10:00
parent ded8f7f31e
commit f4ea1d3b21
7 changed files with 74 additions and 174 deletions
+1 -1
View File
@@ -77,7 +77,7 @@ async def to_code(config: ConfigType) -> None:
def validate_unique_settings(domain: str, config: ConfigType) -> None:
"""Reject a setting configured in two platform blocks of the same hub; the hub keeps one entity per setting."""
"""Reject a setting set in two platform blocks of one hub, which keeps one entity per setting."""
hub_id = config[CONF_LD6002B_ID]
entries = [
entry
@@ -140,7 +140,7 @@ async def to_code(config: ConfigType) -> None:
if not confs:
return
hub = await cg.get_variable(config[CONF_LD6002B_ID])
params = button.sub_buttons(config).apply_entity.params
params = button.APPLY_ENTITY.params
# One function for all buttons, picking the type by pointer: one class instead of one per button.
# Named after the first button so two button blocks on one hub do not clash.
fn = f"esphome__{confs[0][1][CONF_ID].id}__button_fn"
+65 -134
View File
@@ -1369,126 +1369,70 @@ void LD6002BComponent::wake_() {
}
#ifdef USE_NUMBER
// Each setter picks its setting by entity pointer, so the entities share one generated class.
void LD6002BComponent::set_number_value(number::Number *entity, float value) {
// Found by pointer, so the entities share one generated class instead of storing a type each
NumberType type;
if (entity == this->hold_delay_number_) {
type = NumberType::HOLD_DELAY;
if (entity == this->hold_delay_number_ || entity == this->low_power_sleep_number_) {
uint8_t data[4];
write_u32_le(data, static_cast<uint32_t>(value));
this->queue_command_(entity == this->hold_delay_number_ ? TYPE_SET_HOLD_DELAY : TYPE_SET_LOW_POWER_SLEEP, data,
sizeof(data));
} else if (entity == this->z_min_number_) {
type = NumberType::Z_MIN;
this->z_min_ = value;
this->send_z_range_();
} else if (entity == this->z_max_number_) {
type = NumberType::Z_MAX;
} else if (entity == this->low_power_sleep_number_) {
type = NumberType::LOW_POWER_SLEEP;
this->z_max_ = value;
this->send_z_range_();
} else if (entity == this->area_x_min_number_) {
type = NumberType::AREA_X_MIN;
this->area_x_min_ = value;
this->area_edits_.x_min = value;
} else if (entity == this->area_x_max_number_) {
type = NumberType::AREA_X_MAX;
this->area_x_max_ = value;
this->area_edits_.x_max = value;
} else if (entity == this->area_y_min_number_) {
type = NumberType::AREA_Y_MIN;
this->area_y_min_ = value;
this->area_edits_.y_min = value;
} else if (entity == this->area_y_max_number_) {
type = NumberType::AREA_Y_MAX;
this->area_y_max_ = value;
this->area_edits_.y_max = value;
} else if (entity == this->area_z_min_number_) {
type = NumberType::AREA_Z_MIN;
this->area_z_min_ = value;
this->area_edits_.z_min = value;
} else { // Only registered entities call this, so the last one needs no compare
type = NumberType::AREA_Z_MAX;
}
switch (type) {
case NumberType::HOLD_DELAY: {
uint32_t delay = static_cast<uint32_t>(value);
uint8_t data[4];
write_u32_le(data, delay);
this->queue_command_(TYPE_SET_HOLD_DELAY, data, sizeof(data));
break;
}
case NumberType::Z_MIN:
this->z_min_ = value;
this->send_z_range_();
break;
case NumberType::Z_MAX:
this->z_max_ = value;
this->send_z_range_();
break;
case NumberType::LOW_POWER_SLEEP: {
uint32_t sleep_ms = static_cast<uint32_t>(value);
uint8_t data[4];
write_u32_le(data, sleep_ms);
this->queue_command_(TYPE_SET_LOW_POWER_SLEEP, data, sizeof(data));
break;
}
case NumberType::AREA_X_MIN:
this->area_x_min_ = value;
this->area_edits_.x_min = value;
break;
case NumberType::AREA_X_MAX:
this->area_x_max_ = value;
this->area_edits_.x_max = value;
break;
case NumberType::AREA_Y_MIN:
this->area_y_min_ = value;
this->area_edits_.y_min = value;
break;
case NumberType::AREA_Y_MAX:
this->area_y_max_ = value;
this->area_edits_.y_max = value;
break;
case NumberType::AREA_Z_MIN:
this->area_z_min_ = value;
this->area_edits_.z_min = value;
break;
case NumberType::AREA_Z_MAX:
this->area_z_max_ = value;
this->area_edits_.z_max = value;
break;
this->area_z_max_ = value;
this->area_edits_.z_max = value;
}
}
#endif
#ifdef USE_SELECT
void LD6002BComponent::set_select_value(select::Select *entity, size_t index) {
// Found by pointer, so the entities share one generated class instead of storing a type each
SelectType type;
if (entity == this->sensitivity_select_) {
type = 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);
}
} else if (entity == this->trigger_speed_select_) {
type = 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);
}
} else if (entity == this->installation_select_) {
type = SelectType::INSTALLATION_MODE;
if (index == 0) {
this->send_control_command_(CMD_INSTALL_TOP);
} else if (index == 1) {
this->send_control_command_(CMD_INSTALL_SIDE);
}
} else { // Only registered entities call this, so the last one needs no compare
type = SelectType::AREA_ID;
}
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;
case SelectType::AREA_ID:
this->area_id_ = static_cast<uint8_t>(index);
this->area_id_set_ = true;
this->update_area_numbers_for_id_(this->area_id_);
this->save_area_id_pref_(this->area_id_);
break;
this->area_id_ = static_cast<uint8_t>(index);
this->area_id_set_ = true;
this->update_area_numbers_for_id_(this->area_id_);
this->save_area_id_pref_(this->area_id_);
}
}
#endif
@@ -1821,43 +1765,30 @@ void LD6002BComponent::clear_target_state_() {
#ifdef USE_SWITCH
void LD6002BComponent::set_switch_state(switch_::Switch *entity, bool state) {
// Found by pointer, so the entities share one generated class instead of storing a type each
SwitchType type;
if (entity == this->low_power_switch_) {
type = SwitchType::LOW_POWER;
this->low_power_enabled_ = state;
this->low_power_reported_ = true;
this->send_control_command_(state ? CMD_LOW_POWER_ON : CMD_LOW_POWER_OFF);
this->update_work_mode_fallback_();
} else if (entity == this->point_cloud_switch_) {
type = SwitchType::POINT_CLOUD;
} else { // Only registered entities call this, so the last one needs no compare
type = SwitchType::TARGET_DISPLAY;
}
switch (type) {
case SwitchType::LOW_POWER:
this->low_power_enabled_ = state;
this->low_power_reported_ = true;
this->send_control_command_(state ? CMD_LOW_POWER_ON : CMD_LOW_POWER_OFF);
this->update_work_mode_fallback_();
break;
case SwitchType::POINT_CLOUD:
this->point_cloud_enabled_ = state;
this->send_control_command_(state ? CMD_POINT_CLOUD_ON : CMD_POINT_CLOUD_OFF);
this->point_cloud_enabled_ = state;
this->send_control_command_(state ? CMD_POINT_CLOUD_ON : CMD_POINT_CLOUD_OFF);
#ifdef USE_SENSOR
// The count only moves while the stream runs, so the last one would stand as
// a live reading. The dedup sentinel is cleared with it: the same count is
// new again when the stream comes back.
if (!state && this->point_count_sensor_ != nullptr && this->last_point_count_ != 0xFFFFFFFF) {
this->point_count_sensor_->publish_state(NAN);
this->last_point_count_ = 0xFFFFFFFF;
}
// The count only moves while the stream runs, so the last one would stand as
// a live reading. The dedup sentinel is cleared with it: the same count is
// new again when the stream comes back.
if (!state && this->point_count_sensor_ != nullptr && this->last_point_count_ != 0xFFFFFFFF) {
this->point_count_sensor_->publish_state(NAN);
this->last_point_count_ = 0xFFFFFFFF;
}
#endif
break;
case SwitchType::TARGET_DISPLAY:
this->target_display_enabled_ = state;
this->send_control_command_(state ? CMD_TARGET_DISPLAY_ON : CMD_TARGET_DISPLAY_OFF);
if (!state) {
// Every target entity is fed by the reports this just stopped.
this->clear_target_state_();
}
break;
} else { // Only registered entities call this, so the last one needs no compare
this->target_display_enabled_ = state;
this->send_control_command_(state ? CMD_TARGET_DISPLAY_ON : CMD_TARGET_DISPLAY_OFF);
if (!state) {
// Every target entity is fed by the reports this just stopped.
this->clear_target_state_();
}
}
}
#endif
-26
View File
@@ -40,32 +40,6 @@ static constexpr size_t DEFAULT_MAX_DATA_LEN_POINT_CLOUD = 4096;
// Largest protocol payload is TYPE_SET_AREA: int32 area id + 6 floats = 28 bytes.
static constexpr size_t CMD_MAX_DATA_LEN = 28;
enum class NumberType : uint8_t {
HOLD_DELAY,
Z_MIN,
Z_MAX,
LOW_POWER_SLEEP,
AREA_X_MIN,
AREA_X_MAX,
AREA_Y_MIN,
AREA_Y_MAX,
AREA_Z_MIN,
AREA_Z_MAX,
};
enum class SelectType : uint8_t {
SENSITIVITY,
TRIGGER_SPEED,
INSTALLATION_MODE,
AREA_ID,
};
enum class SwitchType : uint8_t {
LOW_POWER,
POINT_CLOUD,
TARGET_DISPLAY,
};
enum class ButtonType : uint8_t {
APPLY_AREA,
AUTO_INTERFERENCE,
@@ -1,7 +1,6 @@
import esphome.codegen as cg
from esphome.components import number
from esphome.components.button import DOMAIN as BUTTON_DOMAIN
from esphome.components.number import DOMAIN as NUMBER_DOMAIN
from esphome.components.select import DOMAIN as SELECT_DOMAIN
import esphome.config_validation as cv
from esphome.const import (
@@ -105,7 +104,7 @@ CONFIG_SCHEMA = cv.Schema(
def final_validate(config: ConfigType) -> None:
validate_unique_settings(NUMBER_DOMAIN, config)
validate_unique_settings(number.DOMAIN, config)
if config.get(CONF_AREA_CONFIG) is None:
return
@@ -1,3 +1,5 @@
from functools import partial
import esphome.codegen as cg
from esphome.components import select
import esphome.config_validation as cv
@@ -39,11 +41,7 @@ CONFIG_SCHEMA = cv.Schema(
)
def final_validate(config: ConfigType) -> None:
validate_unique_settings(select.DOMAIN, config)
FINAL_VALIDATE_SCHEMA = final_validate
FINAL_VALIDATE_SCHEMA = partial(validate_unique_settings, select.DOMAIN)
async def to_code(config: ConfigType) -> None:
@@ -1,3 +1,5 @@
from functools import partial
import esphome.codegen as cg
from esphome.components import switch
import esphome.config_validation as cv
@@ -44,11 +46,7 @@ CONFIG_SCHEMA = cv.Schema(
)
def final_validate(config: ConfigType) -> None:
validate_unique_settings(switch.DOMAIN, config)
FINAL_VALIDATE_SCHEMA = final_validate
FINAL_VALIDATE_SCHEMA = partial(validate_unique_settings, switch.DOMAIN)
async def to_code(config: ConfigType) -> None: