1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-07 13:52:20 +01:00

[sgp30] Tidy up, optimize (#10607)

This commit is contained in:
Keith Burzinski
2025-09-05 14:20:11 -05:00
committed by GitHub
parent 0069163d31
commit 09b40b882e
3 changed files with 47 additions and 45 deletions

View File

@@ -15,6 +15,8 @@ namespace sensirion_common {
* Format: * Format:
* | 16 Bit Command Code | 16 bit Data word 1 | CRC of DW 1 | 16 bit Data word 1 | CRC of DW 2 | .. * | 16 Bit Command Code | 16 bit Data word 1 | CRC of DW 1 | 16 bit Data word 1 | CRC of DW 2 | ..
*/ */
static const uint8_t CRC_POLYNOMIAL = 0x31; // default for Sensirion
class SensirionI2CDevice : public i2c::I2CDevice { class SensirionI2CDevice : public i2c::I2CDevice {
public: public:
enum CommandLen : uint8_t { ADDR_8_BIT = 1, ADDR_16_BIT = 2 }; enum CommandLen : uint8_t { ADDR_8_BIT = 1, ADDR_16_BIT = 2 };

View File

@@ -1,9 +1,11 @@
#include "sgp30.h" #include "sgp30.h"
#include <cinttypes>
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace sgp30 { namespace sgp30 {
@@ -39,9 +41,8 @@ void SGP30Component::setup() {
this->mark_failed(); this->mark_failed();
return; return;
} }
this->serial_number_ = (uint64_t(raw_serial_number[0]) << 24) | (uint64_t(raw_serial_number[1]) << 16) | this->serial_number_ = encode_uint24(raw_serial_number[0], raw_serial_number[1], raw_serial_number[2]);
(uint64_t(raw_serial_number[2])); ESP_LOGD(TAG, "Serial number: %" PRIu64, this->serial_number_);
ESP_LOGD(TAG, "Serial Number: %" PRIu64, this->serial_number_);
// Featureset identification for future use // Featureset identification for future use
uint16_t raw_featureset; uint16_t raw_featureset;
@@ -61,11 +62,11 @@ void SGP30Component::setup() {
this->mark_failed(); this->mark_failed();
return; return;
} }
ESP_LOGD(TAG, "Product version: 0x%0X", uint16_t(this->featureset_ & 0x1FF)); ESP_LOGV(TAG, "Product version: 0x%0X", uint16_t(this->featureset_ & 0x1FF));
// Sensor initialization // Sensor initialization
if (!this->write_command(SGP30_CMD_IAQ_INIT)) { if (!this->write_command(SGP30_CMD_IAQ_INIT)) {
ESP_LOGE(TAG, "Sensor sgp30_iaq_init failed."); ESP_LOGE(TAG, "sgp30_iaq_init failed");
this->error_code_ = MEASUREMENT_INIT_FAILED; this->error_code_ = MEASUREMENT_INIT_FAILED;
this->mark_failed(); this->mark_failed();
return; return;
@@ -123,7 +124,7 @@ void SGP30Component::read_iaq_baseline_() {
uint16_t eco2baseline = (raw_data[0]); uint16_t eco2baseline = (raw_data[0]);
uint16_t tvocbaseline = (raw_data[1]); uint16_t tvocbaseline = (raw_data[1]);
ESP_LOGI(TAG, "Current eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", eco2baseline, tvocbaseline); ESP_LOGI(TAG, "Baselines: eCO2: 0x%04X, TVOC: 0x%04X", eco2baseline, tvocbaseline);
if (eco2baseline != this->eco2_baseline_ || tvocbaseline != this->tvoc_baseline_) { if (eco2baseline != this->eco2_baseline_ || tvocbaseline != this->tvoc_baseline_) {
this->eco2_baseline_ = eco2baseline; this->eco2_baseline_ = eco2baseline;
this->tvoc_baseline_ = tvocbaseline; this->tvoc_baseline_ = tvocbaseline;
@@ -142,7 +143,7 @@ void SGP30Component::read_iaq_baseline_() {
this->baselines_storage_.eco2 = this->eco2_baseline_; this->baselines_storage_.eco2 = this->eco2_baseline_;
this->baselines_storage_.tvoc = this->tvoc_baseline_; this->baselines_storage_.tvoc = this->tvoc_baseline_;
if (this->pref_.save(&this->baselines_storage_)) { if (this->pref_.save(&this->baselines_storage_)) {
ESP_LOGI(TAG, "Store eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", this->baselines_storage_.eco2, ESP_LOGI(TAG, "Store baselines: eCO2: 0x%04X, TVOC: 0x%04X", this->baselines_storage_.eco2,
this->baselines_storage_.tvoc); this->baselines_storage_.tvoc);
} else { } else {
ESP_LOGW(TAG, "Could not store eCO2 and TVOC baselines"); ESP_LOGW(TAG, "Could not store eCO2 and TVOC baselines");
@@ -164,7 +165,7 @@ void SGP30Component::send_env_data_() {
if (this->humidity_sensor_ != nullptr) if (this->humidity_sensor_ != nullptr)
humidity = this->humidity_sensor_->state; humidity = this->humidity_sensor_->state;
if (std::isnan(humidity) || humidity < 0.0f || humidity > 100.0f) { if (std::isnan(humidity) || humidity < 0.0f || humidity > 100.0f) {
ESP_LOGW(TAG, "Compensation not possible yet: bad humidity data."); ESP_LOGW(TAG, "Compensation not possible yet: bad humidity data");
return; return;
} else { } else {
ESP_LOGD(TAG, "External compensation data received: Humidity %0.2f%%", humidity); ESP_LOGD(TAG, "External compensation data received: Humidity %0.2f%%", humidity);
@@ -174,7 +175,7 @@ void SGP30Component::send_env_data_() {
temperature = float(this->temperature_sensor_->state); temperature = float(this->temperature_sensor_->state);
} }
if (std::isnan(temperature) || temperature < -40.0f || temperature > 85.0f) { if (std::isnan(temperature) || temperature < -40.0f || temperature > 85.0f) {
ESP_LOGW(TAG, "Compensation not possible yet: bad temperature value data."); ESP_LOGW(TAG, "Compensation not possible yet: bad temperature value");
return; return;
} else { } else {
ESP_LOGD(TAG, "External compensation data received: Temperature %0.2f°C", temperature); ESP_LOGD(TAG, "External compensation data received: Temperature %0.2f°C", temperature);
@@ -192,18 +193,17 @@ void SGP30Component::send_env_data_() {
((humidity * 0.061121f * std::exp((18.678f - temperature / 234.5f) * (temperature / (257.14f + temperature)))) / ((humidity * 0.061121f * std::exp((18.678f - temperature / 234.5f) * (temperature / (257.14f + temperature)))) /
(273.15f + temperature)); (273.15f + temperature));
} }
uint8_t humidity_full = uint8_t(std::floor(absolute_humidity)); uint8_t data[4] = {
uint8_t humidity_dec = uint8_t(std::floor((absolute_humidity - std::floor(absolute_humidity)) * 256)); SGP30_CMD_SET_ABSOLUTE_HUMIDITY & 0xFF,
ESP_LOGD(TAG, "Calculated Absolute humidity: %0.3f g/m³ (0x%04X)", absolute_humidity, uint8_t(std::floor(absolute_humidity)), // humidity_full
uint16_t(uint16_t(humidity_full) << 8 | uint16_t(humidity_dec))); uint8_t(std::floor((absolute_humidity - std::floor(absolute_humidity)) * 256)), // humidity_dec
uint8_t crc = sht_crc_(humidity_full, humidity_dec); 0,
uint8_t data[4]; };
data[0] = SGP30_CMD_SET_ABSOLUTE_HUMIDITY & 0xFF; data[3] = crc8(&data[1], 2, 0xFF, sensirion_common::CRC_POLYNOMIAL, true);
data[1] = humidity_full; ESP_LOGD(TAG, "Calculated absolute humidity: %0.3f g/m³ (0x%04X)", absolute_humidity,
data[2] = humidity_dec; encode_uint16(data[1], data[2]));
data[3] = crc;
if (!this->write_bytes(SGP30_CMD_SET_ABSOLUTE_HUMIDITY >> 8, data, 4)) { if (!this->write_bytes(SGP30_CMD_SET_ABSOLUTE_HUMIDITY >> 8, data, 4)) {
ESP_LOGE(TAG, "Error sending compensation data."); ESP_LOGE(TAG, "Error sending compensation data");
} }
} }
@@ -212,15 +212,14 @@ void SGP30Component::write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_b
data[0] = SGP30_CMD_SET_IAQ_BASELINE & 0xFF; data[0] = SGP30_CMD_SET_IAQ_BASELINE & 0xFF;
data[1] = tvoc_baseline >> 8; data[1] = tvoc_baseline >> 8;
data[2] = tvoc_baseline & 0xFF; data[2] = tvoc_baseline & 0xFF;
data[3] = sht_crc_(data[1], data[2]); data[3] = crc8(&data[1], 2, 0xFF, sensirion_common::CRC_POLYNOMIAL, true);
data[4] = eco2_baseline >> 8; data[4] = eco2_baseline >> 8;
data[5] = eco2_baseline & 0xFF; data[5] = eco2_baseline & 0xFF;
data[6] = sht_crc_(data[4], data[5]); data[6] = crc8(&data[4], 2, 0xFF, sensirion_common::CRC_POLYNOMIAL, true);
if (!this->write_bytes(SGP30_CMD_SET_IAQ_BASELINE >> 8, data, 7)) { 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); ESP_LOGE(TAG, "Error applying baselines: eCO2: 0x%04X, TVOC: 0x%04X", eco2_baseline, tvoc_baseline);
} else { } else {
ESP_LOGI(TAG, "Initial baselines applied successfully! eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", eco2_baseline, ESP_LOGI(TAG, "Initial baselines applied: eCO2: 0x%04X, TVOC: 0x%04X", eco2_baseline, tvoc_baseline);
tvoc_baseline);
} }
} }
@@ -236,10 +235,10 @@ void SGP30Component::dump_config() {
ESP_LOGW(TAG, "Measurement Initialization failed"); ESP_LOGW(TAG, "Measurement Initialization failed");
break; break;
case INVALID_ID: case INVALID_ID:
ESP_LOGW(TAG, "Sensor reported an invalid ID. Is this an SGP30?"); ESP_LOGW(TAG, "Invalid ID");
break; break;
case UNSUPPORTED_ID: case UNSUPPORTED_ID:
ESP_LOGW(TAG, "Sensor reported an unsupported ID (SGPC3)"); ESP_LOGW(TAG, "Unsupported ID");
break; break;
default: default:
ESP_LOGW(TAG, "Unknown setup error"); ESP_LOGW(TAG, "Unknown setup error");
@@ -249,12 +248,12 @@ void SGP30Component::dump_config() {
ESP_LOGCONFIG(TAG, " Serial number: %" PRIu64, this->serial_number_); ESP_LOGCONFIG(TAG, " Serial number: %" PRIu64, this->serial_number_);
if (this->eco2_baseline_ != 0x0000 && this->tvoc_baseline_ != 0x0000) { if (this->eco2_baseline_ != 0x0000 && this->tvoc_baseline_ != 0x0000) {
ESP_LOGCONFIG(TAG, ESP_LOGCONFIG(TAG,
" Baseline:\n" " Baselines:\n"
" eCO2 Baseline: 0x%04X\n" " eCO2: 0x%04X\n"
" TVOC Baseline: 0x%04X", " TVOC: 0x%04X",
this->eco2_baseline_, this->tvoc_baseline_); this->eco2_baseline_, this->tvoc_baseline_);
} else { } else {
ESP_LOGCONFIG(TAG, " Baseline: No baseline configured"); ESP_LOGCONFIG(TAG, " Baselines not configured");
} }
ESP_LOGCONFIG(TAG, " Warm up time: %" PRIu32 "s", this->required_warm_up_time_); ESP_LOGCONFIG(TAG, " Warm up time: %" PRIu32 "s", this->required_warm_up_time_);
} }
@@ -266,8 +265,8 @@ void SGP30Component::dump_config() {
ESP_LOGCONFIG(TAG, "Store baseline: %s", YESNO(this->store_baseline_)); ESP_LOGCONFIG(TAG, "Store baseline: %s", YESNO(this->store_baseline_));
if (this->humidity_sensor_ != nullptr && this->temperature_sensor_ != nullptr) { if (this->humidity_sensor_ != nullptr && this->temperature_sensor_ != nullptr) {
ESP_LOGCONFIG(TAG, " Compensation:"); ESP_LOGCONFIG(TAG, " Compensation:");
LOG_SENSOR(" ", "Temperature Source:", this->temperature_sensor_); LOG_SENSOR(" ", "Temperature source:", this->temperature_sensor_);
LOG_SENSOR(" ", "Humidity Source:", this->humidity_sensor_); LOG_SENSOR(" ", "Humidity source:", this->humidity_sensor_);
} else { } else {
ESP_LOGCONFIG(TAG, " Compensation: No source configured"); ESP_LOGCONFIG(TAG, " Compensation: No source configured");
} }
@@ -289,7 +288,7 @@ void SGP30Component::update() {
float eco2 = (raw_data[0]); float eco2 = (raw_data[0]);
float tvoc = (raw_data[1]); float tvoc = (raw_data[1]);
ESP_LOGD(TAG, "Got eCO2=%.1fppm TVOC=%.1fppb", eco2, tvoc); ESP_LOGV(TAG, "eCO2=%.1fppm TVOC=%.1fppb", eco2, tvoc);
if (this->eco2_sensor_ != nullptr) if (this->eco2_sensor_ != nullptr)
this->eco2_sensor_->publish_state(eco2); this->eco2_sensor_->publish_state(eco2);
if (this->tvoc_sensor_ != nullptr) if (this->tvoc_sensor_ != nullptr)

View File

@@ -1,8 +1,8 @@
#pragma once #pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/sensirion_common/i2c_sensirion.h" #include "esphome/components/sensirion_common/i2c_sensirion.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/core/component.h"
#include "esphome/core/preferences.h" #include "esphome/core/preferences.h"
#include <cinttypes> #include <cinttypes>
@@ -38,14 +38,16 @@ class SGP30Component : public PollingComponent, public sensirion_common::Sensiri
void read_iaq_baseline_(); void read_iaq_baseline_();
bool is_sensor_baseline_reliable_(); bool is_sensor_baseline_reliable_();
void write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_baseline); void write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_baseline);
uint64_t serial_number_; uint64_t serial_number_;
uint16_t featureset_;
uint32_t required_warm_up_time_; uint32_t required_warm_up_time_;
uint32_t seconds_since_last_store_; uint32_t seconds_since_last_store_;
SGP30Baselines baselines_storage_; uint16_t featureset_;
ESPPreferenceObject pref_; uint16_t eco2_baseline_{0x0000};
uint16_t tvoc_baseline_{0x0000};
bool store_baseline_;
enum ErrorCode { enum ErrorCode : uint8_t {
COMMUNICATION_FAILED, COMMUNICATION_FAILED,
MEASUREMENT_INIT_FAILED, MEASUREMENT_INIT_FAILED,
INVALID_ID, INVALID_ID,
@@ -53,14 +55,13 @@ class SGP30Component : public PollingComponent, public sensirion_common::Sensiri
UNKNOWN UNKNOWN
} error_code_{UNKNOWN}; } error_code_{UNKNOWN};
ESPPreferenceObject pref_;
SGP30Baselines baselines_storage_;
sensor::Sensor *eco2_sensor_{nullptr}; sensor::Sensor *eco2_sensor_{nullptr};
sensor::Sensor *tvoc_sensor_{nullptr}; sensor::Sensor *tvoc_sensor_{nullptr};
sensor::Sensor *eco2_sensor_baseline_{nullptr}; sensor::Sensor *eco2_sensor_baseline_{nullptr};
sensor::Sensor *tvoc_sensor_baseline_{nullptr}; sensor::Sensor *tvoc_sensor_baseline_{nullptr};
uint16_t eco2_baseline_{0x0000};
uint16_t tvoc_baseline_{0x0000};
bool store_baseline_;
/// 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};