mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Add support for QMP6988 Pressure sensor (#3192)
This commit is contained in:
		| @@ -151,6 +151,7 @@ esphome/components/preferences/* @esphome/core | |||||||
| esphome/components/psram/* @esphome/core | esphome/components/psram/* @esphome/core | ||||||
| esphome/components/pulse_meter/* @cstaahl @stevebaxter | esphome/components/pulse_meter/* @cstaahl @stevebaxter | ||||||
| esphome/components/pvvx_mithermometer/* @pasiz | esphome/components/pvvx_mithermometer/* @pasiz | ||||||
|  | esphome/components/qmp6988/* @andrewpc | ||||||
| esphome/components/qr_code/* @wjtje | esphome/components/qr_code/* @wjtje | ||||||
| esphome/components/radon_eye_ble/* @jeffeb3 | esphome/components/radon_eye_ble/* @jeffeb3 | ||||||
| esphome/components/radon_eye_rd200/* @jeffeb3 | esphome/components/radon_eye_rd200/* @jeffeb3 | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								esphome/components/qmp6988/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/qmp6988/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | CODEOWNERS = ["@andrewpc"] | ||||||
							
								
								
									
										397
									
								
								esphome/components/qmp6988/qmp6988.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								esphome/components/qmp6988/qmp6988.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,397 @@ | |||||||
|  | #include "qmp6988.h" | ||||||
|  | #include <cmath> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace qmp6988 { | ||||||
|  |  | ||||||
|  | static const uint8_t QMP6988_CHIP_ID = 0x5C; | ||||||
|  |  | ||||||
|  | static const uint8_t QMP6988_CHIP_ID_REG = 0xD1;     /* Chip ID confirmation Register */ | ||||||
|  | static const uint8_t QMP6988_RESET_REG = 0xE0;       /* Device reset register */ | ||||||
|  | static const uint8_t QMP6988_DEVICE_STAT_REG = 0xF3; /* Device state register */ | ||||||
|  | static const uint8_t QMP6988_CTRLMEAS_REG = 0xF4;    /* Measurement Condition Control Register */ | ||||||
|  | /* data */ | ||||||
|  | static const uint8_t QMP6988_PRESSURE_MSB_REG = 0xF7;    /* Pressure MSB Register */ | ||||||
|  | static const uint8_t QMP6988_TEMPERATURE_MSB_REG = 0xFA; /* Temperature MSB Reg */ | ||||||
|  |  | ||||||
|  | /* compensation calculation */ | ||||||
|  | static const uint8_t QMP6988_CALIBRATION_DATA_START = 0xA0; /* QMP6988 compensation coefficients */ | ||||||
|  | static const uint8_t QMP6988_CALIBRATION_DATA_LENGTH = 25; | ||||||
|  |  | ||||||
|  | static const uint8_t SHIFT_RIGHT_4_POSITION = 4; | ||||||
|  | static const uint8_t SHIFT_LEFT_2_POSITION = 2; | ||||||
|  | static const uint8_t SHIFT_LEFT_4_POSITION = 4; | ||||||
|  | static const uint8_t SHIFT_LEFT_5_POSITION = 5; | ||||||
|  | static const uint8_t SHIFT_LEFT_8_POSITION = 8; | ||||||
|  | static const uint8_t SHIFT_LEFT_12_POSITION = 12; | ||||||
|  | static const uint8_t SHIFT_LEFT_16_POSITION = 16; | ||||||
|  |  | ||||||
|  | /* power mode */ | ||||||
|  | static const uint8_t QMP6988_SLEEP_MODE = 0x00; | ||||||
|  | static const uint8_t QMP6988_FORCED_MODE = 0x01; | ||||||
|  | static const uint8_t QMP6988_NORMAL_MODE = 0x03; | ||||||
|  |  | ||||||
|  | static const uint8_t QMP6988_CTRLMEAS_REG_MODE_POS = 0; | ||||||
|  | static const uint8_t QMP6988_CTRLMEAS_REG_MODE_MSK = 0x03; | ||||||
|  | static const uint8_t QMP6988_CTRLMEAS_REG_MODE_LEN = 2; | ||||||
|  |  | ||||||
|  | static const uint8_t QMP6988_CTRLMEAS_REG_OSRST_POS = 5; | ||||||
|  | static const uint8_t QMP6988_CTRLMEAS_REG_OSRST_MSK = 0xE0; | ||||||
|  | static const uint8_t QMP6988_CTRLMEAS_REG_OSRST_LEN = 3; | ||||||
|  |  | ||||||
|  | static const uint8_t QMP6988_CTRLMEAS_REG_OSRSP_POS = 2; | ||||||
|  | static const uint8_t QMP6988_CTRLMEAS_REG_OSRSP_MSK = 0x1C; | ||||||
|  | static const uint8_t QMP6988_CTRLMEAS_REG_OSRSP_LEN = 3; | ||||||
|  |  | ||||||
|  | static const uint8_t QMP6988_CONFIG_REG = 0xF1; /*IIR filter co-efficient setting Register*/ | ||||||
|  | static const uint8_t QMP6988_CONFIG_REG_FILTER_POS = 0; | ||||||
|  | static const uint8_t QMP6988_CONFIG_REG_FILTER_MSK = 0x07; | ||||||
|  | static const uint8_t QMP6988_CONFIG_REG_FILTER_LEN = 3; | ||||||
|  |  | ||||||
|  | static const uint32_t SUBTRACTOR = 8388608; | ||||||
|  |  | ||||||
|  | static const char *const TAG = "qmp6988"; | ||||||
|  |  | ||||||
|  | static const char *oversampling_to_str(QMP6988Oversampling oversampling) { | ||||||
|  |   switch (oversampling) { | ||||||
|  |     case QMP6988_OVERSAMPLING_SKIPPED: | ||||||
|  |       return "None"; | ||||||
|  |     case QMP6988_OVERSAMPLING_1X: | ||||||
|  |       return "1x"; | ||||||
|  |     case QMP6988_OVERSAMPLING_2X: | ||||||
|  |       return "2x"; | ||||||
|  |     case QMP6988_OVERSAMPLING_4X: | ||||||
|  |       return "4x"; | ||||||
|  |     case QMP6988_OVERSAMPLING_8X: | ||||||
|  |       return "8x"; | ||||||
|  |     case QMP6988_OVERSAMPLING_16X: | ||||||
|  |       return "16x"; | ||||||
|  |     case QMP6988_OVERSAMPLING_32X: | ||||||
|  |       return "32x"; | ||||||
|  |     case QMP6988_OVERSAMPLING_64X: | ||||||
|  |       return "64x"; | ||||||
|  |     default: | ||||||
|  |       return "UNKNOWN"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char *iir_filter_to_str(QMP6988IIRFilter filter) { | ||||||
|  |   switch (filter) { | ||||||
|  |     case QMP6988_IIR_FILTER_OFF: | ||||||
|  |       return "OFF"; | ||||||
|  |     case QMP6988_IIR_FILTER_2X: | ||||||
|  |       return "2x"; | ||||||
|  |     case QMP6988_IIR_FILTER_4X: | ||||||
|  |       return "4x"; | ||||||
|  |     case QMP6988_IIR_FILTER_8X: | ||||||
|  |       return "8x"; | ||||||
|  |     case QMP6988_IIR_FILTER_16X: | ||||||
|  |       return "16x"; | ||||||
|  |     case QMP6988_IIR_FILTER_32X: | ||||||
|  |       return "32x"; | ||||||
|  |     default: | ||||||
|  |       return "UNKNOWN"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool QMP6988Component::device_check_() { | ||||||
|  |   uint8_t ret = 0; | ||||||
|  |  | ||||||
|  |   ret = this->read_register(QMP6988_CHIP_ID_REG, &(qmp6988_data_.chip_id), 1); | ||||||
|  |   if (ret != i2c::ERROR_OK) { | ||||||
|  |     ESP_LOGE(TAG, "%s: read chip ID (0xD1) failed", __func__); | ||||||
|  |   } | ||||||
|  |   ESP_LOGD(TAG, "qmp6988 read chip id = 0x%x", qmp6988_data_.chip_id); | ||||||
|  |  | ||||||
|  |   return qmp6988_data_.chip_id == QMP6988_CHIP_ID; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool QMP6988Component::get_calibration_data_() { | ||||||
|  |   uint8_t status = 0; | ||||||
|  |   // BITFIELDS temp_COE; | ||||||
|  |   uint8_t a_data_uint8_tr[QMP6988_CALIBRATION_DATA_LENGTH] = {0}; | ||||||
|  |   int len; | ||||||
|  |  | ||||||
|  |   for (len = 0; len < QMP6988_CALIBRATION_DATA_LENGTH; len += 1) { | ||||||
|  |     status = this->read_register(QMP6988_CALIBRATION_DATA_START + len, &a_data_uint8_tr[len], 1); | ||||||
|  |     if (status != i2c::ERROR_OK) { | ||||||
|  |       ESP_LOGE(TAG, "qmp6988 read calibration data (0xA0) error!"); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_a0 = | ||||||
|  |       (QMP6988_S32_t)(((a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) | | ||||||
|  |                        (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) | (a_data_uint8_tr[24] & 0x0f)) | ||||||
|  |                       << 12); | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_a0 = qmp6988_data_.qmp6988_cali.COE_a0 >> 12; | ||||||
|  |  | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_a1 = | ||||||
|  |       (QMP6988_S16_t)(((a_data_uint8_tr[20]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]); | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_a2 = | ||||||
|  |       (QMP6988_S16_t)(((a_data_uint8_tr[22]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]); | ||||||
|  |  | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_b00 = | ||||||
|  |       (QMP6988_S32_t)(((a_data_uint8_tr[0] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[1] << SHIFT_LEFT_4_POSITION) | | ||||||
|  |                        ((a_data_uint8_tr[24] & 0xf0) >> SHIFT_RIGHT_4_POSITION)) | ||||||
|  |                       << 12); | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_b00 = qmp6988_data_.qmp6988_cali.COE_b00 >> 12; | ||||||
|  |  | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_bt1 = | ||||||
|  |       (QMP6988_S16_t)(((a_data_uint8_tr[2]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]); | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_bt2 = | ||||||
|  |       (QMP6988_S16_t)(((a_data_uint8_tr[4]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]); | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_bp1 = | ||||||
|  |       (QMP6988_S16_t)(((a_data_uint8_tr[6]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]); | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_b11 = | ||||||
|  |       (QMP6988_S16_t)(((a_data_uint8_tr[8]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]); | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_bp2 = | ||||||
|  |       (QMP6988_S16_t)(((a_data_uint8_tr[10]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]); | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_b12 = | ||||||
|  |       (QMP6988_S16_t)(((a_data_uint8_tr[12]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]); | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_b21 = | ||||||
|  |       (QMP6988_S16_t)(((a_data_uint8_tr[14]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]); | ||||||
|  |   qmp6988_data_.qmp6988_cali.COE_bp3 = | ||||||
|  |       (QMP6988_S16_t)(((a_data_uint8_tr[16]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]); | ||||||
|  |  | ||||||
|  |   ESP_LOGV(TAG, "<-----------calibration data-------------->\r\n"); | ||||||
|  |   ESP_LOGV(TAG, "COE_a0[%d] COE_a1[%d] COE_a2[%d] COE_b00[%d]\r\n", qmp6988_data_.qmp6988_cali.COE_a0, | ||||||
|  |            qmp6988_data_.qmp6988_cali.COE_a1, qmp6988_data_.qmp6988_cali.COE_a2, qmp6988_data_.qmp6988_cali.COE_b00); | ||||||
|  |   ESP_LOGV(TAG, "COE_bt1[%d] COE_bt2[%d] COE_bp1[%d] COE_b11[%d]\r\n", qmp6988_data_.qmp6988_cali.COE_bt1, | ||||||
|  |            qmp6988_data_.qmp6988_cali.COE_bt2, qmp6988_data_.qmp6988_cali.COE_bp1, qmp6988_data_.qmp6988_cali.COE_b11); | ||||||
|  |   ESP_LOGV(TAG, "COE_bp2[%d] COE_b12[%d] COE_b21[%d] COE_bp3[%d]\r\n", qmp6988_data_.qmp6988_cali.COE_bp2, | ||||||
|  |            qmp6988_data_.qmp6988_cali.COE_b12, qmp6988_data_.qmp6988_cali.COE_b21, qmp6988_data_.qmp6988_cali.COE_bp3); | ||||||
|  |   ESP_LOGV(TAG, "<-----------calibration data-------------->\r\n"); | ||||||
|  |  | ||||||
|  |   qmp6988_data_.ik.a0 = qmp6988_data_.qmp6988_cali.COE_a0;    // 20Q4 | ||||||
|  |   qmp6988_data_.ik.b00 = qmp6988_data_.qmp6988_cali.COE_b00;  // 20Q4 | ||||||
|  |  | ||||||
|  |   qmp6988_data_.ik.a1 = 3608L * (QMP6988_S32_t) qmp6988_data_.qmp6988_cali.COE_a1 - 1731677965L;  // 31Q23 | ||||||
|  |   qmp6988_data_.ik.a2 = 16889L * (QMP6988_S32_t) qmp6988_data_.qmp6988_cali.COE_a2 - 87619360L;   // 30Q47 | ||||||
|  |  | ||||||
|  |   qmp6988_data_.ik.bt1 = 2982L * (QMP6988_S64_t) qmp6988_data_.qmp6988_cali.COE_bt1 + 107370906L;    // 28Q15 | ||||||
|  |   qmp6988_data_.ik.bt2 = 329854L * (QMP6988_S64_t) qmp6988_data_.qmp6988_cali.COE_bt2 + 108083093L;  // 34Q38 | ||||||
|  |   qmp6988_data_.ik.bp1 = 19923L * (QMP6988_S64_t) qmp6988_data_.qmp6988_cali.COE_bp1 + 1133836764L;  // 31Q20 | ||||||
|  |   qmp6988_data_.ik.b11 = 2406L * (QMP6988_S64_t) qmp6988_data_.qmp6988_cali.COE_b11 + 118215883L;    // 28Q34 | ||||||
|  |   qmp6988_data_.ik.bp2 = 3079L * (QMP6988_S64_t) qmp6988_data_.qmp6988_cali.COE_bp2 - 181579595L;    // 29Q43 | ||||||
|  |   qmp6988_data_.ik.b12 = 6846L * (QMP6988_S64_t) qmp6988_data_.qmp6988_cali.COE_b12 + 85590281L;     // 29Q53 | ||||||
|  |   qmp6988_data_.ik.b21 = 13836L * (QMP6988_S64_t) qmp6988_data_.qmp6988_cali.COE_b21 + 79333336L;    // 29Q60 | ||||||
|  |   qmp6988_data_.ik.bp3 = 2915L * (QMP6988_S64_t) qmp6988_data_.qmp6988_cali.COE_bp3 + 157155561L;    // 28Q65 | ||||||
|  |   ESP_LOGV(TAG, "<----------- int calibration data -------------->\r\n"); | ||||||
|  |   ESP_LOGV(TAG, "a0[%d] a1[%d] a2[%d] b00[%d]\r\n", qmp6988_data_.ik.a0, qmp6988_data_.ik.a1, qmp6988_data_.ik.a2, | ||||||
|  |            qmp6988_data_.ik.b00); | ||||||
|  |   ESP_LOGV(TAG, "bt1[%lld] bt2[%lld] bp1[%lld] b11[%lld]\r\n", qmp6988_data_.ik.bt1, qmp6988_data_.ik.bt2, | ||||||
|  |            qmp6988_data_.ik.bp1, qmp6988_data_.ik.b11); | ||||||
|  |   ESP_LOGV(TAG, "bp2[%lld] b12[%lld] b21[%lld] bp3[%lld]\r\n", qmp6988_data_.ik.bp2, qmp6988_data_.ik.b12, | ||||||
|  |            qmp6988_data_.ik.b21, qmp6988_data_.ik.bp3); | ||||||
|  |   ESP_LOGV(TAG, "<----------- int calibration data -------------->\r\n"); | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QMP6988_S16_t QMP6988Component::get_compensated_temperature_(qmp6988_ik_data_t *ik, QMP6988_S32_t dt) { | ||||||
|  |   QMP6988_S16_t ret; | ||||||
|  |   QMP6988_S64_t wk1, wk2; | ||||||
|  |  | ||||||
|  |   // wk1: 60Q4 // bit size | ||||||
|  |   wk1 = ((QMP6988_S64_t) ik->a1 * (QMP6988_S64_t) dt);        // 31Q23+24-1=54 (54Q23) | ||||||
|  |   wk2 = ((QMP6988_S64_t) ik->a2 * (QMP6988_S64_t) dt) >> 14;  // 30Q47+24-1=53 (39Q33) | ||||||
|  |   wk2 = (wk2 * (QMP6988_S64_t) dt) >> 10;                     // 39Q33+24-1=62 (52Q23) | ||||||
|  |   wk2 = ((wk1 + wk2) / 32767) >> 19;                          // 54,52->55Q23 (20Q04) | ||||||
|  |   ret = (QMP6988_S16_t)((ik->a0 + wk2) >> 4);                 // 21Q4 -> 17Q0 | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QMP6988_S32_t QMP6988Component::get_compensated_pressure_(qmp6988_ik_data_t *ik, QMP6988_S32_t dp, QMP6988_S16_t tx) { | ||||||
|  |   QMP6988_S32_t ret; | ||||||
|  |   QMP6988_S64_t wk1, wk2, wk3; | ||||||
|  |  | ||||||
|  |   // wk1 = 48Q16 // bit size | ||||||
|  |   wk1 = ((QMP6988_S64_t) ik->bt1 * (QMP6988_S64_t) tx);        // 28Q15+16-1=43 (43Q15) | ||||||
|  |   wk2 = ((QMP6988_S64_t) ik->bp1 * (QMP6988_S64_t) dp) >> 5;   // 31Q20+24-1=54 (49Q15) | ||||||
|  |   wk1 += wk2;                                                  // 43,49->50Q15 | ||||||
|  |   wk2 = ((QMP6988_S64_t) ik->bt2 * (QMP6988_S64_t) tx) >> 1;   // 34Q38+16-1=49 (48Q37) | ||||||
|  |   wk2 = (wk2 * (QMP6988_S64_t) tx) >> 8;                       // 48Q37+16-1=63 (55Q29) | ||||||
|  |   wk3 = wk2;                                                   // 55Q29 | ||||||
|  |   wk2 = ((QMP6988_S64_t) ik->b11 * (QMP6988_S64_t) tx) >> 4;   // 28Q34+16-1=43 (39Q30) | ||||||
|  |   wk2 = (wk2 * (QMP6988_S64_t) dp) >> 1;                       // 39Q30+24-1=62 (61Q29) | ||||||
|  |   wk3 += wk2;                                                  // 55,61->62Q29 | ||||||
|  |   wk2 = ((QMP6988_S64_t) ik->bp2 * (QMP6988_S64_t) dp) >> 13;  // 29Q43+24-1=52 (39Q30) | ||||||
|  |   wk2 = (wk2 * (QMP6988_S64_t) dp) >> 1;                       // 39Q30+24-1=62 (61Q29) | ||||||
|  |   wk3 += wk2;                                                  // 62,61->63Q29 | ||||||
|  |   wk1 += wk3 >> 14;                                            // Q29 >> 14 -> Q15 | ||||||
|  |   wk2 = ((QMP6988_S64_t) ik->b12 * (QMP6988_S64_t) tx);        // 29Q53+16-1=45 (45Q53) | ||||||
|  |   wk2 = (wk2 * (QMP6988_S64_t) tx) >> 22;                      // 45Q53+16-1=61 (39Q31) | ||||||
|  |   wk2 = (wk2 * (QMP6988_S64_t) dp) >> 1;                       // 39Q31+24-1=62 (61Q30) | ||||||
|  |   wk3 = wk2;                                                   // 61Q30 | ||||||
|  |   wk2 = ((QMP6988_S64_t) ik->b21 * (QMP6988_S64_t) tx) >> 6;   // 29Q60+16-1=45 (39Q54) | ||||||
|  |   wk2 = (wk2 * (QMP6988_S64_t) dp) >> 23;                      // 39Q54+24-1=62 (39Q31) | ||||||
|  |   wk2 = (wk2 * (QMP6988_S64_t) dp) >> 1;                       // 39Q31+24-1=62 (61Q20) | ||||||
|  |   wk3 += wk2;                                                  // 61,61->62Q30 | ||||||
|  |   wk2 = ((QMP6988_S64_t) ik->bp3 * (QMP6988_S64_t) dp) >> 12;  // 28Q65+24-1=51 (39Q53) | ||||||
|  |   wk2 = (wk2 * (QMP6988_S64_t) dp) >> 23;                      // 39Q53+24-1=62 (39Q30) | ||||||
|  |   wk2 = (wk2 * (QMP6988_S64_t) dp);                            // 39Q30+24-1=62 (62Q30) | ||||||
|  |   wk3 += wk2;                                                  // 62,62->63Q30 | ||||||
|  |   wk1 += wk3 >> 15;                                            // Q30 >> 15 = Q15 | ||||||
|  |   wk1 /= 32767L; | ||||||
|  |   wk1 >>= 11;      // Q15 >> 7 = Q4 | ||||||
|  |   wk1 += ik->b00;  // Q4 + 20Q4 | ||||||
|  |   // wk1 >>= 4; // 28Q4 -> 24Q0 | ||||||
|  |   ret = (QMP6988_S32_t) wk1; | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::software_reset_() { | ||||||
|  |   uint8_t ret = 0; | ||||||
|  |  | ||||||
|  |   ret = this->write_byte(QMP6988_RESET_REG, 0xe6); | ||||||
|  |   if (ret != i2c::ERROR_OK) { | ||||||
|  |     ESP_LOGE(TAG, "Software Reset (0xe6) failed"); | ||||||
|  |   } | ||||||
|  |   delay(10); | ||||||
|  |  | ||||||
|  |   this->write_byte(QMP6988_RESET_REG, 0x00); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::set_power_mode_(uint8_t power_mode) { | ||||||
|  |   uint8_t data; | ||||||
|  |  | ||||||
|  |   ESP_LOGD(TAG, "Setting Power mode to: %d", power_mode); | ||||||
|  |  | ||||||
|  |   qmp6988_data_.power_mode = power_mode; | ||||||
|  |   this->read_register(QMP6988_CTRLMEAS_REG, &data, 1); | ||||||
|  |   data = data & 0xfc; | ||||||
|  |   if (power_mode == QMP6988_SLEEP_MODE) { | ||||||
|  |     data |= 0x00; | ||||||
|  |   } else if (power_mode == QMP6988_FORCED_MODE) { | ||||||
|  |     data |= 0x01; | ||||||
|  |   } else if (power_mode == QMP6988_NORMAL_MODE) { | ||||||
|  |     data |= 0x03; | ||||||
|  |   } | ||||||
|  |   this->write_byte(QMP6988_CTRLMEAS_REG, data); | ||||||
|  |  | ||||||
|  |   ESP_LOGD(TAG, "Set Power mode 0xf4=0x%x \r\n", data); | ||||||
|  |  | ||||||
|  |   delay(10); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::write_filter_(unsigned char filter) { | ||||||
|  |   uint8_t data; | ||||||
|  |  | ||||||
|  |   data = (filter & 0x03); | ||||||
|  |   this->write_byte(QMP6988_CONFIG_REG, data); | ||||||
|  |   delay(10); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::write_oversampling_pressure_(unsigned char oversampling_p) { | ||||||
|  |   uint8_t data; | ||||||
|  |  | ||||||
|  |   this->read_register(QMP6988_CTRLMEAS_REG, &data, 1); | ||||||
|  |   data &= 0xe3; | ||||||
|  |   data |= (oversampling_p << 2); | ||||||
|  |   this->write_byte(QMP6988_CTRLMEAS_REG, data); | ||||||
|  |   delay(10); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::write_oversampling_temperature_(unsigned char oversampling_t) { | ||||||
|  |   uint8_t data; | ||||||
|  |  | ||||||
|  |   this->read_register(QMP6988_CTRLMEAS_REG, &data, 1); | ||||||
|  |   data &= 0x1f; | ||||||
|  |   data |= (oversampling_t << 5); | ||||||
|  |   this->write_byte(QMP6988_CTRLMEAS_REG, data); | ||||||
|  |   delay(10); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::set_temperature_oversampling(QMP6988Oversampling oversampling_t) { | ||||||
|  |   this->temperature_oversampling_ = oversampling_t; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::set_pressure_oversampling(QMP6988Oversampling oversampling_p) { | ||||||
|  |   this->pressure_oversampling_ = oversampling_p; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::set_iir_filter(QMP6988IIRFilter iirfilter) { this->iir_filter_ = iirfilter; } | ||||||
|  |  | ||||||
|  | void QMP6988Component::calculate_altitude_(float pressure, float temp) { | ||||||
|  |   float altitude; | ||||||
|  |   altitude = (pow((101325 / pressure), 1 / 5.257) - 1) * (temp + 273.15) / 0.0065; | ||||||
|  |   this->qmp6988_data_.altitude = altitude; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::calculate_pressure_() { | ||||||
|  |   uint8_t err = 0; | ||||||
|  |   QMP6988_U32_t p_read, t_read; | ||||||
|  |   QMP6988_S32_t p_raw, t_raw; | ||||||
|  |   uint8_t a_data_uint8_tr[6] = {0}; | ||||||
|  |   QMP6988_S32_t t_int, p_int; | ||||||
|  |   this->qmp6988_data_.temperature = 0; | ||||||
|  |   this->qmp6988_data_.pressure = 0; | ||||||
|  |  | ||||||
|  |   err = this->read_register(QMP6988_PRESSURE_MSB_REG, a_data_uint8_tr, 6); | ||||||
|  |   if (err != i2c::ERROR_OK) { | ||||||
|  |     ESP_LOGE(TAG, "Error reading raw pressure/temp values"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   p_read = (QMP6988_U32_t)((((QMP6988_U32_t)(a_data_uint8_tr[0])) << SHIFT_LEFT_16_POSITION) | | ||||||
|  |                            (((QMP6988_U16_t)(a_data_uint8_tr[1])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[2])); | ||||||
|  |   p_raw = (QMP6988_S32_t)(p_read - SUBTRACTOR); | ||||||
|  |  | ||||||
|  |   t_read = (QMP6988_U32_t)((((QMP6988_U32_t)(a_data_uint8_tr[3])) << SHIFT_LEFT_16_POSITION) | | ||||||
|  |                            (((QMP6988_U16_t)(a_data_uint8_tr[4])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[5])); | ||||||
|  |   t_raw = (QMP6988_S32_t)(t_read - SUBTRACTOR); | ||||||
|  |  | ||||||
|  |   t_int = this->get_compensated_temperature_(&(qmp6988_data_.ik), t_raw); | ||||||
|  |   p_int = this->get_compensated_pressure_(&(qmp6988_data_.ik), p_raw, t_int); | ||||||
|  |  | ||||||
|  |   this->qmp6988_data_.temperature = (float) t_int / 256.0f; | ||||||
|  |   this->qmp6988_data_.pressure = (float) p_int / 16.0f; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up QMP6988"); | ||||||
|  |  | ||||||
|  |   bool ret; | ||||||
|  |   ret = this->device_check_(); | ||||||
|  |   if (!ret) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "Setup failed - device not found"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->software_reset_(); | ||||||
|  |   this->get_calibration_data_(); | ||||||
|  |   this->set_power_mode_(QMP6988_NORMAL_MODE); | ||||||
|  |   this->write_filter_(iir_filter_); | ||||||
|  |   this->write_oversampling_pressure_(this->pressure_oversampling_); | ||||||
|  |   this->write_oversampling_temperature_(this->temperature_oversampling_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void QMP6988Component::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "QMP6988:"); | ||||||
|  |   LOG_I2C_DEVICE(this); | ||||||
|  |   if (this->is_failed()) { | ||||||
|  |     ESP_LOGE(TAG, "Communication with QMP6988 failed!"); | ||||||
|  |   } | ||||||
|  |   LOG_UPDATE_INTERVAL(this); | ||||||
|  |  | ||||||
|  |   LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "    Temperature Oversampling: %s", oversampling_to_str(this->temperature_oversampling_)); | ||||||
|  |   LOG_SENSOR("  ", "Pressure", this->pressure_sensor_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "    Pressure Oversampling: %s", oversampling_to_str(this->pressure_oversampling_)); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  IIR Filter: %s", iir_filter_to_str(this->iir_filter_)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float QMP6988Component::get_setup_priority() const { return setup_priority::DATA; } | ||||||
|  |  | ||||||
|  | void QMP6988Component::update() { | ||||||
|  |   this->calculate_pressure_(); | ||||||
|  |   float pressurehectopascals = this->qmp6988_data_.pressure / 100; | ||||||
|  |   float temperature = this->qmp6988_data_.temperature; | ||||||
|  |  | ||||||
|  |   ESP_LOGD(TAG, "Temperature=%.2f°C, Pressure=%.2fhPa", temperature, pressurehectopascals); | ||||||
|  |   if (this->temperature_sensor_ != nullptr) | ||||||
|  |     this->temperature_sensor_->publish_state(temperature); | ||||||
|  |   if (this->pressure_sensor_ != nullptr) | ||||||
|  |     this->pressure_sensor_->publish_state(pressurehectopascals); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace qmp6988 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										116
									
								
								esphome/components/qmp6988/qmp6988.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								esphome/components/qmp6988/qmp6988.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/core/helpers.h" | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  | #include "esphome/components/i2c/i2c.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace qmp6988 { | ||||||
|  |  | ||||||
|  | #define QMP6988_U16_t unsigned short | ||||||
|  | #define QMP6988_S16_t short | ||||||
|  | #define QMP6988_U32_t unsigned int | ||||||
|  | #define QMP6988_S32_t int | ||||||
|  | #define QMP6988_U64_t unsigned long long | ||||||
|  | #define QMP6988_S64_t long long | ||||||
|  |  | ||||||
|  | /* oversampling */ | ||||||
|  | enum QMP6988Oversampling { | ||||||
|  |   QMP6988_OVERSAMPLING_SKIPPED = 0x00, | ||||||
|  |   QMP6988_OVERSAMPLING_1X = 0x01, | ||||||
|  |   QMP6988_OVERSAMPLING_2X = 0x02, | ||||||
|  |   QMP6988_OVERSAMPLING_4X = 0x03, | ||||||
|  |   QMP6988_OVERSAMPLING_8X = 0x04, | ||||||
|  |   QMP6988_OVERSAMPLING_16X = 0x05, | ||||||
|  |   QMP6988_OVERSAMPLING_32X = 0x06, | ||||||
|  |   QMP6988_OVERSAMPLING_64X = 0x07, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* filter */ | ||||||
|  | enum QMP6988IIRFilter { | ||||||
|  |   QMP6988_IIR_FILTER_OFF = 0x00, | ||||||
|  |   QMP6988_IIR_FILTER_2X = 0x01, | ||||||
|  |   QMP6988_IIR_FILTER_4X = 0x02, | ||||||
|  |   QMP6988_IIR_FILTER_8X = 0x03, | ||||||
|  |   QMP6988_IIR_FILTER_16X = 0x04, | ||||||
|  |   QMP6988_IIR_FILTER_32X = 0x05, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | using qmp6988_cali_data_t = struct Qmp6988CaliData { | ||||||
|  |   QMP6988_S32_t COE_a0; | ||||||
|  |   QMP6988_S16_t COE_a1; | ||||||
|  |   QMP6988_S16_t COE_a2; | ||||||
|  |   QMP6988_S32_t COE_b00; | ||||||
|  |   QMP6988_S16_t COE_bt1; | ||||||
|  |   QMP6988_S16_t COE_bt2; | ||||||
|  |   QMP6988_S16_t COE_bp1; | ||||||
|  |   QMP6988_S16_t COE_b11; | ||||||
|  |   QMP6988_S16_t COE_bp2; | ||||||
|  |   QMP6988_S16_t COE_b12; | ||||||
|  |   QMP6988_S16_t COE_b21; | ||||||
|  |   QMP6988_S16_t COE_bp3; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | using qmp6988_fk_data_t = struct Qmp6988FkData { | ||||||
|  |   float a0, b00; | ||||||
|  |   float a1, a2, bt1, bt2, bp1, b11, bp2, b12, b21, bp3; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | using qmp6988_ik_data_t = struct Qmp6988IkData { | ||||||
|  |   QMP6988_S32_t a0, b00; | ||||||
|  |   QMP6988_S32_t a1, a2; | ||||||
|  |   QMP6988_S64_t bt1, bt2, bp1, b11, bp2, b12, b21, bp3; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | using qmp6988_data_t = struct Qmp6988Data { | ||||||
|  |   uint8_t chip_id; | ||||||
|  |   uint8_t power_mode; | ||||||
|  |   float temperature; | ||||||
|  |   float pressure; | ||||||
|  |   float altitude; | ||||||
|  |   qmp6988_cali_data_t qmp6988_cali; | ||||||
|  |   qmp6988_ik_data_t ik; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class QMP6988Component : public PollingComponent, public i2c::I2CDevice { | ||||||
|  |  public: | ||||||
|  |   void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } | ||||||
|  |   void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; } | ||||||
|  |  | ||||||
|  |   void setup() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |   void update() override; | ||||||
|  |  | ||||||
|  |   void set_iir_filter(QMP6988IIRFilter iirfilter); | ||||||
|  |   void set_temperature_oversampling(QMP6988Oversampling oversampling_t); | ||||||
|  |   void set_pressure_oversampling(QMP6988Oversampling oversampling_p); | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   qmp6988_data_t qmp6988_data_; | ||||||
|  |   sensor::Sensor *temperature_sensor_; | ||||||
|  |   sensor::Sensor *pressure_sensor_; | ||||||
|  |  | ||||||
|  |   QMP6988Oversampling temperature_oversampling_{QMP6988_OVERSAMPLING_16X}; | ||||||
|  |   QMP6988Oversampling pressure_oversampling_{QMP6988_OVERSAMPLING_16X}; | ||||||
|  |   QMP6988IIRFilter iir_filter_{QMP6988_IIR_FILTER_OFF}; | ||||||
|  |  | ||||||
|  |   void software_reset_(); | ||||||
|  |   bool get_calibration_data_(); | ||||||
|  |   bool device_check_(); | ||||||
|  |   void set_power_mode_(uint8_t power_mode); | ||||||
|  |   void write_oversampling_temperature_(unsigned char oversampling_t); | ||||||
|  |   void write_oversampling_pressure_(unsigned char oversampling_p); | ||||||
|  |   void write_filter_(unsigned char filter); | ||||||
|  |   void calculate_pressure_(); | ||||||
|  |   void calculate_altitude_(float pressure, float temp); | ||||||
|  |  | ||||||
|  |   QMP6988_S32_t get_compensated_pressure_(qmp6988_ik_data_t *ik, QMP6988_S32_t dp, QMP6988_S16_t tx); | ||||||
|  |   QMP6988_S16_t get_compensated_temperature_(qmp6988_ik_data_t *ik, QMP6988_S32_t dt); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace qmp6988 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										101
									
								
								esphome/components/qmp6988/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								esphome/components/qmp6988/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import i2c, sensor | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_PRESSURE, | ||||||
|  |     CONF_TEMPERATURE, | ||||||
|  |     DEVICE_CLASS_PRESSURE, | ||||||
|  |     DEVICE_CLASS_TEMPERATURE, | ||||||
|  |     STATE_CLASS_MEASUREMENT, | ||||||
|  |     UNIT_CELSIUS, | ||||||
|  |     UNIT_HECTOPASCAL, | ||||||
|  |     CONF_IIR_FILTER, | ||||||
|  |     CONF_OVERSAMPLING, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  |  | ||||||
|  | qmp6988_ns = cg.esphome_ns.namespace("qmp6988") | ||||||
|  | QMP6988Component = qmp6988_ns.class_( | ||||||
|  |     "QMP6988Component", cg.PollingComponent, i2c.I2CDevice | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | QMP6988Oversampling = qmp6988_ns.enum("QMP6988Oversampling") | ||||||
|  | OVERSAMPLING_OPTIONS = { | ||||||
|  |     "NONE": QMP6988Oversampling.QMP6988_OVERSAMPLING_SKIPPED, | ||||||
|  |     "1X": QMP6988Oversampling.QMP6988_OVERSAMPLING_1X, | ||||||
|  |     "2X": QMP6988Oversampling.QMP6988_OVERSAMPLING_2X, | ||||||
|  |     "4X": QMP6988Oversampling.QMP6988_OVERSAMPLING_4X, | ||||||
|  |     "8X": QMP6988Oversampling.QMP6988_OVERSAMPLING_8X, | ||||||
|  |     "16X": QMP6988Oversampling.QMP6988_OVERSAMPLING_16X, | ||||||
|  |     "32X": QMP6988Oversampling.QMP6988_OVERSAMPLING_32X, | ||||||
|  |     "64X": QMP6988Oversampling.QMP6988_OVERSAMPLING_64X, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QMP6988IIRFilter = qmp6988_ns.enum("QMP6988IIRFilter") | ||||||
|  | IIR_FILTER_OPTIONS = { | ||||||
|  |     "OFF": QMP6988IIRFilter.QMP6988_IIR_FILTER_OFF, | ||||||
|  |     "2X": QMP6988IIRFilter.QMP6988_IIR_FILTER_2X, | ||||||
|  |     "4X": QMP6988IIRFilter.QMP6988_IIR_FILTER_4X, | ||||||
|  |     "8X": QMP6988IIRFilter.QMP6988_IIR_FILTER_8X, | ||||||
|  |     "16X": QMP6988IIRFilter.QMP6988_IIR_FILTER_16X, | ||||||
|  |     "32X": QMP6988IIRFilter.QMP6988_IIR_FILTER_32X, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = ( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(QMP6988Component), | ||||||
|  |             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="8X"): cv.enum( | ||||||
|  |                         OVERSAMPLING_OPTIONS, upper=True | ||||||
|  |                     ), | ||||||
|  |                 } | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_PRESSURE): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_HECTOPASCAL, | ||||||
|  |                 accuracy_decimals=1, | ||||||
|  |                 device_class=DEVICE_CLASS_PRESSURE, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ).extend( | ||||||
|  |                 { | ||||||
|  |                     cv.Optional(CONF_OVERSAMPLING, default="8X"): 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(0x70)) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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 CONF_TEMPERATURE in config: | ||||||
|  |         conf = config[CONF_TEMPERATURE] | ||||||
|  |         sens = await sensor.new_sensor(conf) | ||||||
|  |         cg.add(var.set_temperature_sensor(sens)) | ||||||
|  |         cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING])) | ||||||
|  |  | ||||||
|  |     if CONF_PRESSURE in config: | ||||||
|  |         conf = config[CONF_PRESSURE] | ||||||
|  |         sens = await sensor.new_sensor(conf) | ||||||
|  |         cg.add(var.set_pressure_sensor(sens)) | ||||||
|  |         cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING])) | ||||||
|  |  | ||||||
|  |     cg.add(var.set_iir_filter(config[CONF_IIR_FILTER])) | ||||||
| @@ -798,6 +798,17 @@ sensor: | |||||||
|           value: 12345 |           value: 12345 | ||||||
|     total: |     total: | ||||||
|       name: "Pulse Meter Total" |       name: "Pulse Meter Total" | ||||||
|  |   - platform: qmp6988 | ||||||
|  |     temperature: | ||||||
|  |       name: "Living Temperature QMP" | ||||||
|  |       oversampling: 32x | ||||||
|  |     pressure: | ||||||
|  |       name: "Living Pressure QMP" | ||||||
|  |       oversampling: 2x | ||||||
|  |     address: 0x70 | ||||||
|  |     update_interval: 30s | ||||||
|  |     iir_filter: 16x | ||||||
|  |     i2c_id: i2c_bus | ||||||
|   - platform: rotary_encoder |   - platform: rotary_encoder | ||||||
|     name: "Rotary Encoder" |     name: "Rotary Encoder" | ||||||
|     id: rotary_encoder1 |     id: rotary_encoder1 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user