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:
@@ -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]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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_(wifi_csi_info_t *info) {
|
void MotionMapComponent::process_csi_data_() {
|
||||||
|
if (!this->csi_buffer_.valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user