mirror of
https://github.com/esphome/esphome.git
synced 2026-09-03 19:46:02 +00:00
Merge branch 'dep_heap_fragmenting_helpers' into integration
This commit is contained in:
@@ -293,6 +293,10 @@ This document provides essential context for AI models interacting with this pro
|
||||
* **Configuration Design:** Aim for simplicity with sensible defaults, while allowing for advanced customization.
|
||||
* **Embedded Systems Optimization:** ESPHome targets resource-constrained microcontrollers. Be mindful of flash size and RAM usage.
|
||||
|
||||
**Why Heap Allocation Matters:**
|
||||
|
||||
ESP devices run for months with small heaps shared between Wi-Fi, BLE, LWIP, and application code. Over time, repeated allocations of different sizes fragment the heap. Failures happen when the largest contiguous block shrinks, even if total free heap is still large. We have seen field crashes caused by this. For this reason, ESPHome treats runtime heap allocation in hot paths as a reliability bug, not a performance issue. Helpers that hide allocation (`std::string`, `std::to_string`, string-returning helpers) are being deprecated and replaced with buffer and view based APIs.
|
||||
|
||||
**STL Container Guidelines:**
|
||||
|
||||
ESPHome runs on embedded systems with limited resources. Choose containers carefully:
|
||||
|
||||
@@ -29,7 +29,7 @@ void RuntimeStatsCollector::record_component_time(Component *component, uint32_t
|
||||
void RuntimeStatsCollector::log_stats_() {
|
||||
ESP_LOGI(TAG,
|
||||
"Component Runtime Statistics\n"
|
||||
"Period stats (last %" PRIu32 "ms):",
|
||||
" Period stats (last %" PRIu32 "ms):",
|
||||
this->log_interval_);
|
||||
|
||||
// First collect stats we want to display
|
||||
@@ -55,7 +55,7 @@ void RuntimeStatsCollector::log_stats_() {
|
||||
}
|
||||
|
||||
// Log total stats since boot
|
||||
ESP_LOGI(TAG, "Total stats (since boot):");
|
||||
ESP_LOGI(TAG, " Total stats (since boot):");
|
||||
|
||||
// Re-sort by total runtime for all-time stats
|
||||
std::sort(stats_to_display.begin(), stats_to_display.end(),
|
||||
|
||||
@@ -64,15 +64,21 @@ void MR24HPC1Component::dump_config() {
|
||||
void MR24HPC1Component::setup() {
|
||||
this->check_uart_settings(115200);
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
if (this->custom_mode_number_ != nullptr) {
|
||||
this->custom_mode_number_->publish_state(0); // Zero out the custom mode
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
if (this->custom_mode_num_sensor_ != nullptr) {
|
||||
this->custom_mode_num_sensor_->publish_state(0);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (this->custom_mode_end_text_sensor_ != nullptr) {
|
||||
this->custom_mode_end_text_sensor_->publish_state("Not in custom mode");
|
||||
}
|
||||
#endif
|
||||
this->set_custom_end_mode();
|
||||
this->poll_time_base_func_check_ = true;
|
||||
this->check_dev_inf_sign_ = true;
|
||||
@@ -353,6 +359,7 @@ void MR24HPC1Component::r24_split_data_frame_(uint8_t value) {
|
||||
|
||||
// Parses data frames related to product information
|
||||
void MR24HPC1Component::r24_frame_parse_product_information_(uint8_t *data) {
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
uint16_t product_len = encode_uint16(data[FRAME_COMMAND_WORD_INDEX + 1], data[FRAME_COMMAND_WORD_INDEX + 2]);
|
||||
if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_MODE) {
|
||||
if ((this->product_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
|
||||
@@ -388,109 +395,153 @@ void MR24HPC1Component::r24_frame_parse_product_information_(uint8_t *data) {
|
||||
ESP_LOGD(TAG, "Reply: get firmwareVersion error!");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Parsing the underlying open parameters
|
||||
void MR24HPC1Component::r24_frame_parse_open_underlying_information_(uint8_t *data) {
|
||||
if (data[FRAME_COMMAND_WORD_INDEX] == 0x00) {
|
||||
if (this->underlying_open_function_switch_ != nullptr) {
|
||||
this->underlying_open_function_switch_->publish_state(
|
||||
data[FRAME_DATA_INDEX]); // Underlying Open Parameter Switch Status Updates
|
||||
}
|
||||
if (data[FRAME_DATA_INDEX]) {
|
||||
this->s_output_info_switch_flag_ = OUTPUT_SWITCH_ON;
|
||||
} else {
|
||||
this->s_output_info_switch_flag_ = OUTPUT_SWTICH_OFF;
|
||||
}
|
||||
} else if (data[FRAME_COMMAND_WORD_INDEX] == 0x01) {
|
||||
if (this->custom_spatial_static_value_sensor_ != nullptr) {
|
||||
this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
if (this->custom_presence_of_detection_sensor_ != nullptr) {
|
||||
this->custom_presence_of_detection_sensor_->publish_state(data[FRAME_DATA_INDEX + 1] * 0.5f);
|
||||
}
|
||||
if (this->custom_spatial_motion_value_sensor_ != nullptr) {
|
||||
this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX + 2]);
|
||||
}
|
||||
if (this->custom_motion_distance_sensor_ != nullptr) {
|
||||
this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX + 3] * 0.5f);
|
||||
}
|
||||
if (this->custom_motion_speed_sensor_ != nullptr) {
|
||||
this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX + 4] - 10) * 0.5f);
|
||||
}
|
||||
} else if ((data[FRAME_COMMAND_WORD_INDEX] == 0x06) || (data[FRAME_COMMAND_WORD_INDEX] == 0x86)) {
|
||||
// none:0x00 close_to:0x01 far_away:0x02
|
||||
if ((this->keep_away_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
|
||||
this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]);
|
||||
}
|
||||
} else if ((this->movement_signs_sensor_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x07) || (data[FRAME_COMMAND_WORD_INDEX] == 0x87))) {
|
||||
this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
} else if ((this->existence_threshold_number_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x08) || (data[FRAME_COMMAND_WORD_INDEX] == 0x88))) {
|
||||
this->existence_threshold_number_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
} else if ((this->motion_threshold_number_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x09) || (data[FRAME_COMMAND_WORD_INDEX] == 0x89))) {
|
||||
this->motion_threshold_number_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
} else if ((this->existence_boundary_select_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x0a) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8a))) {
|
||||
if (this->existence_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) {
|
||||
this->existence_boundary_select_->publish_state(data[FRAME_DATA_INDEX] - 1);
|
||||
}
|
||||
} else if ((this->motion_boundary_select_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x0b) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8b))) {
|
||||
if (this->motion_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) {
|
||||
this->motion_boundary_select_->publish_state(data[FRAME_DATA_INDEX] - 1);
|
||||
}
|
||||
} else if ((this->motion_trigger_number_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x0c) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8c))) {
|
||||
uint32_t motion_trigger_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
|
||||
data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
|
||||
this->motion_trigger_number_->publish_state(motion_trigger_time);
|
||||
} else if ((this->motion_to_rest_number_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x0d) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8d))) {
|
||||
uint32_t move_to_rest_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
|
||||
data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
|
||||
this->motion_to_rest_number_->publish_state(move_to_rest_time);
|
||||
} else if ((this->custom_unman_time_number_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x0e) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8e))) {
|
||||
uint32_t enter_unmanned_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
|
||||
data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
|
||||
float custom_unmanned_time = enter_unmanned_time / 1000.0;
|
||||
this->custom_unman_time_number_->publish_state(custom_unmanned_time);
|
||||
} else if (data[FRAME_COMMAND_WORD_INDEX] == 0x80) {
|
||||
if (data[FRAME_DATA_INDEX]) {
|
||||
this->s_output_info_switch_flag_ = OUTPUT_SWITCH_ON;
|
||||
} else {
|
||||
this->s_output_info_switch_flag_ = OUTPUT_SWTICH_OFF;
|
||||
}
|
||||
if (this->underlying_open_function_switch_ != nullptr) {
|
||||
this->underlying_open_function_switch_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
} else if ((this->custom_spatial_static_value_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x81)) {
|
||||
this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
} else if ((this->custom_spatial_motion_value_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x82)) {
|
||||
this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
} else if ((this->custom_presence_of_detection_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x83)) {
|
||||
this->custom_presence_of_detection_sensor_->publish_state(
|
||||
S_PRESENCE_OF_DETECTION_RANGE_STR[data[FRAME_DATA_INDEX]]);
|
||||
} else if ((this->custom_motion_distance_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x84)) {
|
||||
this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX] * 0.5f);
|
||||
} else if ((this->custom_motion_speed_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x85)) {
|
||||
this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX] - 10) * 0.5f);
|
||||
switch (data[FRAME_COMMAND_WORD_INDEX]) {
|
||||
case 0x00:
|
||||
case 0x80:
|
||||
#ifdef USE_SWITCH
|
||||
if (this->underlying_open_function_switch_ != nullptr) {
|
||||
this->underlying_open_function_switch_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
#endif
|
||||
this->s_output_info_switch_flag_ = data[FRAME_DATA_INDEX] ? OUTPUT_SWITCH_ON : OUTPUT_SWTICH_OFF;
|
||||
break;
|
||||
#ifdef USE_SENSOR
|
||||
case 0x01:
|
||||
if (this->custom_spatial_static_value_sensor_ != nullptr) {
|
||||
this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
if (this->custom_presence_of_detection_sensor_ != nullptr) {
|
||||
this->custom_presence_of_detection_sensor_->publish_state(data[FRAME_DATA_INDEX + 1] * 0.5f);
|
||||
}
|
||||
if (this->custom_spatial_motion_value_sensor_ != nullptr) {
|
||||
this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX + 2]);
|
||||
}
|
||||
if (this->custom_motion_distance_sensor_ != nullptr) {
|
||||
this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX + 3] * 0.5f);
|
||||
}
|
||||
if (this->custom_motion_speed_sensor_ != nullptr) {
|
||||
this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX + 4] - 10) * 0.5f);
|
||||
}
|
||||
break;
|
||||
case 0x07:
|
||||
case 0x87:
|
||||
if (this->movement_signs_sensor_ != nullptr) {
|
||||
this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
if (this->custom_spatial_static_value_sensor_ != nullptr) {
|
||||
this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
break;
|
||||
case 0x82:
|
||||
if (this->custom_spatial_motion_value_sensor_ != nullptr) {
|
||||
this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
break;
|
||||
case 0x83:
|
||||
if (this->custom_presence_of_detection_sensor_ != nullptr) {
|
||||
this->custom_presence_of_detection_sensor_->publish_state(
|
||||
S_PRESENCE_OF_DETECTION_RANGE_STR[data[FRAME_DATA_INDEX]]);
|
||||
}
|
||||
break;
|
||||
case 0x84:
|
||||
if (this->custom_motion_distance_sensor_ != nullptr) {
|
||||
this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX] * 0.5f);
|
||||
}
|
||||
break;
|
||||
case 0x85:
|
||||
if (this->custom_motion_speed_sensor_ != nullptr) {
|
||||
this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX] - 10) * 0.5f);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
case 0x06:
|
||||
case 0x86:
|
||||
// none:0x00 close_to:0x01 far_away:0x02
|
||||
if ((this->keep_away_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
|
||||
this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
case 0x08:
|
||||
case 0x88:
|
||||
if (this->existence_threshold_number_ != nullptr) {
|
||||
this->existence_threshold_number_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
break;
|
||||
case 0x09:
|
||||
case 0x89:
|
||||
if (this->motion_threshold_number_ != nullptr) {
|
||||
this->motion_threshold_number_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
break;
|
||||
case 0x0c:
|
||||
case 0x8c:
|
||||
if (this->motion_trigger_number_ != nullptr) {
|
||||
uint32_t motion_trigger_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
|
||||
data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
|
||||
this->motion_trigger_number_->publish_state(motion_trigger_time);
|
||||
}
|
||||
break;
|
||||
case 0x0d:
|
||||
case 0x8d:
|
||||
if (this->motion_to_rest_number_ != nullptr) {
|
||||
uint32_t move_to_rest_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
|
||||
data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
|
||||
this->motion_to_rest_number_->publish_state(move_to_rest_time);
|
||||
}
|
||||
break;
|
||||
case 0x0e:
|
||||
case 0x8e:
|
||||
if (this->custom_unman_time_number_ != nullptr) {
|
||||
uint32_t enter_unmanned_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
|
||||
data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
|
||||
this->custom_unman_time_number_->publish_state(enter_unmanned_time / 1000.0f);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
case 0x0a:
|
||||
case 0x8a:
|
||||
if (this->existence_boundary_select_ != nullptr) {
|
||||
if (this->existence_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) {
|
||||
this->existence_boundary_select_->publish_state(data[FRAME_DATA_INDEX] - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0b:
|
||||
case 0x8b:
|
||||
if (this->motion_boundary_select_ != nullptr) {
|
||||
if (this->motion_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) {
|
||||
this->motion_boundary_select_->publish_state(data[FRAME_DATA_INDEX] - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void MR24HPC1Component::r24_parse_data_frame_(uint8_t *data, uint8_t len) {
|
||||
switch (data[FRAME_CONTROL_WORD_INDEX]) {
|
||||
case 0x01: {
|
||||
if ((this->heartbeat_state_text_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x01)) {
|
||||
this->heartbeat_state_text_sensor_->publish_state("Equipment Normal");
|
||||
} else if (data[FRAME_COMMAND_WORD_INDEX] == 0x02) {
|
||||
if (data[FRAME_COMMAND_WORD_INDEX] == 0x02) {
|
||||
ESP_LOGD(TAG, "Reply: query restart packet");
|
||||
} else if (this->heartbeat_state_text_sensor_ != nullptr) {
|
||||
this->heartbeat_state_text_sensor_->publish_state("Equipment Abnormal");
|
||||
break;
|
||||
}
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (this->heartbeat_state_text_sensor_ != nullptr) {
|
||||
this->heartbeat_state_text_sensor_->publish_state(
|
||||
data[FRAME_COMMAND_WORD_INDEX] == 0x01 ? "Equipment Normal" : "Equipment Abnormal");
|
||||
}
|
||||
#endif
|
||||
} break;
|
||||
case 0x02: {
|
||||
this->r24_frame_parse_product_information_(data);
|
||||
@@ -511,86 +562,123 @@ void MR24HPC1Component::r24_parse_data_frame_(uint8_t *data, uint8_t len) {
|
||||
}
|
||||
|
||||
void MR24HPC1Component::r24_frame_parse_work_status_(uint8_t *data) {
|
||||
if (data[FRAME_COMMAND_WORD_INDEX] == 0x01) {
|
||||
ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]);
|
||||
} else if (data[FRAME_COMMAND_WORD_INDEX] == 0x07) {
|
||||
if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) {
|
||||
this->scene_mode_select_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
} else if ((this->sensitivity_number_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x08) || (data[FRAME_COMMAND_WORD_INDEX] == 0x88))) {
|
||||
// 1-3
|
||||
this->sensitivity_number_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
} else if (data[FRAME_COMMAND_WORD_INDEX] == 0x09) {
|
||||
// 1-4
|
||||
if (this->custom_mode_num_sensor_ != nullptr) {
|
||||
this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
if (this->custom_mode_number_ != nullptr) {
|
||||
this->custom_mode_number_->publish_state(0);
|
||||
}
|
||||
if (this->custom_mode_end_text_sensor_ != nullptr) {
|
||||
this->custom_mode_end_text_sensor_->publish_state("Setup in progress");
|
||||
}
|
||||
} else if (data[FRAME_COMMAND_WORD_INDEX] == 0x81) {
|
||||
ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]);
|
||||
} else if (data[FRAME_COMMAND_WORD_INDEX] == 0x87) {
|
||||
if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) {
|
||||
this->scene_mode_select_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
} else if ((this->custom_mode_end_text_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x0A)) {
|
||||
this->custom_mode_end_text_sensor_->publish_state("Set Success!");
|
||||
} else if (data[FRAME_COMMAND_WORD_INDEX] == 0x89) {
|
||||
if (data[FRAME_DATA_INDEX] == 0) {
|
||||
if (this->custom_mode_end_text_sensor_ != nullptr) {
|
||||
this->custom_mode_end_text_sensor_->publish_state("Not in custom mode");
|
||||
switch (data[FRAME_COMMAND_WORD_INDEX]) {
|
||||
case 0x01:
|
||||
case 0x81:
|
||||
ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]);
|
||||
break;
|
||||
case 0x09:
|
||||
#ifdef USE_SENSOR
|
||||
if (this->custom_mode_num_sensor_ != nullptr) {
|
||||
this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
if (this->custom_mode_number_ != nullptr) {
|
||||
this->custom_mode_number_->publish_state(0);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (this->custom_mode_end_text_sensor_ != nullptr) {
|
||||
this->custom_mode_end_text_sensor_->publish_state("Setup in progress");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 0x89:
|
||||
#ifdef USE_SENSOR
|
||||
if (this->custom_mode_num_sensor_ != nullptr) {
|
||||
this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
} else {
|
||||
if (this->custom_mode_num_sensor_ != nullptr) {
|
||||
this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
#endif
|
||||
if (data[FRAME_DATA_INDEX] == 0) {
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (this->custom_mode_end_text_sensor_ != nullptr) {
|
||||
this->custom_mode_end_text_sensor_->publish_state("Not in custom mode");
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
if (this->custom_mode_number_ != nullptr) {
|
||||
this->custom_mode_number_->publish_state(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]);
|
||||
break;
|
||||
#ifdef USE_SELECT
|
||||
case 0x07:
|
||||
case 0x87:
|
||||
if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) {
|
||||
this->scene_mode_select_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
case 0x08:
|
||||
case 0x88:
|
||||
if (this->sensitivity_number_ != nullptr) {
|
||||
this->sensitivity_number_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
case 0x0A:
|
||||
if (this->custom_mode_end_text_sensor_ != nullptr) {
|
||||
this->custom_mode_end_text_sensor_->publish_state("Set Success!");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MR24HPC1Component::r24_frame_parse_human_information_(uint8_t *data) {
|
||||
if ((this->has_target_binary_sensor_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x01) || (data[FRAME_COMMAND_WORD_INDEX] == 0x81))) {
|
||||
this->has_target_binary_sensor_->publish_state(S_SOMEONE_EXISTS_STR[data[FRAME_DATA_INDEX]]);
|
||||
} else if ((this->motion_status_text_sensor_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x02) || (data[FRAME_COMMAND_WORD_INDEX] == 0x82))) {
|
||||
if (data[FRAME_DATA_INDEX] < 3) {
|
||||
this->motion_status_text_sensor_->publish_state(S_MOTION_STATUS_STR[data[FRAME_DATA_INDEX]]);
|
||||
}
|
||||
} else if ((this->movement_signs_sensor_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x03) || (data[FRAME_COMMAND_WORD_INDEX] == 0x83))) {
|
||||
this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
} else if ((this->unman_time_select_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x0A) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8A))) {
|
||||
// none:0x00 1s:0x01 30s:0x02 1min:0x03 2min:0x04 5min:0x05 10min:0x06 30min:0x07 1hour:0x08
|
||||
if (data[FRAME_DATA_INDEX] < 9) {
|
||||
this->unman_time_select_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
} else if ((this->keep_away_text_sensor_ != nullptr) &&
|
||||
((data[FRAME_COMMAND_WORD_INDEX] == 0x0B) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8B))) {
|
||||
// none:0x00 close_to:0x01 far_away:0x02
|
||||
if (data[FRAME_DATA_INDEX] < 3) {
|
||||
this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]);
|
||||
switch (data[FRAME_COMMAND_WORD_INDEX]) {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
case 0x01:
|
||||
case 0x81:
|
||||
if (this->has_target_binary_sensor_ != nullptr) {
|
||||
this->has_target_binary_sensor_->publish_state(S_SOMEONE_EXISTS_STR[data[FRAME_DATA_INDEX]]);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
case 0x03:
|
||||
case 0x83:
|
||||
if (this->movement_signs_sensor_ != nullptr) {
|
||||
this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
case 0x02:
|
||||
case 0x82:
|
||||
if ((this->motion_status_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
|
||||
this->motion_status_text_sensor_->publish_state(S_MOTION_STATUS_STR[data[FRAME_DATA_INDEX]]);
|
||||
}
|
||||
break;
|
||||
case 0x0B:
|
||||
case 0x8B:
|
||||
// none:0x00 close_to:0x01 far_away:0x02
|
||||
if ((this->keep_away_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
|
||||
this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
case 0x0A:
|
||||
case 0x8A:
|
||||
// none:0x00 1s:0x01 30s:0x02 1min:0x03 2min:0x04 5min:0x05 10min:0x06 30min:0x07 1hour:0x08
|
||||
if ((this->unman_time_select_ != nullptr) && (data[FRAME_DATA_INDEX] < 9)) {
|
||||
this->unman_time_select_->publish_state(data[FRAME_DATA_INDEX]);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,12 +783,15 @@ void MR24HPC1Component::set_underlying_open_function(bool enable) {
|
||||
} else {
|
||||
this->send_query_(UNDERLYING_SWITCH_OFF, sizeof(UNDERLYING_SWITCH_OFF));
|
||||
}
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (this->keep_away_text_sensor_ != nullptr) {
|
||||
this->keep_away_text_sensor_->publish_state("");
|
||||
}
|
||||
if (this->motion_status_text_sensor_ != nullptr) {
|
||||
this->motion_status_text_sensor_->publish_state("");
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
if (this->custom_spatial_static_value_sensor_ != nullptr) {
|
||||
this->custom_spatial_static_value_sensor_->publish_state(NAN);
|
||||
}
|
||||
@@ -716,6 +807,7 @@ void MR24HPC1Component::set_underlying_open_function(bool enable) {
|
||||
if (this->custom_motion_speed_sensor_ != nullptr) {
|
||||
this->custom_motion_speed_sensor_->publish_state(NAN);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MR24HPC1Component::set_scene_mode(uint8_t value) {
|
||||
@@ -723,12 +815,16 @@ void MR24HPC1Component::set_scene_mode(uint8_t value) {
|
||||
uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x07, 0x00, 0x01, value, 0x00, 0x54, 0x43};
|
||||
send_data[7] = get_frame_crc_sum(send_data, send_data_len);
|
||||
this->send_query_(send_data, send_data_len);
|
||||
#ifdef USE_NUMBER
|
||||
if (this->custom_mode_number_ != nullptr) {
|
||||
this->custom_mode_number_->publish_state(0);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
if (this->custom_mode_num_sensor_ != nullptr) {
|
||||
this->custom_mode_num_sensor_->publish_state(0);
|
||||
}
|
||||
#endif
|
||||
this->get_scene_mode();
|
||||
this->get_sensitivity();
|
||||
this->get_custom_mode();
|
||||
@@ -768,9 +864,11 @@ void MR24HPC1Component::set_unman_time(uint8_t value) {
|
||||
void MR24HPC1Component::set_custom_mode(uint8_t mode) {
|
||||
if (mode == 0) {
|
||||
this->set_custom_end_mode(); // Equivalent to end setting
|
||||
#ifdef USE_NUMBER
|
||||
if (this->custom_mode_number_ != nullptr) {
|
||||
this->custom_mode_number_->publish_state(0);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
uint8_t send_data_len = 10;
|
||||
@@ -793,9 +891,11 @@ void MR24HPC1Component::set_custom_end_mode() {
|
||||
uint8_t send_data_len = 10;
|
||||
uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x0a, 0x00, 0x01, 0x0F, 0xCB, 0x54, 0x43};
|
||||
this->send_query_(send_data, send_data_len);
|
||||
#ifdef USE_NUMBER
|
||||
if (this->custom_mode_number_ != nullptr) {
|
||||
this->custom_mode_number_->publish_state(0); // Clear setpoints
|
||||
}
|
||||
#endif
|
||||
this->get_existence_boundary();
|
||||
this->get_motion_boundary();
|
||||
this->get_existence_threshold();
|
||||
@@ -809,8 +909,10 @@ void MR24HPC1Component::set_custom_end_mode() {
|
||||
}
|
||||
|
||||
void MR24HPC1Component::set_existence_boundary(uint8_t value) {
|
||||
#ifdef USE_SENSOR
|
||||
if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
|
||||
return; // You'll have to check that you're in custom mode to set it up
|
||||
#endif
|
||||
uint8_t send_data_len = 10;
|
||||
uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0A, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43};
|
||||
send_data[7] = get_frame_crc_sum(send_data, send_data_len);
|
||||
@@ -819,8 +921,10 @@ void MR24HPC1Component::set_existence_boundary(uint8_t value) {
|
||||
}
|
||||
|
||||
void MR24HPC1Component::set_motion_boundary(uint8_t value) {
|
||||
#ifdef USE_SENSOR
|
||||
if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
|
||||
return; // You'll have to check that you're in custom mode to set it up
|
||||
#endif
|
||||
uint8_t send_data_len = 10;
|
||||
uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0B, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43};
|
||||
send_data[7] = get_frame_crc_sum(send_data, send_data_len);
|
||||
@@ -829,8 +933,10 @@ void MR24HPC1Component::set_motion_boundary(uint8_t value) {
|
||||
}
|
||||
|
||||
void MR24HPC1Component::set_existence_threshold(uint8_t value) {
|
||||
#ifdef USE_SENSOR
|
||||
if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
|
||||
return; // You'll have to check that you're in custom mode to set it up
|
||||
#endif
|
||||
uint8_t send_data_len = 10;
|
||||
uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x08, 0x00, 0x01, value, 0x00, 0x54, 0x43};
|
||||
send_data[7] = get_frame_crc_sum(send_data, send_data_len);
|
||||
@@ -839,8 +945,10 @@ void MR24HPC1Component::set_existence_threshold(uint8_t value) {
|
||||
}
|
||||
|
||||
void MR24HPC1Component::set_motion_threshold(uint8_t value) {
|
||||
#ifdef USE_SENSOR
|
||||
if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
|
||||
return; // You'll have to check that you're in custom mode to set it up
|
||||
#endif
|
||||
uint8_t send_data_len = 10;
|
||||
uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x09, 0x00, 0x01, value, 0x00, 0x54, 0x43};
|
||||
send_data[7] = get_frame_crc_sum(send_data, send_data_len);
|
||||
@@ -849,8 +957,10 @@ void MR24HPC1Component::set_motion_threshold(uint8_t value) {
|
||||
}
|
||||
|
||||
void MR24HPC1Component::set_motion_trigger_time(uint8_t value) {
|
||||
#ifdef USE_SENSOR
|
||||
if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
|
||||
return; // You'll have to check that you're in custom mode to set it up
|
||||
#endif
|
||||
uint8_t send_data_len = 13;
|
||||
uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, value, 0x00, 0x54, 0x43};
|
||||
send_data[10] = get_frame_crc_sum(send_data, send_data_len);
|
||||
@@ -859,8 +969,10 @@ void MR24HPC1Component::set_motion_trigger_time(uint8_t value) {
|
||||
}
|
||||
|
||||
void MR24HPC1Component::set_motion_to_rest_time(uint16_t value) {
|
||||
#ifdef USE_SENSOR
|
||||
if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
|
||||
return; // You'll have to check that you're in custom mode to set it up
|
||||
#endif
|
||||
uint8_t h8_num = (value >> 8) & 0xff;
|
||||
uint8_t l8_num = value & 0xff;
|
||||
uint8_t send_data_len = 13;
|
||||
@@ -871,8 +983,10 @@ void MR24HPC1Component::set_motion_to_rest_time(uint16_t value) {
|
||||
}
|
||||
|
||||
void MR24HPC1Component::set_custom_unman_time(uint16_t value) {
|
||||
#ifdef USE_SENSOR
|
||||
if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
|
||||
return; // You'll have to check that you're in custom mode to set it up
|
||||
#endif
|
||||
uint32_t value_ms = value * 1000;
|
||||
uint8_t h24_num = (value_ms >> 24) & 0xff;
|
||||
uint8_t h16_num = (value_ms >> 16) & 0xff;
|
||||
|
||||
@@ -9,8 +9,8 @@ namespace uptime {
|
||||
|
||||
static const char *const TAG = "uptime.sensor";
|
||||
|
||||
// Cap position to prevent buffer overflow from snprintf return value
|
||||
inline size_t clamp_buffer_pos(size_t pos, size_t buf_size) { return pos < buf_size ? pos : buf_size - 1; }
|
||||
// Clamp position to valid buffer range when snprintf indicates truncation
|
||||
static size_t clamp_buffer_pos(size_t pos, size_t buf_size) { return pos < buf_size ? pos : buf_size - 1; }
|
||||
|
||||
static void append_unit(char *buf, size_t buf_size, size_t &pos, const char *separator, unsigned value,
|
||||
const char *label) {
|
||||
|
||||
@@ -159,7 +159,8 @@ static const char *const TAG = "wifi";
|
||||
/// │ │
|
||||
/// │ Flow with RetryHiddenMode::BLIND_RETRY: │
|
||||
/// │ │
|
||||
/// │ 1. RESTARTING_ADAPTER → Skip actual restart, just disconnect │
|
||||
/// │ 1. RESTARTING_ADAPTER → In this mode, skip adapter restart and │
|
||||
/// │ just disconnect (normal mode restarts the adapter) │
|
||||
/// │ - Sets retry_hidden_mode_ = BLIND_RETRY │
|
||||
/// │ - Enter extended cooldown (30s vs normal 500ms) │
|
||||
/// │ ↓ │
|
||||
|
||||
+20
-2
@@ -532,6 +532,8 @@ bool str_startswith(const std::string &str, const std::string &start);
|
||||
bool str_endswith(const std::string &str, const std::string &end);
|
||||
|
||||
/// Truncate a string to a specific length.
|
||||
/// @deprecated Allocates heap memory and is unused. Removed in 2026.7.0.
|
||||
ESPDEPRECATED("Allocates heap memory and is unused. Removed in 2026.7.0.", "2026.1.0")
|
||||
std::string str_truncate(const std::string &str, size_t length);
|
||||
|
||||
/// Extract the part of the string until either the first occurrence of the specified character, or the end
|
||||
@@ -543,11 +545,15 @@ std::string str_until(const std::string &str, char ch);
|
||||
/// Convert the string to lower case.
|
||||
std::string str_lower_case(const std::string &str);
|
||||
/// Convert the string to upper case.
|
||||
/// @deprecated Allocates heap memory and is unused. Removed in 2026.7.0.
|
||||
ESPDEPRECATED("Allocates heap memory and is unused. Removed in 2026.7.0.", "2026.1.0")
|
||||
std::string str_upper_case(const std::string &str);
|
||||
|
||||
/// Convert a single char to snake_case: lowercase and space to underscore.
|
||||
constexpr char to_snake_case_char(char c) { return (c == ' ') ? '_' : (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; }
|
||||
/// Convert the string to snake case (lowercase with underscores).
|
||||
/// @deprecated Allocates heap memory and is unused in C++. Removed in 2026.7.0.
|
||||
ESPDEPRECATED("Allocates heap memory and is unused in C++. Removed in 2026.7.0.", "2026.1.0")
|
||||
std::string str_snake_case(const std::string &str);
|
||||
|
||||
/// Sanitize a single char: keep alphanumerics, dashes, underscores; replace others with underscore.
|
||||
@@ -862,17 +868,29 @@ inline void format_mac_addr_lower_no_sep(const uint8_t *mac, char *output) {
|
||||
}
|
||||
|
||||
/// Format the six-byte array \p mac into a MAC address.
|
||||
/// @deprecated Allocates heap memory. Use format_mac_addr_upper() with a stack buffer instead. Removed in 2026.7.0.
|
||||
ESPDEPRECATED("Allocates heap memory. Use format_mac_addr_upper() with stack buffer. Removed in 2026.7.0.", "2026.1.0")
|
||||
std::string format_mac_address_pretty(const uint8_t mac[6]);
|
||||
/// Format the byte array \p data of length \p len in lowercased hex.
|
||||
/// @deprecated Allocates heap memory. Use format_hex_to() with a stack buffer instead. Removed in 2026.7.0.
|
||||
ESPDEPRECATED("Allocates heap memory. Use format_hex_to() with stack buffer. Removed in 2026.7.0.", "2026.1.0")
|
||||
std::string format_hex(const uint8_t *data, size_t length);
|
||||
/// Format the vector \p data in lowercased hex.
|
||||
/// @deprecated Allocates heap memory. Use format_hex_to() with a stack buffer instead. Removed in 2026.7.0.
|
||||
ESPDEPRECATED("Allocates heap memory. Use format_hex_to() with stack buffer. Removed in 2026.7.0.", "2026.1.0")
|
||||
std::string format_hex(const std::vector<uint8_t> &data);
|
||||
/// Format an unsigned integer in lowercased hex, starting with the most significant byte.
|
||||
template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> std::string format_hex(T val) {
|
||||
/// @deprecated Allocates heap memory. Use format_hex_to() with a stack buffer instead. Removed in 2026.7.0.
|
||||
template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
|
||||
ESPDEPRECATED("Allocates heap memory. Use format_hex_to() with stack buffer. Removed in 2026.7.0.", "2026.1.0")
|
||||
std::string format_hex(T val) {
|
||||
val = convert_big_endian(val);
|
||||
return format_hex(reinterpret_cast<uint8_t *>(&val), sizeof(T));
|
||||
}
|
||||
template<std::size_t N> std::string format_hex(const std::array<uint8_t, N> &data) {
|
||||
/// @deprecated Allocates heap memory. Use format_hex_to() with a stack buffer instead. Removed in 2026.7.0.
|
||||
template<std::size_t N>
|
||||
ESPDEPRECATED("Allocates heap memory. Use format_hex_to() with stack buffer. Removed in 2026.7.0.", "2026.1.0")
|
||||
std::string format_hex(const std::array<uint8_t, N> &data) {
|
||||
return format_hex(data.data(), data.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ class Platform(StrEnum):
|
||||
ESP32_S2_IDF = "esp32-s2-idf"
|
||||
ESP32_S3_IDF = "esp32-s3-idf"
|
||||
BK72XX_ARD = "bk72xx-ard" # LibreTiny BK7231N
|
||||
RP2040_ARD = "rp2040-ard" # Raspberry Pi Pico
|
||||
|
||||
|
||||
# Memory impact analysis constants
|
||||
@@ -122,6 +123,7 @@ PLATFORM_SPECIFIC_COMPONENTS = frozenset(
|
||||
# 3. ESP32 IDF - Primary ESP32 platform, most representative of modern ESPHome
|
||||
# 4-6. Other ESP32 variants - Less commonly used but still supported
|
||||
# 7. BK72XX - LibreTiny platform (good for detecting LibreTiny-specific changes)
|
||||
# 8. RP2040 - Raspberry Pi Pico platform
|
||||
MEMORY_IMPACT_PLATFORM_PREFERENCE = [
|
||||
Platform.ESP32_C6_IDF, # ESP32-C6 IDF (newest, supports Thread/Zigbee)
|
||||
Platform.ESP8266_ARD, # ESP8266 Arduino (most memory constrained, fastest builds)
|
||||
@@ -130,6 +132,7 @@ MEMORY_IMPACT_PLATFORM_PREFERENCE = [
|
||||
Platform.ESP32_S2_IDF, # ESP32-S2 IDF
|
||||
Platform.ESP32_S3_IDF, # ESP32-S3 IDF
|
||||
Platform.BK72XX_ARD, # LibreTiny BK7231N
|
||||
Platform.RP2040_ARD, # Raspberry Pi Pico
|
||||
]
|
||||
|
||||
|
||||
@@ -408,7 +411,7 @@ def _detect_platform_hint_from_filename(filename: str) -> Platform | None:
|
||||
- wifi_component_esp8266.cpp, *_esp8266.h -> ESP8266_ARD
|
||||
- *_esp32*.cpp -> ESP32 IDF (generic)
|
||||
- *_libretiny.cpp, *_bk72*.* -> BK72XX (LibreTiny)
|
||||
- *_pico.cpp, *_rp2040.* -> RP2040 (not in preference list)
|
||||
- *_pico.cpp, *_rp2040.* -> RP2040_ARD
|
||||
|
||||
Args:
|
||||
filename: File path to check
|
||||
@@ -445,9 +448,9 @@ def _detect_platform_hint_from_filename(filename: str) -> Platform | None:
|
||||
if "libretiny" in filename_lower or "bk72" in filename_lower:
|
||||
return Platform.BK72XX_ARD
|
||||
|
||||
# RP2040 is not in MEMORY_IMPACT_PLATFORM_PREFERENCE
|
||||
# if "pico" in filename_lower or "rp2040" in filename_lower:
|
||||
# return None # No RP2040 platform preference
|
||||
# RP2040 / Raspberry Pi Pico
|
||||
if "pico" in filename_lower or "rp2040" in filename_lower:
|
||||
return Platform.RP2040_ARD
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -1421,6 +1421,135 @@ def test_detect_memory_impact_config_runs_at_component_limit(tmp_path: Path) ->
|
||||
assert len(result["components"]) == 40
|
||||
|
||||
|
||||
# Tests for _detect_platform_hint_from_filename function
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("filename", "expected_platform"),
|
||||
[
|
||||
# ESP-IDF platform detection
|
||||
("esphome/components/wifi/wifi_esp_idf.cpp", determine_jobs.Platform.ESP32_IDF),
|
||||
(
|
||||
"esphome/components/wifi/wifi_component_esp_idf.cpp",
|
||||
determine_jobs.Platform.ESP32_IDF,
|
||||
),
|
||||
(
|
||||
"esphome/components/ethernet/ethernet_idf.cpp",
|
||||
determine_jobs.Platform.ESP32_IDF,
|
||||
),
|
||||
# ESP32 variant detection with IDF suffix
|
||||
(
|
||||
"esphome/components/ble/esp32c3_idf.cpp",
|
||||
determine_jobs.Platform.ESP32_C3_IDF,
|
||||
),
|
||||
(
|
||||
"esphome/components/ble/esp32c6_idf.cpp",
|
||||
determine_jobs.Platform.ESP32_C6_IDF,
|
||||
),
|
||||
(
|
||||
"esphome/components/ble/esp32s2_idf.cpp",
|
||||
determine_jobs.Platform.ESP32_S2_IDF,
|
||||
),
|
||||
(
|
||||
"esphome/components/ble/esp32s3_idf.cpp",
|
||||
determine_jobs.Platform.ESP32_S3_IDF,
|
||||
),
|
||||
# ESP8266 detection
|
||||
(
|
||||
"esphome/components/wifi/wifi_esp8266.cpp",
|
||||
determine_jobs.Platform.ESP8266_ARD,
|
||||
),
|
||||
("esphome/core/helpers_esp8266.h", determine_jobs.Platform.ESP8266_ARD),
|
||||
# Generic ESP32 detection (without IDF suffix)
|
||||
("esphome/components/wifi/wifi_esp32.cpp", determine_jobs.Platform.ESP32_IDF),
|
||||
(
|
||||
"esphome/components/ethernet/ethernet_esp32.cpp",
|
||||
determine_jobs.Platform.ESP32_IDF,
|
||||
),
|
||||
# LibreTiny / BK72xx detection
|
||||
(
|
||||
"esphome/components/wifi/wifi_libretiny.cpp",
|
||||
determine_jobs.Platform.BK72XX_ARD,
|
||||
),
|
||||
("esphome/components/ble/ble_bk72xx.cpp", determine_jobs.Platform.BK72XX_ARD),
|
||||
# RP2040 / Raspberry Pi Pico detection
|
||||
("esphome/components/gpio/gpio_rp2040.cpp", determine_jobs.Platform.RP2040_ARD),
|
||||
("esphome/components/wifi/wifi_rp2040.cpp", determine_jobs.Platform.RP2040_ARD),
|
||||
("esphome/components/i2c/i2c_pico.cpp", determine_jobs.Platform.RP2040_ARD),
|
||||
("esphome/components/spi/spi_pico.cpp", determine_jobs.Platform.RP2040_ARD),
|
||||
(
|
||||
"tests/components/rp2040/test.rp2040-ard.yaml",
|
||||
determine_jobs.Platform.RP2040_ARD,
|
||||
),
|
||||
# No platform hint (generic files)
|
||||
("esphome/components/wifi/wifi.cpp", None),
|
||||
("esphome/components/sensor/sensor.h", None),
|
||||
("esphome/core/helpers.h", None),
|
||||
("README.md", None),
|
||||
],
|
||||
ids=[
|
||||
"esp_idf_suffix",
|
||||
"esp_idf_component_suffix",
|
||||
"idf_suffix",
|
||||
"esp32c3_idf",
|
||||
"esp32c6_idf",
|
||||
"esp32s2_idf",
|
||||
"esp32s3_idf",
|
||||
"esp8266_suffix",
|
||||
"esp8266_core_header",
|
||||
"generic_esp32",
|
||||
"esp32_in_name",
|
||||
"libretiny",
|
||||
"bk72xx",
|
||||
"rp2040_gpio",
|
||||
"rp2040_wifi",
|
||||
"pico_i2c",
|
||||
"pico_spi",
|
||||
"rp2040_test_yaml",
|
||||
"generic_wifi_no_hint",
|
||||
"generic_sensor_no_hint",
|
||||
"core_helpers_no_hint",
|
||||
"readme_no_hint",
|
||||
],
|
||||
)
|
||||
def test_detect_platform_hint_from_filename(
|
||||
filename: str, expected_platform: determine_jobs.Platform | None
|
||||
) -> None:
|
||||
"""Test _detect_platform_hint_from_filename correctly detects platform hints."""
|
||||
result = determine_jobs._detect_platform_hint_from_filename(filename)
|
||||
assert result == expected_platform
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("filename", "expected_platform"),
|
||||
[
|
||||
# RP2040/Pico with different cases
|
||||
("file_RP2040.cpp", determine_jobs.Platform.RP2040_ARD),
|
||||
("file_Rp2040.cpp", determine_jobs.Platform.RP2040_ARD),
|
||||
("file_PICO.cpp", determine_jobs.Platform.RP2040_ARD),
|
||||
("file_Pico.cpp", determine_jobs.Platform.RP2040_ARD),
|
||||
# ESP8266 with different cases
|
||||
("file_ESP8266.cpp", determine_jobs.Platform.ESP8266_ARD),
|
||||
# ESP32 with different cases
|
||||
("file_ESP32.cpp", determine_jobs.Platform.ESP32_IDF),
|
||||
],
|
||||
ids=[
|
||||
"rp2040_uppercase",
|
||||
"rp2040_mixedcase",
|
||||
"pico_uppercase",
|
||||
"pico_titlecase",
|
||||
"esp8266_uppercase",
|
||||
"esp32_uppercase",
|
||||
],
|
||||
)
|
||||
def test_detect_platform_hint_from_filename_case_insensitive(
|
||||
filename: str, expected_platform: determine_jobs.Platform
|
||||
) -> None:
|
||||
"""Test that platform detection is case-insensitive."""
|
||||
result = determine_jobs._detect_platform_hint_from_filename(filename)
|
||||
assert result == expected_platform
|
||||
|
||||
|
||||
def test_component_batching_beta_branch_40_per_batch(
|
||||
tmp_path: Path,
|
||||
mock_should_run_integration_tests: Mock,
|
||||
|
||||
Reference in New Issue
Block a user