From f58bb249c4b7e298afc2db8fbc0ed43584a64b20 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Thu, 14 Mar 2024 19:09:54 +0100 Subject: [PATCH] fsm --- esphome/components/as7343/as7343.cpp | 100 ++++++++++++++++----------- esphome/components/as7343/as7343.h | 25 ++++++- esphome/components/as7343/sensor.py | 14 +++- 3 files changed, 96 insertions(+), 43 deletions(-) diff --git a/esphome/components/as7343/as7343.cpp b/esphome/components/as7343/as7343.cpp index c25a5b0499..b636d47ae7 100644 --- a/esphome/components/as7343/as7343.cpp +++ b/esphome/components/as7343/as7343.cpp @@ -121,6 +121,10 @@ void AS7343Component::setup() { this->setup_gain(this->gain_); // enable led false ? + + this->enable_spectral_measurement(true); + + this->state_ = State::IDLE; } void AS7343Component::dump_config() { @@ -170,14 +174,54 @@ void log13_s(const char *TAG, const char *str, const std::arrayenable_spectral_measurement(true); - this->read_all_channels(); - this->enable_spectral_measurement(false); - this->calculate_basic_counts(); + if (this->is_ready() && this->state_ == State::IDLE) { + ESP_LOGV(TAG, "Update: Initiating new data collection"); - log13_s(TAG, "Channel", CHANNEL_NAMES); - log13_f(TAG, "Nm", CHANNEL_NM); - log13_d(TAG, "Counts", this->readings_.raw_counts); + // this->enable_spectral_measurement(true); + + this->readings_.millis_start = millis(); + this->state_ = State::COLLECTING_DATA; + } else { + ESP_LOGV(TAG, "Update: Component not ready yet"); + } +} + +void AS7343Component::loop() { + if (this->is_ready()) { + switch (this->state_) { + case State::IDLE: + // doing nothing, having best time + break; + + case State::COLLECTING_DATA: + if (this->is_data_ready()) { + this->read_all_channels(); + + log13_s(TAG, "Channel", CHANNEL_NAMES); + log13_f(TAG, "Nm", CHANNEL_NM); + log13_d(TAG, "Counts", this->readings_.raw_counts); + + this->state_ = State::DATA_COLLECTED; + } else if (millis() - this->readings_.millis_start > 30 * 1000) { + ESP_LOGW(TAG, "Data collection timeout (30s)"); + this->state_ = State::IDLE; + } else { + // just do nothing, wait for data + } + break; + + case State::DATA_COLLECTED: + // apply modifications + // publish + this->calculate_and_publish(); + this->state_ = State::IDLE; + break; + } + } +} + +void AS7343Component::calculate_and_publish() { + this->calculate_basic_counts(); uint16_t max_adc = this->get_maximum_spectral_adc_(); uint16_t highest_adc = this->get_highest_value(this->readings_.raw_counts); @@ -193,18 +237,6 @@ void AS7343Component::update() { ESP_LOGD(TAG, " ,ASTEP, %u,", this->readings_.astep); ESP_LOGD(TAG, " ,TINT , %.2f,", this->readings_.t_int); - // ESP_LOGD(TAG, ",nm, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, ", CHANNEL_NM[0], - // CHANNEL_NM[1], CHANNEL_NM[2], CHANNEL_NM[3], CHANNEL_NM[4], CHANNEL_NM[5], CHANNEL_NM[6], CHANNEL_NM[7], - // CHANNEL_NM[8], CHANNEL_NM[9], CHANNEL_NM[10], CHANNEL_NM[11], CHANNEL_NM[12]); - // ESP_LOGD(TAG, ",counts, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, ", - // this->channel_readings_[CHANNEL_IDX[0]], this->channel_readings_[CHANNEL_IDX[1]], - // this->channel_readings_[CHANNEL_IDX[2]], this->channel_readings_[CHANNEL_IDX[3]], - // this->channel_readings_[CHANNEL_IDX[4]], this->channel_readings_[CHANNEL_IDX[5]], - // this->channel_readings_[CHANNEL_IDX[6]], this->channel_readings_[CHANNEL_IDX[7]], - // this->channel_readings_[CHANNEL_IDX[8]], this->channel_readings_[CHANNEL_IDX[9]], - // this->channel_readings_[CHANNEL_IDX[10]], this->channel_readings_[CHANNEL_IDX[11]], - // this->channel_readings_[CHANNEL_IDX[12]]); - float irradiance; float irradiance_photopic; float lux; @@ -292,12 +324,10 @@ void AS7343Component::update() { if (this->nir_ != nullptr) { this->nir_->publish_state(normalized_readings[11]); } - // if (this->clear_ != nullptr) { - // float clear = (this->channel_readings_[AS7343_CHANNEL_CLEAR] + this->channel_readings_[AS7343_CHANNEL_CLEAR_0] + - // this->channel_readings_[AS7343_CHANNEL_CLEAR_1]) / - // 3; - // this->clear_->publish_state(clear); - // } + if (this->clear_ != nullptr) { + float clear = (this->readings_.basic_counts[AS7343_CHANNEL_CLEAR]); + this->clear_->publish_state(clear); + } if (this->saturated_ != nullptr) { this->saturated_->publish_state(this->readings_saturated_); } @@ -431,12 +461,10 @@ bool AS7343Component::read_all_channels() { AS7343_CHANNEL_405_F1, AS7343_CHANNEL_425_F2, AS7343_CHANNEL_450_FZ, AS7343_CHANNEL_475_F3, AS7343_CHANNEL_515_F4, AS7343_CHANNEL_555_FY, AS7343_CHANNEL_550_F5, AS7343_CHANNEL_600_FXL, AS7343_CHANNEL_640_F6, AS7343_CHANNEL_690_F7, AS7343_CHANNEL_745_F8, AS7343_CHANNEL_855_NIR, - AS7343_CHANNEL_CLEAR}; + AS7343_CHANNEL_CLEAR_0}; std::array data; - this->wait_for_data(); - AS7343RegStatus status{0}; status.raw = this->reg((uint8_t) AS7343Registers::STATUS).get(); ESP_LOGD(TAG, "Status 0x%02x, sint %d, fint %d, aint %d, asat %d", status.raw, status.sint, status.fint, status.aint, @@ -458,6 +486,10 @@ bool AS7343Component::read_all_channels() { this->readings_.raw_counts[i] = data[CHANNEL_MAP[i]]; } + ESP_LOGD(TAG, "Clear = %d, Fd = %d", data[AS7343_CHANNEL_CLEAR], data[AS7343_CHANNEL_FD]); + ESP_LOGD(TAG, "Clear_0 = %d, Fd_0 = %d", data[AS7343_CHANNEL_CLEAR_0], data[AS7343_CHANNEL_FD_0]); + ESP_LOGD(TAG, "Clear_1 = %d, Fd_1 = %d", data[AS7343_CHANNEL_CLEAR_1], data[AS7343_CHANNEL_FD_1]); + this->readings_.gain = astatus.again_status; this->readings_.gain_x = get_gain_multiplier(this->readings_.gain); this->readings_.atime = get_atime(); @@ -469,18 +501,6 @@ bool AS7343Component::read_all_channels() { return ret; } -bool AS7343Component::wait_for_data(uint16_t timeout) { - for (uint16_t time = 0; time < timeout; time++) { - if (this->is_data_ready()) { - return true; - } - - delay(1); - } - - return false; -} - bool AS7343Component::is_data_ready() { AS7343RegStatus2 status2{0}; status2.raw = this->reg((uint8_t) AS7343Registers::STATUS2).get(); diff --git a/esphome/components/as7343/as7343.h b/esphome/components/as7343/as7343.h index 156a90d089..25a1d794c6 100644 --- a/esphome/components/as7343/as7343.h +++ b/esphome/components/as7343/as7343.h @@ -15,6 +15,7 @@ class AS7343Component : public PollingComponent, public i2c::I2CDevice { void dump_config() override; float get_setup_priority() const override; void update() override; + void loop() override; void set_f1_sensor(sensor::Sensor *f1_sensor) { f1_ = f1_sensor; } void set_f2_sensor(sensor::Sensor *f2_sensor) { f2_ = f2_sensor; } @@ -57,8 +58,10 @@ class AS7343Component : public PollingComponent, public i2c::I2CDevice { void calculate_ppfd(float &ppfd); void calculate_irradiance(float &irradiance, float &irradiance_photopic, float &lux); - bool wait_for_data(uint16_t timeout = 1000); bool is_data_ready(); + + void calculate_and_publish(); + bool enable_power(bool enable); bool enable_spectral_measurement(bool enable); @@ -69,6 +72,25 @@ class AS7343Component : public PollingComponent, public i2c::I2CDevice { uint16_t swap_bytes(uint16_t data); protected: + // + // Internal state machine, used to split all the actions into + // small steps in loop() to make sure we are not blocking execution + // + enum class State : uint8_t { + NOT_INITIALIZED, + INITIAL_SETUP_COMPLETED, + IDLE, + COLLECTING_DATA, + COLLECTING_DATA_AUTO, + DATA_COLLECTED, + ADJUSTMENT_NEEDED, + ADJUSTMENT_IN_PROGRESS, + READY_TO_APPLY_ADJUSTMENTS, + READY_TO_PUBLISH_PART_1, + READY_TO_PUBLISH_PART_2, + READY_TO_PUBLISH_PART_3 + } state_{State::NOT_INITIALIZED}; + void set_bank_for_reg_(AS7343Registers reg = AS7343Registers::ENABLE); bool bank_{false}; bool readings_saturated_{false}; @@ -106,6 +128,7 @@ class AS7343Component : public PollingComponent, public i2c::I2CDevice { float gain_x; float t_int; + uint32_t millis_start; } readings_; float get_tint_(); diff --git a/esphome/components/as7343/sensor.py b/esphome/components/as7343/sensor.py index 24ec7e4549..1f0ee41d3e 100644 --- a/esphome/components/as7343/sensor.py +++ b/esphome/components/as7343/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( ICON_BRIGHTNESS_5, STATE_CLASS_MEASUREMENT, UNIT_LUX, + UNIT_PERCENT, ) @@ -69,7 +70,7 @@ GAIN_OPTIONS = { SENSOR_SCHEMA = cv.maybe_simple_value( sensor.sensor_schema( - unit_of_measurement=UNIT_COUNTS, + unit_of_measurement=UNIT_PERCENT, icon=ICON_BRIGHTNESS_5, accuracy_decimals=0, device_class=DEVICE_CLASS_ILLUMINANCE, @@ -95,7 +96,16 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_F7): SENSOR_SCHEMA, cv.Optional(CONF_F8): SENSOR_SCHEMA, cv.Optional(CONF_NIR): SENSOR_SCHEMA, - cv.Optional(CONF_CLEAR): SENSOR_SCHEMA, + cv.Optional(CONF_CLEAR): cv.maybe_simple_value( + sensor.sensor_schema( + unit_of_measurement=UNIT_COUNTS, + icon=ICON_BRIGHTNESS_5, + accuracy_decimals=5, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + key=CONF_NAME, + ), cv.Optional(CONF_GAIN, default="X8"): cv.enum(GAIN_OPTIONS), cv.Optional(CONF_ATIME, default=29): cv.int_range(min=0, max=255), cv.Optional(CONF_ASTEP, default=599): cv.int_range(min=0, max=65534),