mirror of
https://github.com/esphome/esphome.git
synced 2024-11-10 01:07:45 +01:00
Fix SGP30 incorrect baseline reading/writing (#936)
* Split the SGP30 baseline into 2 values - According to the SGP30 datasheet, each eCO2 and TVOC baseline is a 2-byte value (MSB first) - The current implementation ignores the MSB of each of the value - Update the schema to allow 2 different baseline values (optional, but both need to be specified for the baseline to apply) * Make both eCO2 and TVOC required if the optional baseline is defined * Make dump_config() looks better
This commit is contained in:
parent
92d93d658c
commit
170d52e0db
3 changed files with 37 additions and 22 deletions
|
@ -12,6 +12,8 @@ SGP30Component = sgp30_ns.class_('SGP30Component', cg.PollingComponent, i2c.I2CD
|
||||||
CONF_ECO2 = 'eco2'
|
CONF_ECO2 = 'eco2'
|
||||||
CONF_TVOC = 'tvoc'
|
CONF_TVOC = 'tvoc'
|
||||||
CONF_BASELINE = 'baseline'
|
CONF_BASELINE = 'baseline'
|
||||||
|
CONF_ECO2_BASELINE = 'eco2_baseline'
|
||||||
|
CONF_TVOC_BASELINE = 'tvoc_baseline'
|
||||||
CONF_UPTIME = 'uptime'
|
CONF_UPTIME = 'uptime'
|
||||||
CONF_COMPENSATION = 'compensation'
|
CONF_COMPENSATION = 'compensation'
|
||||||
CONF_HUMIDITY_SOURCE = 'humidity_source'
|
CONF_HUMIDITY_SOURCE = 'humidity_source'
|
||||||
|
@ -22,7 +24,10 @@ CONFIG_SCHEMA = cv.Schema({
|
||||||
cv.Required(CONF_ECO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION,
|
cv.Required(CONF_ECO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION,
|
||||||
ICON_PERIODIC_TABLE_CO2, 0),
|
ICON_PERIODIC_TABLE_CO2, 0),
|
||||||
cv.Required(CONF_TVOC): sensor.sensor_schema(UNIT_PARTS_PER_BILLION, ICON_RADIATOR, 0),
|
cv.Required(CONF_TVOC): sensor.sensor_schema(UNIT_PARTS_PER_BILLION, ICON_RADIATOR, 0),
|
||||||
cv.Optional(CONF_BASELINE): cv.hex_uint16_t,
|
cv.Optional(CONF_BASELINE): cv.Schema({
|
||||||
|
cv.Required(CONF_ECO2_BASELINE): cv.hex_uint16_t,
|
||||||
|
cv.Required(CONF_TVOC_BASELINE): cv.hex_uint16_t,
|
||||||
|
}),
|
||||||
cv.Optional(CONF_COMPENSATION): cv.Schema({
|
cv.Optional(CONF_COMPENSATION): cv.Schema({
|
||||||
cv.Required(CONF_HUMIDITY_SOURCE): cv.use_id(sensor.Sensor),
|
cv.Required(CONF_HUMIDITY_SOURCE): cv.use_id(sensor.Sensor),
|
||||||
cv.Required(CONF_TEMPERATURE_SOURCE): cv.use_id(sensor.Sensor)
|
cv.Required(CONF_TEMPERATURE_SOURCE): cv.use_id(sensor.Sensor)
|
||||||
|
@ -44,7 +49,9 @@ def to_code(config):
|
||||||
cg.add(var.set_tvoc_sensor(sens))
|
cg.add(var.set_tvoc_sensor(sens))
|
||||||
|
|
||||||
if CONF_BASELINE in config:
|
if CONF_BASELINE in config:
|
||||||
cg.add(var.set_baseline(config[CONF_BASELINE]))
|
baseline_config = config[CONF_BASELINE]
|
||||||
|
cg.add(var.set_eco2_baseline(baseline_config[CONF_ECO2_BASELINE]))
|
||||||
|
cg.add(var.set_tvoc_baseline(baseline_config[CONF_TVOC_BASELINE]))
|
||||||
|
|
||||||
if CONF_COMPENSATION in config:
|
if CONF_COMPENSATION in config:
|
||||||
compensation_config = config[CONF_COMPENSATION]
|
compensation_config = config[CONF_COMPENSATION]
|
||||||
|
|
|
@ -74,9 +74,9 @@ void SGP30Component::setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sensor baseline reliability timer
|
// Sensor baseline reliability timer
|
||||||
if (this->baseline_ > 0) {
|
if (this->eco2_baseline_ > 0 && this->tvoc_baseline_ > 0) {
|
||||||
this->required_warm_up_time_ = IAQ_BASELINE_WARM_UP_SECONDS_WITH_BASELINE_PROVIDED;
|
this->required_warm_up_time_ = IAQ_BASELINE_WARM_UP_SECONDS_WITH_BASELINE_PROVIDED;
|
||||||
this->write_iaq_baseline_(this->baseline_);
|
this->write_iaq_baseline_(this->eco2_baseline_, this->tvoc_baseline_);
|
||||||
} else {
|
} else {
|
||||||
this->required_warm_up_time_ = IAQ_BASELINE_WARM_UP_SECONDS_WITHOUT_BASELINE;
|
this->required_warm_up_time_ = IAQ_BASELINE_WARM_UP_SECONDS_WITHOUT_BASELINE;
|
||||||
}
|
}
|
||||||
|
@ -106,10 +106,10 @@ void SGP30Component::read_iaq_baseline_() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t eco2baseline = (raw_data[0]);
|
uint16_t eco2baseline = (raw_data[0]);
|
||||||
uint8_t tvocbaseline = (raw_data[1]);
|
uint16_t tvocbaseline = (raw_data[1]);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Current eCO2 & TVOC baseline: 0x%04X", uint16_t((eco2baseline << 8) | (tvocbaseline & 0xFF)));
|
ESP_LOGI(TAG, "Current eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", eco2baseline, tvocbaseline);
|
||||||
this->status_clear_warning();
|
this->status_clear_warning();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,18 +159,19 @@ void SGP30Component::send_env_data_() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGP30Component::write_iaq_baseline_(uint16_t baseline) {
|
void SGP30Component::write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_baseline) {
|
||||||
uint8_t e_c_o2_baseline = baseline >> 8;
|
uint8_t data[7];
|
||||||
uint8_t tvoc_baseline = baseline & 0xFF;
|
|
||||||
uint8_t data[4];
|
|
||||||
data[0] = SGP30_CMD_SET_IAQ_BASELINE & 0xFF;
|
data[0] = SGP30_CMD_SET_IAQ_BASELINE & 0xFF;
|
||||||
data[1] = e_c_o2_baseline;
|
data[1] = eco2_baseline >> 8;
|
||||||
data[2] = tvoc_baseline;
|
data[2] = eco2_baseline & 0xFF;
|
||||||
data[3] = sht_crc_(e_c_o2_baseline, tvoc_baseline);
|
data[3] = sht_crc_(data[1], data[2]);
|
||||||
if (!this->write_bytes(SGP30_CMD_SET_IAQ_BASELINE >> 8, data, 4)) {
|
data[4] = tvoc_baseline >> 8;
|
||||||
ESP_LOGE(TAG, "Error applying baseline: 0x%04X", baseline);
|
data[5] = tvoc_baseline & 0xFF;
|
||||||
|
data[6] = sht_crc_(data[4], data[5]);
|
||||||
|
if (!this->write_bytes(SGP30_CMD_SET_IAQ_BASELINE >> 8, data, 7)) {
|
||||||
|
ESP_LOGE(TAG, "Error applying eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", eco2_baseline, tvoc_baseline);
|
||||||
} else
|
} else
|
||||||
ESP_LOGI(TAG, "Initial baseline 0x%04X applied successfully!", baseline);
|
ESP_LOGI(TAG, "Initial eCO2 and TVOC baselines applied successfully!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGP30Component::dump_config() {
|
void SGP30Component::dump_config() {
|
||||||
|
@ -196,8 +197,13 @@ void SGP30Component::dump_config() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGCONFIG(TAG, " Serial number: %llu", this->serial_number_);
|
ESP_LOGCONFIG(TAG, " Serial number: %llu", this->serial_number_);
|
||||||
ESP_LOGCONFIG(TAG, " Baseline: 0x%04X%s", this->baseline_,
|
if (this->eco2_baseline_ != 0x0000 && this->tvoc_baseline_ != 0x0000) {
|
||||||
((this->baseline_ != 0x0000) ? " (enabled)" : " (disabled)"));
|
ESP_LOGCONFIG(TAG, " Baseline:");
|
||||||
|
ESP_LOGCONFIG(TAG, " eCO2 Baseline: 0x%04X", this->eco2_baseline_);
|
||||||
|
ESP_LOGCONFIG(TAG, " TVOC Baseline: 0x%04X", this->tvoc_baseline_);
|
||||||
|
} else {
|
||||||
|
ESP_LOGCONFIG(TAG, " Baseline: No baseline configured");
|
||||||
|
}
|
||||||
ESP_LOGCONFIG(TAG, " Warm up time: %lds", this->required_warm_up_time_);
|
ESP_LOGCONFIG(TAG, " Warm up time: %lds", this->required_warm_up_time_);
|
||||||
}
|
}
|
||||||
LOG_UPDATE_INTERVAL(this);
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
|
|
@ -13,7 +13,8 @@ class SGP30Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
void set_eco2_sensor(sensor::Sensor *eco2) { eco2_sensor_ = eco2; }
|
void set_eco2_sensor(sensor::Sensor *eco2) { eco2_sensor_ = eco2; }
|
||||||
void set_tvoc_sensor(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; }
|
void set_tvoc_sensor(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; }
|
||||||
void set_baseline(uint16_t baseline) { baseline_ = baseline; }
|
void set_eco2_baseline(uint16_t eco2_baseline) { eco2_baseline_ = eco2_baseline; }
|
||||||
|
void set_tvoc_baseline(uint16_t tvoc_baseline) { tvoc_baseline_ = tvoc_baseline; }
|
||||||
void set_humidity_sensor(sensor::Sensor *humidity) { humidity_sensor_ = humidity; }
|
void set_humidity_sensor(sensor::Sensor *humidity) { humidity_sensor_ = humidity; }
|
||||||
void set_temperature_sensor(sensor::Sensor *temperature) { temperature_sensor_ = temperature; }
|
void set_temperature_sensor(sensor::Sensor *temperature) { temperature_sensor_ = temperature; }
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ class SGP30Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
void send_env_data_();
|
void send_env_data_();
|
||||||
void read_iaq_baseline_();
|
void read_iaq_baseline_();
|
||||||
bool is_sensor_baseline_reliable_();
|
bool is_sensor_baseline_reliable_();
|
||||||
void write_iaq_baseline_(uint16_t baseline);
|
void write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_baseline);
|
||||||
uint8_t sht_crc_(uint8_t data1, uint8_t data2);
|
uint8_t sht_crc_(uint8_t data1, uint8_t data2);
|
||||||
uint64_t serial_number_;
|
uint64_t serial_number_;
|
||||||
uint16_t featureset_;
|
uint16_t featureset_;
|
||||||
|
@ -44,7 +45,8 @@ class SGP30Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
|
|
||||||
sensor::Sensor *eco2_sensor_{nullptr};
|
sensor::Sensor *eco2_sensor_{nullptr};
|
||||||
sensor::Sensor *tvoc_sensor_{nullptr};
|
sensor::Sensor *tvoc_sensor_{nullptr};
|
||||||
uint16_t baseline_{0x0000};
|
uint16_t eco2_baseline_{0x0000};
|
||||||
|
uint16_t tvoc_baseline_{0x0000};
|
||||||
/// Input sensor for humidity and temperature compensation.
|
/// Input sensor for humidity and temperature compensation.
|
||||||
sensor::Sensor *humidity_sensor_{nullptr};
|
sensor::Sensor *humidity_sensor_{nullptr};
|
||||||
sensor::Sensor *temperature_sensor_{nullptr};
|
sensor::Sensor *temperature_sensor_{nullptr};
|
||||||
|
|
Loading…
Reference in a new issue