diff --git a/esphome/components/as7343/as7343.cpp b/esphome/components/as7343/as7343.cpp index 2f18f322b9..557e899e49 100644 --- a/esphome/components/as7343/as7343.cpp +++ b/esphome/components/as7343/as7343.cpp @@ -26,6 +26,8 @@ static constexpr float CHANNEL_BASIC_CORRECTIONS[NUM_USEFUL_CHANNELS] = { static constexpr float CHANNEL_NM[NUM_USEFUL_CHANNELS] = {405, 425, 450, 475, 515, 555, 550, 600, 640, 690, 745, 855, 718}; +// static constexpr float CHANNEL_CONTRIB[NUM_USEFUL_CHANNELS] = { +// 0.0603622, 0.0442656, 0.110664, 0.0603622, 0.0804829, 0.201207, 0.0704225, 0.160966, 0.100604, 0.110664, 0}; static constexpr float CHANNEL_NM_WIDTH[NUM_USEFUL_CHANNELS] = {30, 22, 55, 30, 40, 100, 35, 80, 50, 55, 60, 54, 0}; // Irradiation in mW/m² per basic count @@ -38,6 +40,20 @@ static constexpr float PHOTON_ENERGIES[NUM_USEFUL_CHANNELS] = { 4.9048E-19f, 4.67399E-19f, 4.41432E-19f, 4.18199E-19f, 3.85718E-19f, 3.57918E-19f, 3.61172E-19f, 3.31074E-19f, 3.10382E-19f, 2.87891E-19f, 2.66637E-19f, 2.32333E-19f, 2.76664E-19f}; +static constexpr float CHANNEL_CONTRIBUTION[NUM_USEFUL_CHANNELS] = {0.069385773, + 0.04848841, + 0.114486525, + 0.059160501, + 0.072754014, + 0.168776203, + 0.059608686, + 0.124894391, + 0.073180307, + 0.074665125, + 0.075439565, + 0.059160501, + 0}; + // constexpr std::array fill_photon_energy() { // std::array v{0}; // for(int i = 0; i < NUM_USEFUL_CHANNELS; ++i) { @@ -154,41 +170,45 @@ void AS7343Component::update() { this->irradiance_->publish_state(irradiance); } + // for (uint8_t i = 0; i < NUM_USEFUL_CHANNELS; i++) { + // this->channel_readings_[CHANNEL_IDX[1]] /= CHANNEL_SENS[i] * 65535; + // } + if (this->f1_ != nullptr) { - this->f1_->publish_state(this->channel_readings_[AS7343_CHANNEL_405_F1]); + this->f1_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_405_F1]); } if (this->f2_ != nullptr) { - this->f2_->publish_state(this->channel_readings_[AS7343_CHANNEL_425_F2]); + this->f2_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_425_F2]); } if (this->fz_ != nullptr) { - this->fz_->publish_state(this->channel_readings_[AS7343_CHANNEL_450_FZ]); + this->fz_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_450_FZ]); } if (this->f3_ != nullptr) { - this->f3_->publish_state(this->channel_readings_[AS7343_CHANNEL_475_F3]); + this->f3_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_475_F3]); } if (this->f4_ != nullptr) { - this->f4_->publish_state(this->channel_readings_[AS7343_CHANNEL_515_F4]); + this->f4_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_515_F4]); } if (this->fy_ != nullptr) { - this->fy_->publish_state(this->channel_readings_[AS7343_CHANNEL_555_FY]); + this->fy_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_555_FY]); } if (this->f5_ != nullptr) { - this->f5_->publish_state(this->channel_readings_[AS7343_CHANNEL_550_F5]); + this->f5_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_550_F5]); } if (this->fxl_ != nullptr) { - this->fxl_->publish_state(this->channel_readings_[AS7343_CHANNEL_600_FXL]); + this->fxl_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_600_FXL]); } if (this->f6_ != nullptr) { - this->f6_->publish_state(this->channel_readings_[AS7343_CHANNEL_640_F6]); + this->f6_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_640_F6]); } if (this->f7_ != nullptr) { - this->f7_->publish_state(this->channel_readings_[AS7343_CHANNEL_690_F7]); + this->f7_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_690_F7]); } if (this->f8_ != nullptr) { - this->f8_->publish_state(this->channel_readings_[AS7343_CHANNEL_745_F8]); + this->f8_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_745_F8]); } if (this->nir_ != nullptr) { - this->nir_->publish_state(this->channel_readings_[AS7343_CHANNEL_855_NIR]); + this->nir_->publish_state(this->channel_basic_readings_[AS7343_CHANNEL_855_NIR]); } if (this->clear_ != nullptr) { float clear = (this->channel_readings_[AS7343_CHANNEL_CLEAR] + this->channel_readings_[AS7343_CHANNEL_CLEAR_0] + @@ -235,7 +255,7 @@ bool AS7343Component::setup_astep(uint16_t astep) { } static const float OFFSETS[NUM_USEFUL_CHANNELS] = {0.000281, 0.000281, 0.000281, 0.000281, 0.000281, 0.000281, - 0.000281, 0.000281, 0.000422, 0.000281, 0.000422, 0.000281}; + 0.000281, 0.000281, 0.000422, 0.000281, 0.000422, 0.000281}; float AS7343Component::calculate_ppfd(float tint_ms, float gain_x, AS7343Gain gain) { float par = 0; @@ -246,6 +266,7 @@ float AS7343Component::calculate_ppfd(float tint_ms, float gain_x, AS7343Gain ga float basic_count = this->channel_readings_[CHANNEL_IDX[i]] / (gain_x * tint_ms); bc[i] = basic_count * AS7343_GAIN_CORRECTION[(uint8_t) gain][i]; bcc[i] = basic_count / CHANNEL_SENS[i]; + this->channel_basic_readings_[i] = bcc[i]; if (CHANNEL_NM[i] < 400 || CHANNEL_NM[i] > 700) { continue; } @@ -254,23 +275,25 @@ float AS7343Component::calculate_ppfd(float tint_ms, float gain_x, AS7343Gain ga // https://www.berthold.com/en/bioanalytic/knowledge/faq/irradiance-to-photon-flux/ float photon_flux = watts * CHANNEL_NM[i] * 0.836e-2; - + photon_flux *= CHANNEL_CONTRIBUTION[i]; par += photon_flux; } - ESP_LOGD(TAG, ",basic counts, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f", bc[0], bc[1], bc[2], bc[3], bc[4], + ESP_LOGD(TAG, ",basic_counts, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f", bc[0], bc[1], bc[2], bc[3], bc[4], bc[5], bc[6], bc[7], bc[8], bc[9], bc[10], bc[11]); - ESP_LOGD(TAG, ",basic counts sens corrected, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f", bcc[0], bcc[1], bcc[2], + ESP_LOGD(TAG, ",basic_counts_sens_corrected, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f", bcc[0], bcc[1], bcc[2], bcc[3], bcc[4], bcc[5], bcc[6], bcc[7], bcc[8], bcc[9], bcc[10], bcc[11]); return par; } void AS7343Component::calculate_irradiance(float tint_ms, float gain_x, float &irradiance, float &lux, AS7343Gain gain) { + float irr_band; for (uint8_t i = 0; i < NUM_USEFUL_CHANNELS; i++) { float basic_count = this->channel_readings_[CHANNEL_IDX[i]] / (gain_x * tint_ms); basic_count *= AS7343_GAIN_CORRECTION[(uint8_t) gain][i]; - irradiance += (basic_count - OFFSETS[i]) * CHANNEL_IRRAD_MW_PER_BASIC_COUNT[i] / 1000; + irr_band = (basic_count - OFFSETS[i]) * CHANNEL_IRRAD_MW_PER_BASIC_COUNT[i] / 1000; + irradiance += irr_band * CHANNEL_CONTRIBUTION[i]; } lux = irradiance / 0.0079; } @@ -279,6 +302,21 @@ bool AS7343Component::read_channels(uint16_t *data) { this->enable_spectral_measurement(true); 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, + status.asat); + this->reg((uint8_t) AS7343Registers::STATUS) = status.raw; + + AS7343RegAStatus astatus{0}; + astatus.raw = this->reg((uint8_t) AS7343Registers::ASTATUS).get(); + ESP_LOGD(TAG, "AStatus 0x%02x, again_status %d, asat_status %d", astatus.raw, astatus.again_status, + astatus.asat_status); + + if (astatus.asat_status) { + ESP_LOGW(TAG, "AS7343 affected by analog or digital saturation. Readings are not reliable."); + } + return this->read_bytes_16((uint8_t) AS7343Registers::DATA_O, this->channel_readings_, AS7343_NUM_CHANNELS); } @@ -294,7 +332,16 @@ bool AS7343Component::wait_for_data(uint16_t timeout) { return false; } -bool AS7343Component::is_data_ready() { return this->read_register_bit((uint8_t) AS7343Registers::STATUS2, 6); } +bool AS7343Component::is_data_ready() { + AS7343RegStatus2 status2{0}; + status2.raw = this->reg((uint8_t) AS7343Registers::STATUS2).get(); + ESP_LOGD(TAG, "Status2 0x%02x, avalid %d, asat_digital %d, asat_analog %d", status2.raw, status2.avalid, + status2.asat_digital, status2.asat_analog); + this->reg((uint8_t) AS7343Registers::STATUS2) = status2.raw; + + // return this->read_register_bit((uint8_t) AS7343Registers::STATUS2, 6); + return status2.avalid; +} void AS7343Component::set_bank_for_reg_(AS7343Registers reg) { bool bank = (uint8_t) reg < 0x80; diff --git a/esphome/components/as7343/as7343.h b/esphome/components/as7343/as7343.h index ba9051a816..a439a86b7b 100644 --- a/esphome/components/as7343/as7343.h +++ b/esphome/components/as7343/as7343.h @@ -140,10 +140,24 @@ class AS7343Component : public PollingComponent, public i2c::I2CDevice { sensor::Sensor *illuminance_{nullptr}; sensor::Sensor *irradiance_{nullptr}; + sensor::Sensor *bf1_{nullptr}; + sensor::Sensor *bf2_{nullptr}; + sensor::Sensor *bfz_{nullptr}; + sensor::Sensor *bf3_{nullptr}; + sensor::Sensor *bf4_{nullptr}; + sensor::Sensor *bfy_{nullptr}; + sensor::Sensor *bf5_{nullptr}; + sensor::Sensor *bfxl_{nullptr}; + sensor::Sensor *bf6_{nullptr}; + sensor::Sensor *bf7_{nullptr}; + sensor::Sensor *bf8_{nullptr}; + sensor::Sensor *bnir_{nullptr}; + uint16_t astep_; AS7343Gain gain_; uint8_t atime_; uint16_t channel_readings_[AS7343_NUM_CHANNELS]; + float channel_basic_readings_[AS7343_NUM_CHANNELS]; }; } // namespace as7343 diff --git a/esphome/components/as7343/as7343_registers.h b/esphome/components/as7343/as7343_registers.h index 45f2b00174..c2d66565ab 100644 --- a/esphome/components/as7343/as7343_registers.h +++ b/esphome/components/as7343/as7343_registers.h @@ -55,15 +55,6 @@ static constexpr uint8_t AS7343_ENABLE_PON_BIT = 0; static constexpr uint8_t AS7343_ENABLE_SP_EN_BIT = 1; static constexpr uint8_t AS7343_CFG0_REG_BANK_BIT = 4; -union AS7343RegCfg20 { - uint8_t raw; - struct { - uint8_t reserved : 5; - uint8_t auto_smux : 2; - uint8_t fd_fifo_8b : 1; - }; -}; - enum AS7343Gain : uint8_t { AS7343_GAIN_0_5X, AS7343_GAIN_1X, @@ -103,5 +94,51 @@ enum AS7343Channel : uint8_t { static constexpr uint8_t AS7343_NUM_CHANNELS = 18; +union AS7343RegCfg20 { + uint8_t raw; + struct { + uint8_t reserved : 5; + uint8_t auto_smux : 2; + uint8_t fd_fifo_8b : 1; + } __attribute__((packed)); +}; + +union AS7343RegStatus { + uint8_t raw; + struct { + uint8_t sint : 1; + uint8_t reserved_1 : 1; + uint8_t fint : 1; + uint8_t aint : 1; + uint8_t reserved_4_6 : 3; + uint8_t asat : 1; + } __attribute__((packed)); +}; + +union AS7343RegStatus2 { + uint8_t raw; + struct { + uint8_t fdsat_digital : 1; + uint8_t fdsat_analog : 1; + uint8_t reserved_2 : 1; + uint8_t asat_analog : 1; + uint8_t asat_digital : 1; + uint8_t reserved_5 : 1; + uint8_t avalid : 1; + uint8_t reserved_7 : 1; + } __attribute__((packed)); +}; + +union AS7343RegAStatus { + uint8_t raw; + struct { + AS7343Gain again_status : 4; + uint8_t reserved_4_6 : 3; + uint8_t asat_status : 1; + + } __attribute__((packed)); +}; + + } // namespace as7343 } // namespace esphome diff --git a/esphome/components/as7343/sensor.py b/esphome/components/as7343/sensor.py index 7201559d16..2547ce6427 100644 --- a/esphome/components/as7343/sensor.py +++ b/esphome/components/as7343/sensor.py @@ -39,6 +39,8 @@ CONF_F8 = "f8" CONF_NIR = "nir" CONF_CLEAR = "clear" CONF_IRRADIANCE = "irradiance" +CONF_DIGITAL_SATURATION = "digital_saturation" +CONF_ANALOG_SATURATION = "analog_saturation" UNIT_COUNTS = "#" UNIT_IRRADIANCE = "W/m²" @@ -65,7 +67,7 @@ SENSOR_SCHEMA = cv.maybe_simple_value( sensor.sensor_schema( unit_of_measurement=UNIT_COUNTS, icon=ICON_BRIGHTNESS_5, - accuracy_decimals=0, + accuracy_decimals=4, device_class=DEVICE_CLASS_ILLUMINANCE, state_class=STATE_CLASS_MEASUREMENT, ),