8static const char *
const TAG =
"sps30";
10static const uint16_t SPS30_CMD_GET_ARTICLE_CODE = 0xD025;
11static const uint16_t SPS30_CMD_GET_SERIAL_NUMBER = 0xD033;
12static const uint16_t SPS30_CMD_GET_FIRMWARE_VERSION = 0xD100;
13static const uint16_t SPS30_CMD_START_CONTINUOUS_MEASUREMENTS = 0x0010;
14static const uint16_t SPS30_CMD_START_CONTINUOUS_MEASUREMENTS_ARG = 0x0300;
15static const uint16_t SPS30_CMD_GET_DATA_READY_STATUS = 0x0202;
16static const uint16_t SPS30_CMD_READ_MEASUREMENT = 0x0300;
17static const uint16_t SPS30_CMD_STOP_MEASUREMENTS = 0x0104;
18static const uint16_t SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS = 0x8004;
19static const uint16_t SPS30_CMD_START_FAN_CLEANING = 0x5607;
20static const uint16_t SPS30_CMD_SOFT_RESET = 0xD304;
21static const size_t SERIAL_NUMBER_LENGTH = 8;
22static const uint8_t MAX_SKIPPED_DATA_CYCLES_BEFORE_ERROR = 5;
23static const uint32_t SPS30_WARM_UP_SEC = 30;
36 uint16_t raw_serial_number[8];
37 if (!this->
get_register(SPS30_CMD_GET_SERIAL_NUMBER, raw_serial_number, 8, 1)) {
43 for (
size_t i = 0; i < 8; ++i) {
44 this->
serial_number_[i * 2] =
static_cast<char>(raw_serial_number[i] >> 8);
45 this->
serial_number_[i * 2 + 1] = uint16_t(uint16_t(raw_serial_number[i] & 0xFF));
54 result = this->
write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS);
68 this->next_state_ =
READ;
75 ESP_LOGCONFIG(TAG,
"SPS30:");
78 switch (this->error_code_) {
80 ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
83 ESP_LOGW(TAG,
"Measurement Initialization failed");
86 ESP_LOGW(TAG,
"Unable to request serial number");
89 ESP_LOGW(TAG,
"Unable to read serial number");
92 ESP_LOGW(TAG,
"Unable to request firmware version");
95 ESP_LOGW(TAG,
"Unable to read firmware version");
98 ESP_LOGW(TAG,
"Unknown setup error");
102 LOG_UPDATE_INTERVAL(
this);
104 " Serial number: %s\n"
105 " Firmware version v%0d.%0d",
110 LOG_SENSOR(
" ",
"PM1.0 Weight Concentration", this->
pm_1_0_sensor_);
111 LOG_SENSOR(
" ",
"PM2.5 Weight Concentration", this->
pm_2_5_sensor_);
112 LOG_SENSOR(
" ",
"PM4 Weight Concentration", this->
pm_4_0_sensor_);
126 ESP_LOGD(TAG,
"Reconnecting");
128 ESP_LOGD(TAG,
"Soft-reset successful; waiting 500 ms");
134 ESP_LOGD(TAG,
"Reconnected; resuming continuous measurement");
137 ESP_LOGD(TAG,
"Soft-reset failed");
143 const uint32_t update_start_ms =
millis();
144 if (this->next_state_ !=
NONE && (int32_t) (this->
next_state_ms_ - update_start_ms) > 0) {
145 ESP_LOGD(TAG,
"Sensor waiting for %ums before transitioning to state %d.", (this->
next_state_ms_ - update_start_ms),
150 switch (this->next_state_) {
167 uint16_t raw_read_status;
168 if (!this->
read_data(&raw_read_status, 1) || raw_read_status == 0x00) {
169 ESP_LOGD(TAG,
"Not ready");
174 ESP_LOGD(TAG,
"Exceeded max attempts; will reinitialize");
181 ESP_LOGW(TAG,
"Error reading status");
187 uint16_t raw_data[20];
189 ESP_LOGW(TAG,
"Error reading data");
194 union uint32_float_t {
200 uint32_float_t pm_1_0{.uint32 = (((uint32_t(raw_data[0])) << 16) | (uint32_t(raw_data[1])))};
201 uint32_float_t pm_2_5{.uint32 = (((uint32_t(raw_data[2])) << 16) | (uint32_t(raw_data[3])))};
202 uint32_float_t pm_4_0{.uint32 = (((uint32_t(raw_data[4])) << 16) | (uint32_t(raw_data[5])))};
203 uint32_float_t pm_10_0{.uint32 = (((uint32_t(raw_data[6])) << 16) | (uint32_t(raw_data[7])))};
206 uint32_float_t pmc_0_5{.uint32 = (((uint32_t(raw_data[8])) << 16) | (uint32_t(raw_data[9])))};
207 uint32_float_t pmc_1_0{.uint32 = (((uint32_t(raw_data[10])) << 16) | (uint32_t(raw_data[11])))};
208 uint32_float_t pmc_2_5{.uint32 = (((uint32_t(raw_data[12])) << 16) | (uint32_t(raw_data[13])))};
209 uint32_float_t pmc_4_0{.uint32 = (((uint32_t(raw_data[14])) << 16) | (uint32_t(raw_data[15])))};
210 uint32_float_t pmc_10_0{.uint32 = (((uint32_t(raw_data[16])) << 16) | (uint32_t(raw_data[17])))};
213 uint32_float_t pm_size{.uint32 = (((uint32_t(raw_data[18])) << 16) | (uint32_t(raw_data[19])))};
238 this->status_clear_warning();
239 this->skipped_data_read_cycles_ = 0;
244 this->stop_measurement();
245 this->next_state_ms_ = millis() + this->idle_interval_.value();
246 this->next_state_ = WAKE;
248 this->next_state_ms_ = millis();
254 if (!this->
write_command(SPS30_CMD_START_CONTINUOUS_MEASUREMENTS, SPS30_CMD_START_CONTINUOUS_MEASUREMENTS_ARG)) {
255 ESP_LOGE(TAG,
"Error initiating measurements");
258 ESP_LOGD(TAG,
"Started measurements");
262 this->next_state_ =
READ;
270 ESP_LOGE(TAG,
"Error stopping measurements");
273 ESP_LOGD(TAG,
"Stopped measurements");
276 this->next_state_ =
NONE;
284 ESP_LOGE(TAG,
"Start fan cleaning failed (%d)", this->
last_error_);
287 ESP_LOGD(TAG,
"Fan auto clean started");
virtual void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message=nullptr)
bool status_has_warning() const
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.
value_type const & value() const
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_
@ FIRMWARE_VERSION_REQUEST_FAILED
@ FIRMWARE_VERSION_READ_FAILED
@ SERIAL_NUMBER_READ_FAILED
@ SERIAL_NUMBER_REQUEST_FAILED
@ MEASUREMENT_INIT_FAILED
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_
Providing packet encoding functions for exchanging data with a remote host.
uint32_t IRAM_ATTR HOT millis()