ESPHome 2025.6.0
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
bh1750.cpp
Go to the documentation of this file.
1#include "bh1750.h"
2#include "esphome/core/log.h"
3
4namespace esphome {
5namespace bh1750 {
6
7static const char *const TAG = "bh1750.sensor";
8
9static const uint8_t BH1750_COMMAND_POWER_ON = 0b00000001;
10static const uint8_t BH1750_COMMAND_MT_REG_HI = 0b01000000; // last 3 bits
11static const uint8_t BH1750_COMMAND_MT_REG_LO = 0b01100000; // last 5 bits
12static const uint8_t BH1750_COMMAND_ONE_TIME_L = 0b00100011;
13static const uint8_t BH1750_COMMAND_ONE_TIME_H = 0b00100000;
14static const uint8_t BH1750_COMMAND_ONE_TIME_H2 = 0b00100001;
15
16/*
17bh1750 properties:
18
19L-resolution mode:
20- resolution 4lx (@ mtreg=69)
21- measurement time: typ=16ms, max=24ms, scaled by MTreg value divided by 69
22- formula: counts / 1.2 * (69 / MTreg) lx
23H-resolution mode:
24- resolution 1lx (@ mtreg=69)
25- measurement time: typ=120ms, max=180ms, scaled by MTreg value divided by 69
26- formula: counts / 1.2 * (69 / MTreg) lx
27H-resolution mode2:
28- resolution 0.5lx (@ mtreg=69)
29- measurement time: typ=120ms, max=180ms, scaled by MTreg value divided by 69
30- formula: counts / 1.2 * (69 / MTreg) / 2 lx
31
32MTreg:
33- min=31, default=69, max=254
34
35-> only reason to use l-resolution is faster, but offers no higher range
36-> below ~7000lx, makes sense to use H-resolution2 @ MTreg=254
37-> try to maximize MTreg to get lowest noise level
38*/
39
41 ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->name_.c_str());
42 uint8_t turn_on = BH1750_COMMAND_POWER_ON;
43 if (this->write(&turn_on, 1) != i2c::ERROR_OK) {
44 this->mark_failed();
45 return;
46 }
47}
48
49void BH1750Sensor::read_lx_(BH1750Mode mode, uint8_t mtreg, const std::function<void(float)> &f) {
50 // turn on (after one-shot sensor automatically powers down)
51 uint8_t turn_on = BH1750_COMMAND_POWER_ON;
52 if (this->write(&turn_on, 1) != i2c::ERROR_OK) {
53 ESP_LOGW(TAG, "Turning on BH1750 failed");
54 f(NAN);
55 return;
56 }
57
58 if (active_mtreg_ != mtreg) {
59 // set mtreg
60 uint8_t mtreg_hi = BH1750_COMMAND_MT_REG_HI | ((mtreg >> 5) & 0b111);
61 uint8_t mtreg_lo = BH1750_COMMAND_MT_REG_LO | ((mtreg >> 0) & 0b11111);
62 if (this->write(&mtreg_hi, 1) != i2c::ERROR_OK || this->write(&mtreg_lo, 1) != i2c::ERROR_OK) {
63 ESP_LOGW(TAG, "Setting measurement time for BH1750 failed");
64 active_mtreg_ = 0;
65 f(NAN);
66 return;
67 }
68 active_mtreg_ = mtreg;
69 }
70
71 uint8_t cmd;
72 uint16_t meas_time;
73 switch (mode) {
74 case BH1750_MODE_L:
75 cmd = BH1750_COMMAND_ONE_TIME_L;
76 meas_time = 24 * mtreg / 69;
77 break;
78 case BH1750_MODE_H:
79 cmd = BH1750_COMMAND_ONE_TIME_H;
80 meas_time = 180 * mtreg / 69;
81 break;
82 case BH1750_MODE_H2:
83 cmd = BH1750_COMMAND_ONE_TIME_H2;
84 meas_time = 180 * mtreg / 69;
85 break;
86 default:
87 f(NAN);
88 return;
89 }
90 if (this->write(&cmd, 1) != i2c::ERROR_OK) {
91 ESP_LOGW(TAG, "Starting measurement for BH1750 failed");
92 f(NAN);
93 return;
94 }
95
96 // probably not needed, but adjust for rounding
97 meas_time++;
98
99 this->set_timeout("read", meas_time, [this, mode, mtreg, f]() {
100 uint16_t raw_value;
101 if (this->read(reinterpret_cast<uint8_t *>(&raw_value), 2) != i2c::ERROR_OK) {
102 ESP_LOGW(TAG, "Reading BH1750 data failed");
103 f(NAN);
104 return;
105 }
106 raw_value = i2c::i2ctohs(raw_value);
107
108 float lx = float(raw_value) / 1.2f;
109 lx *= 69.0f / mtreg;
110 if (mode == BH1750_MODE_H2)
111 lx /= 2.0f;
112
113 f(lx);
114 });
115}
116
118 LOG_SENSOR("", "BH1750", this);
119 LOG_I2C_DEVICE(this);
120 if (this->is_failed()) {
121 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL_FOR, this->get_name().c_str());
122 }
123
124 LOG_UPDATE_INTERVAL(this);
125}
126
128 // first do a quick measurement in L-mode with full range
129 // to find right range
130 this->read_lx_(BH1750_MODE_L, 31, [this](float val) {
131 if (std::isnan(val)) {
132 this->status_set_warning();
133 this->publish_state(NAN);
134 return;
135 }
136
137 BH1750Mode use_mode;
138 uint8_t use_mtreg;
139 if (val <= 7000) {
140 use_mode = BH1750_MODE_H2;
141 use_mtreg = 254;
142 } else {
143 use_mode = BH1750_MODE_H;
144 // lx = counts / 1.2 * (69 / mtreg)
145 // -> mtreg = counts / 1.2 * (69 / lx)
146 // calculate for counts=50000 (allow some range to not saturate, but maximize mtreg)
147 // -> mtreg = 50000*(10/12)*(69/lx)
148 int ideal_mtreg = 50000 * 10 * 69 / (12 * (int) val);
149 use_mtreg = std::min(254, std::max(31, ideal_mtreg));
150 }
151 ESP_LOGV(TAG, "L result: %f -> Calculated mode=%d, mtreg=%d", val, (int) use_mode, use_mtreg);
152
153 this->read_lx_(use_mode, use_mtreg, [this](float val) {
154 if (std::isnan(val)) {
155 this->status_set_warning();
156 this->publish_state(NAN);
157 return;
158 }
159 ESP_LOGD(TAG, "'%s': Got illuminance=%.1flx", this->get_name().c_str(), val);
160 this->status_clear_warning();
161 this->publish_state(val);
162 });
163 });
164}
165
167
168} // namespace bh1750
169} // namespace esphome
BedjetMode mode
BedJet operating mode.
virtual void mark_failed()
Mark this component as failed.
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.
Definition component.cpp:75
const StringRef & get_name() const
constexpr const char * c_str() const
Definition string_ref.h:69
void read_lx_(BH1750Mode mode, uint8_t mtreg, const std::function< void(float)> &f)
Definition bh1750.cpp:49
void dump_config() override
Definition bh1750.cpp:117
float get_setup_priority() const override
Definition bh1750.cpp:166
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(uint8_t *data, size_t len)
reads an array of bytes from the device using an I2CBus
Definition i2c.h:164
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:39
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
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:20
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7