diff --git a/esphome/components/motion_map/__init__.py b/esphome/components/motion_map/__init__.py index b05e57bf21..a60a74950f 100644 --- a/esphome/components/motion_map/__init__.py +++ b/esphome/components/motion_map/__init__.py @@ -49,7 +49,6 @@ CONFIG_SCHEMA = cv.All( ), } ), - cv.only_with_esp_idf, only_on_variant(supported=[VARIANT_ESP32S3]), ) diff --git a/esphome/components/motion_map/motion_map.cpp b/esphome/components/motion_map/motion_map.cpp index 38f9385cb4..4129854b69 100644 --- a/esphome/components/motion_map/motion_map.cpp +++ b/esphome/components/motion_map/motion_map.cpp @@ -12,8 +12,6 @@ namespace motion_map { static const char *const TAG = "motion_map"; void MotionMapComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up Motion Map..."); - // Reserve space for variance window this->variance_window_.reserve(this->window_size_); @@ -22,6 +20,12 @@ void MotionMapComponent::setup() { } 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) uint32_t now = millis(); if (now - this->last_update_time_ >= 1000) { @@ -32,16 +36,16 @@ void MotionMapComponent::loop() { void MotionMapComponent::dump_config() { ESP_LOGCONFIG(TAG, "Motion Map:"); - ESP_LOGCONFIG(TAG, " Motion Threshold: %.2f", this->motion_threshold_); - ESP_LOGCONFIG(TAG, " Idle Threshold: %.2f", this->idle_threshold_); - ESP_LOGCONFIG(TAG, " Window Size: %u", this->window_size_); - ESP_LOGCONFIG(TAG, " Sensitivity: %.2f", this->sensitivity_); + ESP_LOGCONFIG(TAG, " Motion Threshold: %.2f\n Idle Threshold: %.2f\n Window Size: %u\n Sensitivity: %.2f", + this->motion_threshold_, this->idle_threshold_, this->window_size_, this->sensitivity_); if (this->mac_address_.has_value()) { 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_)[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_() { @@ -76,22 +80,35 @@ void MotionMapComponent::init_csi_() { } 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) { auto *component = static_cast(ctx); - if (component != nullptr && info != nullptr) { - component->process_csi_(info); + if (component == nullptr || info == nullptr || info->buf == nullptr || info->len == 0) { + 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(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_(wifi_csi_info_t *info) { +void MotionMapComponent::process_csi_data_() { + if (!this->csi_buffer_.valid) { + return; + } + // Filter by MAC address if configured if (this->mac_address_.has_value()) { bool mac_match = true; 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; break; } @@ -101,13 +118,9 @@ void MotionMapComponent::process_csi_(wifi_csi_info_t *info) { } } - // Extract CSI data - const int8_t *csi_data = info->buf; - size_t csi_len = info->len; - - if (csi_data == nullptr || csi_len == 0) { - return; - } + // Extract CSI data from buffer + const int8_t *csi_data = this->csi_buffer_.data.data(); + size_t csi_len = this->csi_buffer_.len; // Calculate variance and amplitude float variance = this->calculate_variance_(csi_data, csi_len); @@ -253,7 +266,7 @@ void MotionMapComponent::update_motion_state_(float variance) { // Update state if changed if (new_state != this->current_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 if (this->motion_binary_sensor_ != nullptr) { diff --git a/esphome/components/motion_map/motion_map.h b/esphome/components/motion_map/motion_map.h index c67d453ac3..e2be7c43d2 100644 --- a/esphome/components/motion_map/motion_map.h +++ b/esphome/components/motion_map/motion_map.h @@ -29,11 +29,15 @@ enum class MotionState : uint8_t { MOTION = 1, }; -/// CSI data structure for storing subcarrier amplitude variance -struct CSIData { - float variance{0.0f}; - float amplitude{0.0f}; - uint32_t timestamp{0}; +/// Maximum CSI buffer size for ESP32-S3 +static constexpr size_t MAX_CSI_LEN = 384; + +/// CSI data buffer for cross-task communication +struct CSIDataBuffer { + std::array data; + size_t len{0}; + std::array mac; + bool valid{false}; }; /** @@ -67,11 +71,11 @@ class MotionMapComponent : public Component { /// Initialize CSI capture 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); - /// Process CSI data - void process_csi_(wifi_csi_info_t *info); + /// Process CSI data in main loop + void process_csi_data_(); /// Calculate variance from CSI data float calculate_variance_(const int8_t *data, size_t len); @@ -113,10 +117,9 @@ class MotionMapComponent : public Component { uint32_t last_update_time_{0}; bool csi_initialized_{false}; - // Statistics for moving variance - float moving_sum_{0.0f}; - float moving_sum_sq_{0.0f}; - uint32_t sample_count_{0}; + // CSI data buffer (written by WiFi task, read by main loop) + CSIDataBuffer csi_buffer_; + volatile bool new_csi_data_{false}; }; } // namespace motion_map