12static constexpr uint16_t STCC4_CMD_START_CONTINUOUS_MEASUREMENT = 0x218b;
13static constexpr uint16_t STCC4_CMD_STOP_CONTINUOUS_MEASUREMENT = 0x3f86;
14static constexpr uint16_t STCC4_CMD_MEASURE_SINGLE_SHOT = 0x219d;
15static constexpr uint16_t STCC4_CMD_READ_MEASUREMENT = 0xec05;
16static constexpr uint16_t STCC4_CMD_GET_PRODUCT_ID = 0x365b;
17static constexpr uint16_t STCC4_CMD_SET_RHT_COMPENSATION = 0xe000;
18static constexpr uint16_t STCC4_CMD_SET_PRESSURE_COMPENSATION = 0xe016;
21static constexpr uint8_t STCC4_CMD_EXIT_SLEEP_MODE = 0x00;
23static constexpr uint32_t STCC4_PRODUCT_ID = 0x0901018a;
28static constexpr uint32_t READY_TIMEOUT_MS = 1200;
31static constexpr uint32_t READY_POLL_INTERVAL_MS = 100;
35 return uint16_t((std::clamp(temperature_in_c, -45.f, 130.f) + 45.f) * 65535.f / 175.f);
39 return temperature_in_ticks * 175.f / 65535.f - 45.f;
43 return uint16_t((std::clamp(humidity_in_percent, 0.f, 100.f) + 6.f) * 65535.f / 125.f);
47 return humidity_in_ticks * 125.f / 65535.f - 6.f;
51 return uint16_t(std::clamp(pressure_in_hpa, 400.f, 1100.f) * 50.f);
70 if (this->
write_command(STCC4_CMD_STOP_CONTINUOUS_MEASUREMENT)) {
73 uint16_t raw_product_id[6];
74 if (this->
get_register(STCC4_CMD_GET_PRODUCT_ID, raw_product_id, 6, 1)) {
75 uint32_t product_id = (
uint32_t(raw_product_id[0]) << 16) | raw_product_id[1];
76 uint64_t
serial_number = (uint64_t(raw_product_id[2]) << 48) | (uint64_t(raw_product_id[3]) << 32) |
77 (uint64_t(raw_product_id[4]) << 16) | raw_product_id[5];
78 ESP_LOGD(TAG,
"Product ID: 0x%08" PRIX32
", Serial: 0x%016" PRIX64, product_id,
serial_number);
79 if (product_id != STCC4_PRODUCT_ID) {
80 ESP_LOGE(TAG,
"Unsupported product ID");
108 if (!this->
write_command(STCC4_CMD_START_CONTINUOUS_MEASUREMENT)) {
109 ESP_LOGE(TAG,
"Failed to start continuous measurement");
119 if (
millis() - start_time < READY_TIMEOUT_MS) {
120 ESP_LOGVV(TAG,
"Retry sync");
126 ESP_LOGE(TAG,
"Failed to stop continuous measurements and read product ID");
143void STCC4Component::dump_config() {
144 ESP_LOGCONFIG(TAG,
"STCC4:");
145 LOG_I2C_DEVICE(
this);
147 ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
149 ESP_LOGCONFIG(TAG,
" Measurement mode: %s",
151 : LOG_STR_LITERAL(
"Single shot"));
153 ESP_LOGCONFIG(TAG,
" Dynamic ambient pressure compensation using '%s'",
156 ESP_LOGCONFIG(TAG,
" Ambient pressure compensation: %f hPa",
165 LOG_UPDATE_INTERVAL(
this);
166 LOG_SENSOR(
" ",
"CO2", this->co2_sensor_);
167 LOG_SENSOR(
" ",
"Temperature", this->temperature_sensor_);
168 LOG_SENSOR(
" ",
"Humidity", this->humidity_sensor_);
171void STCC4Component::update() {
177 ESP_LOGW(TAG,
"Failed to start single shot measurement");
185 ESP_LOGW(TAG,
"Failed to read measurement data");
195 this->
set_timeout(retry_for_clock_drift ? 150 : 1000, [
this, retry_for_clock_drift]() {
196 if (this->
read_measurement_(retry_for_clock_drift ? 0 : sensirion_common::SENSIRION_OPTION_READ_MAY_NACK)) {
199 }
else if (!retry_for_clock_drift) {
210 uint16_t raw_data[4];
216 const int16_t co2_raw = int16_t(raw_data[0]);
217 if (this->co2_sensor_ !=
nullptr && co2_raw >= 0) {
218 this->co2_sensor_->publish_state(co2_raw);
221 if (this->temperature_sensor_ !=
nullptr) {
225 if (this->humidity_sensor_ !=
nullptr) {
234 if (std::isnan(temperature_in_c) || std::isnan(humidity_in_percent))
246void STCC4Component::set_ambient_pressure_compensation(
float pressure_in_hpa) {
252 if (std::isnan(pressure_in_hpa))
255 if (pressure_in_hpa < 100.f || pressure_in_hpa > 10000.f) {
260 ESP_LOGW(TAG,
"Ambient pressure compensation sensor might have incompatible units: got %f hPa", pressure_in_hpa);
277 const uint16_t data[2] = {temperature_in_ticks, humidity_in_ticks};
278 if (!this->
write_command(STCC4_CMD_SET_RHT_COMPENSATION, data, 2)) {
279 ESP_LOGE(TAG,
"Failed to set RHT compensation");
287 if (!this->
write_command(STCC4_CMD_SET_PRESSURE_COMPENSATION, pressure_in_pa_2)) {
288 ESP_LOGE(TAG,
"Failed to set ambient pressure compensation");
void mark_failed()
Mark this component as failed.
virtual void setup()
Where the component's initialization should happen.
void status_set_warning()
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
void status_clear_warning()
const StringRef & get_name() const
constexpr const char * c_str() const
bool get_register_(uint16_t reg, CommandLen command_len, uint16_t *data, uint8_t len, uint8_t delay, uint8_t sensirion_options=0)
get data words from I2C register.
bool get_register(uint16_t command, uint16_t *data, uint8_t len, uint8_t delay=0)
get data words from I2C register.
bool write_command(T i2c_register)
Write a command to the I2C device.
void add_on_state_callback(F &&callback)
Add a callback that will be called every time a filtered value arrives.
float state
This member variable stores the last state that has passed through all filters.
sensor::Sensor * temperature_source_
sensor::Sensor * ambient_pressure_source_
bool write_rht_compensation_(uint16_t temperature_in_ticks, uint16_t humidity_in_ticks)
uint16_t ambient_pressure_in_pa_2_
void schedule_continuous_update_(bool retry_for_clock_drift)
bool write_ambient_pressure_compensation_(uint16_t pressure_in_pa_2)
void update_rht_compensation_from_source_()
void poll_until_ready_for_setup_or_timeout_(uint32_t start_time)
bool read_measurement_(uint8_t sensirion_options)
MeasurementMode measurement_mode_
bool ambient_pressure_unit_warning_logged_
uint16_t humidity_in_ticks_
sensor::Sensor * humidity_source_
uint16_t temperature_in_ticks_
void update_ambient_pressure_compensation_from_source_()
constexpr float temperature_in_ticks_to_c(uint16_t temperature_in_ticks)
constexpr uint16_t humidity_in_percent_to_ticks(float humidity_in_percent)
constexpr uint16_t pressure_in_hpa_to_pa_2(float pressure_in_hpa)
constexpr float humidity_in_ticks_to_percent(uint16_t humidity_in_ticks)
ESPHOME_LOG_TAG(TAG, "stcc4")
constexpr float pressure_in_pa_2_to_hpa(uint16_t pressure_in_pa_2)
constexpr uint16_t temperature_in_c_to_ticks(float temperature_in_c)
uint32_t IRAM_ATTR HOT millis()