mirror of
https://github.com/esphome/esphome.git
synced 2024-12-30 17:57:43 +01:00
Correct BME680 gas calculation and heater_off (#4498)
* Fix missing data array * Fix incorrect bit offset * Correct variable types * Do same conversions as in original library * Correct clang-format * Move out float conversion for clarity * Added check for heater stability * Correct clang format * Allow reporting gas resistance when heater is disabled * Correct clang format * Better error reporting by @DAVe3283 * Correct signed operation, range switching error was positive all the time
This commit is contained in:
parent
801fbf44c5
commit
01687a9d57
@ -117,18 +117,24 @@ void BME680Component::setup() {
|
||||
this->calibration_.gh2 = cal2[12] << 8 | cal2[13];
|
||||
this->calibration_.gh3 = cal2[15];
|
||||
|
||||
if (!this->read_byte(0x02, &this->calibration_.res_heat_range)) {
|
||||
uint8_t temp_var = 0;
|
||||
if (!this->read_byte(0x02, &temp_var)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
if (!this->read_byte(0x00, &this->calibration_.res_heat_val)) {
|
||||
this->calibration_.res_heat_range = ((temp_var & 0x30) / 16);
|
||||
|
||||
if (!this->read_byte(0x00, &temp_var)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
if (!this->read_byte(0x04, &this->calibration_.range_sw_err)) {
|
||||
this->calibration_.res_heat_val = (int8_t) temp_var;
|
||||
|
||||
if (!this->read_byte(0x04, &temp_var)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
this->calibration_.range_sw_err = ((int8_t) temp_var & (int8_t) 0xf0) / 16;
|
||||
|
||||
this->calibration_.ambient_temperature = 25; // prime ambient temperature
|
||||
|
||||
@ -181,7 +187,7 @@ void BME680Component::setup() {
|
||||
return;
|
||||
}
|
||||
gas0_control &= ~0b00001000;
|
||||
gas0_control |= heat_off ? 0b100 : 0b000;
|
||||
gas0_control |= heat_off << 3;
|
||||
if (!this->write_byte(BME680_REGISTER_CONTROL_GAS0, gas0_control)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
@ -249,12 +255,12 @@ uint8_t BME680Component::calc_heater_resistance_(uint16_t temperature) {
|
||||
if (temperature > 400)
|
||||
temperature = 400;
|
||||
|
||||
const uint8_t ambient_temperature = this->calibration_.ambient_temperature;
|
||||
const int8_t ambient_temperature = this->calibration_.ambient_temperature;
|
||||
const int8_t gh1 = this->calibration_.gh1;
|
||||
const int16_t gh2 = this->calibration_.gh2;
|
||||
const int8_t gh3 = this->calibration_.gh3;
|
||||
const uint8_t res_heat_range = this->calibration_.res_heat_range;
|
||||
const uint8_t res_heat_val = this->calibration_.res_heat_val;
|
||||
const int8_t res_heat_val = this->calibration_.res_heat_val;
|
||||
|
||||
uint8_t heatr_res;
|
||||
int32_t var1;
|
||||
@ -293,35 +299,57 @@ uint8_t BME680Component::calc_heater_duration_(uint16_t duration) {
|
||||
void BME680Component::read_data_() {
|
||||
uint8_t data[15];
|
||||
if (!this->read_bytes(BME680_REGISTER_FIELD0, data, 15)) {
|
||||
if (this->temperature_sensor_ != nullptr)
|
||||
this->temperature_sensor_->publish_state(NAN);
|
||||
if (this->pressure_sensor_ != nullptr)
|
||||
this->pressure_sensor_->publish_state(NAN);
|
||||
if (this->humidity_sensor_ != nullptr)
|
||||
this->humidity_sensor_->publish_state(NAN);
|
||||
if (this->gas_resistance_sensor_ != nullptr)
|
||||
this->gas_resistance_sensor_->publish_state(NAN);
|
||||
ESP_LOGW(TAG, "Communication with BME680 failed!");
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
this->status_clear_warning();
|
||||
|
||||
uint32_t raw_temperature = (uint32_t(data[5]) << 12) | (uint32_t(data[6]) << 4) | (uint32_t(data[7]) >> 4);
|
||||
uint32_t raw_pressure = (uint32_t(data[2]) << 12) | (uint32_t(data[3]) << 4) | (uint32_t(data[4]) >> 4);
|
||||
uint32_t raw_humidity = (uint32_t(data[8]) << 8) | uint32_t(data[9]);
|
||||
uint16_t raw_gas = (uint16_t(data[13]) << 2) | (uint16_t(14) >> 6);
|
||||
uint16_t raw_gas = (uint16_t)((uint32_t) data[13] * 4 | (((uint32_t) data[14]) / 64));
|
||||
uint8_t gas_range = data[14] & 0x0F;
|
||||
|
||||
float temperature = this->calc_temperature_(raw_temperature);
|
||||
float pressure = this->calc_pressure_(raw_pressure);
|
||||
float humidity = this->calc_humidity_(raw_humidity);
|
||||
float gas_resistance = NAN;
|
||||
if (data[14] & 0x20) {
|
||||
gas_resistance = this->calc_gas_resistance_(raw_gas, gas_range);
|
||||
}
|
||||
float gas_resistance = this->calc_gas_resistance_(raw_gas, gas_range);
|
||||
|
||||
bool gas_valid = (data[14] >> 5) & 1;
|
||||
bool heat_stable = (data[14] >> 4) & 1;
|
||||
if (this->heater_temperature_ == 0 || this->heater_duration_ == 0)
|
||||
heat_stable = true; // Allow reporting gas resistance when heater is disabled
|
||||
|
||||
ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa humidity=%.1f%% gas_resistance=%.1fΩ", temperature, pressure,
|
||||
humidity, gas_resistance);
|
||||
if (!gas_valid)
|
||||
ESP_LOGW(TAG, "Gas measurement unsuccessful, reading invalid!");
|
||||
if (!heat_stable)
|
||||
ESP_LOGW(TAG, "Heater unstable, reading invalid! (Normal for a few readings after a power cycle)");
|
||||
|
||||
if (this->temperature_sensor_ != nullptr)
|
||||
this->temperature_sensor_->publish_state(temperature);
|
||||
if (this->pressure_sensor_ != nullptr)
|
||||
this->pressure_sensor_->publish_state(pressure);
|
||||
if (this->humidity_sensor_ != nullptr)
|
||||
this->humidity_sensor_->publish_state(humidity);
|
||||
if (this->gas_resistance_sensor_ != nullptr)
|
||||
this->gas_resistance_sensor_->publish_state(gas_resistance);
|
||||
this->status_clear_warning();
|
||||
if (this->gas_resistance_sensor_ != nullptr) {
|
||||
if (gas_valid && heat_stable) {
|
||||
this->gas_resistance_sensor_->publish_state(gas_resistance);
|
||||
} else {
|
||||
this->status_set_warning();
|
||||
this->gas_resistance_sensor_->publish_state(NAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float BME680Component::calc_temperature_(uint32_t raw_temperature) {
|
||||
@ -428,20 +456,22 @@ float BME680Component::calc_humidity_(uint16_t raw_humidity) {
|
||||
|
||||
return calc_hum;
|
||||
}
|
||||
uint32_t BME680Component::calc_gas_resistance_(uint16_t raw_gas, uint8_t range) {
|
||||
float BME680Component::calc_gas_resistance_(uint16_t raw_gas, uint8_t range) {
|
||||
float calc_gas_res;
|
||||
float var1 = 0;
|
||||
float var2 = 0;
|
||||
float var3 = 0;
|
||||
float raw_gas_f = raw_gas;
|
||||
float range_f = 1U << range;
|
||||
const float range_sw_err = this->calibration_.range_sw_err;
|
||||
|
||||
var1 = 1340.0f + (5.0f * range_sw_err);
|
||||
var2 = var1 * (1.0f + BME680_GAS_LOOKUP_TABLE_1[range] / 100.0f);
|
||||
var3 = 1.0f + (BME680_GAS_LOOKUP_TABLE_2[range] / 100.0f);
|
||||
|
||||
calc_gas_res = 1.0f / (var3 * 0.000000125f * float(1 << range) * (((float(raw_gas) - 512.0f) / var2) + 1.0f));
|
||||
calc_gas_res = 1.0f / (var3 * 0.000000125f * range_f * (((raw_gas_f - 512.0f) / var2) + 1.0f));
|
||||
|
||||
return static_cast<uint32_t>(calc_gas_res);
|
||||
return calc_gas_res;
|
||||
}
|
||||
uint32_t BME680Component::calc_meas_duration_() {
|
||||
uint32_t tph_dur; // Calculate in us
|
||||
|
@ -59,11 +59,11 @@ struct BME680CalibrationData {
|
||||
int8_t gh3;
|
||||
|
||||
uint8_t res_heat_range;
|
||||
uint8_t res_heat_val;
|
||||
uint8_t range_sw_err;
|
||||
int8_t res_heat_val;
|
||||
int8_t range_sw_err;
|
||||
|
||||
float tfine;
|
||||
uint8_t ambient_temperature;
|
||||
int8_t ambient_temperature;
|
||||
};
|
||||
|
||||
class BME680Component : public PollingComponent, public i2c::I2CDevice {
|
||||
@ -117,7 +117,7 @@ class BME680Component : public PollingComponent, public i2c::I2CDevice {
|
||||
/// Calculate the relative humidity in % using the provided raw ADC value.
|
||||
float calc_humidity_(uint16_t raw_humidity);
|
||||
/// Calculate the gas resistance in Ω using the provided raw ADC value.
|
||||
uint32_t calc_gas_resistance_(uint16_t raw_gas, uint8_t range);
|
||||
float calc_gas_resistance_(uint16_t raw_gas, uint8_t range);
|
||||
/// Calculate how long the sensor will take until we can retrieve data.
|
||||
uint32_t calc_meas_duration_();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user