1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-18 15:55:46 +00:00

[motion_map] Fix threading, logging, and remove ESP-IDF restriction

Critical fixes based on review feedback:

Threading fixes:
- CSI callback now only copies data to buffer (runs in WiFi task)
- Actual processing moved to loop() in main task context
- Added CSIDataBuffer structure for safe cross-task communication
- Prevents race conditions and task priority issues

Logging improvements:
- Combined related config messages with newlines (reduces packets)
- Changed verbose logs to ESP_LOGV (state changes)
- Changed info logs to ESP_LOGD (initialization)
- Only warn if CSI fails to initialize
- Removed redundant setup message

Configuration:
- Removed cv.only_with_esp_idf restriction
- C++ guards (#ifdef USE_ESP_IDF) already handle this
- ESP32-S3 variant restriction remains (CSI requirement)

These changes ensure proper task safety and follow ESPHome
logging best practices for network efficiency.
This commit is contained in:
Claude
2025-11-17 23:34:32 +00:00
parent 755357b7c6
commit 23624aff09
3 changed files with 48 additions and 33 deletions

View File

@@ -49,7 +49,6 @@ CONFIG_SCHEMA = cv.All(
), ),
} }
), ),
cv.only_with_esp_idf,
only_on_variant(supported=[VARIANT_ESP32S3]), only_on_variant(supported=[VARIANT_ESP32S3]),
) )

View File

