11static const char *
const TAG =
"sen5x";
13static const uint16_t SEN5X_CMD_AUTO_CLEANING_INTERVAL = 0x8004;
14static const uint16_t SEN5X_CMD_GET_DATA_READY_STATUS = 0x0202;
15static const uint16_t SEN5X_CMD_GET_FIRMWARE_VERSION = 0xD100;
16static const uint16_t SEN5X_CMD_GET_PRODUCT_NAME = 0xD014;
17static const uint16_t SEN5X_CMD_GET_SERIAL_NUMBER = 0xD033;
18static const uint16_t SEN5X_CMD_NOX_ALGORITHM_TUNING = 0x60E1;
19static const uint16_t SEN5X_CMD_READ_MEASUREMENT = 0x03C4;
20static const uint16_t SEN5X_CMD_RHT_ACCELERATION_MODE = 0x60F7;
21static const uint16_t SEN5X_CMD_START_CLEANING_FAN = 0x5607;
22static const uint16_t SEN5X_CMD_START_MEASUREMENTS = 0x0021;
23static const uint16_t SEN5X_CMD_START_MEASUREMENTS_RHT_ONLY = 0x0037;
24static const uint16_t SEN5X_CMD_STOP_MEASUREMENTS = 0x3f86;
25static const uint16_t SEN5X_CMD_TEMPERATURE_COMPENSATION = 0x60B2;
26static const uint16_t SEN5X_CMD_VOC_ALGORITHM_STATE = 0x6181;
27static const uint16_t SEN5X_CMD_VOC_ALGORITHM_TUNING = 0x60D0;
29static const int8_t SEN5X_INDEX_SCALE_FACTOR = 10;
30static const int8_t SEN5X_MIN_INDEX_VALUE = 1 * SEN5X_INDEX_SCALE_FACTOR;
31static const int16_t SEN5X_MAX_INDEX_VALUE = 500 * SEN5X_INDEX_SCALE_FACTOR;
36 return LOG_STR(
"SEN50");
38 return LOG_STR(
"SEN54");
40 return LOG_STR(
"SEN55");
42 return LOG_STR(
"UNKNOWN");
49 return LOG_STR(
"LOW");
51 return LOG_STR(
"MEDIUM");
53 return LOG_STR(
"HIGH");
55 return LOG_STR(
"UNKNOWN");
64 ESP_LOGE(TAG,
"Failed to write data ready status command");
70 uint16_t raw_read_status;
72 ESP_LOGE(TAG,
"Failed to read data ready status");
77 uint32_t stop_measurement_delay = 0;
79 if (raw_read_status) {
80 ESP_LOGD(TAG,
"Data is available; stopping periodic measurement");
82 ESP_LOGE(TAG,
"Failed to stop measurements");
88 stop_measurement_delay = 200;
90 this->
set_timeout(stop_measurement_delay, [
this]() {
93 uint16_t raw_serial_number[8];
94 if (!this->
get_register(SEN5X_CMD_GET_SERIAL_NUMBER, raw_serial_number, 8, 20)) {
95 ESP_LOGE(TAG,
"Failed to read serial number");
104 uint16_t raw_product_name[16];
105 if (!this->
get_register(SEN5X_CMD_GET_PRODUCT_NAME, raw_product_name, 16, 20)) {
106 ESP_LOGE(TAG,
"Failed to read product name");
112 if (strncmp(product_name,
"SEN50", 5) == 0) {
114 }
else if (strncmp(product_name,
"SEN54", 5) == 0) {
116 }
else if (strncmp(product_name,
"SEN55", 5) == 0) {
120 ESP_LOGE(TAG,
"Unknown product name: %.32s", product_name);
126 ESP_LOGD(TAG,
"Type: %s", LOG_STR_ARG(type_to_string(this->
type_)));
128 ESP_LOGE(TAG,
"Relative humidity requires a SEN54 or SEN55");
132 ESP_LOGE(TAG,
"Temperature requires a SEN54 or SEN55");
136 ESP_LOGE(TAG,
"VOC requires a SEN54 or SEN55");
140 ESP_LOGE(TAG,
"NOx requires a SEN55");
145 ESP_LOGE(TAG,
"Failed to read firmware version");
158 if (this->
pref_.
load(&this->voc_baseline_state_)) {
160 ESP_LOGE(TAG,
"VOC Baseline State write to sensor failed");
162 ESP_LOGV(TAG,
"VOC Baseline State loaded");
172 result = this->
write_command(SEN5X_CMD_AUTO_CLEANING_INTERVAL);
184 result = this->
write_command(SEN5X_CMD_RHT_ACCELERATION_MODE);
187 ESP_LOGE(TAG,
"Failed to set rh/t acceleration mode");
198 ESP_LOGE(TAG,
"Failed to read RHT Acceleration mode");
216 auto cmd = SEN5X_CMD_START_MEASUREMENTS_RHT_ONLY;
219 cmd = SEN5X_CMD_START_MEASUREMENTS;
223 ESP_LOGE(TAG,
"Error starting continuous measurements");
234 ESP_LOGCONFIG(TAG,
"SEN5X:");
235 LOG_I2C_DEVICE(
this);
239 ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
242 ESP_LOGW(TAG,
"Measurement initialization failed");
245 ESP_LOGW(TAG,
"Unable to read serial ID");
248 ESP_LOGW(TAG,
"Unable to read product name");
251 ESP_LOGW(TAG,
"Unable to read firmware version");
254 ESP_LOGW(TAG,
"Unknown setup error");
260 " Firmware version: %d\n"
261 " Serial number: %s",
267 ESP_LOGCONFIG(TAG,
" RH/T acceleration mode: %s",
274 " Store Baseline: %s\n"
278 LOG_UPDATE_INTERVAL(
this);
296 ESP_LOGD(TAG,
"Write error: read measurement (%d)", this->
last_error_);
300 uint16_t measurements[8];
304 ESP_LOGD(TAG,
"Read data error (%d)", this->
last_error_);
308 ESP_LOGVV(TAG,
"pm_1_0 = 0x%.4x", measurements[0]);
309 float pm_1_0 = measurements[0] == UINT16_MAX ? NAN : measurements[0] / 10.0f;
311 ESP_LOGVV(TAG,
"pm_2_5 = 0x%.4x", measurements[1]);
312 float pm_2_5 = measurements[1] == UINT16_MAX ? NAN : measurements[1] / 10.0f;
314 ESP_LOGVV(TAG,
"pm_4_0 = 0x%.4x", measurements[2]);
315 float pm_4_0 = measurements[2] == UINT16_MAX ? NAN : measurements[2] / 10.0f;
317 ESP_LOGVV(TAG,
"pm_10_0 = 0x%.4x", measurements[3]);
318 float pm_10_0 = measurements[3] == UINT16_MAX ? NAN : measurements[3] / 10.0f;
320 ESP_LOGVV(TAG,
"humidity = 0x%.4x", measurements[4]);
321 float humidity = measurements[4] == INT16_MAX ? NAN :
static_cast<int16_t
>(measurements[4]) / 100.0f;
323 ESP_LOGVV(TAG,
"temperature = 0x%.4x", measurements[5]);
324 float temperature = measurements[5] == INT16_MAX ? NAN :
static_cast<int16_t
>(measurements[5]) / 200.0f;
326 ESP_LOGVV(TAG,
"voc = 0x%.4x", measurements[6]);
327 int16_t voc_idx =
static_cast<int16_t
>(measurements[6]);
328 float voc = (voc_idx < SEN5X_MIN_INDEX_VALUE || voc_idx > SEN5X_MAX_INDEX_VALUE)
330 :
static_cast<float>(voc_idx) / 10.0f;
332 ESP_LOGVV(TAG,
"nox = 0x%.4x", measurements[7]);
333 int16_t nox_idx =
static_cast<int16_t
>(measurements[7]);
334 float nox = (nox_idx < SEN5X_MIN_INDEX_VALUE || nox_idx > SEN5X_MAX_INDEX_VALUE)
336 :
static_cast<float>(nox_idx) / 10.0f;
370 ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
375 ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
377 if (this->
pref_.
save(&this->voc_baseline_state_)) {
378 ESP_LOGD(TAG,
"VOC Baseline State saved");
398 ESP_LOGE(TAG,
"Set tuning parameters failed (command=%0xX, err=%d)", i2c_command, this->
last_error_);
405 params[0] = compensation.
offset;
408 if (!
write_command(SEN5X_CMD_TEMPERATURE_COMPENSATION, params, 3)) {
409 ESP_LOGE(TAG,
"Set temperature_compensation failed (%d)", this->
last_error_);
418 ESP_LOGE(TAG,
"Start fan cleaning failed (%d)", this->
last_error_);
421 ESP_LOGD(TAG,
"Fan auto clean started");
BedjetMode mode
BedJet operating mode.
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message=nullptr)
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
void status_clear_warning()
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
value_type const & value() const
optional< RhtAccelerationMode > acceleration_mode_
uint16_t firmware_version_
sensor::Sensor * pm_4_0_sensor_
void dump_config() override
ESPPreferenceObject pref_
bool write_tuning_parameters_(uint16_t i2c_command, const GasTuning &tuning)
sensor::Sensor * pm_2_5_sensor_
sensor::Sensor * temperature_sensor_
optional< uint32_t > auto_cleaning_interval_
sensor::Sensor * pm_1_0_sensor_
sensor::Sensor * voc_sensor_
optional< TemperatureCompensation > temperature_compensation_
sensor::Sensor * nox_sensor_
optional< GasTuning > voc_tuning_params_
sensor::Sensor * pm_10_0_sensor_
sensor::Sensor * humidity_sensor_
bool write_temperature_compensation_(const TemperatureCompensation &compensation)
bool start_fan_cleaning()
optional< GasTuning > nox_tuning_params_
uint32_t voc_baseline_time_
uint16_t voc_baseline_state_[4]
i2c::ErrorCode last_error_
last error code from I2C operation
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.
static const char * sensirion_convert_to_string_in_place(uint16_t *array, size_t length)
This function performs an in-place conversion of the provided buffer from uint16_t values to big endi...
void publish_state(float state)
Publish a new state to the front-end.
@ MEASUREMENT_INIT_FAILED
@ SERIAL_NUMBER_IDENTIFICATION_FAILED
Providing packet encoding functions for exchanging data with a remote host.
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
ESPPreferences * global_preferences
void HOT delay(uint32_t ms)
Application App
Global storage of Application pointer - only one Application can exist.
constexpr uint32_t fnv1a_hash(const char *str)
Calculate a FNV-1a hash of str.
uint16_t learning_time_gain_hours
uint16_t gating_max_duration_minutes
uint16_t learning_time_offset_hours
int16_t normalized_offset_slope