11static const uint16_t SPS30_CMD_GET_ARTICLE_CODE = 0xD025;
12static const uint16_t SPS30_CMD_GET_SERIAL_NUMBER = 0xD033;
13static const uint16_t SPS30_CMD_GET_FIRMWARE_VERSION = 0xD100;
14static const uint16_t SPS30_CMD_START_CONTINUOUS_MEASUREMENTS = 0x0010;
15static const uint16_t SPS30_CMD_START_CONTINUOUS_MEASUREMENTS_ARG = 0x0300;
16static const uint16_t SPS30_CMD_GET_DATA_READY_STATUS = 0x0202;
17static const uint16_t SPS30_CMD_READ_MEASUREMENT = 0x0300;
18static const uint16_t SPS30_CMD_STOP_MEASUREMENTS = 0x0104;
19static const uint16_t SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS = 0x8004;
20static const uint16_t SPS30_CMD_START_FAN_CLEANING = 0x5607;
21static const uint16_t SPS30_CMD_SOFT_RESET = 0xD304;
22static const size_t SERIAL_NUMBER_LENGTH = 8;
23static const uint8_t MAX_SKIPPED_DATA_CYCLES_BEFORE_ERROR = 5;
24static const uint32_t SPS30_WARM_UP_SEC = 30;
32 this->
mark_failed(LOG_STR(
"Unable to read firmware version"));
36 uint16_t raw_serial_number[8];
37 if (!this->
get_register(SPS30_CMD_GET_SERIAL_NUMBER, raw_serial_number, 8, 1)) {
38 this->
mark_failed(LOG_STR(
"Unable to read serial number"));
42 for (
size_t i = 0; i < 8; ++i) {
43 this->
serial_number_[i * 2] =
static_cast<char>(raw_serial_number[i] >> 8);
44 this->
serial_number_[i * 2 + 1] = uint16_t(uint16_t(raw_serial_number[i] & 0xFF));
53 result = this->
write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS);
67 this->next_state_ =
READ;
74 ESP_LOGCONFIG(TAG,
"SPS30:");
76 LOG_UPDATE_INTERVAL(
this);
78 " Serial number: %s\n"
79 " Firmware version v%0d.%0d",
82 ESP_LOGCONFIG(TAG,
" Idle interval: %" PRIu32
"s", this->
idle_interval_.value() / 1000);
84 LOG_SENSOR(
" ",
"PM1.0 Weight Concentration", this->
pm_1_0_sensor_);
85 LOG_SENSOR(
" ",
"PM2.5 Weight Concentration", this->
pm_2_5_sensor_);
100 ESP_LOGD(TAG,
"Reconnecting");
102 ESP_LOGD(TAG,
"Soft-reset successful; waiting 500 ms");
108 ESP_LOGD(TAG,
"Reconnected; resuming continuous measurement");
111 ESP_LOGD(TAG,
"Soft-reset failed");
118 if (this->next_state_ !=
NONE && (int32_t) (this->
next_state_ms_ - update_start_ms) > 0) {
119 ESP_LOGD(TAG,
"Sensor waiting for %" PRIu32
"ms before transitioning to state %d.",
124 switch (this->next_state_) {
141 uint16_t raw_read_status;
142 if (!this->
read_data(&raw_read_status, 1) || raw_read_status == 0x00) {
143 ESP_LOGD(TAG,
"Not ready");
148 ESP_LOGD(TAG,
"Exceeded max attempts; will reinitialize");
155 ESP_LOGW(TAG,
"Error reading status");
161 uint16_t raw_data[20];
163 ESP_LOGW(TAG,
"Error reading data");
168 union uint32_float_t {
174 uint32_float_t pm_1_0{.uint32 = (((
uint32_t(raw_data[0])) << 16) | (
uint32_t(raw_data[1])))};
175 uint32_float_t pm_2_5{.uint32 = (((
uint32_t(raw_data[2])) << 16) | (
uint32_t(raw_data[3])))};
176 uint32_float_t pm_4_0{.uint32 = (((
uint32_t(raw_data[4])) << 16) | (
uint32_t(raw_data[5])))};
177 uint32_float_t pm_10_0{.uint32 = (((
uint32_t(raw_data[6])) << 16) | (
uint32_t(raw_data[7])))};
180 uint32_float_t pmc_0_5{.uint32 = (((
uint32_t(raw_data[8])) << 16) | (
uint32_t(raw_data[9])))};
181 uint32_float_t pmc_1_0{.uint32 = (((
uint32_t(raw_data[10])) << 16) | (
uint32_t(raw_data[11])))};
182 uint32_float_t pmc_2_5{.uint32 = (((
uint32_t(raw_data[12])) << 16) | (
uint32_t(raw_data[13])))};
183 uint32_float_t pmc_4_0{.uint32 = (((
uint32_t(raw_data[14])) << 16) | (
uint32_t(raw_data[15])))};
184 uint32_float_t pmc_10_0{.uint32 = (((
uint32_t(raw_data[16])) << 16) | (
uint32_t(raw_data[17])))};
187 uint32_float_t pm_size{.uint32 = (((
uint32_t(raw_data[18])) << 16) | (
uint32_t(raw_data[19])))};
212 this->status_clear_warning();
213 this->skipped_data_read_cycles_ = 0;
218 this->stop_measurement();
219 this->next_state_ms_ = millis() + this->idle_interval_.value();
220 this->next_state_ = WAKE;
222 this->next_state_ms_ = millis();
228 if (!this->
write_command(SPS30_CMD_START_CONTINUOUS_MEASUREMENTS, SPS30_CMD_START_CONTINUOUS_MEASUREMENTS_ARG)) {
229 ESP_LOGE(TAG,
"Error initiating measurements");
232 ESP_LOGD(TAG,
"Started measurements");
236 this->next_state_ =
READ;
244 ESP_LOGE(TAG,
"Error stopping measurements");
247 ESP_LOGD(TAG,
"Stopped measurements");
250 this->next_state_ =
NONE;
258 ESP_LOGE(TAG,
"Start fan cleaning failed (%d)", this->
last_error_);
261 ESP_LOGD(TAG,
"Fan auto clean started");
void mark_failed()
Mark this component as failed.
void status_set_warning()
bool status_has_warning() const
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()
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.
void publish_state(float state)
Publish a new state to the front-end.
uint16_t raw_firmware_version_
sensor::Sensor * pm_2_5_sensor_
optional< uint32_t > fan_interval_
bool start_continuous_measurement_()
sensor::Sensor * pmc_4_0_sensor_
sensor::Sensor * pmc_2_5_sensor_
sensor::Sensor * pm_10_0_sensor_
uint8_t skipped_data_read_cycles_
Terminating NULL character.
enum esphome::sps30::SPS30Component::NextState NONE
bool start_fan_cleaning()
sensor::Sensor * pm_1_0_sensor_
sensor::Sensor * pm_size_sensor_
void dump_config() override
sensor::Sensor * pmc_0_5_sensor_
sensor::Sensor * pm_4_0_sensor_
optional< uint32_t > idle_interval_
sensor::Sensor * pmc_10_0_sensor_
sensor::Sensor * pmc_1_0_sensor_
ESPHOME_LOG_TAG(TAG, "sps30")
uint32_t IRAM_ATTR HOT millis()