8static const char *
const TAG =
"veml7700";
9static const size_t VEML_REG_SIZE = 2;
11static float reduce_to_zero(
float a,
float b) {
return (a > b) ? (a - b) : 0; }
13template<
typename T,
size_t size> T
get_next(
const T (&array)[size],
const T
val) {
16 while (idx == -1 && i < size) {
17 if (array[i] ==
val) {
23 if (idx == -1 || i + 1 >= size)
28template<
typename T,
size_t size> T
get_prev(
const T (&array)[size],
const T
val) {
31 while (idx == -1 && i > 0) {
32 if (array[i] ==
val) {
38 if (idx == -1 || i == 0)
70static float get_gain_coeff(
Gain gain) {
71 static const float GAIN_FLOAT[
GAINS_COUNT] = {1.0f, 2.0f, 0.125f, 0.25f};
72 return GAIN_FLOAT[
gain & 0b11];
75static const char *get_gain_str(
Gain gain) {
76 static const char *gain_str[
GAINS_COUNT] = {
"1x",
"2x",
"1/8x",
"1/4x"};
77 return gain_str[
gain & 0b11];
81 ESP_LOGCONFIG(TAG,
"Running setup");
85 ESP_LOGW(TAG,
"Sensor configuration failed");
98 " Integration time: %d ms",
102 " Lux compensation: %s\n"
103 " Glass attenuation factor: %f",
105 LOG_UPDATE_INTERVAL(
this);
116 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
122 ESP_LOGV(TAG,
"Update: Initiating new data collection");
134 ESP_LOGV(TAG,
"Update: Component not ready yet");
149 switch (this->state_) {
170 [
this]() { this->state_ = State::READY_TO_APPLY_ADJUSTMENTS; });
188 [
this]() { this->state_ = State::COLLECTING_DATA; });
224 ESP_LOGV(TAG,
"Configure");
230 als_conf.ALS_GAIN = this->
gain_;
232 als_conf.ALS_SD =
true;
233 ESP_LOGV(TAG,
"Shutdown before config. ALS_CONF_0 to 0x%04X", als_conf.raw);
236 ESP_LOGW(TAG,
"Failed to shutdown, I2C error %d", err);
241 als_conf.ALS_SD =
false;
242 ESP_LOGV(TAG,
"Turning on. Setting ALS_CONF_0 to 0x%04X", als_conf.raw);
245 ESP_LOGW(TAG,
"Failed to turn on, I2C error %d", err);
252 ESP_LOGV(TAG,
"Setting PSM to 0x%04X", psm.raw);
255 ESP_LOGW(TAG,
"Failed to set PSM, I2C error %d", err);
263 ESP_LOGV(TAG,
"Reconfigure time and gain (%d ms, %s) %s", get_itime_ms(time), get_gain_str(
gain),
264 shutdown ?
"Shutting down" :
"Turning back on");
270 als_conf.ALS_SD = shutdown;
271 als_conf.ALS_INT_EN =
false;
273 als_conf.ALS_IT = time;
274 als_conf.ALS_GAIN =
gain;
277 ESP_LOGW(TAG,
"%s failed", shutdown ?
"Shutdown" :
"Turn on");
287 ESP_LOGW(TAG,
"Error reading ALS register, err = %d", als_err);
292 ESP_LOGW(TAG,
"Error reading WHITE register, err = %d", white_err);
299 ESP_LOGW(TAG,
"Error reading ALS_CONF_0 register, err = %d", white_err);
304 ESP_LOGV(TAG,
"Data from sensors: ALS = %d, WHITE = %d, Gain = %s, Time = %d ms", data.
als_counts, data.
white_counts,
306 return std::max(als_err, white_err);
319 static constexpr uint16_t LOW_INTENSITY_THRESHOLD = 100;
320 static constexpr uint16_t HIGH_INTENSITY_THRESHOLD = 10000;
327 if (data.
als_counts <= LOW_INTENSITY_THRESHOLD) {
338 }
else if (data.
als_counts >= HIGH_INTENSITY_THRESHOLD) {
357 static const float MAX_GAIN = 2.0f;
358 static const float MAX_ITIME_MS = 800.0f;
359 static const float MAX_LX_RESOLUTION = 0.0036f;
360 float lux_resolution = (MAX_ITIME_MS / (float) get_itime_ms(data.
actual_time)) *
361 (MAX_GAIN / get_gain_coeff(data.
actual_gain)) * MAX_LX_RESOLUTION;
362 ESP_LOGV(TAG,
"Lux resolution for (%d, %s) = %.4f ", get_itime_ms(data.
actual_time), get_gain_str(data.
actual_gain),
369 ESP_LOGV(TAG,
"%s mode - ALS = %.1f lx, WHITE = %.1f lx, FAKE_IR = %.1f lx",
377 auto &local_data = data;
385 auto compensate = [&local_data](
float &lux) {
386 auto calculate_high_lux_compensation = [](
float lux_veml) ->
float {
387 return (((6.0135e-13 * lux_veml - 9.3924e-9) * lux_veml + 8.1488e-5) * lux_veml + 1.0023) * lux_veml;
391 lux = calculate_high_lux_compensation(lux);
399 ESP_LOGV(TAG,
"Lux compensation - ALS = %.1f lx, WHITE = %.1f lx, FAKE_IR = %.1f lx", data.
als_lux, data.
white_lux,
407 ESP_LOGV(TAG,
"Glass attenuation - ALS = %.1f lx, WHITE = %.1f lx, FAKE_IR = %.1f lx", data.
als_lux, data.
white_lux,
virtual void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message="unspecified")
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.
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a specific register in the I²C device
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len, bool stop=true)
reads an array of bytes from a specific register in the I²C device
void publish_state(float state)
Publish a new state to the front-end.
void publish_data_part_1_(Readings &data)
bool lux_compensation_enabled_
float glass_attenuation_factor_
void dump_config() override
void publish_data_part_2_(Readings &data)
void publish_data_part_3_(Readings &data)
IntegrationTime integration_time_
sensor::Sensor * white_counts_sensor_
void apply_glass_attenuation_(Readings &data)
sensor::Sensor * ambient_light_counts_sensor_
sensor::Sensor * white_sensor_
bool are_adjustments_required_(Readings &data)
ErrorCode reconfigure_time_and_gain_(IntegrationTime time, Gain gain, bool shutdown)
sensor::Sensor * actual_integration_time_sensor_
@ READY_TO_PUBLISH_PART_1
@ INITIAL_SETUP_COMPLETED
@ READY_TO_PUBLISH_PART_3
@ READY_TO_PUBLISH_PART_2
@ READY_TO_APPLY_ADJUSTMENTS
void apply_lux_calculation_(Readings &data)
bool automatic_mode_enabled_
sensor::Sensor * actual_gain_sensor_
struct esphome::veml7700::VEML7700Component::Readings readings_
sensor::Sensor * fake_infrared_sensor_
void apply_lux_compensation_(Readings &data)
sensor::Sensor * ambient_light_sensor_
ErrorCode read_sensor_output_(Readings &data)
ErrorCode
Error codes returned by I2CBus and I2CDevice methods.
@ ERROR_OK
No error found during execution of method.
T get_prev(const T(&array)[size], const T val)
T get_next(const T(&array)[size], const T val)
const uint8_t INTEGRATION_TIMES_COUNT
const uint8_t GAINS_COUNT
Providing packet encoding functions for exchanging data with a remote host.
void IRAM_ATTR HOT delay(uint32_t ms)
IntegrationTime actual_time