9static const uint16_t SCD41_ID = 0x1408;
10static const uint16_t SCD40_ID = 0x440;
11static const uint16_t SCD4X_CMD_GET_SERIAL_NUMBER = 0x3682;
12static const uint16_t SCD4X_CMD_TEMPERATURE_OFFSET = 0x241d;
13static const uint16_t SCD4X_CMD_ALTITUDE_COMPENSATION = 0x2427;
14static const uint16_t SCD4X_CMD_AMBIENT_PRESSURE_COMPENSATION = 0xe000;
15static const uint16_t SCD4X_CMD_AUTOMATIC_SELF_CALIBRATION = 0x2416;
16static const uint16_t SCD4X_CMD_START_CONTINUOUS_MEASUREMENTS = 0x21b1;
17static const uint16_t SCD4X_CMD_START_LOW_POWER_CONTINUOUS_MEASUREMENTS = 0x21ac;
18static const uint16_t SCD4X_CMD_START_LOW_POWER_SINGLE_SHOT = 0x219d;
19static const uint16_t SCD4X_CMD_START_LOW_POWER_SINGLE_SHOT_RHT_ONLY = 0x2196;
20static const uint16_t SCD4X_CMD_GET_DATA_READY_STATUS = 0xe4b8;
21static const uint16_t SCD4X_CMD_READ_MEASUREMENT = 0xec05;
22static const uint16_t SCD4X_CMD_PERFORM_FORCED_CALIBRATION = 0x362f;
23static const uint16_t SCD4X_CMD_STOP_MEASUREMENTS = 0x3f86;
24static const uint16_t SCD4X_CMD_FACTORY_RESET = 0x3632;
25static const uint16_t SCD4X_CMD_GET_FEATURESET = 0x202f;
26static const float SCD4X_TEMPERATURE_OFFSET_MULTIPLIER = (1 << 16) / 175.0f;
33 this->
mark_failed(LOG_STR(
"Failed to stop measurements"));
39 uint16_t raw_serial_number[3];
40 if (!this->
get_register(SCD4X_CMD_GET_SERIAL_NUMBER, raw_serial_number, 3, 1)) {
41 this->
mark_failed(LOG_STR(
"Unable to read serial number"));
44 ESP_LOGD(TAG,
"Serial number %02d.%02d.%02d", (uint16_t(raw_serial_number[0]) >> 8),
45 uint16_t(raw_serial_number[0] & 0xFF), (uint16_t(raw_serial_number[1]) >> 8));
49 this->
mark_failed(LOG_STR(
"Error setting temperature offset"));
56 this->
mark_failed(LOG_STR(
"Error setting ambient pressure compensation"));
61 this->
mark_failed(LOG_STR(
"Error setting altitude compensation"));
67 this->
mark_failed(LOG_STR(
"Error setting automatic self calibration"));
79 static const char *
const MM_PERIODIC_STR =
"Periodic (5s)";
80 static const char *
const MM_LOW_POWER_PERIODIC_STR =
"Low power periodic (30s)";
81 static const char *
const MM_SINGLE_SHOT_STR =
"Single shot";
82 static const char *
const MM_SINGLE_SHOT_RHT_ONLY_STR =
"Single shot rht only";
83 const char *measurement_mode_str = MM_PERIODIC_STR;
90 measurement_mode_str = MM_LOW_POWER_PERIODIC_STR;
93 measurement_mode_str = MM_SINGLE_SHOT_STR;
96 measurement_mode_str = MM_SINGLE_SHOT_RHT_ONLY_STR;
100 ESP_LOGCONFIG(TAG,
"SCD4X:");
101 LOG_I2C_DEVICE(
this);
103 " Automatic self calibration: %s\n"
104 " Measurement mode: %s\n"
105 " Temperature offset: %.2f °C",
108 ESP_LOGCONFIG(TAG,
" Dynamic ambient pressure compensation using '%s'",
113 " Altitude compensation disabled\n"
114 " Ambient pressure compensation: %dmBar",
118 " Ambient pressure compensation disabled\n"
119 " Altitude compensation: %dm",
123 LOG_UPDATE_INTERVAL(
this);
154 uint16_t raw_read_status;
156 if (!this->
read_data(raw_read_status) || raw_read_status == 0x00) {
158 ESP_LOGW(TAG,
"Data not ready");
163 ESP_LOGW(TAG,
"Error reading measurement");
168 uint16_t raw_data[3];
177 const float temperature = -45.0f + (175.0f * (raw_data[1])) / (1 << 16);
181 const float humidity = (100.0f * raw_data[2]) / (1 << 16);
195 ESP_LOGE(TAG,
"Failed to stop measurements");
198 this->
set_timeout(500, [
this, current_co2_concentration]() {
199 if (this->
write_command(SCD4X_CMD_PERFORM_FORCED_CALIBRATION, current_co2_concentration)) {
200 ESP_LOGD(TAG,
"Setting forced calibration Co2 level %d ppm", current_co2_concentration);
208 ESP_LOGD(TAG,
"Forced calibration complete");
212 ESP_LOGE(TAG,
"Force calibration failed");
222 ESP_LOGE(TAG,
"Failed to stop measurements");
229 ESP_LOGE(TAG,
"Failed to send factory reset command");
233 ESP_LOGD(TAG,
"Factory reset complete");
240 uint16_t new_ambient_pressure =
static_cast<uint16_t
>(pressure_in_hpa);
250 ESP_LOGD(TAG,
"Ambient pressure compensation skipped; no change required");
255 if (this->
write_command(SCD4X_CMD_AMBIENT_PRESSURE_COMPENSATION, pressure_in_hpa)) {
256 ESP_LOGD(TAG,
"Setting ambient pressure compensation to %d hPa", pressure_in_hpa);
259 ESP_LOGE(TAG,
"Error setting ambient pressure compensation");
265 uint16_t measurement_command = SCD4X_CMD_START_CONTINUOUS_MEASUREMENTS;
268 measurement_command = SCD4X_CMD_START_CONTINUOUS_MEASUREMENTS;
271 measurement_command = SCD4X_CMD_START_LOW_POWER_CONTINUOUS_MEASUREMENTS;
274 measurement_command = SCD4X_CMD_START_LOW_POWER_SINGLE_SHOT;
277 measurement_command = SCD4X_CMD_START_LOW_POWER_SINGLE_SHOT_RHT_ONLY;
281 uint8_t remaining_retries = 3;
282 while (remaining_retries) {
284 ESP_LOGE(TAG,
"Error starting measurements");
286 if (--remaining_retries == 0)
void mark_failed()
Mark this component as failed.
void status_set_warning()
void status_clear_error()
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 LogString * get_log_name() const
Get the name for a "%s" log argument (LOG_STR_ARG).
sensor::Sensor * humidity_sensor_
uint16_t ambient_pressure_
bool update_ambient_pressure_compensation_(uint16_t pressure_in_hpa)
bool start_measurement_()
sensor::Sensor * ambient_pressure_source_
bool perform_forced_calibration(uint16_t current_co2_concentration)
uint16_t altitude_compensation_
sensor::Sensor * temperature_sensor_
MeasurementMode measurement_mode_
float temperature_offset_
sensor::Sensor * co2_sensor_
void set_ambient_pressure_compensation(float pressure_in_hpa)
void dump_config() override
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.
bool read_data(uint16_t *data, uint8_t len)
Read data words from I2C device.
void publish_state(float state)
Publish a new state to the front-end.
float state
This member variable stores the last state that has passed through all filters.
ESPHOME_LOG_TAG(TAG, "scd4x")
void HOT delay(uint32_t ms)