1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-18 07:45:56 +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]),
)

View File

@@ -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<MotionMapComponent *>(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<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
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) {

View File

@@ -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<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
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