ESPHome  2024.3.1
tsl2561.cpp
Go to the documentation of this file.
1 #include "tsl2561.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace tsl2561 {
6 
7 static const char *const TAG = "tsl2561";
8 
9 static const uint8_t TSL2561_COMMAND_BIT = 0x80;
10 static const uint8_t TSL2561_WORD_BIT = 0x20;
11 static const uint8_t TSL2561_REGISTER_CONTROL = 0x00;
12 static const uint8_t TSL2561_REGISTER_TIMING = 0x01;
13 static const uint8_t TSL2561_REGISTER_ID = 0x0A;
14 static const uint8_t TSL2561_REGISTER_DATA_0 = 0x0C;
15 static const uint8_t TSL2561_REGISTER_DATA_1 = 0x0E;
16 
18  ESP_LOGCONFIG(TAG, "Setting up TSL2561...");
19  uint8_t id;
20  if (!this->tsl2561_read_byte(TSL2561_REGISTER_ID, &id)) {
21  this->mark_failed();
22  return;
23  }
24 
25  uint8_t timing;
26  if (!this->tsl2561_read_byte(TSL2561_REGISTER_TIMING, &timing)) {
27  this->mark_failed();
28  return;
29  }
30 
31  timing &= ~0b00010000;
32  timing |= this->gain_ == TSL2561_GAIN_16X ? 0b00010000 : 0;
33 
34  timing &= ~0b00000011;
35  timing |= this->integration_time_ & 0b11;
36 
37  this->tsl2561_write_byte(TSL2561_REGISTER_TIMING, timing);
38 }
40  LOG_SENSOR("", "TSL2561", this);
41  LOG_I2C_DEVICE(this);
42 
43  if (this->is_failed()) {
44  ESP_LOGE(TAG, "Communication with TSL2561 failed!");
45  }
46 
47  int gain = this->gain_ == TSL2561_GAIN_1X ? 1 : 16;
48  ESP_LOGCONFIG(TAG, " Gain: %dx", gain);
49  ESP_LOGCONFIG(TAG, " Integration Time: %.1f ms", this->get_integration_time_ms_());
50 
51  LOG_UPDATE_INTERVAL(this);
52 }
54  // Power on
55  if (!this->tsl2561_write_byte(TSL2561_REGISTER_CONTROL, 0b00000011)) {
56  this->status_set_warning();
57  return;
58  }
59 
60  // Make sure the data is there when we will read it.
61  auto timeout = static_cast<uint32_t>(this->get_integration_time_ms_() + 20);
62 
63  this->set_timeout("illuminance", timeout, [this]() { this->read_data_(); });
64 }
65 
66 float TSL2561Sensor::calculate_lx_(uint16_t ch0, uint16_t ch1) {
67  if ((ch0 == 0xFFFF) || (ch1 == 0xFFFF)) {
68  ESP_LOGW(TAG, "TSL2561 sensor is saturated.");
69  return NAN;
70  }
71 
72  float d0 = ch0, d1 = ch1;
73  float ratio = d1 / d0;
74 
75  float ms = this->get_integration_time_ms_();
76  d0 *= (402.0f / ms);
77  d1 *= (402.0f / ms);
78 
79  if (this->gain_ == TSL2561_GAIN_1X) {
80  d0 *= 16;
81  d1 *= 16;
82  }
83 
84  if (this->package_cs_) {
85  if (ratio < 0.52f) {
86  return 0.0315f * d0 - 0.0593f * d0 * powf(ratio, 1.4f);
87  } else if (ratio < 0.65f) {
88  return 0.0229f * d0 - 0.0291f * d1;
89  } else if (ratio < 0.80f) {
90  return 0.0157f * d0 - 0.0153f * d1;
91  } else if (ratio < 1.30f) {
92  return 0.00338f * d0 - 0.00260f * d1;
93  }
94 
95  return 0.0f;
96  } else {
97  if (ratio < 0.5f) {
98  return 0.0304f * d0 - 0.062f * d0 * powf(ratio, 1.4f);
99  } else if (ratio < 0.61f) {
100  return 0.0224f * d0 - 0.031f * d1;
101  } else if (ratio < 0.80f) {
102  return 0.0128f * d0 - 0.0153f * d1;
103  } else if (ratio < 1.30f) {
104  return 0.00146f * d0 - 0.00112f * d1;
105  }
106  return 0.0f;
107  }
108 }
110  uint16_t data1, data0;
111  if (!this->tsl2561_read_uint(TSL2561_WORD_BIT | TSL2561_REGISTER_DATA_1, &data1)) {
112  this->status_set_warning();
113  return;
114  }
115  if (!this->tsl2561_read_uint(TSL2561_WORD_BIT | TSL2561_REGISTER_DATA_0, &data0)) {
116  this->status_set_warning();
117  return;
118  }
119  // Power off
120  if (!this->tsl2561_write_byte(TSL2561_REGISTER_CONTROL, 0b00000000)) {
121  this->status_set_warning();
122  return;
123  }
124 
125  float lx = this->calculate_lx_(data0, data1);
126  ESP_LOGD(TAG, "Got illuminance=%.1flx", lx);
127  this->publish_state(lx);
128  this->status_clear_warning();
129 }
131  switch (this->integration_time_) {
133  return 13.7f;
135  return 100.0f;
137  return 402.0f;
138  }
139  return 0.0f;
140 }
142  this->integration_time_ = integration_time;
143 }
144 void TSL2561Sensor::set_gain(TSL2561Gain gain) { this->gain_ = gain; }
145 void TSL2561Sensor::set_is_cs_package(bool package_cs) { this->package_cs_ = package_cs; }
147 bool TSL2561Sensor::tsl2561_write_byte(uint8_t a_register, uint8_t value) {
148  return this->write_byte(a_register | TSL2561_COMMAND_BIT, value);
149 }
150 bool TSL2561Sensor::tsl2561_read_uint(uint8_t a_register, uint16_t *value) {
151  uint8_t data[2];
152  if (!this->read_bytes(a_register | TSL2561_COMMAND_BIT, data, 2))
153  return false;
154  const uint16_t hi = data[1];
155  const uint16_t lo = data[0];
156  *value = (hi << 8) | lo;
157  return true;
158 }
159 bool TSL2561Sensor::tsl2561_read_byte(uint8_t a_register, uint8_t *value) {
160  return this->read_byte(a_register | TSL2561_COMMAND_BIT, value);
161 }
162 
163 } // namespace tsl2561
164 } // namespace esphome
bool read_byte(uint8_t a_register, uint8_t *data, bool stop=true)
Definition: i2c.h:235
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
void set_integration_time(TSL2561IntegrationTime integration_time)
Set the time that sensor values should be accumulated for.
Definition: tsl2561.cpp:141
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:146
float calculate_lx_(uint16_t ch0, uint16_t ch1)
Definition: tsl2561.cpp:66
void set_gain(TSL2561Gain gain)
Set the internal gain of the sensor.
Definition: tsl2561.cpp:144
bool tsl2561_read_byte(uint8_t a_register, uint8_t *value)
Definition: tsl2561.cpp:159
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:69
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:689
void set_is_cs_package(bool package_cs)
The "CS" package of this sensor has a slightly different formula for converting the raw values...
Definition: tsl2561.cpp:145
TSL2561IntegrationTime integration_time_
Definition: tsl2561.h:81
bool tsl2561_write_byte(uint8_t a_register, uint8_t value)
Definition: tsl2561.cpp:147
TSL2561IntegrationTime
Enum listing all conversion/integration time settings for the TSL2561.
Definition: tsl2561.h:14
TSL2561Gain
Enum listing all gain settings for the TSL2561.
Definition: tsl2561.h:24
void status_clear_warning()
Definition: component.cpp:161
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
float get_setup_priority() const override
Definition: tsl2561.cpp:146
bool write_byte(uint8_t a_register, uint8_t data, bool stop=true)
Definition: i2c.h:262
void dump_config() override
Definition: tsl2561.cpp:39
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:113
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
bool tsl2561_read_uint(uint8_t a_register, uint16_t *value)
Definition: tsl2561.cpp:150