11 static const char *
const TAG =
"ltr_als_ps";
13 static const uint8_t MAX_TRIES = 5;
15 template<
typename T,
size_t size> T
get_next(
const T (&array)[size],
const T
val) {
18 while (idx == -1 && i < size) {
19 if (array[i] == val) {
25 if (idx == -1 || i + 1 >= size)
30 template<
typename T,
size_t size> T
get_prev(
const T (&array)[size],
const T
val) {
33 while (idx == -1 && i > 0) {
34 if (array[i] == val) {
40 if (idx == -1 || i == 0)
46 static const uint16_t ALS_INT_TIME[8] = {100, 50, 200, 400, 150, 250, 300, 350};
47 return ALS_INT_TIME[time & 0b111];
51 static const uint16_t ALS_MEAS_RATE[8] = {50, 100, 200, 500, 1000, 2000, 2000, 2000};
52 return ALS_MEAS_RATE[rate & 0b111];
56 static const float ALS_GAIN[8] = {1, 2, 4, 8, 0, 0, 48, 96};
57 return ALS_GAIN[gain & 0b111];
60 static float get_ps_gain_coeff(
PsGain gain) {
61 static const float PS_GAIN[4] = {16, 0, 32, 64};
62 return PS_GAIN[gain & 0
b11];
66 ESP_LOGCONFIG(TAG,
"Setting up LTR-303/329/55x/659");
72 auto get_device_type = [](
LtrType typ) {
86 ESP_LOGCONFIG(TAG,
" Device type: %s", get_device_type(this->
ltr_type_));
89 ESP_LOGCONFIG(TAG,
" Gain: %.0fx", get_gain_coeff(this->
gain_));
90 ESP_LOGCONFIG(TAG,
" Integration time: %d ms", get_itime_ms(this->
integration_time_));
91 ESP_LOGCONFIG(TAG,
" Measurement repeat rate: %d ms", get_meas_time_ms(this->
repeat_rate_));
99 ESP_LOGCONFIG(TAG,
" Proximity gain: %.0fx", get_ps_gain_coeff(this->
ps_gain_));
105 LOG_UPDATE_INTERVAL(
this);
108 ESP_LOGE(TAG,
"Communication with I2C LTR-303/329/55x/659 failed!");
113 ESP_LOGV(TAG,
"Updating");
115 ESP_LOGV(TAG,
"Initiating new data collection");
127 ESP_LOGV(TAG,
"Component not ready yet");
133 static uint8_t tries{0};
135 switch (this->state_) {
137 err = this->
write(
nullptr, 0);
139 ESP_LOGV(TAG,
"i2c connection failed");
163 ESP_LOGV(TAG,
"Reading sensor data having gain = %.0fx, time = %d ms", get_gain_coeff(this->
als_readings_.
gain),
168 }
else if (tries >= MAX_TRIES) {
169 ESP_LOGW(TAG,
"Can't get data after several tries.");
184 ESP_LOGD(TAG,
"Reconfiguring sensitivity: gain = %.0fx, time = %d ms", get_gain_coeff(this->
als_readings_.
gain),
217 static uint32_t last_high_trigger_time{0};
218 static uint32_t last_low_trigger_time{0};
226 last_high_trigger_time = now;
227 ESP_LOGV(TAG,
"Proximity high threshold triggered. Value = %d, Trigger level = %d", ps_data,
231 last_low_trigger_time = now;
232 ESP_LOGV(TAG,
"Proximity low threshold triggered. Value = %d, Trigger level = %d", ps_data,
241 if (manuf_id != 0x05) {
242 ESP_LOGW(TAG,
"Unknown manufacturer ID: 0x%02X", manuf_id);
260 if (part_id.part_number_id != 0x0a && part_id.part_number_id != 0x09) {
261 ESP_LOGW(TAG,
"Unknown part number ID: 0x%02X. It might not work properly.", part_id.part_number_id);
269 ESP_LOGV(TAG,
"Resetting");
276 uint8_t tries = MAX_TRIES;
278 ESP_LOGV(TAG,
"Waiting for chip to reset");
280 als_ctrl.raw = this->
reg((uint8_t) CommandRegisters::ALS_CONTR).
get();
281 }
while (als_ctrl.sw_reset && tries--);
283 if (als_ctrl.sw_reset) {
284 ESP_LOGW(TAG,
"Reset timed out");
292 als_ctrl.active_mode =
true;
293 als_ctrl.gain = this->
gain_;
295 ESP_LOGV(TAG,
"Setting active mode and gain reg 0x%02X", als_ctrl.raw);
299 uint8_t tries = MAX_TRIES;
301 ESP_LOGV(TAG,
"Waiting for device to become active...");
303 als_ctrl.raw = this->
reg((uint8_t) CommandRegisters::ALS_CONTR).
get();
304 }
while (!als_ctrl.active_mode && tries--);
306 if (!als_ctrl.active_mode) {
307 ESP_LOGW(TAG,
"Failed to activate device");
318 ps_ctrl.ps_mode_xxx =
true;
325 if (!als_status.ps_new_data || als_status.data_invalid) {
343 als_ctrl.gain =
gain;
348 read_als_ctrl.
raw = this->
reg((uint8_t) CommandRegisters::ALS_CONTR).
get();
349 if (read_als_ctrl.gain != gain) {
350 ESP_LOGW(TAG,
"Failed to set gain. We will try one more time.");
351 this->
reg((uint8_t) CommandRegisters::ALS_CONTR) = als_ctrl.raw;
359 meas.integration_time = time;
364 read_meas.
raw = this->
reg((uint8_t) CommandRegisters::MEAS_RATE).
get();
365 if (read_meas.integration_time != time) {
366 ESP_LOGW(TAG,
"Failed to set integration time. We will try one more time.");
367 this->
reg((uint8_t) CommandRegisters::MEAS_RATE) = meas.raw;
376 if (!als_status.als_new_data)
379 if (als_status.data_invalid) {
380 ESP_LOGW(TAG,
"Data available but not valid");
383 ESP_LOGV(TAG,
"Data ready, reported gain is %.0f", get_gain_coeff(als_status.gain));
384 if (data.
gain != als_status.gain) {
385 ESP_LOGW(TAG,
"Actual gain differs from requested (%.0f)", get_gain_coeff(data.
gain));
401 ESP_LOGV(TAG,
"Got sensor data: CH1 = %d, CH0 = %d", data.
ch1, data.
ch0);
410 ESP_LOGW(TAG,
"Too many sensitivity adjustments done. Apparently, sensor reconfiguration fails. Stopping.");
416 static const uint16_t LOW_INTENSITY_THRESHOLD = 1000;
417 static const uint16_t HIGH_INTENSITY_THRESHOLD = 30000;
423 if (data.
ch0 <= LOW_INTENSITY_THRESHOLD) {
425 if (next_gain != data.
gain) {
426 data.
gain = next_gain;
427 ESP_LOGV(TAG,
"Low illuminance. Increasing gain.");
433 ESP_LOGV(TAG,
"Low illuminance. Increasing integration time.");
436 }
else if (data.
ch0 >= HIGH_INTENSITY_THRESHOLD) {
438 if (prev_gain != data.
gain) {
439 data.
gain = prev_gain;
440 ESP_LOGV(TAG,
"High illuminance. Decreasing gain.");
446 ESP_LOGV(TAG,
"High illuminance. Decreasing integration time.");
450 ESP_LOGD(TAG,
"Illuminance is sufficient.");
453 ESP_LOGD(TAG,
"Can't adjust sensitivity anymore.");
458 if ((data.
ch0 == 0xFFFF) || (data.
ch1 == 0xFFFF)) {
459 ESP_LOGW(TAG,
"Sensors got saturated");
464 if ((data.
ch0 == 0x0000) && (data.
ch1 == 0x0000)) {
465 ESP_LOGW(TAG,
"Sensors blacked out");
470 float ch0 = data.
ch0;
471 float ch1 = data.
ch1;
472 float ratio = ch1 / (ch0 + ch1);
473 float als_gain = get_gain_coeff(data.
gain);
479 lux = (1.7743 * ch0 + 1.1059 * ch1);
480 }
else if (ratio < 0.64 && ratio >= 0.45) {
481 lux = (4.2785 * ch0 - 1.9548 * ch1);
482 }
else if (ratio < 0.85 && ratio >= 0.64) {
483 lux = (0.5926 * ch0 + 0.1185 * ch1);
485 ESP_LOGW(TAG,
"Impossible ch1/(ch0 + ch1) ratio");
488 lux = inv_pfactor * lux / als_gain / als_time;
491 ESP_LOGV(TAG,
"Lux calculation: ratio %.3f, gain %.0fx, int time %.1f, inv_pfactor %.3f, lux %.3f", ratio, als_gain,
492 als_time, inv_pfactor, lux);
uint16_t ps_cooldown_time_s_
sensor::Sensor * actual_gain_sensor_
void status_set_warning(const char *message="unspecified")
I2CRegister reg(uint8_t a_register)
calls the I2CRegister constructor
uint8_t get() const
returns the register value
uint16_t ps_threshold_high_
bool check_part_number_()
DataAvail is_als_data_ready_(AlsReadings &data)
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
float glass_attenuation_factor_
T get_prev(const T(&array)[size], const T val)
CallbackManager< void()> on_ps_high_trigger_callback_
void apply_lux_calculation_(AlsReadings &data)
uint16_t ps_threshold_low_
uint32_t IRAM_ATTR HOT millis()
ErrorCode write(const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a device using an I2CBus
void check_and_trigger_ps_()
struct esphome::ltr_als_ps::LTRAlsPsComponent::AlsReadings als_readings_
IntegrationTime integration_time_
No error found during execution of method.
MeasurementRepeatRate repeat_rate_
bool automatic_mode_enabled_
void status_clear_warning()
CallbackManager< void()> on_ps_low_trigger_callback_
void publish_state(float state)
Publish a new state to the front-end.
bool are_adjustments_required_(AlsReadings &data)
sensor::Sensor * infrared_counts_sensor_
MeasurementRepeatRate measurement_repeat_rate
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
sensor::Sensor * full_spectrum_counts_sensor_
void configure_integration_time_(IntegrationTime time)
sensor::Sensor * proximity_counts_sensor_
uint8_t number_of_adjustments
void dump_config() override
sensor::Sensor * actual_integration_time_sensor_
void read_sensor_data_(AlsReadings &data)
virtual void mark_failed()
Mark this component as failed.
PsMeasurementRate ps_measurement_rate
Implementation of SPI Controller mode.
void publish_data_part_1_(AlsReadings &data)
ErrorCode
Error codes returned by I2CBus and I2CDevice methods.
void configure_gain_(AlsGain gain)
IntegrationTime integration_time
sensor::Sensor * ambient_light_sensor_
T get_next(const T(&array)[size], const T val)
void publish_data_part_2_(AlsReadings &data)
void IRAM_ATTR HOT delay(uint32_t ms)