From ebf13a0ba0a48453c2cc80bfc942d6a588859233 Mon Sep 17 00:00:00 2001 From: Trevor North Date: Tue, 26 Apr 2022 20:51:22 +0100 Subject: [PATCH] Queue sensor publishes so we don't block for too long (#3422) --- .../components/bme680_bsec/bme680_bsec.cpp | 44 ++++++++++++------- esphome/components/bme680_bsec/bme680_bsec.h | 8 +++- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/esphome/components/bme680_bsec/bme680_bsec.cpp b/esphome/components/bme680_bsec/bme680_bsec.cpp index 0a8ca7f3c3..b84ca3318b 100644 --- a/esphome/components/bme680_bsec/bme680_bsec.cpp +++ b/esphome/components/bme680_bsec/bme680_bsec.cpp @@ -169,6 +169,14 @@ void BME680BSECComponent::loop() { } else { this->status_clear_warning(); } + + // Process a single action from the queue. These are primarily sensor state publishes + // that in totality take too long to send in a single call. + if (this->queue_.size()) { + auto action = std::move(this->queue_.front()); + this->queue_.pop(); + action(); + } } void BME680BSECComponent::run_() { @@ -306,37 +314,39 @@ void BME680BSECComponent::read_(int64_t trigger_time_ns, bsec_bme_settings_t bme } void BME680BSECComponent::publish_(const bsec_output_t *outputs, uint8_t num_outputs) { - ESP_LOGV(TAG, "Publishing sensor states"); + ESP_LOGV(TAG, "Queuing sensor state publish actions"); for (uint8_t i = 0; i < num_outputs; i++) { + float signal = outputs[i].signal; switch (outputs[i].sensor_id) { case BSEC_OUTPUT_IAQ: - case BSEC_OUTPUT_STATIC_IAQ: - uint8_t accuracy; - accuracy = outputs[i].accuracy; - this->publish_sensor_state_(this->iaq_sensor_, outputs[i].signal); - this->publish_sensor_state_(this->iaq_accuracy_text_sensor_, IAQ_ACCURACY_STATES[accuracy]); - this->publish_sensor_state_(this->iaq_accuracy_sensor_, accuracy, true); + case BSEC_OUTPUT_STATIC_IAQ: { + uint8_t accuracy = outputs[i].accuracy; + this->queue_push_([this, signal]() { this->publish_sensor_(this->iaq_sensor_, signal); }); + this->queue_push_([this, accuracy]() { + this->publish_sensor_(this->iaq_accuracy_text_sensor_, IAQ_ACCURACY_STATES[accuracy]); + }); + this->queue_push_([this, accuracy]() { this->publish_sensor_(this->iaq_accuracy_sensor_, accuracy, true); }); // Queue up an opportunity to save state - this->defer("save_state", [this, accuracy]() { this->save_state_(accuracy); }); - break; + this->queue_push_([this, accuracy]() { this->save_state_(accuracy); }); + } break; case BSEC_OUTPUT_CO2_EQUIVALENT: - this->publish_sensor_state_(this->co2_equivalent_sensor_, outputs[i].signal); + this->queue_push_([this, signal]() { this->publish_sensor_(this->co2_equivalent_sensor_, signal); }); break; case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT: - this->publish_sensor_state_(this->breath_voc_equivalent_sensor_, outputs[i].signal); + this->queue_push_([this, signal]() { this->publish_sensor_(this->breath_voc_equivalent_sensor_, signal); }); break; case BSEC_OUTPUT_RAW_PRESSURE: - this->publish_sensor_state_(this->pressure_sensor_, outputs[i].signal / 100.0f); + this->queue_push_([this, signal]() { this->publish_sensor_(this->pressure_sensor_, signal / 100.0f); }); break; case BSEC_OUTPUT_RAW_GAS: - this->publish_sensor_state_(this->gas_resistance_sensor_, outputs[i].signal); + this->queue_push_([this, signal]() { this->publish_sensor_(this->gas_resistance_sensor_, signal); }); break; case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE: - this->publish_sensor_state_(this->temperature_sensor_, outputs[i].signal); + this->queue_push_([this, signal]() { this->publish_sensor_(this->temperature_sensor_, signal); }); break; case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY: - this->publish_sensor_state_(this->humidity_sensor_, outputs[i].signal); + this->queue_push_([this, signal]() { this->publish_sensor_(this->humidity_sensor_, signal); }); break; } } @@ -352,14 +362,14 @@ int64_t BME680BSECComponent::get_time_ns_() { return (time_ms + ((int64_t) this->millis_overflow_counter_ << 32)) * INT64_C(1000000); } -void BME680BSECComponent::publish_sensor_state_(sensor::Sensor *sensor, float value, bool change_only) { +void BME680BSECComponent::publish_sensor_(sensor::Sensor *sensor, float value, bool change_only) { if (!sensor || (change_only && sensor->has_state() && sensor->state == value)) { return; } sensor->publish_state(value); } -void BME680BSECComponent::publish_sensor_state_(text_sensor::TextSensor *sensor, const std::string &value) { +void BME680BSECComponent::publish_sensor_(text_sensor::TextSensor *sensor, const std::string &value) { if (!sensor || (sensor->has_state() && sensor->state == value)) { return; } diff --git a/esphome/components/bme680_bsec/bme680_bsec.h b/esphome/components/bme680_bsec/bme680_bsec.h index 53bc5c3280..650b4d2413 100644 --- a/esphome/components/bme680_bsec/bme680_bsec.h +++ b/esphome/components/bme680_bsec/bme680_bsec.h @@ -70,12 +70,14 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice { void publish_(const bsec_output_t *outputs, uint8_t num_outputs); int64_t get_time_ns_(); - void publish_sensor_state_(sensor::Sensor *sensor, float value, bool change_only = false); - void publish_sensor_state_(text_sensor::TextSensor *sensor, const std::string &value); + void publish_sensor_(sensor::Sensor *sensor, float value, bool change_only = false); + void publish_sensor_(text_sensor::TextSensor *sensor, const std::string &value); void load_state_(); void save_state_(uint8_t accuracy); + void queue_push_(std::function &&f) { this->queue_.push(std::move(f)); } + struct bme680_dev bme680_; bsec_library_return_t bsec_status_{BSEC_OK}; int8_t bme680_status_{BME680_OK}; @@ -84,6 +86,8 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice { uint32_t millis_overflow_counter_{0}; int64_t next_call_ns_{0}; + std::queue> queue_; + ESPPreferenceObject bsec_state_; uint32_t state_save_interval_ms_{21600000}; // 6 hours - 4 times a day uint32_t last_state_save_ms_ = 0;