mirror of
https://github.com/Threnklyn/esphome-dev.git
synced 2026-06-13 16:13:32 +02:00
Refactor Sensirion Sensors (#3374)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.components import i2c, sensor, sensirion_common
|
||||
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_BASELINE,
|
||||
CONF_ECO2,
|
||||
CONF_STORE_BASELINE,
|
||||
CONF_TEMPERATURE_SOURCE,
|
||||
CONF_TVOC,
|
||||
ICON_RADIATOR,
|
||||
DEVICE_CLASS_CARBON_DIOXIDE,
|
||||
@@ -17,17 +20,19 @@ from esphome.const import (
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
AUTO_LOAD = ["sensirion_common"]
|
||||
|
||||
sgp30_ns = cg.esphome_ns.namespace("sgp30")
|
||||
SGP30Component = sgp30_ns.class_("SGP30Component", cg.PollingComponent, i2c.I2CDevice)
|
||||
SGP30Component = sgp30_ns.class_(
|
||||
"SGP30Component", cg.PollingComponent, sensirion_common.SensirionI2CDevice
|
||||
)
|
||||
|
||||
CONF_ECO2_BASELINE = "eco2_baseline"
|
||||
CONF_TVOC_BASELINE = "tvoc_baseline"
|
||||
CONF_STORE_BASELINE = "store_baseline"
|
||||
CONF_UPTIME = "uptime"
|
||||
CONF_COMPENSATION = "compensation"
|
||||
CONF_HUMIDITY_SOURCE = "humidity_source"
|
||||
CONF_TEMPERATURE_SOURCE = "temperature_source"
|
||||
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
|
||||
@@ -36,14 +36,8 @@ void SGP30Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up SGP30...");
|
||||
|
||||
// Serial Number identification
|
||||
if (!this->write_command_(SGP30_CMD_GET_SERIAL_ID)) {
|
||||
this->error_code_ = COMMUNICATION_FAILED;
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
uint16_t raw_serial_number[3];
|
||||
|
||||
if (!this->read_data_(raw_serial_number, 3)) {
|
||||
if (!this->get_register(SGP30_CMD_GET_SERIAL_ID, raw_serial_number, 3)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
@@ -52,16 +46,12 @@ void SGP30Component::setup() {
|
||||
ESP_LOGD(TAG, "Serial Number: %" PRIu64, this->serial_number_);
|
||||
|
||||
// Featureset identification for future use
|
||||
if (!this->write_command_(SGP30_CMD_GET_FEATURESET)) {
|
||||
uint16_t raw_featureset;
|
||||
if (!this->get_register(SGP30_CMD_GET_FEATURESET, raw_featureset)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
uint16_t raw_featureset[1];
|
||||
if (!this->read_data_(raw_featureset, 1)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
this->featureset_ = raw_featureset[0];
|
||||
this->featureset_ = raw_featureset;
|
||||
if (uint16_t(this->featureset_ >> 12) != 0x0) {
|
||||
if (uint16_t(this->featureset_ >> 12) == 0x1) {
|
||||
// ID matching a different sensor: SGPC3
|
||||
@@ -76,7 +66,7 @@ void SGP30Component::setup() {
|
||||
ESP_LOGD(TAG, "Product version: 0x%0X", uint16_t(this->featureset_ & 0x1FF));
|
||||
|
||||
// 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.");
|
||||
this->error_code_ = MEASUREMENT_INIT_FAILED;
|
||||
this->mark_failed();
|
||||
@@ -119,14 +109,14 @@ bool SGP30Component::is_sensor_baseline_reliable_() {
|
||||
|
||||
void SGP30Component::read_iaq_baseline_() {
|
||||
if (this->is_sensor_baseline_reliable_()) {
|
||||
if (!this->write_command_(SGP30_CMD_GET_IAQ_BASELINE)) {
|
||||
if (!this->write_command(SGP30_CMD_GET_IAQ_BASELINE)) {
|
||||
ESP_LOGD(TAG, "Error getting baseline");
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
this->set_timeout(50, [this]() {
|
||||
uint16_t raw_data[2];
|
||||
if (!this->read_data_(raw_data, 2)) {
|
||||
if (!this->read_data(raw_data, 2)) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
@@ -274,14 +264,14 @@ void SGP30Component::dump_config() {
|
||||
}
|
||||
|
||||
void SGP30Component::update() {
|
||||
if (!this->write_command_(SGP30_CMD_MEASURE_IAQ)) {
|
||||
if (!this->write_command(SGP30_CMD_MEASURE_IAQ)) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
this->seconds_since_last_store_ += this->update_interval_ / 1000;
|
||||
this->set_timeout(50, [this]() {
|
||||
uint16_t raw_data[2];
|
||||
if (!this->read_data_(raw_data, 2)) {
|
||||
if (!this->read_data(raw_data, 2)) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
@@ -305,56 +295,5 @@ void SGP30Component::update() {
|
||||
});
|
||||
}
|
||||
|
||||
bool SGP30Component::write_command_(uint16_t command) {
|
||||
// Warning ugly, trick the I2Ccomponent base by setting register to the first 8 bit.
|
||||
return this->write_byte(command >> 8, command & 0xFF);
|
||||
}
|
||||
|
||||
uint8_t SGP30Component::sht_crc_(uint8_t data1, uint8_t data2) {
|
||||
uint8_t bit;
|
||||
uint8_t crc = 0xFF;
|
||||
|
||||
crc ^= data1;
|
||||
for (bit = 8; bit > 0; --bit) {
|
||||
if (crc & 0x80) {
|
||||
crc = (crc << 1) ^ 0x131;
|
||||
} else {
|
||||
crc = (crc << 1);
|
||||
}
|
||||
}
|
||||
|
||||
crc ^= data2;
|
||||
for (bit = 8; bit > 0; --bit) {
|
||||
if (crc & 0x80) {
|
||||
crc = (crc << 1) ^ 0x131;
|
||||
} else {
|
||||
crc = (crc << 1);
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
bool SGP30Component::read_data_(uint16_t *data, uint8_t len) {
|
||||
const uint8_t num_bytes = len * 3;
|
||||
std::vector<uint8_t> buf(num_bytes);
|
||||
|
||||
if (this->read(buf.data(), num_bytes) != i2c::ERROR_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
const uint8_t j = 3 * i;
|
||||
uint8_t crc = sht_crc_(buf[j], buf[j + 1]);
|
||||
if (crc != buf[j + 2]) {
|
||||
ESP_LOGE(TAG, "CRC8 Checksum invalid! 0x%02X != 0x%02X", buf[j + 2], crc);
|
||||
return false;
|
||||
}
|
||||
data[i] = (buf[j] << 8) | buf[j + 1];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace sgp30
|
||||
} // namespace esphome
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/components/sensirion_common/i2c_sensirion.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include <cmath>
|
||||
|
||||
@@ -15,7 +15,7 @@ struct SGP30Baselines {
|
||||
} PACKED;
|
||||
|
||||
/// This class implements support for the Sensirion SGP30 i2c GAS (VOC and CO2eq) sensors.
|
||||
class SGP30Component : public PollingComponent, public i2c::I2CDevice {
|
||||
class SGP30Component : public PollingComponent, public sensirion_common::SensirionI2CDevice {
|
||||
public:
|
||||
void set_eco2_sensor(sensor::Sensor *eco2) { eco2_sensor_ = eco2; }
|
||||
void set_tvoc_sensor(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; }
|
||||
@@ -33,13 +33,10 @@ class SGP30Component : public PollingComponent, public i2c::I2CDevice {
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
|
||||
protected:
|
||||
bool write_command_(uint16_t command);
|
||||
bool read_data_(uint16_t *data, uint8_t len);
|
||||
void send_env_data_();
|
||||
void read_iaq_baseline_();
|
||||
bool is_sensor_baseline_reliable_();
|
||||
void write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_baseline);
|
||||
uint8_t sht_crc_(uint8_t data1, uint8_t data2);
|
||||
uint64_t serial_number_;
|
||||
uint16_t featureset_;
|
||||
uint32_t required_warm_up_time_;
|
||||
|
||||
Reference in New Issue
Block a user