8static const char *
const TAG =
"scd4x";
10static const uint16_t SCD41_ID = 0x1408;
11static const uint16_t SCD40_ID = 0x440;
12static const uint16_t SCD4X_CMD_GET_SERIAL_NUMBER = 0x3682;
13static const uint16_t SCD4X_CMD_TEMPERATURE_OFFSET = 0x241d;
14static const uint16_t SCD4X_CMD_ALTITUDE_COMPENSATION = 0x2427;
15static const uint16_t SCD4X_CMD_AMBIENT_PRESSURE_COMPENSATION = 0xe000;
16static const uint16_t SCD4X_CMD_AUTOMATIC_SELF_CALIBRATION = 0x2416;
17static const uint16_t SCD4X_CMD_START_CONTINUOUS_MEASUREMENTS = 0x21b1;
18static const uint16_t SCD4X_CMD_START_LOW_POWER_CONTINUOUS_MEASUREMENTS = 0x21ac;
19static const uint16_t SCD4X_CMD_START_LOW_POWER_SINGLE_SHOT = 0x219d;
20static const uint16_t SCD4X_CMD_START_LOW_POWER_SINGLE_SHOT_RHT_ONLY = 0x2196;
21static const uint16_t SCD4X_CMD_GET_DATA_READY_STATUS = 0xe4b8;
22static const uint16_t SCD4X_CMD_READ_MEASUREMENT = 0xec05;
23static const uint16_t SCD4X_CMD_PERFORM_FORCED_CALIBRATION = 0x362f;
24static const uint16_t SCD4X_CMD_STOP_MEASUREMENTS = 0x3f86;
25static const uint16_t SCD4X_CMD_FACTORY_RESET = 0x3632;
26static const uint16_t SCD4X_CMD_GET_FEATURESET = 0x202f;
27static const float SCD4X_TEMPERATURE_OFFSET_MULTIPLIER = (1 << 16) / 175.0f;
34 ESP_LOGE(TAG,
"Failed to stop measurements");
41 uint16_t raw_serial_number[3];
42 if (!this->
get_register(SCD4X_CMD_GET_SERIAL_NUMBER, raw_serial_number, 3, 1)) {
43 ESP_LOGE(TAG,
"Failed to read serial number");
48 ESP_LOGD(TAG,
"Serial number %02d.%02d.%02d", (uint16_t(raw_serial_number[0]) >> 8),
49 uint16_t(raw_serial_number[0] & 0xFF), (uint16_t(raw_serial_number[1]) >> 8));
53 ESP_LOGE(TAG,
"Error setting temperature offset");
62 ESP_LOGE(TAG,
"Error setting ambient pressure compensation");
69 ESP_LOGE(TAG,
"Error setting altitude compensation");
77 ESP_LOGE(TAG,
"Error setting automatic self calibration");
91 static const char *
const MM_PERIODIC_STR =
"Periodic (5s)";
92 static const char *
const MM_LOW_POWER_PERIODIC_STR =
"Low power periodic (30s)";
93 static const char *
const MM_SINGLE_SHOT_STR =
"Single shot";
94 static const char *
const MM_SINGLE_SHOT_RHT_ONLY_STR =
"Single shot rht only";
95 const char *measurement_mode_str = MM_PERIODIC_STR;
102 measurement_mode_str = MM_LOW_POWER_PERIODIC_STR;
105 measurement_mode_str = MM_SINGLE_SHOT_STR;
108 measurement_mode_str = MM_SINGLE_SHOT_RHT_ONLY_STR;
112 ESP_LOGCONFIG(TAG,
"SCD4X:");
113 LOG_I2C_DEVICE(
this);
117 ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
120 ESP_LOGW(TAG,
"Measurement Initialization failed");
123 ESP_LOGW(TAG,
"Unable to read firmware version");
126 ESP_LOGW(TAG,
"Unknown setup error");
131 " Automatic self calibration: %s\n"
132 " Measurement mode: %s\n"
133 " Temperature offset: %.2f °C",
136 ESP_LOGCONFIG(TAG,
" Dynamic ambient pressure compensation using '%s'",
141 " Altitude compensation disabled\n"
142 " Ambient pressure compensation: %dmBar",
146 " Ambient pressure compensation disabled\n"
147 " Altitude compensation: %dm",
151 LOG_UPDATE_INTERVAL(
this);
169 uint32_t wait_time = 0;
182 uint16_t raw_read_status;
184 if (!this->
read_data(raw_read_status) || raw_read_status == 0x00) {
186 ESP_LOGW(TAG,
"Data not ready");
191 ESP_LOGW(TAG,
"Error reading measurement");
196 uint16_t raw_data[3];
205 const float temperature = -45.0f + (175.0f * (raw_data[1])) / (1 << 16);
209 const float humidity = (100.0f * raw_data[2]) / (1 << 16);
223 ESP_LOGE(TAG,
"Failed to stop measurements");
226 this->
set_timeout(500, [
this, current_co2_concentration]() {
227 if (this->
write_command(SCD4X_CMD_PERFORM_FORCED_CALIBRATION, current_co2_concentration)) {
228 ESP_LOGD(TAG,
"Setting forced calibration Co2 level %d ppm", current_co2_concentration);
236 ESP_LOGD(TAG,
"Forced calibration complete");
240 ESP_LOGE(TAG,
"Force calibration failed");
251 ESP_LOGE(TAG,
"Failed to stop measurements");
258 ESP_LOGE(TAG,
"Failed to send factory reset command");
262 ESP_LOGD(TAG,
"Factory reset complete");
269 uint16_t new_ambient_pressure =
static_cast<uint16_t
>(pressure_in_hpa);
279 ESP_LOGD(TAG,
"Ambient pressure compensation skipped; no change required");
284 if (this->
write_command(SCD4X_CMD_AMBIENT_PRESSURE_COMPENSATION, pressure_in_hpa)) {
285 ESP_LOGD(TAG,
"Setting ambient pressure compensation to %d hPa", pressure_in_hpa);
288 ESP_LOGE(TAG,
"Error setting ambient pressure compensation");
294 uint16_t measurement_command = SCD4X_CMD_START_CONTINUOUS_MEASUREMENTS;
297 measurement_command = SCD4X_CMD_START_CONTINUOUS_MEASUREMENTS;
300 measurement_command = SCD4X_CMD_START_LOW_POWER_CONTINUOUS_MEASUREMENTS;
303 measurement_command = SCD4X_CMD_START_LOW_POWER_SINGLE_SHOT;
306 measurement_command = SCD4X_CMD_START_LOW_POWER_SINGLE_SHOT_RHT_ONLY;
310 static uint8_t remaining_retries = 3;
311 while (remaining_retries) {
313 ESP_LOGE(TAG,
"Error starting measurements");
316 if (--remaining_retries == 0)
virtual void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message=nullptr)
void status_clear_error()
void status_clear_warning()
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
const StringRef & get_name() const
constexpr const char * c_str() const
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.
@ SERIAL_NUMBER_IDENTIFICATION_FAILED
@ MEASUREMENT_INIT_FAILED
Providing packet encoding functions for exchanging data with a remote host.
void IRAM_ATTR HOT delay(uint32_t ms)