ESPHome  2024.12.2
apds9306.cpp
Go to the documentation of this file.
1 // Based on this datasheet:
2 // https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
3 
4 #include "apds9306.h"
5 #include "esphome/core/helpers.h"
6 #include "esphome/core/log.h"
7 
8 namespace esphome {
9 namespace apds9306 {
10 
11 static const char *const TAG = "apds9306";
12 
13 enum { // APDS9306 registers
19  APDS9306_CLEAR_DATA_0 = 0x0A, // LSB
21  APDS9306_CLEAR_DATA_2 = 0x0C, // MSB
22  APDS9306_ALS_DATA_0 = 0x0D, // LSB
24  APDS9306_ALS_DATA_2 = 0x0F, // MSB
27  APDS9306_ALS_THRES_UP_0 = 0x21, // LSB
29  APDS9306_ALS_THRES_UP_2 = 0x23, // MSB
30  APDS9306_ALS_THRES_LOW_0 = 0x24, // LSB
32  APDS9306_ALS_THRES_LOW_2 = 0x26, // MSB
34 };
35 
36 #define APDS9306_ERROR_CHECK(func, error) \
37  if (!(func)) { \
38  ESP_LOGE(TAG, error); \
39  this->mark_failed(); \
40  return; \
41  }
42 #define APDS9306_WARNING_CHECK(func, warning) \
43  if (!(func)) { \
44  ESP_LOGW(TAG, warning); \
45  this->status_set_warning(); \
46  return; \
47  }
48 #define APDS9306_WRITE_BYTE(reg, value) \
49  ESP_LOGV(TAG, "Writing 0x%02x to 0x%02x", value, reg); \
50  if (!this->write_byte(reg, value)) { \
51  ESP_LOGE(TAG, "Failed writing 0x%02x to 0x%02x", value, reg); \
52  this->mark_failed(); \
53  return; \
54  }
55 
57  ESP_LOGCONFIG(TAG, "Setting up APDS9306...");
58 
59  uint8_t id;
60  if (!this->read_byte(APDS9306_PART_ID, &id)) { // Part ID register
61  this->error_code_ = COMMUNICATION_FAILED;
62  this->mark_failed();
63  return;
64  }
65 
66  if (id != 0xB1 && id != 0xB3) { // 0xB1 for APDS9306 0xB3 for APDS9306-065
67  this->error_code_ = WRONG_ID;
68  this->mark_failed();
69  return;
70  }
71 
72  // ALS resolution and measurement, see datasheet or init.py for options
73  uint8_t als_meas_rate = ((this->bit_width_ & 0x07) << 4) | (this->measurement_rate_ & 0x07);
74  APDS9306_WRITE_BYTE(APDS9306_ALS_MEAS_RATE, als_meas_rate);
75 
76  // ALS gain, see datasheet or init.py for options
77  uint8_t als_gain = (this->gain_ & 0x07);
78  APDS9306_WRITE_BYTE(APDS9306_ALS_GAIN, als_gain);
79 
80  // Set to standby mode
81  APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x00);
82 
83  // Check for data, clear main status
84  uint8_t status;
85  APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed.");
86 
87  // Set to active mode
88  APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02);
89 
90  ESP_LOGCONFIG(TAG, "APDS9306 setup complete");
91 }
92 
94  LOG_SENSOR("", "APDS9306", this);
95  LOG_I2C_DEVICE(this);
96 
97  if (this->is_failed()) {
98  switch (this->error_code_) {
100  ESP_LOGE(TAG, "Communication with APDS9306 failed!");
101  break;
102  case WRONG_ID:
103  ESP_LOGE(TAG, "APDS9306 has invalid id!");
104  break;
105  default:
106  ESP_LOGE(TAG, "Setting up APDS9306 registers failed!");
107  break;
108  }
109  }
110 
111  ESP_LOGCONFIG(TAG, " Gain: %u", AMBIENT_LIGHT_GAIN_VALUES[this->gain_]);
112  ESP_LOGCONFIG(TAG, " Measurement rate: %u", MEASUREMENT_RATE_VALUES[this->measurement_rate_]);
113  ESP_LOGCONFIG(TAG, " Measurement Resolution/Bit width: %d", MEASUREMENT_BIT_WIDTH_VALUES[this->bit_width_]);
114 
115  LOG_UPDATE_INTERVAL(this);
116 }
117 
119  // Check for new data
120  uint8_t status;
121  APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed.");
122 
123  this->status_clear_warning();
124 
125  status &= 0b00001000;
126  if (!status) { // No new data
127  return;
128  }
129 
130  // Set to standby mode
131  APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x00);
132 
133  // Clear MAIN STATUS
134  APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed.");
135 
136  uint8_t als_data[3];
137  APDS9306_WARNING_CHECK(this->read_bytes(APDS9306_ALS_DATA_0, als_data, 3), "Reading ALS data has failed.");
138 
139  // Set to active mode
140  APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02);
141 
142  uint32_t light_level = 0x00 | encode_uint24(als_data[2], als_data[1], als_data[0]);
143 
144  float lux = ((float) light_level / AMBIENT_LIGHT_GAIN_VALUES[this->gain_]) *
145  (100.0f / MEASUREMENT_RATE_VALUES[this->measurement_rate_]);
146 
147  ESP_LOGD(TAG, "Got illuminance=%.1flx from", lux);
148  this->publish_state(lux);
149 }
150 
151 } // namespace apds9306
152 } // namespace esphome
MeasurementBitWidth bit_width_
Definition: apds9306.h:60
bool read_byte(uint8_t a_register, uint8_t *data, bool stop=true)
Definition: i2c.h:235
bool is_failed() const
Definition: component.cpp:143
bool read_bytes(uint8_t a_register, uint8_t *data, uint8_t len)
Compat APIs All methods below have been added for compatibility reasons.
Definition: i2c.h:212
T id(T value)
Helper function to make id(var) known from lambdas work in custom components.
Definition: helpers.h:728
MeasurementRate measurement_rate_
Definition: apds9306.h:61
void status_clear_warning()
Definition: component.cpp:166
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3)
Encode a 24-bit value given three bytes in most to least significant byte order.
Definition: helpers.h:192
void setup() override
Definition: apds9306.cpp:56
uint8_t status
Definition: bl0942.h:74
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
void dump_config() override
Definition: apds9306.cpp:93
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
void update() override
Definition: apds9306.cpp:118
AmbientLightGain gain_
Definition: apds9306.h:62