mirror of
https://github.com/esphome/esphome.git
synced 2026-08-18 03:59:08 +08:00
[sgp4x] Fix sgp4x VOC baseline restoration (#15667)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
Keith Burzinski
pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
parent
dd2fbdd43a
commit
427a504308
@@ -52,29 +52,6 @@ void SGP4xComponent::setup() {
|
||||
|
||||
ESP_LOGD(TAG, "Version 0x%0X", featureset);
|
||||
|
||||
if (this->store_baseline_) {
|
||||
// Hash with config hash, version, and serial number
|
||||
// This ensures the baseline storage is cleared after OTA
|
||||
// Serial numbers are unique to each sensor, so multiple sensors can be used without conflict
|
||||
uint32_t hash = fnv1a_hash_extend(App.get_config_version_hash(), this->serial_number_);
|
||||
this->pref_ = global_preferences->make_preference<SGP4xBaselines>(hash, true);
|
||||
|
||||
if (this->pref_.load(&this->voc_baselines_storage_)) {
|
||||
this->voc_state0_ = this->voc_baselines_storage_.state0;
|
||||
this->voc_state1_ = this->voc_baselines_storage_.state1;
|
||||
ESP_LOGV(TAG, "Loaded VOC baseline state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32,
|
||||
this->voc_baselines_storage_.state0, voc_baselines_storage_.state1);
|
||||
}
|
||||
|
||||
// Initialize storage timestamp
|
||||
this->seconds_since_last_store_ = 0;
|
||||
|
||||
if (this->voc_baselines_storage_.state0 > 0 && this->voc_baselines_storage_.state1 > 0) {
|
||||
ESP_LOGV(TAG, "Setting VOC baseline from save state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32,
|
||||
this->voc_baselines_storage_.state0, voc_baselines_storage_.state1);
|
||||
voc_algorithm_.set_states(this->voc_baselines_storage_.state0, this->voc_baselines_storage_.state1);
|
||||
}
|
||||
}
|
||||
if (this->voc_sensor_ && this->voc_tuning_params_.has_value()) {
|
||||
voc_algorithm_.set_tuning_parameters(
|
||||
voc_tuning_params_.value().index_offset, voc_tuning_params_.value().learning_time_offset_hours,
|
||||
@@ -89,6 +66,31 @@ void SGP4xComponent::setup() {
|
||||
nox_tuning_params_.value().std_initial, nox_tuning_params_.value().gain_factor);
|
||||
}
|
||||
|
||||
if (this->store_baseline_) {
|
||||
// Initialize storage timestamp
|
||||
this->seconds_since_last_store_ = 0;
|
||||
|
||||
// Hash with config hash, version, and serial number
|
||||
// This ensures the baseline storage is cleared after OTA
|
||||
// Serial numbers are unique to each sensor, so multiple sensors can be used without conflict
|
||||
uint32_t hash = fnv1a_hash_extend(App.get_config_version_hash(), this->serial_number_);
|
||||
this->pref_ = global_preferences->make_preference<SGP4xBaselines>(hash, true);
|
||||
|
||||
if (this->pref_.load(&this->voc_baselines_storage_)) {
|
||||
this->voc_state0_ = this->voc_baselines_storage_.state0;
|
||||
this->voc_state1_ = this->voc_baselines_storage_.state1;
|
||||
|
||||
ESP_LOGV(TAG, "Loaded VOC baseline state0: %f, state1: %f", this->voc_baselines_storage_.state0,
|
||||
this->voc_baselines_storage_.state1);
|
||||
|
||||
if (std::isnormal(this->voc_baselines_storage_.state0) && std::isnormal(this->voc_baselines_storage_.state1)) {
|
||||
ESP_LOGV(TAG, "Setting VOC baseline from save state0: %f, state1: %f", this->voc_baselines_storage_.state0,
|
||||
this->voc_baselines_storage_.state1);
|
||||
voc_algorithm_.set_states(this->voc_baselines_storage_.state0, this->voc_baselines_storage_.state1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->self_test_();
|
||||
|
||||
/* The official spec for this sensor at
|
||||
@@ -138,15 +140,15 @@ void SGP4xComponent::update_gas_indices_() {
|
||||
// much
|
||||
if (this->store_baseline_ && this->seconds_since_last_store_ > SHORTEST_BASELINE_STORE_INTERVAL) {
|
||||
this->voc_algorithm_.get_states(this->voc_state0_, this->voc_state1_);
|
||||
if (std::abs(this->voc_baselines_storage_.state0 - this->voc_state0_) > MAXIMUM_STORAGE_DIFF ||
|
||||
std::abs(this->voc_baselines_storage_.state1 - this->voc_state1_) > MAXIMUM_STORAGE_DIFF) {
|
||||
if (std::abs(this->voc_baselines_storage_.state0 - this->voc_state0_) > MAXIMUM_STORAGE_DIFF_STATE0 ||
|
||||
std::abs(this->voc_baselines_storage_.state1 - this->voc_state1_) > MAXIMUM_STORAGE_DIFF_STATE1) {
|
||||
this->seconds_since_last_store_ = 0;
|
||||
this->voc_baselines_storage_.state0 = this->voc_state0_;
|
||||
this->voc_baselines_storage_.state1 = this->voc_state1_;
|
||||
|
||||
if (this->pref_.save(&this->voc_baselines_storage_)) {
|
||||
ESP_LOGV(TAG, "Stored VOC baseline state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32,
|
||||
this->voc_baselines_storage_.state0, this->voc_baselines_storage_.state1);
|
||||
ESP_LOGV(TAG, "Stored VOC baseline state0: %f, state1: %f", this->voc_baselines_storage_.state0,
|
||||
this->voc_baselines_storage_.state1);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Storing VOC baselines failed");
|
||||
}
|
||||
@@ -232,7 +234,9 @@ void SGP4xComponent::measure_raw_() {
|
||||
void SGP4xComponent::take_sample() {
|
||||
if (!this->self_test_complete_)
|
||||
return;
|
||||
this->seconds_since_last_store_ += 1;
|
||||
if (this->store_baseline_) {
|
||||
this->seconds_since_last_store_ += 1;
|
||||
}
|
||||
this->measure_raw_();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
namespace esphome::sgp4x {
|
||||
|
||||
struct SGP4xBaselines {
|
||||
int32_t state0;
|
||||
int32_t state1;
|
||||
} PACKED; // NOLINT
|
||||
float state0;
|
||||
float state1;
|
||||
};
|
||||
|
||||
enum SgpType { SGP40, SGP41 };
|
||||
|
||||
@@ -49,7 +49,11 @@ static const uint16_t SPG41_SELFTEST_TIME = 320; // 320 ms for self test
|
||||
static const uint16_t SGP40_MEASURE_TIME = 30;
|
||||
static const uint16_t SGP41_MEASURE_TIME = 55;
|
||||
// Store anyway if the baseline difference exceeds the max storage diff value
|
||||
const float MAXIMUM_STORAGE_DIFF = 50.0f;
|
||||
// state0 is mean of variance estimator, hence can have larger absolute values and a larger diff threshold
|
||||
const float MAXIMUM_STORAGE_DIFF_STATE0 = 50.0f;
|
||||
// state1 is std of variance estimator, so it typically has smaller absolute values than state0, hence we use a smaller
|
||||
// diff threshold
|
||||
const float MAXIMUM_STORAGE_DIFF_STATE1 = 5.0f;
|
||||
|
||||
class SGP4xComponent;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user