ESPHome  2022.12.8
ltr390.cpp
Go to the documentation of this file.
1 #include "ltr390.h"
2 #include "esphome/core/hal.h"
3 #include "esphome/core/log.h"
4 #include <bitset>
5 
6 namespace esphome {
7 namespace ltr390 {
8 
9 static const char *const TAG = "ltr390";
10 
11 static const float GAINVALUES[5] = {1.0, 3.0, 6.0, 9.0, 18.0};
12 static const float RESOLUTIONVALUE[6] = {4.0, 2.0, 1.0, 0.5, 0.25, 0.125};
13 static const uint32_t MODEADDRESSES[2] = {0x0D, 0x10};
14 
15 uint32_t little_endian_bytes_to_int(const uint8_t *buffer, uint8_t num_bytes) {
16  uint32_t value = 0;
17 
18  for (int i = 0; i < num_bytes; i++) {
19  value <<= 8;
20  value |= buffer[num_bytes - i - 1];
21  }
22 
23  return value;
24 }
25 
27  const uint8_t num_bytes = 3;
28  uint8_t buffer[num_bytes];
29 
30  // Wait until data available
31  const uint32_t now = millis();
32  while (true) {
33  std::bitset<8> status = this->reg(LTR390_MAIN_STATUS).get();
34  bool available = status[3];
35  if (available)
36  break;
37 
38  if (millis() - now > 100) {
39  ESP_LOGW(TAG, "Sensor didn't return any data, aborting");
40  return {};
41  }
42  ESP_LOGD(TAG, "Waiting for data");
43  delay(2);
44  }
45 
46  if (!this->read_bytes(MODEADDRESSES[mode], buffer, num_bytes)) {
47  ESP_LOGW(TAG, "Reading data from sensor failed!");
48  return {};
49  }
50 
51  return little_endian_bytes_to_int(buffer, num_bytes);
52 }
53 
56  if (!val.has_value())
57  return;
58  uint32_t als = *val;
59 
60  if (this->light_sensor_ != nullptr) {
61  float lux = (0.6 * als) / (GAINVALUES[this->gain_] * RESOLUTIONVALUE[this->res_]) * this->wfac_;
62  this->light_sensor_->publish_state(lux);
63  }
64 
65  if (this->als_sensor_ != nullptr) {
66  this->als_sensor_->publish_state(als);
67  }
68 }
69 
72  if (!val.has_value())
73  return;
74  uint32_t uv = *val;
75 
76  if (this->uvi_sensor_ != nullptr) {
77  this->uvi_sensor_->publish_state(uv / LTR390_SENSITIVITY * this->wfac_);
78  }
79 
80  if (this->uv_sensor_ != nullptr) {
81  this->uv_sensor_->publish_state(uv);
82  }
83 }
84 
85 void LTR390Component::read_mode_(int mode_index) {
86  // Set mode
87  LTR390MODE mode = std::get<0>(this->mode_funcs_[mode_index]);
88 
89  std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get();
90  ctrl[LTR390_CTRL_MODE] = mode;
91  this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong();
92 
93  // After the sensor integration time do the following
94  this->set_timeout(((uint32_t) RESOLUTIONVALUE[this->res_]) * 100, [this, mode_index]() {
95  // Read from the sensor
96  std::get<1>(this->mode_funcs_[mode_index])();
97 
98  // If there are more modes to read then begin the next
99  // otherwise stop
100  if (mode_index + 1 < (int) this->mode_funcs_.size()) {
101  this->read_mode_(mode_index + 1);
102  } else {
103  this->reading_ = false;
104  }
105  });
106 }
107 
109  ESP_LOGCONFIG(TAG, "Setting up ltr390...");
110 
111  // reset
112  std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get();
113  ctrl[LTR390_CTRL_RST] = true;
114  this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong();
115  delay(10);
116 
117  // Enable
118  ctrl = this->reg(LTR390_MAIN_CTRL).get();
119  ctrl[LTR390_CTRL_EN] = true;
120  this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong();
121 
122  // check enabled
123  ctrl = this->reg(LTR390_MAIN_CTRL).get();
124  bool enabled = ctrl[LTR390_CTRL_EN];
125 
126  if (!enabled) {
127  ESP_LOGW(TAG, "Sensor didn't respond with enabled state");
128  this->mark_failed();
129  return;
130  }
131 
132  // Set gain
133  this->reg(LTR390_GAIN) = gain_;
134 
135  // Set resolution
136  uint8_t res = this->reg(LTR390_MEAS_RATE).get();
137  // resolution is in bits 5-7
138  res &= ~0b01110000;
139  res |= res << 4;
140  this->reg(LTR390_MEAS_RATE) = res;
141 
142  // Set sensor read state
143  this->reading_ = false;
144 
145  // If we need the light sensor then add to the list
146  if (this->light_sensor_ != nullptr || this->als_sensor_ != nullptr) {
147  this->mode_funcs_.emplace_back(LTR390_MODE_ALS, std::bind(&LTR390Component::read_als_, this));
148  }
149 
150  // If we need the UV sensor then add to the list
151  if (this->uvi_sensor_ != nullptr || this->uv_sensor_ != nullptr) {
152  this->mode_funcs_.emplace_back(LTR390_MODE_UVS, std::bind(&LTR390Component::read_uvs_, this));
153  }
154 }
155 
156 void LTR390Component::dump_config() { LOG_I2C_DEVICE(this); }
157 
159  if (!this->reading_ && !mode_funcs_.empty()) {
160  this->reading_ = true;
161  this->read_mode_(0);
162  }
163 }
164 
165 } // namespace ltr390
166 } // namespace esphome
void read_mode_(int mode_index)
Definition: ltr390.cpp:85
uint32_t little_endian_bytes_to_int(const uint8_t *buffer, uint8_t num_bytes)
Definition: ltr390.cpp:15
I2CRegister reg(uint8_t a_register)
Definition: i2c.h:46
uint8_t get() const
Definition: i2c.cpp:33
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition: component.cpp:68
bool read_bytes(uint8_t a_register, uint8_t *data, uint8_t len)
Definition: i2c.h:68
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:26
optional< uint32_t > read_sensor_data_(LTR390MODE mode)
Definition: ltr390.cpp:26
BedjetMode mode
BedJet operating mode.
Definition: bedjet_codec.h:151
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:72
sensor::Sensor * uv_sensor_
Definition: ltr390.h:90
sensor::Sensor * light_sensor_
Definition: ltr390.h:86
uint8_t status
Definition: bl0942.h:23
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:112
LTR390RESOLUTION res_
Definition: ltr390.h:83
std::vector< std::tuple< LTR390MODE, std::function< void()> > > mode_funcs_
Definition: ltr390.h:80
Definition: a4988.cpp:4
uint32_t val
Definition: datatypes.h:85
sensor::Sensor * uvi_sensor_
Definition: ltr390.h:89
sensor::Sensor * als_sensor_
Definition: ltr390.h:87
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:27