From f4ea1d3b218eae1da088207f787ba16f9cfcc78d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 16 Oct 2026 13:44:52 -1000 Subject: [PATCH] [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. --- esphome/components/ld6002b/__init__.py | 2 +- esphome/components/ld6002b/button/__init__.py | 2 +- esphome/components/ld6002b/ld6002b.cpp | 199 ++++++------------ esphome/components/ld6002b/ld6002b.h | 26 --- esphome/components/ld6002b/number/__init__.py | 3 +- esphome/components/ld6002b/select/__init__.py | 8 +- esphome/components/ld6002b/switch/__init__.py | 8 +- 7 files changed, 74 insertions(+), 174 deletions(-) diff --git a/esphome/components/ld6002b/__init__.py b/esphome/components/ld6002b/__init__.py index 8ba7bbb2da1..9663f3802a7 100644 --- a/esphome/components/ld6002b/__init__.py +++ b/esphome/components/ld6002b/__init__.py @@ -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 diff --git a/esphome/components/ld6002b/button/__init__.py b/esphome/components/ld6002b/button/__init__.py index 961527cef18..1c15fad9968 100644 --- a/esphome/components/ld6002b/button/__init__.py +++ b/esphome/components/ld6002b/button/__init__.py @@ -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" diff --git a/esphome/components/ld6002b/ld6002b.cpp b/esphome/components/ld6002b/ld6002b.cpp index 84b08abd78f..bc6a2d8b4c6 100644 --- a/esphome/components/ld6002b/ld6002b.cpp +++ b/esphome/components/ld6002b/ld6002b.cpp @@ -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(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(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(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(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(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 diff --git a/esphome/components/ld6002b/ld6002b.h b/esphome/components/ld6002b/ld6002b.h index a47ec4a8709..a5c75f6ef36 100644 --- a/esphome/components/ld6002b/ld6002b.h +++ b/esphome/components/ld6002b/ld6002b.h @@ -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, diff --git a/esphome/components/ld6002b/number/__init__.py b/esphome/components/ld6002b/number/__init__.py index dd38e4519d9..e2024cdd2f3 100644 --- a/esphome/components/ld6002b/number/__init__.py +++ b/esphome/components/ld6002b/number/__init__.py @@ -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 diff --git a/esphome/components/ld6002b/select/__init__.py b/esphome/components/ld6002b/select/__init__.py index 27c2e065428..18a9f997f2e 100644 --- a/esphome/components/ld6002b/select/__init__.py +++ b/esphome/components/ld6002b/select/__init__.py @@ -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: diff --git a/esphome/components/ld6002b/switch/__init__.py b/esphome/components/ld6002b/switch/__init__.py index 59477dc5973..a6a09cee688 100644 --- a/esphome/components/ld6002b/switch/__init__.py +++ b/esphome/components/ld6002b/switch/__init__.py @@ -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: