ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
sensor_mlx90393.cpp
Go to the documentation of this file.
1#include "sensor_mlx90393.h"
2#include "esphome/core/log.h"
3
5
6static const char *const TAG = "mlx90393";
7
8const LogString *settings_to_string(MLX90393Setting setting) {
9 switch (setting) {
11 return LOG_STR("gain");
13 return LOG_STR("resolution");
15 return LOG_STR("oversampling");
17 return LOG_STR("digital filtering");
19 return LOG_STR("temperature oversampling");
21 return LOG_STR("temperature compensation");
23 return LOG_STR("hallconf");
24 case MLX90393_LAST:
25 return LOG_STR("error");
26 default:
27 return LOG_STR("unknown");
28 }
29};
30
31bool MLX90393Cls::transceive(const uint8_t *request, size_t request_size, uint8_t *response, size_t response_size) {
32 i2c::ErrorCode e = this->write(request, request_size);
33 if (e != i2c::ErrorCode::ERROR_OK) {
34 ESP_LOGV(TAG, "i2c failed to write %u", e);
35 return false;
36 }
37 e = this->read(response, response_size);
38 if (e != i2c::ErrorCode::ERROR_OK) {
39 ESP_LOGV(TAG, "i2c failed to read %u", e);
40 return false;
41 }
42 return true;
43}
44
45bool MLX90393Cls::has_drdy_pin() { return this->drdy_pin_ != nullptr; }
46
48 if (this->drdy_pin_ == nullptr) {
49 return false;
50 } else {
51 return this->drdy_pin_->digital_read();
52 }
53}
56
58 uint8_t ret = -1;
59 switch (which) {
61 ret = this->mlx_.setGainSel(this->gain_);
62 break;
64 ret = this->mlx_.setResolution(this->resolutions_[0], this->resolutions_[1], this->resolutions_[2]);
65 break;
67 ret = this->mlx_.setOverSampling(this->oversampling_);
68 break;
70 ret = this->mlx_.setDigitalFiltering(this->filter_);
71 break;
73 ret = this->mlx_.setTemperatureOverSampling(this->temperature_oversampling_);
74 break;
76 ret = this->mlx_.setTemperatureCompensation(this->temperature_compensation_);
77 break;
79 ret = this->mlx_.setHallConf(this->hallconf_);
80 break;
81 default:
82 break;
83 }
84 if (ret != MLX90393::STATUS_OK) {
85 ESP_LOGE(TAG, "failed to apply %s", LOG_STR_ARG(settings_to_string(which)));
86 }
87 return ret;
88}
89
91 // perform dummy read after reset
92 // first one always gets NAK even tough everything is fine
93 uint8_t ignore = 0;
94 this->mlx_.getGainSel(ignore);
95
96 uint8_t result = MLX90393::STATUS_OK;
97 for (int i = MLX90393_GAIN_SEL; i != MLX90393_LAST; i++) {
98 MLX90393Setting stage = static_cast<MLX90393Setting>(i);
99 result |= this->apply_setting_(stage);
100 }
101 return result == MLX90393::STATUS_OK;
102}
103
105 // note the two arguments A0 and A1 which are used to construct an i2c address
106 // we can hard-code these because we never actually use the constructed address
107 // see the transceive function above, which uses the address from I2CComponent
108 this->mlx_.begin_with_hal(this, 0, 0);
109
110 if (!this->apply_all_settings_()) {
111 this->mark_failed();
112 }
113
114 // start verify settings process
115 this->set_timeout("verify settings", 3000, [this]() { this->verify_settings_timeout_(MLX90393_GAIN_SEL); });
116}
117
119 ESP_LOGCONFIG(TAG, "MLX90393:");
120 LOG_I2C_DEVICE(this);
121
122 if (this->is_failed()) {
123 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
124 return;
125 }
126 LOG_UPDATE_INTERVAL(this);
127
128 LOG_SENSOR(" ", "X Axis", this->x_sensor_);
129 LOG_SENSOR(" ", "Y Axis", this->y_sensor_);
130 LOG_SENSOR(" ", "Z Axis", this->z_sensor_);
131 LOG_SENSOR(" ", "Temperature", this->t_sensor_);
132}
133
135 MLX90393::txyz data;
136
137 if (this->mlx_.readData(data) == MLX90393::STATUS_OK) {
138 ESP_LOGD(TAG, "received %f %f %f", data.x, data.y, data.z);
139 if (this->x_sensor_ != nullptr) {
140 this->x_sensor_->publish_state(data.x);
141 }
142 if (this->y_sensor_ != nullptr) {
143 this->y_sensor_->publish_state(data.y);
144 }
145 if (this->z_sensor_ != nullptr) {
146 this->z_sensor_->publish_state(data.z);
147 }
148 if (this->t_sensor_ != nullptr) {
149 this->t_sensor_->publish_state(data.t);
150 }
151 this->status_clear_warning();
152 } else {
153 ESP_LOGE(TAG, "failed to read data");
154 this->status_set_warning();
155 }
156}
157
159 uint8_t read_value = 0xFF;
160 uint8_t expected_value = 0xFF;
161 uint8_t read_status = -1;
162 char read_back_str[33] = {0};
163
164 switch (which) {
165 case MLX90393_GAIN_SEL: {
166 read_status = this->mlx_.getGainSel(read_value);
167 expected_value = this->gain_;
168 break;
169 }
170
171 case MLX90393_RESOLUTION: {
172 uint8_t read_resolutions[3] = {0xFF};
173 read_status = this->mlx_.getResolution(read_resolutions[0], read_resolutions[1], read_resolutions[2]);
174 snprintf(read_back_str, sizeof(read_back_str), "%u %u %u expected %u %u %u", read_resolutions[0],
175 read_resolutions[1], read_resolutions[2], this->resolutions_[0], this->resolutions_[1],
176 this->resolutions_[2]);
177 bool is_correct = true;
178 for (int i = 0; i < 3; i++) {
179 is_correct &= read_resolutions[i] == this->resolutions_[i];
180 }
181 if (is_correct) {
182 // set read_value and expected_value to same number, so the code blow recognizes it is correct
183 read_value = 0;
184 expected_value = 0;
185 } else {
186 // set to different numbers, to show incorrect
187 read_value = 1;
188 expected_value = 0;
189 }
190 break;
191 }
193 read_status = this->mlx_.getOverSampling(read_value);
194 expected_value = this->oversampling_;
195 break;
196 }
198 read_status = this->mlx_.getDigitalFiltering(read_value);
199 expected_value = this->filter_;
200 break;
201 }
203 read_status = this->mlx_.getTemperatureOverSampling(read_value);
204 expected_value = this->temperature_oversampling_;
205 break;
206 }
208 read_status = this->mlx_.getTemperatureCompensation(read_value);
209 expected_value = (bool) this->temperature_compensation_;
210 break;
211 }
212 case MLX90393_HALLCONF: {
213 read_status = this->mlx_.getHallConf(read_value);
214 expected_value = this->hallconf_;
215 break;
216 }
217 default: {
218 return false;
219 }
220 }
221 if (read_status != MLX90393::STATUS_OK) {
222 ESP_LOGE(TAG, "verify error: failed to read %s", LOG_STR_ARG(settings_to_string(which)));
223 return false;
224 }
225 if (read_back_str[0] == 0x0) {
226 snprintf(read_back_str, sizeof(read_back_str), "%u expected %u", read_value, expected_value);
227 }
228 bool is_correct = read_value == expected_value;
229 if (!is_correct) {
230 ESP_LOGW(TAG, "verify failed: read back wrong %s: got %s", LOG_STR_ARG(settings_to_string(which)), read_back_str);
231 return false;
232 }
233 ESP_LOGD(TAG, "verify succeeded for %s. got %s", LOG_STR_ARG(settings_to_string(which)), read_back_str);
234 return true;
235}
236
245 bool is_setting_ok = this->verify_setting_(stage);
246
247 if (!is_setting_ok) {
248 if (this->mlx_.checkStatus(this->mlx_.reset()) != MLX90393::STATUS_OK) {
249 ESP_LOGE(TAG, "failed to reset device");
250 this->status_set_error();
251 this->mark_failed();
252 return;
253 }
254
255 if (!this->apply_all_settings_()) {
256 ESP_LOGE(TAG, "failed to re-apply settings");
257 this->status_set_error();
258 this->mark_failed();
259 } else {
260 ESP_LOGI(TAG, "reset and re-apply settings completed");
261 }
262 }
263
264 MLX90393Setting next_stage = static_cast<MLX90393Setting>(static_cast<int>(stage) + 1);
265 if (next_stage == MLX90393_LAST) {
266 next_stage = static_cast<MLX90393Setting>(0);
267 }
268
269 this->set_timeout("verify settings", 3000, [this, next_stage]() { this->verify_settings_timeout_(next_stage); });
270}
271
272} // namespace esphome::mlx90393
void mark_failed()
Mark this component as failed.
bool is_failed() const
Definition component.h:272
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.h:493
void status_clear_warning()
Definition component.h:289
virtual bool digital_read()=0
ErrorCode write(const uint8_t *data, size_t len) const
writes an array of bytes to a device using an I2CBus
Definition i2c.h:183
ErrorCode read(uint8_t *data, size_t len) const
reads an array of bytes from the device using an I2CBus
Definition i2c.h:163
void sleep_micros(uint32_t micros) override
void sleep_millis(uint32_t millis) override
void verify_settings_timeout_(MLX90393Setting stage)
Regularly checks that our settings are still applied.
bool verify_setting_(MLX90393Setting which)
bool transceive(const uint8_t *request, size_t request_size, uint8_t *response, size_t response_size) override
uint8_t apply_setting_(MLX90393Setting which)
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:68
ErrorCode
Error codes returned by I2CBus and I2CDevice methods.
Definition i2c_bus.h:12
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:14
const LogString * settings_to_string(MLX90393Setting setting)
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition hal.cpp:48
uint32_t IRAM_ATTR HOT micros()
Definition hal.cpp:43
void HOT delay(uint32_t ms)
Definition hal.cpp:85
uint32_t IRAM_ATTR HOT millis()
Definition hal.cpp:28
static void uint32_t