mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Add pressure compensation during runtime (#2493)
Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
This commit is contained in:
		| @@ -1,4 +1,5 @@ | ||||
| #include "scd4x.h" | ||||
| #include "esphome/core/hal.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| @@ -38,6 +39,7 @@ void SCD4XComponent::setup() { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     uint32_t stop_measurement_delay = 0; | ||||
|     // In order to query the device periodic measurement must be ceased | ||||
|     if (raw_read_status[0]) { | ||||
|       ESP_LOGD(TAG, "Sensor has data available, stopping periodic measurement"); | ||||
| @@ -46,8 +48,11 @@ void SCD4XComponent::setup() { | ||||
|         this->mark_failed(); | ||||
|         return; | ||||
|       } | ||||
|       // According to the SCD4x datasheet the sensor will only respond to other commands after waiting 500 ms after | ||||
|       // issuing the stop_periodic_measurement command | ||||
|       stop_measurement_delay = 500; | ||||
|     } | ||||
|  | ||||
|     this->set_timeout(stop_measurement_delay, [this]() { | ||||
|       if (!this->write_command_(SCD4X_CMD_GET_SERIAL_NUMBER)) { | ||||
|         ESP_LOGE(TAG, "Failed to write get serial command"); | ||||
|         this->error_code_ = COMMUNICATION_FAILED; | ||||
| @@ -76,7 +81,7 @@ void SCD4XComponent::setup() { | ||||
|       // If pressure compensation available use it | ||||
|       // else use altitude | ||||
|       if (ambient_pressure_compensation_) { | ||||
|       if (!this->write_command_(SCD4X_CMD_AMBIENT_PRESSURE_COMPENSATION, ambient_pressure_compensation_)) { | ||||
|         if (!this->update_ambient_pressure_compensation_(ambient_pressure_)) { | ||||
|           ESP_LOGE(TAG, "Error setting ambient pressure compensation."); | ||||
|           this->error_code_ = MEASUREMENT_INIT_FAILED; | ||||
|           this->mark_failed(); | ||||
| @@ -109,6 +114,7 @@ void SCD4XComponent::setup() { | ||||
|       initialized_ = true; | ||||
|       ESP_LOGD(TAG, "Sensor initialized"); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| void SCD4XComponent::dump_config() { | ||||
| @@ -150,6 +156,13 @@ void SCD4XComponent::update() { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   if (this->ambient_pressure_source_ != nullptr) { | ||||
|     float pressure = this->ambient_pressure_source_->state / 1000.0f; | ||||
|     if (!std::isnan(pressure)) { | ||||
|       set_ambient_pressure_compensation(this->ambient_pressure_source_->state / 1000.0f); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Check if data is ready | ||||
|   if (!this->write_command_(SCD4X_CMD_GET_DATA_READY_STATUS)) { | ||||
|     this->status_set_warning(); | ||||
| @@ -191,6 +204,28 @@ void SCD4XComponent::update() { | ||||
|  | ||||
|   this->status_clear_warning(); | ||||
| } | ||||
| // Note pressure in bar here. Convert to hPa | ||||
| void SCD4XComponent::set_ambient_pressure_compensation(float pressure_in_bar) { | ||||
|   ambient_pressure_compensation_ = true; | ||||
|   uint16_t new_ambient_pressure = (uint16_t)(pressure_in_bar * 1000); | ||||
|   // remove millibar from comparison to avoid frequent updates +/- 10 millibar doesn't matter | ||||
|   if (initialized_ && (new_ambient_pressure / 10 != ambient_pressure_ / 10)) { | ||||
|     update_ambient_pressure_compensation_(new_ambient_pressure); | ||||
|     ambient_pressure_ = new_ambient_pressure; | ||||
|   } else { | ||||
|     ESP_LOGD(TAG, "ambient pressure compensation skipped - no change required"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| bool SCD4XComponent::update_ambient_pressure_compensation_(uint16_t 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); | ||||
|     return true; | ||||
|   } else { | ||||
|     ESP_LOGE(TAG, "Error setting ambient pressure compensation."); | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
|  | ||||
| uint8_t SCD4XComponent::sht_crc_(uint8_t data1, uint8_t data2) { | ||||
|   uint8_t bit; | ||||
|   | ||||
| @@ -18,10 +18,8 @@ class SCD4XComponent : public PollingComponent, public i2c::I2CDevice { | ||||
|  | ||||
|   void set_automatic_self_calibration(bool asc) { enable_asc_ = asc; } | ||||
|   void set_altitude_compensation(uint16_t altitude) { altitude_compensation_ = altitude; } | ||||
|   void set_ambient_pressure_compensation(float pressure) { | ||||
|     ambient_pressure_compensation_ = true; | ||||
|     ambient_pressure_ = (uint16_t)(pressure * 1000); | ||||
|   } | ||||
|   void set_ambient_pressure_compensation(float pressure_in_bar); | ||||
|   void set_ambient_pressure_source(sensor::Sensor *pressure) { ambient_pressure_source_ = pressure; } | ||||
|   void set_temperature_offset(float offset) { temperature_offset_ = offset; }; | ||||
|  | ||||
|   void set_co2_sensor(sensor::Sensor *co2) { co2_sensor_ = co2; } | ||||
| @@ -33,6 +31,7 @@ class SCD4XComponent : public PollingComponent, public i2c::I2CDevice { | ||||
|   bool read_data_(uint16_t *data, uint8_t len); | ||||
|   bool write_command_(uint16_t command); | ||||
|   bool write_command_(uint16_t command, uint16_t data); | ||||
|   bool update_ambient_pressure_compensation_(uint16_t pressure_in_hpa); | ||||
|  | ||||
|   ERRORCODE error_code_; | ||||
|  | ||||
| @@ -47,6 +46,8 @@ class SCD4XComponent : public PollingComponent, public i2c::I2CDevice { | ||||
|   sensor::Sensor *co2_sensor_{nullptr}; | ||||
|   sensor::Sensor *temperature_sensor_{nullptr}; | ||||
|   sensor::Sensor *humidity_sensor_{nullptr}; | ||||
|   // used for compensation | ||||
|   sensor::Sensor *ambient_pressure_source_{nullptr}; | ||||
| }; | ||||
|  | ||||
| }  // namespace scd4x | ||||
|   | ||||
| @@ -29,6 +29,7 @@ CONF_AUTOMATIC_SELF_CALIBRATION = "automatic_self_calibration" | ||||
| CONF_ALTITUDE_COMPENSATION = "altitude_compensation" | ||||
| CONF_AMBIENT_PRESSURE_COMPENSATION = "ambient_pressure_compensation" | ||||
| CONF_TEMPERATURE_OFFSET = "temperature_offset" | ||||
| CONF_AMBIENT_PRESSURE_COMPENSATION_SOURCE = "ambient_pressure_compensation_source" | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cv.Schema( | ||||
| @@ -62,6 +63,9 @@ CONFIG_SCHEMA = ( | ||||
|             ), | ||||
|             cv.Optional(CONF_AMBIENT_PRESSURE_COMPENSATION): cv.pressure, | ||||
|             cv.Optional(CONF_TEMPERATURE_OFFSET, default="4°C"): cv.temperature, | ||||
|             cv.Optional(CONF_AMBIENT_PRESSURE_COMPENSATION_SOURCE): cv.use_id( | ||||
|                 sensor.Sensor | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.polling_component_schema("60s")) | ||||
| @@ -92,7 +96,10 @@ async def to_code(config): | ||||
|             cg.add(getattr(var, funcName)(config[key])) | ||||
|  | ||||
|     for key, funcName in SENSOR_MAP.items(): | ||||
|  | ||||
|         if key in config: | ||||
|             sens = await sensor.new_sensor(config[key]) | ||||
|             cg.add(getattr(var, funcName)(sens)) | ||||
|  | ||||
|     if CONF_AMBIENT_PRESSURE_COMPENSATION_SOURCE in config: | ||||
|         sens = await cg.get_variable(config[CONF_AMBIENT_PRESSURE_COMPENSATION_SOURCE]) | ||||
|         cg.add(var.set_ambient_pressure_source(sens)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user