ESPHome  2024.12.2
veml3235.cpp
Go to the documentation of this file.
1 #include "veml3235.h"
2 #include "esphome/core/helpers.h"
3 #include "esphome/core/log.h"
4 
5 namespace esphome {
6 namespace veml3235 {
7 
8 static const char *const TAG = "veml3235.sensor";
9 
11  uint8_t device_id[] = {0, 0};
12 
13  ESP_LOGCONFIG(TAG, "Setting up VEML3235 '%s'...", this->name_.c_str());
14 
15  if (!this->refresh_config_reg()) {
16  ESP_LOGE(TAG, "Unable to write configuration");
17  this->mark_failed();
18  return;
19  }
20  if ((this->write(&ID_REG, 1, false) != i2c::ERROR_OK) || !this->read_bytes_raw(device_id, 2)) {
21  ESP_LOGE(TAG, "Unable to read ID");
22  this->mark_failed();
23  return;
24  } else if (device_id[0] != DEVICE_ID) {
25  ESP_LOGE(TAG, "Incorrect device ID - expected 0x%.2x, read 0x%.2x", DEVICE_ID, device_id[0]);
26  this->mark_failed();
27  return;
28  }
29 }
30 
32  uint16_t data = this->power_on_ || force_on ? 0 : SHUTDOWN_BITS;
33 
34  data |= (uint16_t(this->integration_time_ << CONFIG_REG_IT_BIT));
35  data |= (uint16_t(this->digital_gain_ << CONFIG_REG_DG_BIT));
36  data |= (uint16_t(this->gain_ << CONFIG_REG_G_BIT));
37  data |= 0x1; // mandatory 1 here per RM
38 
39  ESP_LOGVV(TAG, "Writing 0x%.4x to register 0x%.2x", data, CONFIG_REG);
40  return this->write_byte_16(CONFIG_REG, data);
41 }
42 
44  if (!this->power_on_) { // if off, turn on
45  if (!this->refresh_config_reg(true)) {
46  ESP_LOGW(TAG, "Turning on failed");
47  this->status_set_warning();
48  return NAN;
49  }
50  delay(4); // from RM: a wait time of 4 ms should be observed before the first measurement is picked up, to allow
51  // for a correct start of the signal processor and oscillator
52  }
53 
54  uint8_t als_regs[] = {0, 0};
55  if ((this->write(&ALS_REG, 1, false) != i2c::ERROR_OK) || !this->read_bytes_raw(als_regs, 2)) {
56  this->status_set_warning();
57  return NAN;
58  }
59 
60  this->status_clear_warning();
61 
62  float als_raw_value_multiplier = LUX_MULTIPLIER_BASE;
63  uint16_t als_raw_value = encode_uint16(als_regs[1], als_regs[0]);
64  // determine multiplier value based on gains and integration time
66  als_raw_value_multiplier *= 2;
67  }
68  switch (this->gain_) {
69  case VEML3235_GAIN_1X:
70  als_raw_value_multiplier *= 4;
71  break;
72  case VEML3235_GAIN_2X:
73  als_raw_value_multiplier *= 2;
74  break;
75  default:
76  break;
77  }
78  switch (this->integration_time_) {
80  als_raw_value_multiplier *= 16;
81  break;
83  als_raw_value_multiplier *= 8;
84  break;
86  als_raw_value_multiplier *= 4;
87  break;
89  als_raw_value_multiplier *= 2;
90  break;
91  default:
92  break;
93  }
94  // finally, determine and return the actual lux value
95  float lx = float(als_raw_value) * als_raw_value_multiplier;
96  ESP_LOGVV(TAG, "'%s': ALS raw = %u, multiplier = %.5f", this->get_name().c_str(), als_raw_value,
97  als_raw_value_multiplier);
98  ESP_LOGD(TAG, "'%s': Illuminance = %.4flx", this->get_name().c_str(), lx);
99 
100  if (!this->power_on_) { // turn off if required
101  if (!this->refresh_config_reg()) {
102  ESP_LOGW(TAG, "Turning off failed");
103  this->status_set_warning();
104  }
105  }
106 
107  if (this->auto_gain_) {
108  this->adjust_gain_(als_raw_value);
109  }
110 
111  return lx;
112 }
113 
114 void VEML3235Sensor::adjust_gain_(const uint16_t als_raw_value) {
115  if ((als_raw_value > UINT16_MAX * this->auto_gain_threshold_low_) &&
116  (als_raw_value < UINT16_MAX * this->auto_gain_threshold_high_)) {
117  return;
118  }
119 
120  if (als_raw_value >= UINT16_MAX * 0.9) { // over-saturated, reset all gains and start over
122  this->gain_ = VEML3235_GAIN_1X;
124  this->refresh_config_reg();
125  return;
126  }
127 
128  if (this->gain_ != VEML3235_GAIN_4X) { // increase gain if possible
129  switch (this->gain_) {
130  case VEML3235_GAIN_1X:
131  this->gain_ = VEML3235_GAIN_2X;
132  break;
133  case VEML3235_GAIN_2X:
134  this->gain_ = VEML3235_GAIN_4X;
135  break;
136  default:
137  break;
138  }
139  this->refresh_config_reg();
140  return;
141  }
142  // gain is maxed out; reset it and try to increase digital gain
143  if (this->digital_gain_ != VEML3235_DIGITAL_GAIN_2X) { // increase digital gain if possible
145  this->gain_ = VEML3235_GAIN_1X;
146  this->refresh_config_reg();
147  return;
148  }
149  // digital gain is maxed out; reset it and try to increase integration time
150  if (this->integration_time_ != VEML3235_INTEGRATION_TIME_800MS) { // increase integration time if possible
151  switch (this->integration_time_) {
154  break;
157  break;
160  break;
163  break;
164  default:
165  break;
166  }
168  this->gain_ = VEML3235_GAIN_1X;
169  this->refresh_config_reg();
170  return;
171  }
172 }
173 
175  uint8_t digital_gain = 1;
176  uint8_t gain = 1;
177  uint16_t integration_time = 0;
178 
180  digital_gain = 2;
181  }
182  switch (this->gain_) {
183  case VEML3235_GAIN_2X:
184  gain = 2;
185  break;
186  case VEML3235_GAIN_4X:
187  gain = 4;
188  break;
189  default:
190  break;
191  }
192  switch (this->integration_time_) {
194  integration_time = 50;
195  break;
197  integration_time = 100;
198  break;
200  integration_time = 200;
201  break;
203  integration_time = 400;
204  break;
206  integration_time = 800;
207  break;
208  default:
209  break;
210  }
211 
212  LOG_SENSOR("", "VEML3235", this);
213  LOG_I2C_DEVICE(this);
214  if (this->is_failed()) {
215  ESP_LOGE(TAG, "Communication failed");
216  }
217  LOG_UPDATE_INTERVAL(this);
218  ESP_LOGCONFIG(TAG, " Auto-gain enabled: %s", YESNO(this->auto_gain_));
219  if (this->auto_gain_) {
220  ESP_LOGCONFIG(TAG, " Auto-gain upper threshold: %f%%", this->auto_gain_threshold_high_ * 100.0);
221  ESP_LOGCONFIG(TAG, " Auto-gain lower threshold: %f%%", this->auto_gain_threshold_low_ * 100.0);
222  ESP_LOGCONFIG(TAG, " Values below will be used as initial values only");
223  }
224  ESP_LOGCONFIG(TAG, " Digital gain: %uX", digital_gain);
225  ESP_LOGCONFIG(TAG, " Gain: %uX", gain);
226  ESP_LOGCONFIG(TAG, " Integration time: %ums", integration_time);
227 }
228 
229 } // namespace veml3235
230 } // namespace esphome
void adjust_gain_(uint16_t als_raw_value)
Definition: veml3235.cpp:114
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
bool is_failed() const
Definition: component.cpp:143
VEML3235ComponentGain gain()
Definition: veml3235.h:89
optional< std::array< uint8_t, N > > read_bytes_raw()
Definition: i2c.h:225
VEML3235ComponentIntegrationTime integration_time_
Definition: veml3235.h:105
VEML3235ComponentDigitalGain digital_gain_
Definition: veml3235.h:103
bool refresh_config_reg(bool force_on=false)
Definition: veml3235.cpp:31
ErrorCode write(const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a device using an I2CBus
Definition: i2c.h:186
No error found during execution of method.
Definition: i2c_bus.h:13
void status_clear_warning()
Definition: component.cpp:166
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition: helpers.h:183
VEML3235ComponentDigitalGain digital_gain()
Definition: veml3235.h:88
constexpr const char * c_str() const
Definition: string_ref.h:68
VEML3235ComponentIntegrationTime integration_time()
Definition: veml3235.h:90
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
VEML3235ComponentGain gain_
Definition: veml3235.h:104
bool write_byte_16(uint8_t a_register, uint16_t data)
Definition: i2c.h:266
const StringRef & get_name() const
Definition: entity_base.cpp:10
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26