diff --git a/esphome/components/ld2450/ld2450.cpp b/esphome/components/ld2450/ld2450.cpp index 583918e5f5..eb17cc7de7 100644 --- a/esphome/components/ld2450/ld2450.cpp +++ b/esphome/components/ld2450/ld2450.cpp @@ -474,15 +474,12 @@ void LD2450Component::handle_periodic_data_() { is_moving = false; // tx is used for further calculations, so always needs to be populated tx = ld2450::decode_coordinate(this->buffer_data_[start], this->buffer_data_[start + 1]); - SAFE_PUBLISH_SENSOR(this->move_x_sensors_[index], tx); // Y start = TARGET_Y + index * 8; ty = ld2450::decode_coordinate(this->buffer_data_[start], this->buffer_data_[start + 1]); - SAFE_PUBLISH_SENSOR(this->move_y_sensors_[index], ty); // RESOLUTION start = TARGET_RESOLUTION + index * 8; res = (this->buffer_data_[start + 1] << 8) | this->buffer_data_[start]; - SAFE_PUBLISH_SENSOR(this->move_resolution_sensors_[index], res); #endif // SPEED start = TARGET_SPEED + index * 8; @@ -491,9 +488,6 @@ void LD2450Component::handle_periodic_data_() { is_moving = true; moving_target_count++; } -#ifdef USE_SENSOR - SAFE_PUBLISH_SENSOR(this->move_speed_sensors_[index], ts); -#endif // DISTANCE // Optimized: use already decoded tx and ty values, replace pow() with multiplication int32_t x_squared = (int32_t) tx * tx; @@ -503,10 +497,23 @@ void LD2450Component::handle_periodic_data_() { target_count++; } #ifdef USE_SENSOR - SAFE_PUBLISH_SENSOR(this->move_distance_sensors_[index], td); - // ANGLE - atan2f computes angle from Y axis directly, no sqrt/division needed - angle = atan2f(static_cast(-tx), static_cast(ty)) * (180.0f / std::numbers::pi_v); - SAFE_PUBLISH_SENSOR(this->move_angle_sensors_[index], angle); + if (td == 0) { + SAFE_PUBLISH_SENSOR_UNKNOWN(this->move_x_sensors_[index]); + SAFE_PUBLISH_SENSOR_UNKNOWN(this->move_y_sensors_[index]); + SAFE_PUBLISH_SENSOR_UNKNOWN(this->move_resolution_sensors_[index]); + SAFE_PUBLISH_SENSOR_UNKNOWN(this->move_speed_sensors_[index]); + SAFE_PUBLISH_SENSOR_UNKNOWN(this->move_distance_sensors_[index]); + SAFE_PUBLISH_SENSOR_UNKNOWN(this->move_angle_sensors_[index]); + } else { + SAFE_PUBLISH_SENSOR(this->move_x_sensors_[index], tx); + SAFE_PUBLISH_SENSOR(this->move_y_sensors_[index], ty); + SAFE_PUBLISH_SENSOR(this->move_resolution_sensors_[index], res); + SAFE_PUBLISH_SENSOR(this->move_speed_sensors_[index], ts); + SAFE_PUBLISH_SENSOR(this->move_distance_sensors_[index], td); + // ANGLE - atan2f computes angle from Y axis directly, no sqrt/division needed + angle = atan2f(static_cast(-tx), static_cast(ty)) * (180.0f / std::numbers::pi_v); + SAFE_PUBLISH_SENSOR(this->move_angle_sensors_[index], angle); + } #endif #ifdef USE_TEXT_SENSOR // DIRECTION diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index a3cd28a982..240d5e3e45 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -707,7 +707,7 @@ float gamma_correct(float value, float gamma) { if (gamma <= 0.0f) return value; - return powf(value, gamma); + return powf(value, gamma); // NOLINT - deprecated, removal 2026.9.0 } float gamma_uncorrect(float value, float gamma) { if (value <= 0.0f) @@ -715,7 +715,7 @@ float gamma_uncorrect(float value, float gamma) { if (gamma <= 0.0f) return value; - return powf(value, 1 / gamma); + return powf(value, 1 / gamma); // NOLINT - deprecated, removal 2026.9.0 } void rgb_to_hsv(float red, float green, float blue, int &hue, float &saturation, float &value) { diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 9ed13a1dc2..4422c42988 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -515,8 +515,8 @@ template class SmallBufferWithHeapFallb ///@{ /// Compute 10^exp using iterative multiplication/division. -/// Avoids pulling in powf/__ieee754_powf (~2.3KB flash) for small integer exponents. -/// Matches powf(10, exp) for the int8_t exponent range used by sensor accuracy_decimals. +/// Avoids pulling in powf/__ieee754_powf (~2.3KB flash) for small integer exponents. // NOLINT +/// Matches powf(10, exp) for the int8_t exponent range used by sensor accuracy_decimals. // NOLINT inline float pow10_int(int8_t exp) { float result = 1.0f; if (exp >= 0) { diff --git a/script/ci-custom.py b/script/ci-custom.py index f428eb0821..b60d7d7740 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -841,6 +841,54 @@ def lint_no_scanf(fname, match): ) +# Base entity platforms - these are linked into most builds and should not +# pull in powf/__ieee754_powf (~2.3KB flash). +BASE_ENTITY_PLATFORMS = [ + "alarm_control_panel", + "binary_sensor", + "button", + "climate", + "cover", + "datetime", + "event", + "fan", + "light", + "lock", + "media_player", + "number", + "select", + "sensor", + "switch", + "text", + "text_sensor", + "update", + "valve", + "water_heater", +] + +# Directories protected from powf: core + all base entity platforms +POWF_PROTECTED_DIRS = ["esphome/core"] + [ + f"esphome/components/{p}" for p in BASE_ENTITY_PLATFORMS +] + + +@lint_re_check( + r"[^\w]powf\s*\(" + CPP_RE_EOL, + include=[ + f"{d}/*.{ext}" for d in POWF_PROTECTED_DIRS for ext in ["h", "cpp", "tcc"] + ], +) +def lint_no_powf_in_core(fname, match): + return ( + f"{highlight('powf()')} pulls in __ieee754_powf (~2.3KB flash) and is not allowed in " + f"core or base entity platform code. These files are linked into every build.\n" + f"Please use alternatives:\n" + f" - {highlight('pow10_int(exp)')} for integer powers of 10 (from helpers.h)\n" + f" - Precomputed lookup tables for gamma/non-integer exponents\n" + f"(If powf is strictly necessary, add `// NOLINT` to the line)" + ) + + LOG_MULTILINE_RE = re.compile(r"ESP_LOG\w+\s*\(.*?;", re.DOTALL) LOG_BAD_CONTINUATION_RE = re.compile(r'\\n(?:[^ \\"\r\n\t]|"\s*\n\s*"[^ \\])') LOG_PERCENT_S_CONTINUATION_RE = re.compile(r'\\n(?:%s|"\s*\n\s*"%s)')