mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Fix SGP30 incorrect baseline reading/writing (#936)
* Split the SGP30 baseline into 2 values - According to the SGP30 datasheet, each eCO2 and TVOC baseline is a 2-byte value (MSB first) - The current implementation ignores the MSB of each of the value - Update the schema to allow 2 different baseline values (optional, but both need to be specified for the baseline to apply) * Make both eCO2 and TVOC required if the optional baseline is defined * Make dump_config() looks better
This commit is contained in:
		
				
					committed by
					
						 Otto Winter
						Otto Winter
					
				
			
			
				
	
			
			
			
						parent
						
							92d93d658c
						
					
				
				
					commit
					170d52e0db
				
			| @@ -12,6 +12,8 @@ SGP30Component = sgp30_ns.class_('SGP30Component', cg.PollingComponent, i2c.I2CD | |||||||
| CONF_ECO2 = 'eco2' | CONF_ECO2 = 'eco2' | ||||||
| CONF_TVOC = 'tvoc' | CONF_TVOC = 'tvoc' | ||||||
| CONF_BASELINE = 'baseline' | CONF_BASELINE = 'baseline' | ||||||
|  | CONF_ECO2_BASELINE = 'eco2_baseline' | ||||||
|  | CONF_TVOC_BASELINE = 'tvoc_baseline' | ||||||
| CONF_UPTIME = 'uptime' | CONF_UPTIME = 'uptime' | ||||||
| CONF_COMPENSATION = 'compensation' | CONF_COMPENSATION = 'compensation' | ||||||
| CONF_HUMIDITY_SOURCE = 'humidity_source' | CONF_HUMIDITY_SOURCE = 'humidity_source' | ||||||
| @@ -22,7 +24,10 @@ CONFIG_SCHEMA = cv.Schema({ | |||||||
|     cv.Required(CONF_ECO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION, |     cv.Required(CONF_ECO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION, | ||||||
|                                                  ICON_PERIODIC_TABLE_CO2, 0), |                                                  ICON_PERIODIC_TABLE_CO2, 0), | ||||||
|     cv.Required(CONF_TVOC): sensor.sensor_schema(UNIT_PARTS_PER_BILLION, ICON_RADIATOR, 0), |     cv.Required(CONF_TVOC): sensor.sensor_schema(UNIT_PARTS_PER_BILLION, ICON_RADIATOR, 0), | ||||||
|     cv.Optional(CONF_BASELINE): cv.hex_uint16_t, |     cv.Optional(CONF_BASELINE): cv.Schema({ | ||||||
|  |         cv.Required(CONF_ECO2_BASELINE): cv.hex_uint16_t, | ||||||
|  |         cv.Required(CONF_TVOC_BASELINE): cv.hex_uint16_t, | ||||||
|  |     }), | ||||||
|     cv.Optional(CONF_COMPENSATION): cv.Schema({ |     cv.Optional(CONF_COMPENSATION): cv.Schema({ | ||||||
|         cv.Required(CONF_HUMIDITY_SOURCE): cv.use_id(sensor.Sensor), |         cv.Required(CONF_HUMIDITY_SOURCE): cv.use_id(sensor.Sensor), | ||||||
|         cv.Required(CONF_TEMPERATURE_SOURCE): cv.use_id(sensor.Sensor) |         cv.Required(CONF_TEMPERATURE_SOURCE): cv.use_id(sensor.Sensor) | ||||||
| @@ -44,7 +49,9 @@ def to_code(config): | |||||||
|         cg.add(var.set_tvoc_sensor(sens)) |         cg.add(var.set_tvoc_sensor(sens)) | ||||||
|  |  | ||||||
|     if CONF_BASELINE in config: |     if CONF_BASELINE in config: | ||||||
|         cg.add(var.set_baseline(config[CONF_BASELINE])) |         baseline_config = config[CONF_BASELINE] | ||||||
|  |         cg.add(var.set_eco2_baseline(baseline_config[CONF_ECO2_BASELINE])) | ||||||
|  |         cg.add(var.set_tvoc_baseline(baseline_config[CONF_TVOC_BASELINE])) | ||||||
|  |  | ||||||
|     if CONF_COMPENSATION in config: |     if CONF_COMPENSATION in config: | ||||||
|         compensation_config = config[CONF_COMPENSATION] |         compensation_config = config[CONF_COMPENSATION] | ||||||
|   | |||||||
| @@ -74,9 +74,9 @@ void SGP30Component::setup() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Sensor baseline reliability timer |   // Sensor baseline reliability timer | ||||||
|   if (this->baseline_ > 0) { |   if (this->eco2_baseline_ > 0 && this->tvoc_baseline_ > 0) { | ||||||
|     this->required_warm_up_time_ = IAQ_BASELINE_WARM_UP_SECONDS_WITH_BASELINE_PROVIDED; |     this->required_warm_up_time_ = IAQ_BASELINE_WARM_UP_SECONDS_WITH_BASELINE_PROVIDED; | ||||||
|     this->write_iaq_baseline_(this->baseline_); |     this->write_iaq_baseline_(this->eco2_baseline_, this->tvoc_baseline_); | ||||||
|   } else { |   } else { | ||||||
|     this->required_warm_up_time_ = IAQ_BASELINE_WARM_UP_SECONDS_WITHOUT_BASELINE; |     this->required_warm_up_time_ = IAQ_BASELINE_WARM_UP_SECONDS_WITHOUT_BASELINE; | ||||||
|   } |   } | ||||||
| @@ -106,10 +106,10 @@ void SGP30Component::read_iaq_baseline_() { | |||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       uint8_t eco2baseline = (raw_data[0]); |       uint16_t eco2baseline = (raw_data[0]); | ||||||
|       uint8_t tvocbaseline = (raw_data[1]); |       uint16_t tvocbaseline = (raw_data[1]); | ||||||
|  |  | ||||||
|       ESP_LOGI(TAG, "Current eCO2 & TVOC baseline: 0x%04X", uint16_t((eco2baseline << 8) | (tvocbaseline & 0xFF))); |       ESP_LOGI(TAG, "Current eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", eco2baseline, tvocbaseline); | ||||||
|       this->status_clear_warning(); |       this->status_clear_warning(); | ||||||
|     }); |     }); | ||||||
|   } else { |   } else { | ||||||
| @@ -159,18 +159,19 @@ void SGP30Component::send_env_data_() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void SGP30Component::write_iaq_baseline_(uint16_t baseline) { | void SGP30Component::write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_baseline) { | ||||||
|   uint8_t e_c_o2_baseline = baseline >> 8; |   uint8_t data[7]; | ||||||
|   uint8_t tvoc_baseline = baseline & 0xFF; |  | ||||||
|   uint8_t data[4]; |  | ||||||
|   data[0] = SGP30_CMD_SET_IAQ_BASELINE & 0xFF; |   data[0] = SGP30_CMD_SET_IAQ_BASELINE & 0xFF; | ||||||
|   data[1] = e_c_o2_baseline; |   data[1] = eco2_baseline >> 8; | ||||||
|   data[2] = tvoc_baseline; |   data[2] = eco2_baseline & 0xFF; | ||||||
|   data[3] = sht_crc_(e_c_o2_baseline, tvoc_baseline); |   data[3] = sht_crc_(data[1], data[2]); | ||||||
|   if (!this->write_bytes(SGP30_CMD_SET_IAQ_BASELINE >> 8, data, 4)) { |   data[4] = tvoc_baseline >> 8; | ||||||
|     ESP_LOGE(TAG, "Error applying baseline: 0x%04X", baseline); |   data[5] = tvoc_baseline & 0xFF; | ||||||
|  |   data[6] = sht_crc_(data[4], data[5]); | ||||||
|  |   if (!this->write_bytes(SGP30_CMD_SET_IAQ_BASELINE >> 8, data, 7)) { | ||||||
|  |     ESP_LOGE(TAG, "Error applying eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", eco2_baseline, tvoc_baseline); | ||||||
|   } else |   } else | ||||||
|     ESP_LOGI(TAG, "Initial baseline 0x%04X applied successfully!", baseline); |     ESP_LOGI(TAG, "Initial eCO2 and TVOC baselines applied successfully!"); | ||||||
| } | } | ||||||
|  |  | ||||||
| void SGP30Component::dump_config() { | void SGP30Component::dump_config() { | ||||||
| @@ -196,8 +197,13 @@ void SGP30Component::dump_config() { | |||||||
|     } |     } | ||||||
|   } else { |   } else { | ||||||
|     ESP_LOGCONFIG(TAG, "  Serial number: %llu", this->serial_number_); |     ESP_LOGCONFIG(TAG, "  Serial number: %llu", this->serial_number_); | ||||||
|     ESP_LOGCONFIG(TAG, "  Baseline: 0x%04X%s", this->baseline_, |     if (this->eco2_baseline_ != 0x0000 && this->tvoc_baseline_ != 0x0000) { | ||||||
|                   ((this->baseline_ != 0x0000) ? " (enabled)" : " (disabled)")); |       ESP_LOGCONFIG(TAG, "  Baseline:"); | ||||||
|  |       ESP_LOGCONFIG(TAG, "    eCO2 Baseline: 0x%04X", this->eco2_baseline_); | ||||||
|  |       ESP_LOGCONFIG(TAG, "    TVOC Baseline: 0x%04X", this->tvoc_baseline_); | ||||||
|  |     } else { | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Baseline: No baseline configured"); | ||||||
|  |     } | ||||||
|     ESP_LOGCONFIG(TAG, "  Warm up time: %lds", this->required_warm_up_time_); |     ESP_LOGCONFIG(TAG, "  Warm up time: %lds", this->required_warm_up_time_); | ||||||
|   } |   } | ||||||
|   LOG_UPDATE_INTERVAL(this); |   LOG_UPDATE_INTERVAL(this); | ||||||
|   | |||||||
| @@ -13,7 +13,8 @@ class SGP30Component : public PollingComponent, public i2c::I2CDevice { | |||||||
|  public: |  public: | ||||||
|   void set_eco2_sensor(sensor::Sensor *eco2) { eco2_sensor_ = eco2; } |   void set_eco2_sensor(sensor::Sensor *eco2) { eco2_sensor_ = eco2; } | ||||||
|   void set_tvoc_sensor(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } |   void set_tvoc_sensor(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } | ||||||
|   void set_baseline(uint16_t baseline) { baseline_ = baseline; } |   void set_eco2_baseline(uint16_t eco2_baseline) { eco2_baseline_ = eco2_baseline; } | ||||||
|  |   void set_tvoc_baseline(uint16_t tvoc_baseline) { tvoc_baseline_ = tvoc_baseline; } | ||||||
|   void set_humidity_sensor(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } |   void set_humidity_sensor(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } | ||||||
|   void set_temperature_sensor(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } |   void set_temperature_sensor(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } | ||||||
|  |  | ||||||
| @@ -28,7 +29,7 @@ class SGP30Component : public PollingComponent, public i2c::I2CDevice { | |||||||
|   void send_env_data_(); |   void send_env_data_(); | ||||||
|   void read_iaq_baseline_(); |   void read_iaq_baseline_(); | ||||||
|   bool is_sensor_baseline_reliable_(); |   bool is_sensor_baseline_reliable_(); | ||||||
|   void write_iaq_baseline_(uint16_t baseline); |   void write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_baseline); | ||||||
|   uint8_t sht_crc_(uint8_t data1, uint8_t data2); |   uint8_t sht_crc_(uint8_t data1, uint8_t data2); | ||||||
|   uint64_t serial_number_; |   uint64_t serial_number_; | ||||||
|   uint16_t featureset_; |   uint16_t featureset_; | ||||||
| @@ -44,7 +45,8 @@ class SGP30Component : public PollingComponent, public i2c::I2CDevice { | |||||||
|  |  | ||||||
|   sensor::Sensor *eco2_sensor_{nullptr}; |   sensor::Sensor *eco2_sensor_{nullptr}; | ||||||
|   sensor::Sensor *tvoc_sensor_{nullptr}; |   sensor::Sensor *tvoc_sensor_{nullptr}; | ||||||
|   uint16_t baseline_{0x0000}; |   uint16_t eco2_baseline_{0x0000}; | ||||||
|  |   uint16_t tvoc_baseline_{0x0000}; | ||||||
|   /// Input sensor for humidity and temperature compensation. |   /// Input sensor for humidity and temperature compensation. | ||||||
|   sensor::Sensor *humidity_sensor_{nullptr}; |   sensor::Sensor *humidity_sensor_{nullptr}; | ||||||
|   sensor::Sensor *temperature_sensor_{nullptr}; |   sensor::Sensor *temperature_sensor_{nullptr}; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user