@@ -12,8 +12,6 @@ namespace motion_map {
static const char *const TAG = "motion_map"; static const char *const TAG = "motion_map";
void MotionMapComponent::setup() { void MotionMapComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up Motion Map...");
// Reserve space for variance window // Reserve space for variance window
this->variance_window_.reserve(this->window_size_); this->variance_window_.reserve(this->window_size_);
@@ -22,6 +20,12 @@ void MotionMapComponent::setup() {
} }
void MotionMapComponent::loop() { void MotionMapComponent::loop() {
// Process new CSI data if available
if (this->new_csi_data_) {
this->new_csi_data_ = false;
this->process_csi_data_();
}
// Periodic sensor publishing (every 1 second) // Periodic sensor publishing (every 1 second)
uint32_t now = millis(); uint32_t now = millis();
if (now - this->last_update_time_ >= 1000) { if (now - this->last_update_time_ >= 1000) {
@@ -32,16 +36,16 @@ void MotionMapComponent::loop() {
void MotionMapComponent::dump_config() { void MotionMapComponent::dump_config() {
ESP_LOGCONFIG(TAG, "Motion Map:"); ESP_LOGCONFIG(TAG, "Motion Map:");
ESP_LOGCONFIG(TAG, " Motion Threshold: %.2f", this->motion_threshold_); ESP_LOGCONFIG(TAG, " Motion Threshold: %.2f\n Idle Threshold: %.2f\n Window Size: %u\n Sensitivity: %.2f",
ESP_LOGCONFIG(TAG, " Idle Threshold: %.2f", this->idle_threshold_); this->motion_threshold_, this->idle_threshold_, this->window_size_, this->sensitivity_);
ESP_LOGCONFIG(TAG, " Window Size: %u", this->window_size_);
ESP_LOGCONFIG(TAG, " Sensitivity: %.2f", this->sensitivity_);
if (this->mac_address_.has_value()) { if (this->mac_address_.has_value()) {
ESP_LOGCONFIG(TAG, " MAC Filter: %02X:%02X:%02X:%02X:%02X:%02X", (*this->mac_address_)[0], ESP_LOGCONFIG(TAG, " MAC Filter: %02X:%02X:%02X:%02X:%02X:%02X", (*this->mac_address_)[0],
(*this->mac_address_)[1], (*this->mac_address_)[2], (*this->mac_address_)[3], (*this->mac_address_)[1], (*this->mac_address_)[2], (*this->mac_address_)[3],
(*this->mac_address_)[4], (*this->mac_address_)[5]); (*this->mac_address_)[4], (*this->mac_address_)[5]);
} }
ESP_LOGCONFIG(TAG, " CSI Initialized: %s", this->csi_initialized_ ? "YES" : "NO"); if (!this->csi_initialized_) {
ESP_LOGW(TAG, "CSI not initialized");
}
} }
void MotionMapComponent::init_csi_() { void MotionMapComponent::init_csi_() {
@@ -76,22 +80,35 @@ void MotionMapComponent::init_csi_() {
} }
this->csi_initialized_ = true; this->csi_initialized_ = true;
ESP_LOGI(TAG, "CSI initialized successfully"); ESP_LOGD(TAG, "CSI initialized");
} }
void MotionMapComponent::csi_callback_(void *ctx, wifi_csi_info_t *info) { void MotionMapComponent::csi_callback_(void *ctx, wifi_csi_info_t *info) {
auto *component = static_cast<MotionMapComponent *>(ctx); auto *component = static_cast<MotionMapComponent *>(ctx);
if (component != nullptr && info != nullptr) { if (component == nullptr || info == nullptr || info->buf == nullptr || info->len == 0) {
component->process_csi_(info); return;
} }
// Copy CSI data to buffer for processing in main loop
// This callback runs in WiFi task context
size_t len = std::min(static_cast<size_t>(info->len), MAX_CSI_LEN);
memcpy(component->csi_buffer_.data.data(), info->buf, len);
component->csi_buffer_.len = len;
memcpy(component->csi_buffer_.mac.data(), info->mac, 6);
component->csi_buffer_.valid = true;
component->new_csi_data_ = true;
}
void MotionMapComponent::process_csi_data_() {
if (!this->csi_buffer_.valid) {
return;
} }
void MotionMapComponent::process_csi_(wifi_csi_info_t *info) {
// Filter by MAC address if configured // Filter by MAC address if configured
if (this->mac_address_.has_value()) { if (this->mac_address_.has_value()) {
bool mac_match = true; bool mac_match = true;
for (size_t i = 0; i < 6; i++) { for (size_t i = 0; i < 6; i++) {
if (info->mac[i] != (*this->mac_address_)[i]) { if (this->csi_buffer_.mac[i] != (*this->mac_address_)[i]) {
mac_match = false; mac_match = false;
break; break;
} }
@@ -101,13 +118,9 @@ void MotionMapComponent::process_csi_(wifi_csi_info_t *info) {
} }
} }
// Extract CSI data // Extract CSI data from buffer
const int8_t *csi_data = info->buf; const int8_t *csi_data = this->csi_buffer_.data.data();
size_t csi_len = info->len; size_t csi_len = this->csi_buffer_.len;
if (csi_data == nullptr || csi_len == 0) {
return;
}
// Calculate variance and amplitude // Calculate variance and amplitude
float variance = this->calculate_variance_(csi_data, csi_len); float variance = this->calculate_variance_(csi_data, csi_len);
@@ -253,7 +266,7 @@ void MotionMapComponent::update_motion_state_(float variance) {
// Update state if changed // Update state if changed
if (new_state != this->current_state_) { if (new_state != this->current_state_) {
this->current_state_ = new_state; this->current_state_ = new_state;
ESP_LOGD(TAG, "Motion state changed: %s", new_state == MotionState::MOTION ? "MOTION" : "IDLE"); ESP_LOGV(TAG, "State: %s", new_state == MotionState::MOTION ? "MOTION" : "IDLE");
// Publish binary sensor immediately on state change // Publish binary sensor immediately on state change
if (this->motion_binary_sensor_ != nullptr) { if (this->motion_binary_sensor_ != nullptr) {

View File

@@ -29,11 +29,15 @@ enum class MotionState : uint8_t {
MOTION = 1, MOTION = 1,
}; };
/// CSI data structure for storing subcarrier amplitude variance /// Maximum CSI buffer size for ESP32-S3
struct CSIData { static constexpr size_t MAX_CSI_LEN = 384;
float variance{0.0f};
float amplitude{0.0f}; /// CSI data buffer for cross-task communication
uint32_t timestamp{0}; struct CSIDataBuffer {
std::array<int8_t, MAX_CSI_LEN> data;
size_t len{0};
std::array<uint8_t, 6> mac;
bool valid{false};
}; };
/** /**
@@ -67,11 +71,11 @@ class MotionMapComponent : public Component {
/// Initialize CSI capture /// Initialize CSI capture
void init_csi_(); void init_csi_();
/// CSI callback (static wrapper for ESP-IDF) /// CSI callback (static wrapper for ESP-IDF) - runs in WiFi task
static void csi_callback_(void *ctx, wifi_csi_info_t *info); static void csi_callback_(void *ctx, wifi_csi_info_t *info);
/// Process CSI data /// Process CSI data in main loop
void process_csi_(wifi_csi_info_t *info); void process_csi_data_();
/// Calculate variance from CSI data /// Calculate variance from CSI data
float calculate_variance_(const int8_t *data, size_t len); float calculate_variance_(const int8_t *data, size_t len);
@@ -113,10 +117,9 @@ class MotionMapComponent : public Component {
uint32_t last_update_time_{0}; uint32_t last_update_time_{0};
bool csi_initialized_{false}; bool csi_initialized_{false};
// Statistics for moving variance // CSI data buffer (written by WiFi task, read by main loop)
float moving_sum_{0.0f}; CSIDataBuffer csi_buffer_;
float moving_sum_sq_{0.0f}; volatile bool new_csi_data_{false};
uint32_t sample_count_{0};
}; };
} // namespace motion_map } // namespace motion_map