mirror of
https://github.com/esphome/esphome.git
synced 2024-11-29 10:14:13 +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
7c91b4474a
commit
d82c6df57e
2 changed files with 51 additions and 21 deletions
|
@ -117,18 +117,24 @@ void BME680Component::setup() {
|
||||||
this->calibration_.gh2 = cal2[12] << 8 | cal2[13];
|
this->calibration_.gh2 = cal2[12] << 8 | cal2[13];
|
||||||
this->calibration_.gh3 = cal2[15];
|
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();
|
this->mark_failed();
|
||||||
return;
|
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();
|
this->mark_failed();
|
||||||
return;
|
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();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this->calibration_.range_sw_err = ((int8_t) temp_var & (int8_t) 0xf0) / 16;
|
||||||
|
|
||||||
this->calibration_.ambient_temperature = 25; // prime ambient temperature
|
this->calibration_.ambient_temperature = 25; // prime ambient temperature
|
||||||
|
|
||||||
|
@ -181,7 +187,7 @@ void BME680Component::setup() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gas0_control &= ~0b00001000;
|
gas0_control &= ~0b00001000;
|
||||||
gas0_control |= heat_off ? 0b100 : 0b000;
|
gas0_control |= heat_off << 3;
|
||||||
if (!this->write_byte(BME680_REGISTER_CONTROL_GAS0, gas0_control)) {
|
if (!this->write_byte(BME680_REGISTER_CONTROL_GAS0, gas0_control)) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
|
@ -249,12 +255,12 @@ uint8_t BME680Component::calc_heater_resistance_(uint16_t temperature) {
|
||||||
if (temperature > 400)
|
if (temperature > 400)
|
||||||
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 int8_t gh1 = this->calibration_.gh1;
|
||||||
const int16_t gh2 = this->calibration_.gh2;
|
const int16_t gh2 = this->calibration_.gh2;
|
||||||
const int8_t gh3 = this->calibration_.gh3;
|
const int8_t gh3 = this->calibration_.gh3;
|
||||||
const uint8_t res_heat_range = this->calibration_.res_heat_range;
|
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;
|
uint8_t heatr_res;
|
||||||
int32_t var1;
|
int32_t var1;
|
||||||
|
@ -293,35 +299,57 @@ uint8_t BME680Component::calc_heater_duration_(uint16_t duration) {
|
||||||
void BME680Component::read_data_() {
|
void BME680Component::read_data_() {
|
||||||
uint8_t data[15];
|
uint8_t data[15];
|
||||||
if (!this->read_bytes(BME680_REGISTER_FIELD0, 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();
|
this->status_set_warning();
|
||||||
return;
|
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_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_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]);
|
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;
|
uint8_t gas_range = data[14] & 0x0F;
|
||||||
|
|
||||||
float temperature = this->calc_temperature_(raw_temperature);
|
float temperature = this->calc_temperature_(raw_temperature);
|
||||||
float pressure = this->calc_pressure_(raw_pressure);
|
float pressure = this->calc_pressure_(raw_pressure);
|
||||||
float humidity = this->calc_humidity_(raw_humidity);
|
float humidity = this->calc_humidity_(raw_humidity);
|
||||||
float gas_resistance = NAN;
|
float gas_resistance = this->calc_gas_resistance_(raw_gas, gas_range);
|
||||||
if (data[14] & 0x20) {
|
|
||||||
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,
|
ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa humidity=%.1f%% gas_resistance=%.1fΩ", temperature, pressure,
|
||||||
humidity, gas_resistance);
|
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)
|
if (this->temperature_sensor_ != nullptr)
|
||||||
this->temperature_sensor_->publish_state(temperature);
|
this->temperature_sensor_->publish_state(temperature);
|
||||||
if (this->pressure_sensor_ != nullptr)
|
if (this->pressure_sensor_ != nullptr)
|
||||||
this->pressure_sensor_->publish_state(pressure);
|
this->pressure_sensor_->publish_state(pressure);
|
||||||
if (this->humidity_sensor_ != nullptr)
|
if (this->humidity_sensor_ != nullptr)
|
||||||
this->humidity_sensor_->publish_state(humidity);
|
this->humidity_sensor_->publish_state(humidity);
|
||||||
if (this->gas_resistance_sensor_ != nullptr)
|
if (this->gas_resistance_sensor_ != nullptr) {
|
||||||
this->gas_resistance_sensor_->publish_state(gas_resistance);
|
if (gas_valid && heat_stable) {
|
||||||
this->status_clear_warning();
|
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) {
|
float BME680Component::calc_temperature_(uint32_t raw_temperature) {
|
||||||
|
@ -428,20 +456,22 @@ float BME680Component::calc_humidity_(uint16_t raw_humidity) {
|
||||||
|
|
||||||
return calc_hum;
|
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 calc_gas_res;
|
||||||
float var1 = 0;
|
float var1 = 0;
|
||||||
float var2 = 0;
|
float var2 = 0;
|
||||||
float var3 = 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;
|
const float range_sw_err = this->calibration_.range_sw_err;
|
||||||
|
|
||||||
var1 = 1340.0f + (5.0f * range_sw_err);
|
var1 = 1340.0f + (5.0f * range_sw_err);
|
||||||
var2 = var1 * (1.0f + BME680_GAS_LOOKUP_TABLE_1[range] / 100.0f);
|
var2 = var1 * (1.0f + BME680_GAS_LOOKUP_TABLE_1[range] / 100.0f);
|
||||||
var3 = 1.0f + (BME680_GAS_LOOKUP_TABLE_2[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 BME680Component::calc_meas_duration_() {
|
||||||
uint32_t tph_dur; // Calculate in us
|
uint32_t tph_dur; // Calculate in us
|
||||||
|
|
|
@ -59,11 +59,11 @@ struct BME680CalibrationData {
|
||||||
int8_t gh3;
|
int8_t gh3;
|
||||||
|
|
||||||
uint8_t res_heat_range;
|
uint8_t res_heat_range;
|
||||||
uint8_t res_heat_val;
|
int8_t res_heat_val;
|
||||||
uint8_t range_sw_err;
|
int8_t range_sw_err;
|
||||||
|
|
||||||
float tfine;
|
float tfine;
|
||||||
uint8_t ambient_temperature;
|
int8_t ambient_temperature;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BME680Component : public PollingComponent, public i2c::I2CDevice {
|
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.
|
/// Calculate the relative humidity in % using the provided raw ADC value.
|
||||||
float calc_humidity_(uint16_t raw_humidity);
|
float calc_humidity_(uint16_t raw_humidity);
|
||||||
/// Calculate the gas resistance in Ω using the provided raw ADC value.
|
/// 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.
|
/// Calculate how long the sensor will take until we can retrieve data.
|
||||||
uint32_t calc_meas_duration_();
|
uint32_t calc_meas_duration_();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue