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:
@@ -49,7 +49,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.only_with_esp_idf,
|
||||
only_on_variant(supported=[VARIANT_ESP32S3]),
|
||||
)
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user