mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	New component: Add support for bmp581 pressure and temperature sensors (#4657)
This commit is contained in:
		| @@ -49,6 +49,7 @@ esphome/components/ble_client/* @buxtronix | ||||
| esphome/components/bluetooth_proxy/* @jesserockz | ||||
| esphome/components/bme680_bsec/* @trvrnrth | ||||
| esphome/components/bmp3xx/* @martgras | ||||
| esphome/components/bmp581/* @kahrendt | ||||
| esphome/components/bp1658cj/* @Cossid | ||||
| esphome/components/bp5758d/* @Cossid | ||||
| esphome/components/button/* @esphome/core | ||||
|   | ||||
							
								
								
									
										0
									
								
								esphome/components/bmp581/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/bmp581/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										596
									
								
								esphome/components/bmp581/bmp581.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										596
									
								
								esphome/components/bmp581/bmp581.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,596 @@ | ||||
| /* | ||||
|  * Adds support for Bosch's BMP581 high accuracy pressure and temperature sensor | ||||
|  *  - Component structure based on ESPHome's BMP3XX component (as of March, 2023) | ||||
|  *    - Implementation is easier as the sensor itself automatically compensates pressure for the temperature | ||||
|  *      - Temperature and pressure data is converted via simple divison operations in this component | ||||
|  *    - IIR filter level can independently be applied to temperature and pressure measurements | ||||
|  *  - Bosch's BMP5-Sensor-API was consulted to verify that sensor configuration is done correctly | ||||
|  *    - Copyright (c) 2022 Bosch Sensortec Gmbh, SPDX-License-Identifier: BSD-3-Clause | ||||
|  *  - This component uses forced power mode only so measurements are synchronized by the host | ||||
|  *  - All datasheet page references refer to Bosch Document Number BST-BMP581-DS004-04 (revision number 1.4) | ||||
|  */ | ||||
|  | ||||
| #include "bmp581.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include "esphome/core/hal.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace bmp581 { | ||||
|  | ||||
| static const char *const TAG = "bmp581"; | ||||
|  | ||||
| static const LogString *oversampling_to_str(Oversampling oversampling) { | ||||
|   switch (oversampling) { | ||||
|     case Oversampling::OVERSAMPLING_NONE: | ||||
|       return LOG_STR("None"); | ||||
|     case Oversampling::OVERSAMPLING_X2: | ||||
|       return LOG_STR("2x"); | ||||
|     case Oversampling::OVERSAMPLING_X4: | ||||
|       return LOG_STR("4x"); | ||||
|     case Oversampling::OVERSAMPLING_X8: | ||||
|       return LOG_STR("8x"); | ||||
|     case Oversampling::OVERSAMPLING_X16: | ||||
|       return LOG_STR("16x"); | ||||
|     case Oversampling::OVERSAMPLING_X32: | ||||
|       return LOG_STR("32x"); | ||||
|     case Oversampling::OVERSAMPLING_X64: | ||||
|       return LOG_STR("64x"); | ||||
|     case Oversampling::OVERSAMPLING_X128: | ||||
|       return LOG_STR("128x"); | ||||
|     default: | ||||
|       return LOG_STR(""); | ||||
|   } | ||||
| } | ||||
|  | ||||
| static const LogString *iir_filter_to_str(IIRFilter filter) { | ||||
|   switch (filter) { | ||||
|     case IIRFilter::IIR_FILTER_OFF: | ||||
|       return LOG_STR("OFF"); | ||||
|     case IIRFilter::IIR_FILTER_2: | ||||
|       return LOG_STR("2x"); | ||||
|     case IIRFilter::IIR_FILTER_4: | ||||
|       return LOG_STR("4x"); | ||||
|     case IIRFilter::IIR_FILTER_8: | ||||
|       return LOG_STR("8x"); | ||||
|     case IIRFilter::IIR_FILTER_16: | ||||
|       return LOG_STR("16x"); | ||||
|     case IIRFilter::IIR_FILTER_32: | ||||
|       return LOG_STR("32x"); | ||||
|     case IIRFilter::IIR_FILTER_64: | ||||
|       return LOG_STR("64x"); | ||||
|     case IIRFilter::IIR_FILTER_128: | ||||
|       return LOG_STR("128x"); | ||||
|     default: | ||||
|       return LOG_STR(""); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void BMP581Component::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "BMP581:"); | ||||
|  | ||||
|   switch (this->error_code_) { | ||||
|     case NONE: | ||||
|       break; | ||||
|     case ERROR_COMMUNICATION_FAILED: | ||||
|       ESP_LOGE(TAG, "  Communication with BMP581 failed!"); | ||||
|       break; | ||||
|     case ERROR_WRONG_CHIP_ID: | ||||
|       ESP_LOGE(TAG, "  BMP581 has wrong chip ID - please verify you are using a BMP 581"); | ||||
|       break; | ||||
|     case ERROR_SENSOR_RESET: | ||||
|       ESP_LOGE(TAG, "  BMP581 failed to reset"); | ||||
|       break; | ||||
|     case ERROR_SENSOR_STATUS: | ||||
|       ESP_LOGE(TAG, "  BMP581 sensor status failed, there were NVM problems"); | ||||
|       break; | ||||
|     case ERROR_PRIME_IIR_FAILED: | ||||
|       ESP_LOGE(TAG, "  BMP581's IIR Filter failed to prime with an initial measurement"); | ||||
|       break; | ||||
|     default: | ||||
|       ESP_LOGE(TAG, "  BMP581 error code %d", (int) this->error_code_); | ||||
|       break; | ||||
|   } | ||||
|  | ||||
|   LOG_I2C_DEVICE(this); | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
|  | ||||
|   ESP_LOGCONFIG(TAG, "  Measurement conversion time: %ums", this->conversion_time_); | ||||
|  | ||||
|   if (this->temperature_sensor_) { | ||||
|     LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); | ||||
|     ESP_LOGCONFIG(TAG, "    IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_temperature_level_))); | ||||
|     ESP_LOGCONFIG(TAG, "    Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->temperature_oversampling_))); | ||||
|   } | ||||
|  | ||||
|   if (this->pressure_sensor_) { | ||||
|     LOG_SENSOR("  ", "Pressure", this->pressure_sensor_); | ||||
|     ESP_LOGCONFIG(TAG, "    IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_pressure_level_))); | ||||
|     ESP_LOGCONFIG(TAG, "    Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->pressure_oversampling_))); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void BMP581Component::setup() { | ||||
|   /* | ||||
|    * Setup goes through several stages, which follows the post-power-up procedure (page 18 of datasheet) and then sets | ||||
|    * configured options | ||||
|    *  1) Soft reboot | ||||
|    *  2) Verify ASIC chip ID matches BMP581 | ||||
|    *  3) Verify sensor status (check if NVM is okay) | ||||
|    *  4) Enable data ready interrupt | ||||
|    *  5) Write oversampling settings and set internal configuration values | ||||
|    *  6) Configure and prime IIR Filter(s), if enabled | ||||
|    */ | ||||
|  | ||||
|   this->error_code_ = NONE; | ||||
|   ESP_LOGCONFIG(TAG, "Setting up BMP581..."); | ||||
|  | ||||
|   //////////////////// | ||||
|   // 1) Soft reboot // | ||||
|   //////////////////// | ||||
|  | ||||
|   // Power-On-Reboot bit is asserted if sensor successfully reset | ||||
|   if (!this->reset_()) { | ||||
|     ESP_LOGE(TAG, "BMP581 failed to reset"); | ||||
|  | ||||
|     this->error_code_ = ERROR_SENSOR_RESET; | ||||
|     this->mark_failed(); | ||||
|  | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   /////////////////////////////////////////// | ||||
|   // 2) Verify ASIC chip ID matches BMP581 // | ||||
|   /////////////////////////////////////////// | ||||
|  | ||||
|   uint8_t chip_id; | ||||
|  | ||||
|   // read chip id from sensor | ||||
|   if (!this->read_byte(BMP581_CHIP_ID, &chip_id)) { | ||||
|     ESP_LOGE(TAG, "Failed to read chip id"); | ||||
|  | ||||
|     this->error_code_ = ERROR_COMMUNICATION_FAILED; | ||||
|     this->mark_failed(); | ||||
|  | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // verify id | ||||
|   if (chip_id != BMP581_ASIC_ID) { | ||||
|     ESP_LOGE(TAG, "Unknown chip ID, is this a BMP581?"); | ||||
|  | ||||
|     this->error_code_ = ERROR_WRONG_CHIP_ID; | ||||
|     this->mark_failed(); | ||||
|  | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   //////////////////////////////////////////////////// | ||||
|   // 3) Verify sensor status (check if NVM is okay) // | ||||
|   //////////////////////////////////////////////////// | ||||
|  | ||||
|   if (!this->read_byte(BMP581_STATUS, &this->status_.reg)) { | ||||
|     ESP_LOGE(TAG, "Failed to read status register"); | ||||
|  | ||||
|     this->error_code_ = ERROR_COMMUNICATION_FAILED; | ||||
|     this->mark_failed(); | ||||
|  | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // verify status_nvm_rdy bit (it is asserted if boot was successful) | ||||
|   if (!(this->status_.bit.status_nvm_rdy)) { | ||||
|     ESP_LOGE(TAG, "NVM not ready after boot"); | ||||
|  | ||||
|     this->error_code_ = ERROR_SENSOR_STATUS; | ||||
|     this->mark_failed(); | ||||
|  | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // verify status_nvm_err bit (it is asserted if an error is detected) | ||||
|   if (this->status_.bit.status_nvm_err) { | ||||
|     ESP_LOGE(TAG, "NVM error detected on boot"); | ||||
|  | ||||
|     this->error_code_ = ERROR_SENSOR_STATUS; | ||||
|     this->mark_failed(); | ||||
|  | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   //////////////////////////////////// | ||||
|   // 4) Enable data ready interrupt // | ||||
|   //////////////////////////////////// | ||||
|  | ||||
|   // enable the data ready interrupt source | ||||
|   if (!this->write_interrupt_source_settings_(true)) { | ||||
|     ESP_LOGE(TAG, "Failed to write interrupt source register"); | ||||
|  | ||||
|     this->error_code_ = ERROR_COMMUNICATION_FAILED; | ||||
|     this->mark_failed(); | ||||
|  | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////// | ||||
|   // 5) Write oversampling settings and set internal configuration values // | ||||
|   ////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   // configure pressure readings, if sensor is defined | ||||
|   // otherwise, disable pressure oversampling | ||||
|   if (this->pressure_sensor_) { | ||||
|     this->osr_config_.bit.press_en = true; | ||||
|   } else { | ||||
|     this->pressure_oversampling_ = OVERSAMPLING_NONE; | ||||
|   } | ||||
|  | ||||
|   // write oversampling settings | ||||
|   if (!this->write_oversampling_settings_(this->temperature_oversampling_, this->pressure_oversampling_)) { | ||||
|     ESP_LOGE(TAG, "Failed to write oversampling register"); | ||||
|  | ||||
|     this->error_code_ = ERROR_COMMUNICATION_FAILED; | ||||
|     this->mark_failed(); | ||||
|  | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // set output data rate to 4 Hz=0x19 (page 65 of datasheet) | ||||
|   //  - ?shouldn't? matter as this component only uses FORCED_MODE - datasheet is ambiguous | ||||
|   //  - If in NORMAL_MODE or NONSTOP_MODE, then this would still allow deep standby to save power | ||||
|   //  - will be written to BMP581 at next requested measurement | ||||
|   this->odr_config_.bit.odr = 0x19; | ||||
|  | ||||
|   /////////////////////////////////////////////////////// | ||||
|   /// 6) Configure and prime IIR Filter(s), if enabled // | ||||
|   /////////////////////////////////////////////////////// | ||||
|  | ||||
|   if ((this->iir_temperature_level_ != IIR_FILTER_OFF) || (this->iir_pressure_level_ != IIR_FILTER_OFF)) { | ||||
|     if (!this->write_iir_settings_(this->iir_temperature_level_, this->iir_pressure_level_)) { | ||||
|       ESP_LOGE(TAG, "Failed to write IIR configuration registers"); | ||||
|  | ||||
|       this->error_code_ = ERROR_COMMUNICATION_FAILED; | ||||
|       this->mark_failed(); | ||||
|  | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (!this->prime_iir_filter_()) { | ||||
|       ESP_LOGE(TAG, "Failed to prime the IIR filter with an intiial measurement"); | ||||
|  | ||||
|       this->error_code_ = ERROR_PRIME_IIR_FAILED; | ||||
|       this->mark_failed(); | ||||
|  | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void BMP581Component::update() { | ||||
|   /* | ||||
|    * Each update goes through several stages | ||||
|    *  0) Verify either a temperature or pressure sensor is defined before proceeding | ||||
|    *  1) Request a measurement | ||||
|    *  2) Wait for measurement to finish (based on oversampling rates) | ||||
|    *  3) Read data registers for temperature and pressure, if applicable | ||||
|    *  4) Publish measurements to sensor(s), if applicable | ||||
|    */ | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////////////////////////// | ||||
|   // 0) Verify either a temperature or pressure sensor is defined before proceeding // | ||||
|   //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   if ((!this->temperature_sensor_) && (!this->pressure_sensor_)) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////// | ||||
|   // 1) Request a measurement // | ||||
|   ////////////////////////////// | ||||
|  | ||||
|   ESP_LOGVV(TAG, "Requesting a measurement from sensor"); | ||||
|  | ||||
|   if (!this->start_measurement_()) { | ||||
|     ESP_LOGW(TAG, "Failed to request forced measurement of sensor"); | ||||
|     this->status_set_warning(); | ||||
|  | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////// | ||||
|   // 2) Wait for measurement to finish (based on oversampling rates) // | ||||
|   ////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   ESP_LOGVV(TAG, "Measurement is expected to take %d ms to complete", this->conversion_time_); | ||||
|  | ||||
|   this->set_timeout("measurement", this->conversion_time_, [this]() { | ||||
|     float temperature = 0.0; | ||||
|     float pressure = 0.0; | ||||
|  | ||||
|     //////////////////////////////////////////////////////////////////////// | ||||
|     // 3) Read data registers for temperature and pressure, if applicable // | ||||
|     //////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     if (this->pressure_sensor_) { | ||||
|       if (!this->read_temperature_and_pressure_(temperature, pressure)) { | ||||
|         ESP_LOGW(TAG, "Failed to read temperature and pressure measurements, skipping update"); | ||||
|         this->status_set_warning(); | ||||
|  | ||||
|         return; | ||||
|       } | ||||
|     } else { | ||||
|       if (!this->read_temperature_(temperature)) { | ||||
|         ESP_LOGW(TAG, "Failed to read temperature measurement, skipping update"); | ||||
|         this->status_set_warning(); | ||||
|  | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     ///////////////////////////////////////////////////////// | ||||
|     // 4) Publish measurements to sensor(s), if applicable // | ||||
|     ///////////////////////////////////////////////////////// | ||||
|  | ||||
|     if (this->temperature_sensor_) { | ||||
|       this->temperature_sensor_->publish_state(temperature); | ||||
|     } | ||||
|  | ||||
|     if (this->pressure_sensor_) { | ||||
|       this->pressure_sensor_->publish_state(pressure); | ||||
|     } | ||||
|  | ||||
|     this->status_clear_warning(); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| bool BMP581Component::check_data_readiness_() { | ||||
|   //   - verifies component is not internally in standby mode | ||||
|   //   - reads interrupt status register | ||||
|   //   - checks if data ready bit is asserted | ||||
|   //      - If true, then internally sets component to standby mode if in forced mode | ||||
|   //   - returns data readiness state | ||||
|  | ||||
|   if (this->odr_config_.bit.pwr_mode == STANDBY_MODE) { | ||||
|     ESP_LOGD(TAG, "Data is not ready, sensor is in standby mode"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   uint8_t status; | ||||
|  | ||||
|   if (!this->read_byte(BMP581_INT_STATUS, &status)) { | ||||
|     ESP_LOGE(TAG, "Failed to read interrupt status register"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   this->int_status_.reg = status; | ||||
|  | ||||
|   if (this->int_status_.bit.drdy_data_reg) { | ||||
|     // If in forced mode, then set internal record of the power mode to STANDBY_MODE | ||||
|     //  - sensor automatically returns to standby mode after completing a forced measurement | ||||
|     if (this->odr_config_.bit.pwr_mode == FORCED_MODE) { | ||||
|       this->odr_config_.bit.pwr_mode = STANDBY_MODE; | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool BMP581Component::prime_iir_filter_() { | ||||
|   // - temporarily disables oversampling for a fast initial measurement; avoids slowing down ESPHome's startup process | ||||
|   // - enables IIR filter flushing with forced measurements | ||||
|   // - forces a measurement; flushing the IIR filter and priming it with a current value | ||||
|   // - disables IIR filter flushing with forced measurements | ||||
|   // - reverts to internally configured oversampling rates | ||||
|   // - returns success of all register writes/priming | ||||
|  | ||||
|   // store current internal oversampling settings to revert to after priming | ||||
|   Oversampling current_temperature_oversampling = (Oversampling) this->osr_config_.bit.osr_t; | ||||
|   Oversampling current_pressure_oversampling = (Oversampling) this->osr_config_.bit.osr_p; | ||||
|  | ||||
|   // temporarily disables oversampling for temperature and pressure for a fast priming measurement | ||||
|   if (!this->write_oversampling_settings_(OVERSAMPLING_NONE, OVERSAMPLING_NONE)) { | ||||
|     ESP_LOGE(TAG, "Failed to write oversampling register"); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // flush the IIR filter with forced measurements (we will only flush once) | ||||
|   this->dsp_config_.bit.iir_flush_forced_en = true; | ||||
|   if (!this->write_byte(BMP581_DSP, this->dsp_config_.reg)) { | ||||
|     ESP_LOGE(TAG, "Failed to write IIR source register"); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // forces an intial measurement | ||||
|   //  - this measurements flushes the IIR filter reflecting written DSP settings | ||||
|   //  - flushing with this initial reading avoids having the internal previous data aquisition being 0, which | ||||
|   //    (I)nfinitely affects future values | ||||
|   if (!this->start_measurement_()) { | ||||
|     ESP_LOGE(TAG, "Failed to request a forced measurement"); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // wait for priming measurement to complete | ||||
|   //  - with oversampling disabled, the conversion time for a single measurement for pressure and temperature is | ||||
|   //    ceilf(1.05*(1.0+1.0)) = 3ms | ||||
|   //  - see page 12 of datasheet for details | ||||
|   delay(3); | ||||
|  | ||||
|   if (!this->check_data_readiness_()) { | ||||
|     ESP_LOGE(TAG, "IIR priming measurement was not ready"); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // disable IIR filter flushings on future forced measurements | ||||
|   this->dsp_config_.bit.iir_flush_forced_en = false; | ||||
|   if (!this->write_byte(BMP581_DSP, this->dsp_config_.reg)) { | ||||
|     ESP_LOGE(TAG, "Failed to write IIR source register"); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // revert oversampling rates to original settings | ||||
|   return this->write_oversampling_settings_(current_temperature_oversampling, current_pressure_oversampling); | ||||
| } | ||||
|  | ||||
| bool BMP581Component::read_temperature_(float &temperature) { | ||||
|   // - verifies data is ready to be read | ||||
|   // - reads in 3 bytes of temperature data | ||||
|   // - returns whether successful, where the the variable parameter contains | ||||
|   //    - the measured temperature (in degrees Celsius) | ||||
|  | ||||
|   if (!this->check_data_readiness_()) { | ||||
|     ESP_LOGW(TAG, "Data from sensor isn't ready, skipping this update"); | ||||
|     this->status_set_warning(); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   uint8_t data[3]; | ||||
|   if (!this->read_bytes(BMP581_MEASUREMENT_DATA, &data[0], 3)) { | ||||
|     ESP_LOGW(TAG, "Failed to read sensor's measurement data"); | ||||
|     this->status_set_warning(); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // temperature MSB is in data[2], LSB is in data[1], XLSB in data[0] | ||||
|   int32_t raw_temp = (int32_t) data[2] << 16 | (int32_t) data[1] << 8 | (int32_t) data[0]; | ||||
|   temperature = (float) (raw_temp / 65536.0);  // convert measurement to degrees Celsius (page 22 of datasheet) | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool BMP581Component::read_temperature_and_pressure_(float &temperature, float &pressure) { | ||||
|   // - verifies data is ready to be read | ||||
|   // - reads in 6 bytes of temperature data (3 for temeperature, 3 for pressure) | ||||
|   // - returns whether successful, where the variable parameters contain | ||||
|   //    - the measured temperature (in degrees Celsius) | ||||
|   //    - the measured pressure (in Pa) | ||||
|  | ||||
|   if (!this->check_data_readiness_()) { | ||||
|     ESP_LOGW(TAG, "Data from sensor isn't ready, skipping this update"); | ||||
|     this->status_set_warning(); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   uint8_t data[6]; | ||||
|   if (!this->read_bytes(BMP581_MEASUREMENT_DATA, &data[0], 6)) { | ||||
|     ESP_LOGW(TAG, "Failed to read sensor's measurement data"); | ||||
|     this->status_set_warning(); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // temperature MSB is in data[2], LSB is in data[1], XLSB in data[0] | ||||
|   int32_t raw_temp = (int32_t) data[2] << 16 | (int32_t) data[1] << 8 | (int32_t) data[0]; | ||||
|   temperature = (float) (raw_temp / 65536.0);  // convert measurement to degrees Celsius (page 22 of datasheet) | ||||
|  | ||||
|   // pressure MSB is in data[5], LSB is in data[4], XLSB in data[3] | ||||
|   int32_t raw_press = (int32_t) data[5] << 16 | (int32_t) data[4] << 8 | (int32_t) data[3]; | ||||
|   pressure = (float) (raw_press / 64.0);  // Divide by 2^6=64 for Pa (page 22 of datasheet) | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool BMP581Component::reset_() { | ||||
|   // - writes reset command to the command register | ||||
|   // - waits for sensor to complete reset | ||||
|   // - returns the Power-On-Reboot interrupt status, which is asserted if successful | ||||
|  | ||||
|   // writes reset command to BMP's command register | ||||
|   if (!this->write_byte(BMP581_COMMAND, RESET_COMMAND)) { | ||||
|     ESP_LOGE(TAG, "Failed to write reset command"); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // t_{soft_res} = 2ms (page 11 of datasheet); time it takes to enter standby mode | ||||
|   //  - round up to 3 ms | ||||
|   delay(3); | ||||
|  | ||||
|   // read interrupt status register | ||||
|   if (!this->read_byte(BMP581_INT_STATUS, &this->int_status_.reg)) { | ||||
|     ESP_LOGE(TAG, "Failed to read interrupt status register"); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // Power-On-Reboot bit is asserted if sensor successfully reset | ||||
|   return this->int_status_.bit.por; | ||||
| } | ||||
|  | ||||
| bool BMP581Component::start_measurement_() { | ||||
|   // - only pushes the sensor into FORCED_MODE for a reading if already in STANDBY_MODE | ||||
|   // - returns whether a measurement is in progress or has been initiated | ||||
|  | ||||
|   if (this->odr_config_.bit.pwr_mode == STANDBY_MODE) { | ||||
|     return this->write_power_mode_(FORCED_MODE); | ||||
|   } else { | ||||
|     return true; | ||||
|   } | ||||
| } | ||||
|  | ||||
| bool BMP581Component::write_iir_settings_(IIRFilter temperature_iir, IIRFilter pressure_iir) { | ||||
|   // - ensures data registers store filtered values | ||||
|   // - sets IIR filter levels on sensor | ||||
|   // - matches other default settings on sensor | ||||
|   // - writes configuration to the two relevant registers | ||||
|   // - returns success or failure of write to the registers | ||||
|  | ||||
|   // If the temperature/pressure IIR filter is configured, then ensure data registers store the filtered measurement | ||||
|   this->dsp_config_.bit.shdw_sel_iir_t = (temperature_iir != IIR_FILTER_OFF); | ||||
|   this->dsp_config_.bit.shdw_sel_iir_p = (pressure_iir != IIR_FILTER_OFF); | ||||
|  | ||||
|   // set temperature and pressure IIR filter level to configured values | ||||
|   this->iir_config_.bit.set_iir_t = temperature_iir; | ||||
|   this->iir_config_.bit.set_iir_p = pressure_iir; | ||||
|  | ||||
|   // enable pressure and temperature compensation (page 61 of datasheet) | ||||
|   //  - ?only relevant if IIR filter is applied?; the datasheet is ambiguous | ||||
|   //  - matches BMP's default setting | ||||
|   this->dsp_config_.bit.comp_pt_en = 0x3; | ||||
|  | ||||
|   // BMP581_DSP register and BMP581_DSP_IIR registers are successive | ||||
|   //  - allows us to write the IIR configuration with one command to both registers | ||||
|   uint8_t register_data[2] = {this->dsp_config_.reg, this->iir_config_.reg}; | ||||
|   return this->write_bytes(BMP581_DSP, register_data, sizeof(register_data)); | ||||
| } | ||||
|  | ||||
| bool BMP581Component::write_interrupt_source_settings_(bool data_ready_enable) { | ||||
|   // - updates component's internal setting | ||||
|   // - returns success or failure of write to interrupt source register | ||||
|  | ||||
|   this->int_source_.bit.drdy_data_reg_en = data_ready_enable; | ||||
|  | ||||
|   // write interrupt source register | ||||
|   return this->write_byte(BMP581_INT_SOURCE, this->int_source_.reg); | ||||
| } | ||||
|  | ||||
| bool BMP581Component::write_oversampling_settings_(Oversampling temperature_oversampling, | ||||
|                                                    Oversampling pressure_oversampling) { | ||||
|   // - updates component's internal setting | ||||
|   // - returns success or failure of write to Over-Sampling Rate register | ||||
|  | ||||
|   this->osr_config_.bit.osr_t = temperature_oversampling; | ||||
|   this->osr_config_.bit.osr_p = pressure_oversampling; | ||||
|  | ||||
|   return this->write_byte(BMP581_OSR, this->osr_config_.reg); | ||||
| } | ||||
|  | ||||
| bool BMP581Component::write_power_mode_(OperationMode mode) { | ||||
|   // - updates the component's internal power mode | ||||
|   // - returns success or failure of write to Output Data Rate register | ||||
|  | ||||
|   this->odr_config_.bit.pwr_mode = mode; | ||||
|  | ||||
|   // write odr register | ||||
|   return this->write_byte(BMP581_ODR, this->odr_config_.reg); | ||||
| } | ||||
|  | ||||
| }  // namespace bmp581 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										222
									
								
								esphome/components/bmp581/bmp581.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								esphome/components/bmp581/bmp581.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,222 @@ | ||||
| // All datasheet page references refer to Bosch Document Number BST-BMP581-DS004-04 (revision number 1.4) | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace bmp581 { | ||||
|  | ||||
| static const uint8_t BMP581_ASIC_ID = 0x50;  // BMP581's ASIC chip ID (page 51 of datasheet) | ||||
| static const uint8_t RESET_COMMAND = 0xB6;   // Soft reset command | ||||
|  | ||||
| // BMP581 Register Addresses | ||||
| enum { | ||||
|   BMP581_CHIP_ID = 0x01,     // read chip ID | ||||
|   BMP581_INT_SOURCE = 0x15,  // write interrupt sources | ||||
|   BMP581_MEASUREMENT_DATA = | ||||
|       0x1D,  // read measurement registers, 0x1D-0x1F are temperature XLSB to MSB and 0x20-0x22 are pressure XLSB to MSB | ||||
|   BMP581_INT_STATUS = 0x27,  // read interrupt statuses | ||||
|   BMP581_STATUS = 0x28,      // read sensor status | ||||
|   BMP581_DSP = 0x30,         // write sensor configuration | ||||
|   BMP581_DSP_IIR = 0x31,     // write IIR filter configuration | ||||
|   BMP581_OSR = 0x36,         // write oversampling configuration | ||||
|   BMP581_ODR = 0x37,         // write data rate and power mode configuration | ||||
|   BMP581_COMMAND = 0x7E      // write sensor command | ||||
| }; | ||||
|  | ||||
| // BMP581 Power mode operations | ||||
| enum OperationMode { | ||||
|   STANDBY_MODE = 0x0,  // no active readings | ||||
|   NORMAL_MODE = 0x1,   // read continuously at ODR configured rate and standby between | ||||
|   FORCED_MODE = 0x2,   // read sensor once (only reading mode used by this component) | ||||
|   NONSTOP_MODE = 0x3   // read continuously with no standby | ||||
| }; | ||||
|  | ||||
| // Temperature and pressure sensors can be oversampled to reduce noise | ||||
| enum Oversampling { | ||||
|   OVERSAMPLING_NONE = 0x0, | ||||
|   OVERSAMPLING_X2 = 0x1, | ||||
|   OVERSAMPLING_X4 = 0x2, | ||||
|   OVERSAMPLING_X8 = 0x3, | ||||
|   OVERSAMPLING_X16 = 0x4, | ||||
|   OVERSAMPLING_X32 = 0x5, | ||||
|   OVERSAMPLING_X64 = 0x6, | ||||
|   OVERSAMPLING_X128 = 0x7 | ||||
| }; | ||||
|  | ||||
| // Infinite Impulse Response filter reduces noise caused by ambient disturbances | ||||
| enum IIRFilter { | ||||
|   IIR_FILTER_OFF = 0x0, | ||||
|   IIR_FILTER_2 = 0x1, | ||||
|   IIR_FILTER_4 = 0x2, | ||||
|   IIR_FILTER_8 = 0x3, | ||||
|   IIR_FILTER_16 = 0x4, | ||||
|   IIR_FILTER_32 = 0x5, | ||||
|   IIR_FILTER_64 = 0x6, | ||||
|   IIR_FILTER_128 = 0x7 | ||||
| }; | ||||
|  | ||||
| class BMP581Component : public PollingComponent, public i2c::I2CDevice { | ||||
|  public: | ||||
|   float get_setup_priority() const override { return setup_priority::DATA; } | ||||
|  | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void setup() override; | ||||
|   void update() override; | ||||
|  | ||||
|   void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; } | ||||
|   void set_pressure_sensor(sensor::Sensor *pressure_sensor) { this->pressure_sensor_ = pressure_sensor; } | ||||
|  | ||||
|   void set_temperature_oversampling_config(Oversampling temperature_oversampling) { | ||||
|     this->temperature_oversampling_ = temperature_oversampling; | ||||
|   } | ||||
|   void set_pressure_oversampling_config(Oversampling pressure_oversampling) { | ||||
|     this->pressure_oversampling_ = pressure_oversampling; | ||||
|   } | ||||
|  | ||||
|   void set_temperature_iir_filter_config(IIRFilter iir_temperature_level) { | ||||
|     this->iir_temperature_level_ = iir_temperature_level; | ||||
|   } | ||||
|   void set_pressure_iir_filter_config(IIRFilter iir_pressure_level) { this->iir_pressure_level_ = iir_pressure_level; } | ||||
|  | ||||
|   void set_conversion_time(uint8_t conversion_time) { this->conversion_time_ = conversion_time; } | ||||
|  | ||||
|  protected: | ||||
|   sensor::Sensor *temperature_sensor_{nullptr}; | ||||
|   sensor::Sensor *pressure_sensor_{nullptr}; | ||||
|  | ||||
|   Oversampling temperature_oversampling_; | ||||
|   Oversampling pressure_oversampling_; | ||||
|  | ||||
|   IIRFilter iir_temperature_level_; | ||||
|   IIRFilter iir_pressure_level_; | ||||
|  | ||||
|   // Stores the sensors conversion time needed for a measurement based on oversampling settings and datasheet (page 12) | ||||
|   // Computed in Python during codegen | ||||
|   uint8_t conversion_time_; | ||||
|  | ||||
|   // Checks if the BMP581 has measurement data ready by checking the sensor's interrupts | ||||
|   bool check_data_readiness_(); | ||||
|  | ||||
|   // Flushes the IIR filter and primes an initial reading | ||||
|   bool prime_iir_filter_(); | ||||
|  | ||||
|   // Reads temperature data from sensor and converts data to measurement in degrees Celsius | ||||
|   bool read_temperature_(float &temperature); | ||||
|   // Reads temperature and pressure data from sensor and converts data to measurements in degrees Celsius and Pa | ||||
|   bool read_temperature_and_pressure_(float &temperature, float &pressure); | ||||
|  | ||||
|   // Soft resets the BMP581 | ||||
|   bool reset_(); | ||||
|  | ||||
|   // Initiates a measurement on sensor by switching to FORCED_MODE | ||||
|   bool start_measurement_(); | ||||
|  | ||||
|   // Writes the IIR filter configuration to the DSP and DSP_IIR registers | ||||
|   bool write_iir_settings_(IIRFilter temperature_iir, IIRFilter pressure_iir); | ||||
|  | ||||
|   // Writes whether to enable the data ready interrupt to the interrupt source register | ||||
|   bool write_interrupt_source_settings_(bool data_ready_enable); | ||||
|  | ||||
|   // Writes the oversampling settings to the OSR register | ||||
|   bool write_oversampling_settings_(Oversampling temperature_oversampling, Oversampling pressure_oversampling); | ||||
|  | ||||
|   // Sets the power mode on the BMP581 by writing to the ODR register | ||||
|   bool write_power_mode_(OperationMode mode); | ||||
|  | ||||
|   enum ErrorCode { | ||||
|     NONE = 0, | ||||
|     ERROR_COMMUNICATION_FAILED, | ||||
|     ERROR_WRONG_CHIP_ID, | ||||
|     ERROR_SENSOR_STATUS, | ||||
|     ERROR_SENSOR_RESET, | ||||
|     ERROR_PRIME_IIR_FAILED | ||||
|   } error_code_{NONE}; | ||||
|  | ||||
|   // BMP581's interrupt source register (address 0x15) to configure which interrupts are enabled (page 54 of datasheet) | ||||
|   union { | ||||
|     struct { | ||||
|       uint8_t drdy_data_reg_en : 1;  // Data ready interrupt enable | ||||
|       uint8_t fifo_full_en : 1;      // FIFO full interrupt enable | ||||
|       uint8_t fifo_ths_en : 1;       // FIFO threshold/watermark interrupt enable | ||||
|       uint8_t oor_p_en : 1;          // Pressure data out-of-range interrupt enable | ||||
|     } bit; | ||||
|     uint8_t reg; | ||||
|   } int_source_ = {.reg = 0}; | ||||
|  | ||||
|   // BMP581's interrupt status register (address 0x27) to determine ensor's current state (page 58 of datasheet) | ||||
|   union { | ||||
|     struct { | ||||
|       uint8_t drdy_data_reg : 1;  // Data ready | ||||
|       uint8_t fifo_full : 1;      // FIFO full | ||||
|       uint8_t fifo_ths : 1;       // FIFO fhreshold/watermark | ||||
|       uint8_t oor_p : 1;          // Pressure data out-of-range | ||||
|       uint8_t por : 1;            // Power-On-Reset complete | ||||
|     } bit; | ||||
|     uint8_t reg; | ||||
|   } int_status_ = {.reg = 0}; | ||||
|  | ||||
|   // BMP581's status register (address 0x28) to determine if sensor has setup correctly (page 58 of datasheet) | ||||
|   union { | ||||
|     struct { | ||||
|       uint8_t status_core_rdy : 1; | ||||
|       uint8_t status_nvm_rdy : 1;             // asserted if NVM is ready of operations | ||||
|       uint8_t status_nvm_err : 1;             // asserted if NVM error | ||||
|       uint8_t status_nvm_cmd_err : 1;         // asserted if boot command error | ||||
|       uint8_t status_boot_err_corrected : 1;  // asserted if a boot error has been corrected | ||||
|       uint8_t : 2; | ||||
|       uint8_t st_crack_pass : 1;  // asserted if crack check has executed without detecting a crack | ||||
|     } bit; | ||||
|     uint8_t reg; | ||||
|   } status_ = {.reg = 0}; | ||||
|  | ||||
|   // BMP581's dsp register (address 0x30) to configure data registers iir selection (page 61 of datasheet) | ||||
|   union { | ||||
|     struct { | ||||
|       uint8_t comp_pt_en : 2;           // enable temperature and pressure compensation | ||||
|       uint8_t iir_flush_forced_en : 1;  // IIR filter is flushed in forced mode | ||||
|       uint8_t shdw_sel_iir_t : 1;       // temperature data register value selected before or after iir | ||||
|       uint8_t fifo_sel_iir_t : 1;       // FIFO temperature data register value secected before or after iir | ||||
|       uint8_t shdw_sel_iir_p : 1;       // pressure data register value selected before or after iir | ||||
|       uint8_t fifo_sel_iir_p : 1;       // FIFO pressure data register value selected before or after iir | ||||
|       uint8_t oor_sel_iir_p : 1;        // pressure out-of-range value selected before or after iir | ||||
|     } bit; | ||||
|     uint8_t reg; | ||||
|   } dsp_config_ = {.reg = 0}; | ||||
|  | ||||
|   // BMP581's iir register (address 0x31) to configure iir filtering(page 62 of datasheet) | ||||
|   union { | ||||
|     struct { | ||||
|       uint8_t set_iir_t : 3;  // Temperature IIR filter coefficient | ||||
|       uint8_t set_iir_p : 3;  // Pressure IIR filter coefficient | ||||
|     } bit; | ||||
|     uint8_t reg; | ||||
|   } iir_config_ = {.reg = 0}; | ||||
|  | ||||
|   // BMP581's OSR register (address 0x36) to configure Over-Sampling Rates (page 64 of datasheet) | ||||
|   union { | ||||
|     struct { | ||||
|       uint8_t osr_t : 3;     // Temperature oversampling | ||||
|       uint8_t osr_p : 3;     // Pressure oversampling | ||||
|       uint8_t press_en : 1;  // Enables pressure measurement | ||||
|     } bit; | ||||
|     uint8_t reg; | ||||
|   } osr_config_ = {.reg = 0}; | ||||
|  | ||||
|   // BMP581's odr register (address 0x37) to configure output data rate and power mode (page 64 of datasheet) | ||||
|   union { | ||||
|     struct { | ||||
|       uint8_t pwr_mode : 2;  // power mode of sensor | ||||
|       uint8_t odr : 5;       // output data rate | ||||
|       uint8_t deep_dis : 1;  // deep standby disabled if asserted | ||||
|     } bit; | ||||
|     uint8_t reg; | ||||
|   } odr_config_ = {.reg = 0}; | ||||
| }; | ||||
|  | ||||
| }  // namespace bmp581 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										163
									
								
								esphome/components/bmp581/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								esphome/components/bmp581/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | ||||
| import math | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import i2c, sensor | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_IIR_FILTER, | ||||
|     CONF_OVERSAMPLING, | ||||
|     CONF_PRESSURE, | ||||
|     CONF_TEMPERATURE, | ||||
|     DEVICE_CLASS_ATMOSPHERIC_PRESSURE, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     UNIT_PASCAL, | ||||
| ) | ||||
|  | ||||
| CODEOWNERS = ["@kahrendt"] | ||||
| DEPENDENCIES = ["i2c"] | ||||
|  | ||||
| bmp581_ns = cg.esphome_ns.namespace("bmp581") | ||||
|  | ||||
| Oversampling = bmp581_ns.enum("Oversampling") | ||||
| OVERSAMPLING_OPTIONS = { | ||||
|     "NONE": Oversampling.OVERSAMPLING_NONE, | ||||
|     "2X": Oversampling.OVERSAMPLING_X2, | ||||
|     "4X": Oversampling.OVERSAMPLING_X4, | ||||
|     "8X": Oversampling.OVERSAMPLING_X8, | ||||
|     "16X": Oversampling.OVERSAMPLING_X16, | ||||
|     "32X": Oversampling.OVERSAMPLING_X32, | ||||
|     "64X": Oversampling.OVERSAMPLING_X64, | ||||
|     "128X": Oversampling.OVERSAMPLING_X128, | ||||
| } | ||||
|  | ||||
| IIRFilter = bmp581_ns.enum("IIRFilter") | ||||
| IIR_FILTER_OPTIONS = { | ||||
|     "OFF": IIRFilter.IIR_FILTER_OFF, | ||||
|     "2X": IIRFilter.IIR_FILTER_2, | ||||
|     "4X": IIRFilter.IIR_FILTER_4, | ||||
|     "8X": IIRFilter.IIR_FILTER_8, | ||||
|     "16X": IIRFilter.IIR_FILTER_16, | ||||
|     "32X": IIRFilter.IIR_FILTER_32, | ||||
|     "64X": IIRFilter.IIR_FILTER_64, | ||||
|     "128X": IIRFilter.IIR_FILTER_128, | ||||
| } | ||||
|  | ||||
| BMP581Component = bmp581_ns.class_( | ||||
|     "BMP581Component", cg.PollingComponent, i2c.I2CDevice | ||||
| ) | ||||
|  | ||||
|  | ||||
| def compute_measurement_conversion_time(config): | ||||
|     # - adds up sensor conversion time based on temperature and pressure oversampling rates given in datasheet | ||||
|     # - returns a rounded up time in ms | ||||
|  | ||||
|     # Page 12 of datasheet | ||||
|     PRESSURE_OVERSAMPLING_CONVERSION_TIMES = { | ||||
|         "NONE": 1.0, | ||||
|         "2X": 1.7, | ||||
|         "4X": 2.9, | ||||
|         "8X": 5.4, | ||||
|         "16X": 10.4, | ||||
|         "32X": 20.4, | ||||
|         "64X": 40.4, | ||||
|         "128X": 80.4, | ||||
|     } | ||||
|  | ||||
|     # Page 12 of datasheet | ||||
|     TEMPERATURE_OVERSAMPLING_CONVERSION_TIMES = { | ||||
|         "NONE": 1.0, | ||||
|         "2X": 1.1, | ||||
|         "4X": 1.5, | ||||
|         "8X": 2.1, | ||||
|         "16X": 3.3, | ||||
|         "32X": 5.8, | ||||
|         "64X": 10.8, | ||||
|         "128X": 20.8, | ||||
|     } | ||||
|  | ||||
|     pressure_conversion_time = ( | ||||
|         0.0  # No conversion time necessary without a pressure sensor | ||||
|     ) | ||||
|     if pressure_config := config.get(CONF_PRESSURE): | ||||
|         pressure_conversion_time = PRESSURE_OVERSAMPLING_CONVERSION_TIMES[ | ||||
|             pressure_config.get(CONF_OVERSAMPLING) | ||||
|         ] | ||||
|  | ||||
|     temperature_conversion_time = ( | ||||
|         1.0  # BMP581 always samples the temperature even if only reading pressure | ||||
|     ) | ||||
|     if temperature_config := config.get(CONF_TEMPERATURE): | ||||
|         temperature_conversion_time = TEMPERATURE_OVERSAMPLING_CONVERSION_TIMES[ | ||||
|             temperature_config.get(CONF_OVERSAMPLING) | ||||
|         ] | ||||
|  | ||||
|     # Datasheet indicates a 5% possible error in each conversion time listed | ||||
|     return math.ceil(1.05 * (pressure_conversion_time + temperature_conversion_time)) | ||||
|  | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(BMP581Component), | ||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_OVERSAMPLING, default="NONE"): cv.enum( | ||||
|                         OVERSAMPLING_OPTIONS, upper=True | ||||
|                     ), | ||||
|                     cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( | ||||
|                         IIR_FILTER_OPTIONS, upper=True | ||||
|                     ), | ||||
|                 } | ||||
|             ), | ||||
|             cv.Optional(CONF_PRESSURE): sensor.sensor_schema( | ||||
|                 unit_of_measurement=UNIT_PASCAL, | ||||
|                 accuracy_decimals=0, | ||||
|                 device_class=DEVICE_CLASS_ATMOSPHERIC_PRESSURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( | ||||
|                         OVERSAMPLING_OPTIONS, upper=True | ||||
|                     ), | ||||
|                     cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( | ||||
|                         IIR_FILTER_OPTIONS, upper=True | ||||
|                     ), | ||||
|                 } | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.polling_component_schema("60s")) | ||||
|     .extend(i2c.i2c_device_schema(0x46)) | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|     await i2c.register_i2c_device(var, config) | ||||
|     if temperature_config := config.get(CONF_TEMPERATURE): | ||||
|         sens = await sensor.new_sensor(temperature_config) | ||||
|         cg.add(var.set_temperature_sensor(sens)) | ||||
|         cg.add( | ||||
|             var.set_temperature_oversampling_config( | ||||
|                 temperature_config[CONF_OVERSAMPLING] | ||||
|             ) | ||||
|         ) | ||||
|         cg.add( | ||||
|             var.set_temperature_iir_filter_config(temperature_config[CONF_IIR_FILTER]) | ||||
|         ) | ||||
|  | ||||
|     if pressure_config := config.get(CONF_PRESSURE): | ||||
|         sens = await sensor.new_sensor(pressure_config) | ||||
|         cg.add(var.set_pressure_sensor(sens)) | ||||
|         cg.add(var.set_pressure_oversampling_config(pressure_config[CONF_OVERSAMPLING])) | ||||
|         cg.add(var.set_pressure_iir_filter_config(pressure_config[CONF_IIR_FILTER])) | ||||
|  | ||||
|     cg.add(var.set_conversion_time(compute_measurement_conversion_time(config))) | ||||
| @@ -1355,6 +1355,14 @@ sensor: | ||||
|     name: "Distance" | ||||
|     update_interval: 60s | ||||
|     i2c_id: i2c_bus | ||||
|   - platform: bmp581 | ||||
|     i2c_id: i2c_bus | ||||
|     temperature: | ||||
|       name: "BMP581 Temperature" | ||||
|       iir_filter: 2x | ||||
|     pressure: | ||||
|       name: "BMP581 Pressure" | ||||
|       oversampling: 128x | ||||
|  | ||||
| esp32_touch: | ||||
|   setup_mode: false | ||||
|   | ||||
		Reference in New Issue
	
	Block a user