diff --git a/esphome/components/as734x/as734x.cpp b/esphome/components/as734x/as734x.cpp index 2331d89c5fe..5337b3918eb 100644 --- a/esphome/components/as734x/as734x.cpp +++ b/esphome/components/as734x/as734x.cpp @@ -1,10 +1,12 @@ #include "as734x.h" +#include "color_helpers.h" #include "esphome/core/application.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" #include "esphome/core/progmem.h" #include +#include namespace esphome::as734x { @@ -78,6 +80,41 @@ static_assert(sizeof(AS7341_WAVELENGTHS) == NUM_BANDS * sizeof(uint16_t)); static const float AS7341_GAIN_CORRECTION[] PROGMEM = {1.0577f, 1.0491f, 1.0479f, 1.0491f, 1.0207f, 1.0158f, 1.0109f, 1.0000f, 1.0003f, 0.9873f, 0.9593f, 0.0f, 0.0f}; static_assert(sizeof(AS7341_GAIN_CORRECTION) == GAIN_COUNT * sizeof(float)); +// clang-format off +// The three bands this chip does not have contribute nothing to the weighted sums. +static const ChannelContribution AS7341_CONTRIBUTIONS[] PROGMEM = { + {0.005261294f, 5.936230324f, 0.020518273f}, // F1 + {0.242615252f, 3.572528495f, 0.013525490f}, // F2 + {0.0f, 0.0f, 0.0f}, // FZ, absent + {0.174482552f, 2.914113437f, 0.011585145f}, // F3 + {1.479499075f, 2.452851227f, 0.010604986f}, // F4 + {0.0f, 0.0f, 0.0f}, // FY, absent + {1.906818555f, 1.940656433f, 0.008890531f}, // F5 + {0.0f, 0.0f, 0.0f}, // FXL, absent + {1.162058142f, 1.533976606f, 0.007441544f}, // F6 + {0.462374845f, 1.819838250f, 0.009393590f}, // F7 + {-0.017794572f, 1.232942274f, 0.006890812f}, // F8 + {-0.260730901f, -1.102368000f, -0.004647911f}, // NIR + {-0.022604075f, -0.033304813f, -0.000129106f}, // Clear +}; +static const ChannelTristimulus AS7341_TRISTIMULUS[] PROGMEM = { + {0.39814f, 0.01396f, 1.95010f}, // F1 + {1.29540f, 0.16748f, 6.45490f}, // F2 + {0.0f, 0.0f, 0.0f}, // FZ, absent + {0.36956f, 0.23538f, 2.78010f}, // F3 + {0.10902f, 1.42750f, 0.18501f}, // F4 + {0.0f, 0.0f, 0.0f}, // FY, absent + {0.71942f, 1.88670f, 0.15325f}, // F5 + {0.0f, 0.0f, 0.0f}, // FXL, absent + {1.78180f, 1.14200f, 0.09539f}, // F6 + {1.10110f, 0.46497f, 0.10563f}, // F7 + {-0.03991f, -0.02702f, 0.08866f}, // F8 + {-0.27597f, -0.24468f, -0.61140f}, // NIR + {-0.02347f, -0.01993f, -0.00938f}, // Clear +}; +// clang-format on +static_assert(sizeof(AS7341_CONTRIBUTIONS) == NUM_BANDS * sizeof(ChannelContribution)); +static_assert(sizeof(AS7341_TRISTIMULUS) == NUM_BANDS * sizeof(ChannelTristimulus)); const ChipInfo AS7341_CHIP PROGMEM = { .name = AS7341_NAME, .init = AS7341_INIT, @@ -85,6 +122,8 @@ const ChipInfo AS7341_CHIP PROGMEM = { .readout = AS7341_READOUT, .wavelengths = AS7341_WAVELENGTHS, .gain_correction = AS7341_GAIN_CORRECTION, + .contributions = AS7341_CONTRIBUTIONS, + .tristimulus = AS7341_TRISTIMULUS, .init_count = 1, .astep_reg = 0xCA, .cfg0_reg = 0xA9, @@ -147,6 +186,40 @@ static const float AS7343_GAIN_CORRECTION[] PROGMEM = { }; // clang-format on static_assert(sizeof(AS7343_GAIN_CORRECTION) == GAIN_COUNT * NUM_BANDS * sizeof(float)); +// clang-format off +static const ChannelContribution AS7343_CONTRIBUTIONS[] PROGMEM = { + {-0.028559089f, 0.450293995f, 0.001266925f}, // F1 + {-0.042150948f, 3.566379984f, 0.012515925f}, // F2 + {0.000661721f, 2.877424672f, 0.010243005f}, // FZ + {-0.108791278f, 2.273837581f, 0.009376157f}, // F3 + {-0.167172180f, 1.519298503f, 0.006017556f}, // F4 + {5.726660294f, 4.199345859f, 0.019357905f}, // FY + {0.0f, 0.0f, 0.0f}, // F5 + {-0.241492014f, 1.185259160f, 0.006516325f}, // FXL + {-0.047665296f, 1.759469826f, 0.009780714f}, // F6 + {-0.012516990f, 1.702006611f, 0.009950228f}, // F7 + {-0.026424974f, -1.059196137f, -0.005425656f}, // F8 + {-0.007565221f, -0.064827881f, -0.000232267f}, // NIR + {0.0f, 0.0f, 0.0f}, // Clear +}; +static const ChannelTristimulus AS7343_TRISTIMULUS[] PROGMEM = { + {-0.07879f, -0.03269f, -0.31295f}, // F1 + {-0.12235f, -0.01297f, -0.57885f}, // F2 + {1.99879f, -0.04011f, 10.00197f}, // FZ + {-0.33364f, -0.06889f, -0.31281f}, // F3 + {-0.06795f, -0.17453f, -0.19657f}, // F4 + {-0.45419f, 5.69083f, -0.11077f}, // FY + {0.0f, 0.0f, 0.0f}, // F5 + {5.27242f, -0.22956f, -0.06132f}, // FXL + {-0.05072f, -0.04762f, -0.03536f}, // F6 + {-0.04666f, -0.01295f, -0.06025f}, // F7 + {-0.03931f, -0.02797f, -0.12174f}, // F8 + {0.0f, 0.0f, 0.0f}, // NIR + {0.0f, 0.0f, 0.0f}, // Clear +}; +// clang-format on +static_assert(sizeof(AS7343_CONTRIBUTIONS) == NUM_BANDS * sizeof(ChannelContribution)); +static_assert(sizeof(AS7343_TRISTIMULUS) == NUM_BANDS * sizeof(ChannelTristimulus)); static constexpr ChipInfo as7343_chip(const char *name) { return { .name = name, @@ -155,6 +228,8 @@ static constexpr ChipInfo as7343_chip(const char *name) { .readout = AS7343_READOUT, .wavelengths = AS7343_WAVELENGTHS, .gain_correction = AS7343_GAIN_CORRECTION, + .contributions = AS7343_CONTRIBUTIONS, + .tristimulus = AS7343_TRISTIMULUS, .init_count = sizeof(AS7343_INIT) / sizeof(RegValue), .astep_reg = 0xD4, .cfg0_reg = 0xBF, @@ -272,6 +347,14 @@ void AS734XComponent::dump_config() { sensor::log_sensor(TAG, " ", label, this->basic_counts_sensors_[band]); } LOG_SENSOR(" ", "Saturation level", this->saturation_level_sensor_); + LOG_SENSOR(" ", "Illuminance", this->illuminance_sensor_); + LOG_SENSOR(" ", "Irradiance photopic", this->irradiance_photopic_sensor_); + LOG_SENSOR(" ", "Irradiance PAR", this->irradiance_par_sensor_); + LOG_SENSOR(" ", "PPFD", this->ppfd_sensor_); + LOG_SENSOR(" ", "Color temperature", this->color_temperature_sensor_); +#ifdef USE_AS734X_RGB + LOG_TEXT_SENSOR(" ", "RGB hex", this->rgb_hex_sensor_); +#endif if (this->is_failed()) { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); } @@ -484,6 +567,83 @@ void AS734XComponent::publish_basic_counts_() { } } +// Each band contributes a fixed amount per basic count to every integrated quantity, so the +// totals are a weighted sum over the bands. +// The weighted sums can go negative under light the tables were not fitted for, such as pure blue or +// far red, so the published values are floored at zero. +void AS734XComponent::publish_light_metrics_() { + float irradiance_photopic = 0.0f; + float irradiance_par = 0.0f; + float ppfd = 0.0f; + + const ChannelContribution *contributions = pgm(this->chip_->contributions); + for (uint8_t band = 0; band < NUM_BANDS; band++) { + const float basic_count = this->basic_counts_[band]; + const ChannelContribution contribution = pgm(contributions[band]); + + irradiance_photopic += contribution.irradiance_photopic * basic_count; + irradiance_par += contribution.irradiance_par * basic_count; + ppfd += contribution.ppfd * basic_count; + } + irradiance_photopic = std::max(irradiance_photopic, 0.0f); + irradiance_par = std::max(irradiance_par, 0.0f); + ppfd = std::max(ppfd, 0.0f) * 1e3f; + const float illuminance = irradiance_photopic * LUMENS_PER_WATT; + + ESP_LOGV(TAG, "Photopic irradiance %.4f, PAR %.4f, PPFD %.4f, illuminance %.2f lx", irradiance_photopic, + irradiance_par, ppfd, illuminance); + if (this->illuminance_sensor_ != nullptr) { + this->illuminance_sensor_->publish_state(illuminance); + } + if (this->irradiance_photopic_sensor_ != nullptr) { + this->irradiance_photopic_sensor_->publish_state(irradiance_photopic); + } + if (this->irradiance_par_sensor_ != nullptr) { + this->irradiance_par_sensor_->publish_state(irradiance_par); + } + if (this->ppfd_sensor_ != nullptr) { + this->ppfd_sensor_->publish_state(ppfd); + } +} + +void AS734XComponent::publish_color_() { + float tri_x = 0.0f; + float tri_y = 0.0f; + float tri_z = 0.0f; + + const ChannelTristimulus *table = pgm(this->chip_->tristimulus); + for (uint8_t band = 0; band < NUM_BANDS; band++) { + const float basic_count = this->basic_counts_[band]; + const ChannelTristimulus tristimulus = pgm(table[band]); + + tri_x += tristimulus.x * basic_count; + tri_y += tristimulus.y * basic_count; + tri_z += tristimulus.z * basic_count; + } + + const float color_temperature = tristimulus_to_cct(tri_x, tri_y, tri_z); + ESP_LOGV(TAG, "XYZ %.4f, %.4f, %.4f -> CCT %.0f K", tri_x, tri_y, tri_z, color_temperature); + if (this->color_temperature_sensor_ != nullptr) { + this->color_temperature_sensor_->publish_state(color_temperature); + } + +#ifdef USE_AS734X_RGB + if (this->rgb_hex_sensor_ == nullptr) { + return; + } + // Convert to chromaticity first, so the colour describes the hue rather than the brightness. + // Absolute tristimulus values clamp to white under anything but dim light. + char rgb_hex[7] = "000000"; // no usable chromaticity reads as black rather than an empty string + const float sum = tri_x + tri_y + tri_z; + if (sum > MIN_TRISTIMULUS_SUM) { + uint8_t rgb[3]; + tristimulus_to_rgb(tri_x / sum, tri_y / sum, tri_z / sum, rgb[0], rgb[1], rgb[2]); + format_hex_to(rgb_hex, rgb, sizeof(rgb)); + } + this->rgb_hex_sensor_->publish_state(rgb_hex); +#endif +} + void AS734XComponent::publish_measurement_() { this->calculate_basic_counts_(); for (uint8_t band = 0; band < NUM_BANDS; band++) { @@ -492,6 +652,8 @@ void AS734XComponent::publish_measurement_() { } } this->publish_basic_counts_(); + this->publish_light_metrics_(); + this->publish_color_(); if (this->saturation_level_sensor_ != nullptr) { const uint32_t max_adc = std::min((this->reading_atime_ + 1UL) * (this->reading_astep_ + 1UL), MAX_ADC_COUNT); diff --git a/esphome/components/as734x/as734x.h b/esphome/components/as734x/as734x.h index f2b68d380ec..95c694da9ab 100644 --- a/esphome/components/as734x/as734x.h +++ b/esphome/components/as734x/as734x.h @@ -7,6 +7,9 @@ #include "esphome/core/hal.h" #include "esphome/components/i2c/i2c.h" #include "esphome/components/sensor/sensor.h" +#ifdef USE_AS734X_RGB +#include "esphome/components/text_sensor/text_sensor.h" +#endif namespace esphome::as734x { @@ -47,6 +50,24 @@ static constexpr uint16_t VISIBLE_MAX_NM = 700; static constexpr uint16_t WIDEBAND_NM = 0; static constexpr uint16_t ABSENT_NM = 0xFFFF; // band this chip does not have +// Luminous efficacy at 555 nm, for turning photopic irradiance into lux. +static constexpr float LUMENS_PER_WATT = 683.002f; + +// How much one basic count of a band contributes to each integrated quantity. The factors come +// from the manufacturer's golden-device calibration, convolved for a reconstructed spectrum. +struct ChannelContribution { + float irradiance_photopic; // weighted by the CIE 1931 V(lambda) curve + float irradiance_par; // 400-700 nm only + float ppfd; // 400-700 nm only, scaled by 1e3 before publishing +}; + +// CIE 1931 tristimulus contribution of one basic count of a band. +struct ChannelTristimulus { + float x; + float y; + float z; +}; + struct RegValue { uint8_t reg; uint8_t value; @@ -55,11 +76,13 @@ struct RegValue { /// Per-chip constants, stored in flash. The pointed-to tables are in flash too. struct ChipInfo { const char *name; - const RegValue *init; // written in order; the bank is selected per register address - const uint8_t *smux; // AS7341: SMUX RAM image per step; AS7343: the three chain images - const uint8_t *readout; // per step, the ADC slot of each band (0xFF: not read in this step) - const uint16_t *wavelengths; // per band, WIDEBAND_NM for clear and ABSENT_NM for a missing band - const float *gain_correction; // GAIN_COUNT entries, or GAIN_COUNT * NUM_BANDS when per band + const RegValue *init; // written in order; the bank is selected per register address + const uint8_t *smux; // AS7341: SMUX RAM image per step; AS7343: the three chain images + const uint8_t *readout; // per step, the ADC slot of each band (0xFF: not read in this step) + const uint16_t *wavelengths; // per band, WIDEBAND_NM for clear and ABSENT_NM for a missing band + const float *gain_correction; // GAIN_COUNT entries, or GAIN_COUNT * NUM_BANDS when per band + const ChannelContribution *contributions; // per band + const ChannelTristimulus *tristimulus; // per band uint8_t init_count; uint8_t astep_reg; uint8_t cfg0_reg; @@ -117,6 +140,15 @@ class AS734XComponent : public PollingComponent, public i2c::I2CDevice { void set_basic_counts_sensor(sensor::Sensor *sensor, uint8_t band) { this->basic_counts_sensors_[band] = sensor; } SUB_SENSOR(saturation_level) + SUB_SENSOR(illuminance) + SUB_SENSOR(irradiance_photopic) + SUB_SENSOR(irradiance_par) + SUB_SENSOR(ppfd) + SUB_SENSOR(color_temperature) + +#ifdef USE_AS734X_RGB + void set_rgb_hex_sensor(text_sensor::TextSensor *sensor) { this->rgb_hex_sensor_ = sensor; } +#endif protected: bool select_bank_(uint8_t reg); @@ -126,6 +158,8 @@ class AS734XComponent : public PollingComponent, public i2c::I2CDevice { void read_step_(); void abort_measurement_(const LogString *reason); void calculate_basic_counts_(); + void publish_light_metrics_(); + void publish_color_(); void publish_measurement_(); void publish_basic_counts_(); float normalization_divisor_() const; @@ -157,6 +191,9 @@ class AS734XComponent : public PollingComponent, public i2c::I2CDevice { uint8_t atime_{0}; uint8_t step_{0}; bool bank_low_{true}; // unknown until setup() writes CFG0 +#ifdef USE_AS734X_RGB + text_sensor::TextSensor *rgb_hex_sensor_{nullptr}; +#endif }; } // namespace esphome::as734x diff --git a/esphome/components/as734x/color_helpers.cpp b/esphome/components/as734x/color_helpers.cpp new file mode 100644 index 00000000000..b456038eda7 --- /dev/null +++ b/esphome/components/as734x/color_helpers.cpp @@ -0,0 +1,63 @@ +#include "color_helpers.h" + +#include +#include + +namespace esphome::as734x { + +namespace { + +// Range McCamy's approximation is meaningful over. +constexpr float CCT_MIN_K = 1000.0f; +constexpr float CCT_MAX_K = 25000.0f; + +#ifdef USE_AS734X_RGB +// sRGB transfer function. +float gamma_correct(float channel) { + if (channel <= 0.0031308f) { + return 12.92f * channel; + } + return 1.055f * std::pow(channel, 1.0f / 2.4f) - 0.055f; +} + +uint8_t to_byte(float channel) { return static_cast(std::clamp(channel, 0.0f, 1.0f) * 255.0f); } +#endif + +} // namespace + +float tristimulus_to_cct(float x, float y, float z) { + const float sum = x + y + z; + // The conversion matrices carry negative coefficients, so a spectrum unlike the one they were + // calibrated against can drive the sum to zero or below. Chromaticity is undefined there, and + // McCamy's formula would still return a plausible looking number from it. + if (sum <= MIN_TRISTIMULUS_SUM) { + return NAN; + } + const float chroma_x = x / sum; + const float chroma_y = y / sum; + + // McCamy's approximation: cct = 437 n^3 + 3601 n^2 + 6861 n + 5517. The pole at + // chroma_y = 0.1858 sends the cubic off to either infinity, and it stays meaningless well + // either side of that, so the answer is only reported where the approximation holds. + const float denominator = 0.1858f - chroma_y; + if (std::abs(denominator) < 1e-4f) { + return NAN; + } + const float n = (chroma_x - 0.3320f) / denominator; + const float cct = ((437.0f * n + 3601.0f) * n + 6861.0f) * n + 5517.0f; + return (cct >= CCT_MIN_K && cct <= CCT_MAX_K) ? cct : NAN; +} + +#ifdef USE_AS734X_RGB +void tristimulus_to_rgb(float x, float y, float z, uint8_t &r, uint8_t &g, uint8_t &b) { + const float r_linear = 3.2406f * x - 1.5372f * y - 0.4986f * z; + const float g_linear = -0.9689f * x + 1.8758f * y + 0.0415f * z; + const float b_linear = 0.0557f * x - 0.2040f * y + 1.0570f * z; + + r = to_byte(gamma_correct(r_linear)); + g = to_byte(gamma_correct(g_linear)); + b = to_byte(gamma_correct(b_linear)); +} +#endif + +} // namespace esphome::as734x diff --git a/esphome/components/as734x/color_helpers.h b/esphome/components/as734x/color_helpers.h new file mode 100644 index 00000000000..1bf382c4bc6 --- /dev/null +++ b/esphome/components/as734x/color_helpers.h @@ -0,0 +1,22 @@ +#pragma once +#include + +#include "esphome/core/defines.h" + +namespace esphome::as734x { + +// Smallest tristimulus sum that still carries a usable hue. +constexpr float MIN_TRISTIMULUS_SUM = 0.001f; + +// Correlated colour temperature in kelvin from CIE 1931 tristimulus values, using McCamy's +// approximation. Returns NAN when the input carries no usable hue, or when the result falls +// outside the range the approximation holds over. +float tristimulus_to_cct(float x, float y, float z); + +#ifdef USE_AS734X_RGB +// sRGB components for CIE 1931 tristimulus values. Pass chromaticity (x + y + z == 1) rather than +// absolute values, otherwise anything but dim light clamps to white. +void tristimulus_to_rgb(float x, float y, float z, uint8_t &r, uint8_t &g, uint8_t &b); +#endif + +} // namespace esphome::as734x diff --git a/esphome/components/as734x/sensor.py b/esphome/components/as734x/sensor.py index 726d15d6fff..85fa6635320 100644 --- a/esphome/components/as734x/sensor.py +++ b/esphome/components/as734x/sensor.py @@ -2,7 +2,18 @@ import esphome.codegen as cg from esphome.components import sensor from esphome.components.const import UNIT_COUNTS import esphome.config_validation as cv -from esphome.const import CONF_COUNTS, CONF_TYPE, STATE_CLASS_MEASUREMENT, UNIT_PERCENT +from esphome.const import ( + CONF_COLOR_TEMPERATURE, + CONF_COUNTS, + CONF_ILLUMINANCE, + CONF_TYPE, + DEVICE_CLASS_ILLUMINANCE, + DEVICE_CLASS_IRRADIANCE, + STATE_CLASS_MEASUREMENT, + UNIT_KELVIN, + UNIT_LUX, + UNIT_PERCENT, +) import esphome.final_validate as fv from esphome.types import ConfigType @@ -11,10 +22,21 @@ from . import BANDS_41, BANDS_43, CONF_AS734X_ID, DOMAIN, AS734XComponent DEPENDENCIES = [DOMAIN] CONF_BASIC_COUNTS = "basic_counts" +CONF_IRRADIANCE_PAR = "irradiance_par" +CONF_IRRADIANCE_PHOTOPIC = "irradiance_photopic" +CONF_PPFD = "ppfd" CONF_SATURATION_LEVEL = "saturation_level" +UNIT_IRRADIANCE = "W/m\u00b2" +UNIT_PPFD = "\u00b5mol/m\u00b2/s" + ICON_COUNTS = "mdi:counter" ICON_SATURATION = "mdi:weather-sunny-alert" +ICON_ILLUMINANCE = "mdi:weather-sunny" +ICON_IRRADIANCE_PHOTOPIC = "mdi:sun-wireless-outline" +ICON_PAR = "mdi:sprout" +ICON_PPFD = "mdi:sprout-outline" +ICON_COLOR_TEMPERATURE = "mdi:sun-thermometer-outline" _COUNTS_SENSOR = sensor.sensor_schema( unit_of_measurement=UNIT_COUNTS, @@ -48,6 +70,39 @@ CONFIG_SCHEMA = cv.Schema( accuracy_decimals=0, state_class=STATE_CLASS_MEASUREMENT, ), + cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema( + unit_of_measurement=UNIT_LUX, + icon=ICON_ILLUMINANCE, + accuracy_decimals=0, + device_class=DEVICE_CLASS_ILLUMINANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_IRRADIANCE_PHOTOPIC): sensor.sensor_schema( + unit_of_measurement=UNIT_IRRADIANCE, + icon=ICON_IRRADIANCE_PHOTOPIC, + accuracy_decimals=3, + device_class=DEVICE_CLASS_IRRADIANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_IRRADIANCE_PAR): sensor.sensor_schema( + unit_of_measurement=UNIT_IRRADIANCE, + icon=ICON_PAR, + accuracy_decimals=3, + device_class=DEVICE_CLASS_IRRADIANCE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_PPFD): sensor.sensor_schema( + unit_of_measurement=UNIT_PPFD, + icon=ICON_PPFD, + accuracy_decimals=3, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_COLOR_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_KELVIN, + icon=ICON_COLOR_TEMPERATURE, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + ), } ) @@ -82,3 +137,8 @@ async def to_code(config: ConfigType) -> None: sensors = sensor.sub_sensors(config) await sensors(CONF_SATURATION_LEVEL, hub.set_saturation_level_sensor) + await sensors(CONF_ILLUMINANCE, hub.set_illuminance_sensor) + await sensors(CONF_IRRADIANCE_PHOTOPIC, hub.set_irradiance_photopic_sensor) + await sensors(CONF_IRRADIANCE_PAR, hub.set_irradiance_par_sensor) + await sensors(CONF_PPFD, hub.set_ppfd_sensor) + await sensors(CONF_COLOR_TEMPERATURE, hub.set_color_temperature_sensor) diff --git a/esphome/components/as734x/text_sensor.py b/esphome/components/as734x/text_sensor.py new file mode 100644 index 00000000000..d010f2d6a42 --- /dev/null +++ b/esphome/components/as734x/text_sensor.py @@ -0,0 +1,28 @@ +import esphome.codegen as cg +from esphome.components import text_sensor +import esphome.config_validation as cv +from esphome.types import ConfigType + +from . import CONF_AS734X_ID, DOMAIN, AS734XComponent + +DEPENDENCIES = [DOMAIN] + +CONF_RGB_HEX = "rgb_hex" + +ICON_PALETTE = "mdi:palette" + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_AS734X_ID): cv.use_id(AS734XComponent), + cv.Optional(CONF_RGB_HEX): text_sensor.text_sensor_schema(icon=ICON_PALETTE), + } +) + + +async def to_code(config: ConfigType) -> None: + if (conf := config.get(CONF_RGB_HEX)) is None: + return + hub = await cg.get_variable(config[CONF_AS734X_ID]) + cg.add_define("USE_AS734X_RGB") + sens = await text_sensor.new_text_sensor(conf) + cg.add(hub.set_rgb_hex_sensor(sens)) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 607bc7a42b4..c901ff3e844 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -45,6 +45,7 @@ #define USE_AREAS #define USE_AS7341 #define USE_AS7343 +#define USE_AS734X_RGB #define USE_BINARY_SENSOR #define USE_BINARY_SENSOR_CLICK_TRIGGER #define USE_BINARY_SENSOR_FILTER diff --git a/tests/components/as734x/common.yaml b/tests/components/as734x/common.yaml index 0ad83bac4dc..48f77ac907e 100644 --- a/tests/components/as734x/common.yaml +++ b/tests/components/as734x/common.yaml @@ -42,6 +42,16 @@ sensor: name: AS7341 Clear basic saturation_level: name: AS7341 Saturation + illuminance: + name: AS7341 Illuminance + irradiance_photopic: + name: AS7341 Photopic irradiance + irradiance_par: + name: AS7341 PAR + ppfd: + name: AS7341 PPFD + color_temperature: + name: AS7341 Colour temperature - platform: as734x as734x_id: as7343_hub counts: @@ -58,6 +68,10 @@ sensor: name: AS7343 FY basic saturation_level: name: AS7343 Saturation + illuminance: + name: AS7343 Illuminance + color_temperature: + name: AS7343 Colour temperature - platform: as734x as734x_id: tcs3448_hub counts: @@ -65,3 +79,9 @@ sensor: name: TCS3448 F1 fy: name: TCS3448 FY + +text_sensor: + - platform: as734x + as734x_id: as7343_hub + rgb_hex: + name: AS7343 RGB