[scd4x] Optimize logging + minor code clean-up (#9347)

This commit is contained in:
Keith Burzinski 2025-07-06 08:37:50 -05:00 committed by GitHub
parent 4673a5b48c
commit e061b6dc55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 71 additions and 58 deletions

View File

@ -7,6 +7,8 @@ namespace scd4x {
static const char *const TAG = "scd4x"; static const char *const TAG = "scd4x";
static const uint16_t SCD41_ID = 0x1408;
static const uint16_t SCD40_ID = 0x440;
static const uint16_t SCD4X_CMD_GET_SERIAL_NUMBER = 0x3682; static const uint16_t SCD4X_CMD_GET_SERIAL_NUMBER = 0x3682;
static const uint16_t SCD4X_CMD_TEMPERATURE_OFFSET = 0x241d; static const uint16_t SCD4X_CMD_TEMPERATURE_OFFSET = 0x241d;
static const uint16_t SCD4X_CMD_ALTITUDE_COMPENSATION = 0x2427; static const uint16_t SCD4X_CMD_ALTITUDE_COMPENSATION = 0x2427;
@ -23,8 +25,6 @@ static const uint16_t SCD4X_CMD_STOP_MEASUREMENTS = 0x3f86;
static const uint16_t SCD4X_CMD_FACTORY_RESET = 0x3632; static const uint16_t SCD4X_CMD_FACTORY_RESET = 0x3632;
static const uint16_t SCD4X_CMD_GET_FEATURESET = 0x202f; static const uint16_t SCD4X_CMD_GET_FEATURESET = 0x202f;
static const float SCD4X_TEMPERATURE_OFFSET_MULTIPLIER = (1 << 16) / 175.0f; static const float SCD4X_TEMPERATURE_OFFSET_MULTIPLIER = (1 << 16) / 175.0f;
static const uint16_t SCD41_ID = 0x1408;
static const uint16_t SCD40_ID = 0x440;
void SCD4XComponent::setup() { void SCD4XComponent::setup() {
ESP_LOGCONFIG(TAG, "Running setup"); ESP_LOGCONFIG(TAG, "Running setup");
@ -51,47 +51,66 @@ void SCD4XComponent::setup() {
if (!this->write_command(SCD4X_CMD_TEMPERATURE_OFFSET, if (!this->write_command(SCD4X_CMD_TEMPERATURE_OFFSET,
(uint16_t) (temperature_offset_ * SCD4X_TEMPERATURE_OFFSET_MULTIPLIER))) { (uint16_t) (temperature_offset_ * SCD4X_TEMPERATURE_OFFSET_MULTIPLIER))) {
ESP_LOGE(TAG, "Error setting temperature offset."); ESP_LOGE(TAG, "Error setting temperature offset");
this->error_code_ = MEASUREMENT_INIT_FAILED; this->error_code_ = MEASUREMENT_INIT_FAILED;
this->mark_failed(); this->mark_failed();
return; return;
} }
// If pressure compensation available use it // If pressure compensation available use it, else use altitude
// else use altitude if (this->ambient_pressure_compensation_) {
if (ambient_pressure_compensation_) { if (!this->update_ambient_pressure_compensation_(this->ambient_pressure_)) {
if (!this->update_ambient_pressure_compensation_(ambient_pressure_)) { ESP_LOGE(TAG, "Error setting ambient pressure compensation");
ESP_LOGE(TAG, "Error setting ambient pressure compensation.");
this->error_code_ = MEASUREMENT_INIT_FAILED; this->error_code_ = MEASUREMENT_INIT_FAILED;
this->mark_failed(); this->mark_failed();
return; return;
} }
} else { } else {
if (!this->write_command(SCD4X_CMD_ALTITUDE_COMPENSATION, altitude_compensation_)) { if (!this->write_command(SCD4X_CMD_ALTITUDE_COMPENSATION, this->altitude_compensation_)) {
ESP_LOGE(TAG, "Error setting altitude compensation."); ESP_LOGE(TAG, "Error setting altitude compensation");
this->error_code_ = MEASUREMENT_INIT_FAILED; this->error_code_ = MEASUREMENT_INIT_FAILED;
this->mark_failed(); this->mark_failed();
return; return;
} }
} }
if (!this->write_command(SCD4X_CMD_AUTOMATIC_SELF_CALIBRATION, enable_asc_ ? 1 : 0)) { if (!this->write_command(SCD4X_CMD_AUTOMATIC_SELF_CALIBRATION, this->enable_asc_ ? 1 : 0)) {
ESP_LOGE(TAG, "Error setting automatic self calibration."); ESP_LOGE(TAG, "Error setting automatic self calibration");
this->error_code_ = MEASUREMENT_INIT_FAILED; this->error_code_ = MEASUREMENT_INIT_FAILED;
this->mark_failed(); this->mark_failed();
return; return;
} }
initialized_ = true; this->initialized_ = true;
// Finally start sensor measurements // Finally start sensor measurements
this->start_measurement_(); this->start_measurement_();
ESP_LOGD(TAG, "Sensor initialized");
}); });
}); });
} }
void SCD4XComponent::dump_config() { void SCD4XComponent::dump_config() {
ESP_LOGCONFIG(TAG, "scd4x:"); static const char *const MM_PERIODIC_STR = "Periodic (5s)";
static const char *const MM_LOW_POWER_PERIODIC_STR = "Low power periodic (30s)";
static const char *const MM_SINGLE_SHOT_STR = "Single shot";
static const char *const MM_SINGLE_SHOT_RHT_ONLY_STR = "Single shot rht only";
const char *measurement_mode_str = MM_PERIODIC_STR;
switch (this->measurement_mode_) {
case PERIODIC:
// measurement_mode_str = MM_PERIODIC_STR;
break;
case LOW_POWER_PERIODIC:
measurement_mode_str = MM_LOW_POWER_PERIODIC_STR;
break;
case SINGLE_SHOT:
measurement_mode_str = MM_SINGLE_SHOT_STR;
break;
case SINGLE_SHOT_RHT_ONLY:
measurement_mode_str = MM_SINGLE_SHOT_RHT_ONLY_STR;
break;
}
ESP_LOGCONFIG(TAG, "SCD4X:");
LOG_I2C_DEVICE(this); LOG_I2C_DEVICE(this);
if (this->is_failed()) { if (this->is_failed()) {
switch (this->error_code_) { switch (this->error_code_) {
@ -102,16 +121,20 @@ void SCD4XComponent::dump_config() {
ESP_LOGW(TAG, "Measurement Initialization failed"); ESP_LOGW(TAG, "Measurement Initialization failed");
break; break;
case SERIAL_NUMBER_IDENTIFICATION_FAILED: case SERIAL_NUMBER_IDENTIFICATION_FAILED:
ESP_LOGW(TAG, "Unable to read sensor firmware version"); ESP_LOGW(TAG, "Unable to read firmware version");
break; break;
default: default:
ESP_LOGW(TAG, "Unknown setup error"); ESP_LOGW(TAG, "Unknown setup error");
break; break;
} }
} }
ESP_LOGCONFIG(TAG, " Automatic self calibration: %s", ONOFF(this->enable_asc_)); ESP_LOGCONFIG(TAG,
" Automatic self calibration: %s\n"
" Measurement mode: %s\n"
" Temperature offset: %.2f °C",
ONOFF(this->enable_asc_), measurement_mode_str, this->temperature_offset_);
if (this->ambient_pressure_source_ != nullptr) { if (this->ambient_pressure_source_ != nullptr) {
ESP_LOGCONFIG(TAG, " Dynamic ambient pressure compensation using sensor '%s'", ESP_LOGCONFIG(TAG, " Dynamic ambient pressure compensation using '%s'",
this->ambient_pressure_source_->get_name().c_str()); this->ambient_pressure_source_->get_name().c_str());
} else { } else {
if (this->ambient_pressure_compensation_) { if (this->ambient_pressure_compensation_) {
@ -126,21 +149,6 @@ void SCD4XComponent::dump_config() {
this->altitude_compensation_); this->altitude_compensation_);
} }
} }
switch (this->measurement_mode_) {
case PERIODIC:
ESP_LOGCONFIG(TAG, " Measurement mode: periodic (5s)");
break;
case LOW_POWER_PERIODIC:
ESP_LOGCONFIG(TAG, " Measurement mode: low power periodic (30s)");
break;
case SINGLE_SHOT:
ESP_LOGCONFIG(TAG, " Measurement mode: single shot");
break;
case SINGLE_SHOT_RHT_ONLY:
ESP_LOGCONFIG(TAG, " Measurement mode: single shot rht only");
break;
}
ESP_LOGCONFIG(TAG, " Temperature offset: %.2f °C", this->temperature_offset_);
LOG_UPDATE_INTERVAL(this); LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "CO2", this->co2_sensor_); LOG_SENSOR(" ", "CO2", this->co2_sensor_);
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
@ -148,20 +156,20 @@ void SCD4XComponent::dump_config() {
} }
void SCD4XComponent::update() { void SCD4XComponent::update() {
if (!initialized_) { if (!this->initialized_) {
return; return;
} }
if (this->ambient_pressure_source_ != nullptr) { if (this->ambient_pressure_source_ != nullptr) {
float pressure = this->ambient_pressure_source_->state; float pressure = this->ambient_pressure_source_->state;
if (!std::isnan(pressure)) { if (!std::isnan(pressure)) {
set_ambient_pressure_compensation(pressure); this->set_ambient_pressure_compensation(pressure);
} }
} }
uint32_t wait_time = 0; uint32_t wait_time = 0;
if (this->measurement_mode_ == SINGLE_SHOT || this->measurement_mode_ == SINGLE_SHOT_RHT_ONLY) { if (this->measurement_mode_ == SINGLE_SHOT || this->measurement_mode_ == SINGLE_SHOT_RHT_ONLY) {
start_measurement_(); this->start_measurement_();
wait_time = wait_time =
this->measurement_mode_ == SINGLE_SHOT ? 5000 : 50; // Single shot measurement takes 5 secs rht mode 50 ms this->measurement_mode_ == SINGLE_SHOT ? 5000 : 50; // Single shot measurement takes 5 secs rht mode 50 ms
} }
@ -176,12 +184,12 @@ void SCD4XComponent::update() {
if (!this->read_data(raw_read_status) || raw_read_status == 0x00) { if (!this->read_data(raw_read_status) || raw_read_status == 0x00) {
this->status_set_warning(); this->status_set_warning();
ESP_LOGW(TAG, "Data not ready yet!"); ESP_LOGW(TAG, "Data not ready");
return; return;
} }
if (!this->write_command(SCD4X_CMD_READ_MEASUREMENT)) { if (!this->write_command(SCD4X_CMD_READ_MEASUREMENT)) {
ESP_LOGW(TAG, "Error reading measurement!"); ESP_LOGW(TAG, "Error reading measurement");
this->status_set_warning(); this->status_set_warning();
return; // NO RETRY return; // NO RETRY
} }
@ -218,7 +226,7 @@ bool SCD4XComponent::perform_forced_calibration(uint16_t current_co2_concentrati
} }
this->set_timeout(500, [this, current_co2_concentration]() { this->set_timeout(500, [this, current_co2_concentration]() {
if (this->write_command(SCD4X_CMD_PERFORM_FORCED_CALIBRATION, current_co2_concentration)) { if (this->write_command(SCD4X_CMD_PERFORM_FORCED_CALIBRATION, current_co2_concentration)) {
ESP_LOGD(TAG, "setting forced calibration Co2 level %d ppm", current_co2_concentration); ESP_LOGD(TAG, "Setting forced calibration Co2 level %d ppm", current_co2_concentration);
// frc takes 400 ms // frc takes 400 ms
// because this method will be used very rarly // because this method will be used very rarly
// the simple approach with delay is ok // the simple approach with delay is ok
@ -226,11 +234,11 @@ bool SCD4XComponent::perform_forced_calibration(uint16_t current_co2_concentrati
if (!this->start_measurement_()) { if (!this->start_measurement_()) {
return false; return false;
} else { } else {
ESP_LOGD(TAG, "forced calibration complete"); ESP_LOGD(TAG, "Forced calibration complete");
} }
return true; return true;
} else { } else {
ESP_LOGE(TAG, "force calibration failed"); ESP_LOGE(TAG, "Force calibration failed");
this->error_code_ = FRC_FAILED; this->error_code_ = FRC_FAILED;
this->status_set_warning(); this->status_set_warning();
return false; return false;
@ -261,25 +269,25 @@ bool SCD4XComponent::factory_reset() {
void SCD4XComponent::set_ambient_pressure_compensation(float pressure_in_hpa) { void SCD4XComponent::set_ambient_pressure_compensation(float pressure_in_hpa) {
ambient_pressure_compensation_ = true; ambient_pressure_compensation_ = true;
uint16_t new_ambient_pressure = (uint16_t) pressure_in_hpa; uint16_t new_ambient_pressure = (uint16_t) pressure_in_hpa;
if (!initialized_) { if (!this->initialized_) {
ambient_pressure_ = new_ambient_pressure; this->ambient_pressure_ = new_ambient_pressure;
return; return;
} }
// Only send pressure value if it has changed since last update // Only send pressure value if it has changed since last update
if (new_ambient_pressure != ambient_pressure_) { if (new_ambient_pressure != this->ambient_pressure_) {
update_ambient_pressure_compensation_(new_ambient_pressure); this->update_ambient_pressure_compensation_(new_ambient_pressure);
ambient_pressure_ = new_ambient_pressure; this->ambient_pressure_ = new_ambient_pressure;
} else { } else {
ESP_LOGD(TAG, "ambient pressure compensation skipped - no change required"); ESP_LOGD(TAG, "Ambient pressure compensation skipped; no change required");
} }
} }
bool SCD4XComponent::update_ambient_pressure_compensation_(uint16_t pressure_in_hpa) { bool SCD4XComponent::update_ambient_pressure_compensation_(uint16_t pressure_in_hpa) {
if (this->write_command(SCD4X_CMD_AMBIENT_PRESSURE_COMPENSATION, pressure_in_hpa)) { if (this->write_command(SCD4X_CMD_AMBIENT_PRESSURE_COMPENSATION, pressure_in_hpa)) {
ESP_LOGD(TAG, "setting ambient pressure compensation to %d hPa", pressure_in_hpa); ESP_LOGD(TAG, "Setting ambient pressure compensation to %d hPa", pressure_in_hpa);
return true; return true;
} else { } else {
ESP_LOGE(TAG, "Error setting ambient pressure compensation."); ESP_LOGE(TAG, "Error setting ambient pressure compensation");
return false; return false;
} }
} }
@ -304,7 +312,7 @@ bool SCD4XComponent::start_measurement_() {
static uint8_t remaining_retries = 3; static uint8_t remaining_retries = 3;
while (remaining_retries) { while (remaining_retries) {
if (!this->write_command(measurement_command)) { if (!this->write_command(measurement_command)) {
ESP_LOGE(TAG, "Error starting measurements."); ESP_LOGE(TAG, "Error starting measurements");
this->error_code_ = MEASUREMENT_INIT_FAILED; this->error_code_ = MEASUREMENT_INIT_FAILED;
this->status_set_warning(); this->status_set_warning();
if (--remaining_retries == 0) if (--remaining_retries == 0)

View File

@ -8,14 +8,20 @@
namespace esphome { namespace esphome {
namespace scd4x { namespace scd4x {
enum ERRORCODE { enum ErrorCode : uint8_t {
COMMUNICATION_FAILED, COMMUNICATION_FAILED,
SERIAL_NUMBER_IDENTIFICATION_FAILED, SERIAL_NUMBER_IDENTIFICATION_FAILED,
MEASUREMENT_INIT_FAILED, MEASUREMENT_INIT_FAILED,
FRC_FAILED, FRC_FAILED,
UNKNOWN UNKNOWN,
};
enum MeasurementMode : uint8_t {
PERIODIC,
LOW_POWER_PERIODIC,
SINGLE_SHOT,
SINGLE_SHOT_RHT_ONLY,
}; };
enum MeasurementMode { PERIODIC, LOW_POWER_PERIODIC, SINGLE_SHOT, SINGLE_SHOT_RHT_ONLY };
class SCD4XComponent : public PollingComponent, public sensirion_common::SensirionI2CDevice { class SCD4XComponent : public PollingComponent, public sensirion_common::SensirionI2CDevice {
public: public:
@ -39,15 +45,14 @@ class SCD4XComponent : public PollingComponent, public sensirion_common::Sensiri
protected: protected:
bool update_ambient_pressure_compensation_(uint16_t pressure_in_hpa); bool update_ambient_pressure_compensation_(uint16_t pressure_in_hpa);
bool start_measurement_(); bool start_measurement_();
ERRORCODE error_code_;
bool initialized_{false};
float temperature_offset_;
uint16_t altitude_compensation_; uint16_t altitude_compensation_;
bool ambient_pressure_compensation_;
uint16_t ambient_pressure_; uint16_t ambient_pressure_;
bool initialized_{false};
bool ambient_pressure_compensation_;
bool enable_asc_; bool enable_asc_;
float temperature_offset_;
ErrorCode error_code_;
MeasurementMode measurement_mode_{PERIODIC}; MeasurementMode measurement_mode_{PERIODIC};
sensor::Sensor *co2_sensor_{nullptr}; sensor::Sensor *co2_sensor_{nullptr};
sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *temperature_sensor_{nullptr};