ESPHome 2025.7.1
Loading...
Searching...
No Matches
opt3001.cpp
Go to the documentation of this file.
1#include "opt3001.h"
2#include "esphome/core/log.h"
3
4namespace esphome {
5namespace opt3001 {
6
7static const char *const TAG = "opt3001.sensor";
8
9static const uint8_t OPT3001_REG_RESULT = 0x00;
10static const uint8_t OPT3001_REG_CONFIGURATION = 0x01;
11// See datasheet for full description of each bit.
12static const uint16_t OPT3001_CONFIGURATION_RANGE_FULL = 0b1100000000000000;
13static const uint16_t OPT3001_CONFIGURATION_CONVERSION_TIME_800 = 0b100000000000;
14static const uint16_t OPT3001_CONFIGURATION_CONVERSION_MODE_MASK = 0b11000000000;
15static const uint16_t OPT3001_CONFIGURATION_CONVERSION_MODE_SINGLE_SHOT = 0b01000000000;
16static const uint16_t OPT3001_CONFIGURATION_CONVERSION_MODE_SHUTDOWN = 0b00000000000;
17// tl;dr: Configure an automatic-ranged, 800ms single shot reading,
18// with INT processing disabled
19static const uint16_t OPT3001_CONFIGURATION_FULL_RANGE_ONE_SHOT = OPT3001_CONFIGURATION_RANGE_FULL |
20 OPT3001_CONFIGURATION_CONVERSION_TIME_800 |
21 OPT3001_CONFIGURATION_CONVERSION_MODE_SINGLE_SHOT;
22static const uint16_t OPT3001_CONVERSION_TIME_800 = 825; // give it 25 extra ms; it seems to not be ready quite often
23
24/*
25opt3001 properties:
26
27- e (exponent) = high 4 bits of result register
28- m (mantissa) = low 12 bits of result register
29- formula: (0.01 * 2^e) * m lx
30
31*/
32
33void OPT3001Sensor::read_result_(const std::function<void(float)> &f) {
34 // ensure the single shot flag is clear, indicating it's done
35 uint16_t raw_value;
36 if (this->read(reinterpret_cast<uint8_t *>(&raw_value), 2) != i2c::ERROR_OK) {
37 ESP_LOGW(TAG, "Reading configuration register failed");
38 f(NAN);
39 return;
40 }
41 raw_value = i2c::i2ctohs(raw_value);
42
43 if ((raw_value & OPT3001_CONFIGURATION_CONVERSION_MODE_MASK) != OPT3001_CONFIGURATION_CONVERSION_MODE_SHUTDOWN) {
44 // not ready; wait 10ms and try again
45 ESP_LOGW(TAG, "Data not ready; waiting 10ms");
46 this->set_timeout("opt3001_wait", 10, [this, f]() { read_result_(f); });
47 return;
48 }
49
50 if (this->read_register(OPT3001_REG_RESULT, reinterpret_cast<uint8_t *>(&raw_value), 2) != i2c::ERROR_OK) {
51 ESP_LOGW(TAG, "Reading result register failed");
52 f(NAN);
53 return;
54 }
55 raw_value = i2c::i2ctohs(raw_value);
56
57 uint8_t exponent = raw_value >> 12;
58 uint16_t mantissa = raw_value & 0b111111111111;
59
60 double lx = 0.01 * pow(2.0, double(exponent)) * double(mantissa);
61 f(float(lx));
62}
63
64void OPT3001Sensor::read_lx_(const std::function<void(float)> &f) {
65 // turn on (after one-shot sensor automatically powers down)
66 uint16_t start_measurement = i2c::htoi2cs(OPT3001_CONFIGURATION_FULL_RANGE_ONE_SHOT);
67 if (this->write_register(OPT3001_REG_CONFIGURATION, reinterpret_cast<uint8_t *>(&start_measurement), 2) !=
69 ESP_LOGW(TAG, "Triggering one shot measurement failed");
70 f(NAN);
71 return;
72 }
73
74 this->set_timeout("read", OPT3001_CONVERSION_TIME_800, [this, f]() {
75 if (this->write(&OPT3001_REG_CONFIGURATION, 1, true) != i2c::ERROR_OK) {
76 ESP_LOGW(TAG, "Starting configuration register read failed");
77 f(NAN);
78 return;
79 }
80
81 this->read_result_(f);
82 });
83}
84
86 LOG_SENSOR("", "OPT3001", this);
87 LOG_I2C_DEVICE(this);
88 if (this->is_failed()) {
89 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
90 }
91
92 LOG_UPDATE_INTERVAL(this);
93}
94
96 // Set a flag and skip just in case the sensor isn't responding,
97 // and we just keep waiting for it in read_result_.
98 // This way we don't end up with potentially boundless "threads"
99 // using up memory and eventually crashing the device
100 if (this->updating_) {
101 return;
102 }
103 this->updating_ = true;
104
105 this->read_lx_([this](float val) {
106 this->updating_ = false;
107
108 if (std::isnan(val)) {
109 this->status_set_warning();
110 this->publish_state(NAN);
111 return;
112 }
113 ESP_LOGD(TAG, "'%s': Illuminance=%.1flx", this->get_name().c_str(), val);
114 this->status_clear_warning();
115 this->publish_state(val);
116 });
117}
118
120
121} // namespace opt3001
122} // namespace esphome
bool is_failed() const
void status_set_warning(const char *message="unspecified")
void status_clear_warning()
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
const StringRef & get_name() const
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a specific register in the I²C device
Definition i2c.cpp:25
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:190
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len, bool stop=true)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:10
ErrorCode read(uint8_t *data, size_t len)
reads an array of bytes from the device using an I2CBus
Definition i2c.h:164
void read_result_(const std::function< void(float)> &f)
Definition opt3001.cpp:33
void read_lx_(const std::function< void(float)> &f)
Definition opt3001.cpp:64
float get_setup_priority() const override
Definition opt3001.cpp:119
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:45
mopeka_std_values val[4]
uint16_t i2ctohs(uint16_t i2cshort)
Definition i2c.h:128
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:13
uint16_t htoi2cs(uint16_t hostshort)
Definition i2c.h:129
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:46
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7