ESPHome 2026.6.2
Loading...
Searching...
No Matches
xdb401.cpp
Go to the documentation of this file.
1#include "esphome/core/log.h"
3#include "xdb401.h"
4
5namespace esphome::xdb401 {
6
7static const char *const TAG = "xdb401";
8
9static const uint8_t REG_PRESSURE = 0x06;
10static const uint8_t REG_TEMPERATURE = 0x09;
11static const uint8_t REG_MAKE_MEASURE = 0x30;
12static const uint8_t CMD_MAKE_MEASURE = 0x0A;
13static const uint8_t MASK_MEASURE_READY = 0x08;
14static const float CONVERT_PRESSURE = 8388608.0f; // 0x800000
15
16static const uint32_t CHECK_DELAY = 5;
17static const uint8_t CHECK_ATTEMPTS = 6;
18static const uint8_t MARK_FAIL_AFTER = 5;
19
21 ESP_LOGCONFIG(TAG, "Running setup");
22
23 uint8_t meas_resp[1] = {};
24 i2c::ErrorCode err_code = this->read_register(REG_MAKE_MEASURE, meas_resp, sizeof(meas_resp));
25 if (err_code != i2c::ERROR_OK) {
26 this->mark_failed(LOG_STR("I2C communication failed"));
27 return;
28 }
29
30 this->comm_err_counter_ = 0;
31}
32
34 ESP_LOGCONFIG(TAG, "XDB401:");
35 LOG_I2C_DEVICE(this);
36 LOG_UPDATE_INTERVAL(this);
37 ESP_LOGCONFIG(TAG, " Pressure Range: %u bar", this->pressure_range_bar_);
38 LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
39 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
40}
41
43 this->status_set_warning(message);
44
45 if (this->comm_err_counter_ >= MARK_FAIL_AFTER) {
46 this->mark_failed(LOG_STR("Too many consecutive I2C communication errors"));
47 } else {
48 this->comm_err_counter_++;
49 }
50
51 this->measurement_in_progress_ = false;
52}
53
55 i2c::ErrorCode err_code = this->write_register(REG_MAKE_MEASURE, &CMD_MAKE_MEASURE, sizeof(CMD_MAKE_MEASURE));
56 if (err_code != i2c::ERROR_OK) {
57 ESP_LOGE(TAG, "Error starting measurement, code: %u", err_code);
58 return err_code;
59 }
60
61 return i2c::ERROR_OK;
62}
63
65 uint8_t meas_resp[1] = {};
66 i2c::ErrorCode err_code = this->read_register(REG_MAKE_MEASURE, meas_resp, sizeof(meas_resp));
67 if (err_code != i2c::ERROR_OK) {
68 ESP_LOGE(TAG, "Error reading measurement status, code: %u", err_code);
69 this->handle_comm_failure_("I2C communication failed");
70 return;
71 }
72
73 ESP_LOGV(TAG, "Config response %02X", meas_resp[0]);
74
75 // Bit 3 shall be 0 when measurement is ready
76 if ((meas_resp[0] & MASK_MEASURE_READY) == 0) {
77 ESP_LOGV(TAG, "Meas mode entered after %u ms", attempt * CHECK_DELAY);
78 this->read_measurement_();
79 return;
80 }
81
82 if (attempt >= CHECK_ATTEMPTS) {
83 ESP_LOGE(TAG, "Device not in measurement mode after timeout of %u ms", CHECK_DELAY * CHECK_ATTEMPTS);
84 this->handle_comm_failure_("Measurement timeout");
85 return;
86 }
87
88 this->set_timeout(CHECK_DELAY, [this, attempt]() { this->check_measurement_ready_(attempt + 1); });
89}
90
92 float temperature{};
93 float pressure{};
94
95 i2c::ErrorCode err_code = this->read_pressure_(pressure);
96 if (err_code != i2c::ERROR_OK) {
97 this->handle_comm_failure_("Could not read pressure data");
98 return;
99 }
100
101 err_code = this->read_temperature_(temperature);
102 if (err_code != i2c::ERROR_OK) {
103 this->handle_comm_failure_("Could not read temperature data");
104 return;
105 }
106
107 ESP_LOGD(TAG, "Got pressure=%.1f Pa, temperature=%.2f°C", pressure, temperature);
108
109 if (this->temperature_sensor_ != nullptr)
111 if (this->pressure_sensor_ != nullptr)
113
114 this->comm_err_counter_ = 0;
115 this->status_clear_warning();
116 this->measurement_in_progress_ = false;
117}
118
120 uint8_t p_data[3]{};
121 i2c::ErrorCode err_code = this->read_register(REG_PRESSURE, p_data, 3);
122 if (err_code != i2c::ERROR_OK) {
123 ESP_LOGE(TAG, "Error reading pressure register");
124 return err_code;
125 }
126 char pressure_buf[format_hex_pretty_size(3)];
127 format_hex_pretty_to(pressure_buf, sizeof(pressure_buf), p_data, 3);
128 ESP_LOGV(TAG, "Got pressure data: %s", pressure_buf);
129
130 // Sign-extend 24-bit big-endian pressure value to int32_t.
131 int32_t raw_pressure = static_cast<int32_t>(encode_uint24(p_data[0], p_data[1], p_data[2]) << 8) >> 8;
132 ESP_LOGD(TAG, "Pressure data raw %i", raw_pressure);
133
134 pressure = (static_cast<float>(raw_pressure) / CONVERT_PRESSURE) *
136
137 return err_code;
138}
139
141 uint8_t t_data[2]{};
142 i2c::ErrorCode err_code = this->read_register(REG_TEMPERATURE, t_data, 2);
143 if (err_code != i2c::ERROR_OK) {
144 ESP_LOGE(TAG, "Error reading temperature register");
145 return err_code;
146 }
147
148 char temperature_buf[format_hex_pretty_size(2)];
149 format_hex_pretty_to(temperature_buf, sizeof(temperature_buf), t_data, 2);
150 ESP_LOGV(TAG, "Got temperature data: %s", temperature_buf);
151
152 // Temperature is a signed 16-bit big-endian value in 1/256 °C (Q8.8 fixed point).
153 int16_t raw_temperature = static_cast<int16_t>(encode_uint16(t_data[0], t_data[1]));
154 ESP_LOGD(TAG, "Temperature data raw %i", raw_temperature);
155
156 temperature = static_cast<float>(raw_temperature) / 256.0f;
157
158 return err_code;
159}
160
162 if (this->measurement_in_progress_) {
163 ESP_LOGV(TAG, "Skipping update, measurement already in progress");
164 return;
165 }
166
167 i2c::ErrorCode err_code = this->start_measurement_();
168 if (err_code != i2c::ERROR_OK) {
169 this->handle_comm_failure_("I2C communication failed");
170 return;
171 }
172
173 this->measurement_in_progress_ = true;
174 this->set_timeout(CHECK_DELAY, [this]() { this->check_measurement_ready_(1); });
175}
176
177} // namespace esphome::xdb401
void mark_failed()
Mark this component as failed.
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
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len) const
writes an array of bytes to a specific register in the I²C device
Definition i2c.cpp:34
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:25
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:68
void handle_comm_failure_(const char *message)
Definition xdb401.cpp:42
sensor::Sensor * temperature_sensor_
Definition xdb401.h:33
i2c::ErrorCode start_measurement_()
Definition xdb401.cpp:54
i2c::ErrorCode read_temperature_(float &temperature)
Definition xdb401.cpp:140
static constexpr float full_scale_pressure_pa(uint8_t pressure_range_bar)
Definition xdb401.h:27
void check_measurement_ready_(uint8_t attempt)
Definition xdb401.cpp:64
sensor::Sensor * pressure_sensor_
Definition xdb401.h:34
i2c::ErrorCode read_pressure_(float &pressure)
Definition xdb401.cpp:119
const LogString * message
Definition component.cpp:35
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
constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3)
Encode a 24-bit value given three bytes in most to least significant byte order.
Definition helpers.h:863
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
Definition helpers.cpp:340
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
Definition helpers.h:1386
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:859
static void uint32_t
uint16_t temperature
Definition sun_gtil2.cpp:12
uint8_t pressure
Definition tt21100.cpp:7