ESPHome 2025.6.0
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
htu31d.cpp
Go to the documentation of this file.
1/*
2 * This file contains source code derived from Adafruit_HTU31D which is under
3 * the BSD license:
4 * Written by Limor Fried/Ladyada for Adafruit Industries.
5 * BSD license, all text above must be included in any redistribution.
6 *
7 * Modifications made by Mark Spicer.
8 */
9
10#include "htu31d.h"
11#include "esphome/core/hal.h"
13#include "esphome/core/log.h"
14
15#include <cinttypes>
16
17namespace esphome {
18namespace htu31d {
19
21static const char *const TAG = "htu31d";
22
24static const uint8_t HTU31D_DEFAULT_I2CADDR = 0x40;
25
27static const uint8_t HTU31D_READTEMPHUM = 0x00;
28
30static const uint8_t HTU31D_CONVERSION = 0x40;
31
33static const uint8_t HTU31D_READSERIAL = 0x0A;
34
36static const uint8_t HTU31D_HEATERON = 0x04;
37
39static const uint8_t HTU31D_HEATEROFF = 0x02;
40
42static const uint8_t HTU31D_RESET = 0x1E;
43
45static const uint8_t HTU31D_DIAGNOSTICS = 0x08;
46
52uint8_t compute_crc(uint32_t value) {
53 uint32_t polynom = 0x98800000; // x^8 + x^5 + x^4 + 1
54 uint32_t msb = 0x80000000;
55 uint32_t mask = 0xFF800000;
56 uint32_t threshold = 0x00000080;
57 uint32_t result = value;
58
59 while (msb != threshold) {
60 // Check if msb of current value is 1 and apply XOR mask
61 if (result & msb)
62 result = ((result ^ polynom) & mask) | (result & ~mask);
63
64 // Shift by one
65 msb >>= 1;
66 mask >>= 1;
67 polynom >>= 1;
68 }
69
70 return result;
71}
72
78 ESP_LOGCONFIG(TAG, "Running setup");
79
80 if (!this->reset_()) {
81 this->mark_failed();
82 return;
83 }
84
85 if (this->read_serial_num_() == 0) {
86 this->mark_failed();
87 return;
88 }
89}
90
96 ESP_LOGD(TAG, "Checking temperature and humidty values");
97
98 // Trigger a conversion. From the spec sheet: The conversion command triggers
99 // a single temperature and humidity conversion.
100 if (this->write_register(HTU31D_CONVERSION, nullptr, 0) != i2c::ERROR_OK) {
101 this->status_set_warning();
102 ESP_LOGE(TAG, "Received errror writing conversion register");
103 return;
104 }
105
106 // Wait conversion time.
107 this->set_timeout(20, [this]() {
108 uint8_t thdata[6];
109 if (this->read_register(HTU31D_READTEMPHUM, thdata, 6) != i2c::ERROR_OK) {
110 this->status_set_warning();
111 ESP_LOGE(TAG, "Error reading temperature/humidty register");
112 return;
113 }
114
115 // Calculate temperature value.
116 uint16_t raw_temp = encode_uint16(thdata[0], thdata[1]);
117
118 uint8_t crc = compute_crc((uint32_t) raw_temp << 8);
119 if (crc != thdata[2]) {
120 this->status_set_warning();
121 ESP_LOGE(TAG, "Error validating temperature CRC");
122 return;
123 }
124
125 float temperature = raw_temp;
126 temperature /= 65535.0f;
127 temperature *= 165;
128 temperature -= 40;
129
130 if (this->temperature_ != nullptr) {
131 this->temperature_->publish_state(temperature);
132 }
133
134 // Calculate humidty value.
135 uint16_t raw_hum = encode_uint16(thdata[3], thdata[4]);
136
137 crc = compute_crc((uint32_t) raw_hum << 8);
138 if (crc != thdata[5]) {
139 this->status_set_warning();
140 ESP_LOGE(TAG, "Error validating humidty CRC");
141 return;
142 }
143
144 float humidity = raw_hum;
145 humidity /= 65535.0f;
146 humidity *= 100;
147
148 if (this->humidity_ != nullptr) {
149 this->humidity_->publish_state(humidity);
150 }
151
152 ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%%", temperature, humidity);
153 this->status_clear_warning();
154 });
155}
156
161 ESP_LOGCONFIG(TAG, "HTU31D:");
162 LOG_I2C_DEVICE(this);
163 if (this->is_failed()) {
164 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
165 }
166 LOG_UPDATE_INTERVAL(this);
167 LOG_SENSOR(" ", "Temperature", this->temperature_);
168 LOG_SENSOR(" ", "Humidity", this->humidity_);
169}
170
177 if (this->write_register(HTU31D_RESET, nullptr, 0) != i2c::ERROR_OK) {
178 return false;
179 }
180
181 delay(15);
182 return true;
183}
184
191 uint8_t reply[4];
192 uint32_t serial = 0;
193 uint8_t padding = 0;
194
195 // Verify we can read the device serial.
196 if (this->read_register(HTU31D_READSERIAL, reply, 4) != i2c::ERROR_OK) {
197 ESP_LOGE(TAG, "Error reading device serial");
198 return 0;
199 }
200
201 serial = encode_uint32(reply[0], reply[1], reply[2], padding);
202
203 uint8_t crc = compute_crc(serial);
204 if (crc != reply[3]) {
205 ESP_LOGE(TAG, "Error validating serial CRC");
206 return 0;
207 }
208
209 ESP_LOGD(TAG, "Found serial: 0x%" PRIX32, serial);
210
211 return serial;
212}
213
221 uint8_t reply[1];
222 uint8_t heater_enabled_position = 0;
223 uint8_t mask = 1 << heater_enabled_position;
224 uint8_t diagnostics = 0;
225
226 if (this->read_register(HTU31D_DIAGNOSTICS, reply, 1) != i2c::ERROR_OK) {
227 ESP_LOGE(TAG, "Error reading device serial");
228 return false;
229 }
230
231 diagnostics = reply[0];
232 return (diagnostics & mask) != 0;
233}
234
241 bool current = this->is_heater_enabled();
242
243 // If the current state matches the desired state, there is nothing to do.
244 if (current == desired) {
245 return;
246 }
247
248 // Update heater state.
250 if (desired) {
251 err = this->write_register(HTU31D_HEATERON, nullptr, 0);
252 } else {
253 err = this->write_register(HTU31D_HEATEROFF, nullptr, 0);
254 }
255
256 // Record any error.
257 if (err != i2c::ERROR_OK) {
258 this->status_set_warning();
259 ESP_LOGE(TAG, "Received error updating heater state");
260 return;
261 }
262}
263
270} // namespace htu31d
271} // namespace esphome
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
void update() override
Setup (reset) the sensor and check connection.
Definition htu31d.cpp:95
uint32_t read_serial_num_()
Reads the serial number from the device and checks the CRC.
Definition htu31d.cpp:190
sensor::Sensor * temperature_
Definition htu31d.h:29
void setup() override
Resets the sensor and ensures that the devices serial number can be read over I2C.
Definition htu31d.cpp:77
float get_setup_priority() const override
Sets the startup priority for this component.
Definition htu31d.cpp:269
sensor::Sensor * humidity_
Definition htu31d.h:30
bool is_heater_enabled()
Checks the diagnostics register to determine if the heater is currently enabled.
Definition htu31d.cpp:220
void set_heater_state(bool desired)
Sets the heater state on or off.
Definition htu31d.cpp:240
bool reset_()
Sends a 'reset' request to the HTU31D, followed by a 15ms delay.
Definition htu31d.cpp:176
void dump_config() override
Update the sensor values (temperature+humidity).
Definition htu31d.cpp:160
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 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
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:39
u_int8_t raw_temp
uint8_t compute_crc(uint32_t value)
Computes a CRC result for the provided input.
Definition htu31d.cpp:52
ErrorCode
Error codes returned by I2CBus and I2CDevice methods.
Definition i2c_bus.h:11
@ 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
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition helpers.h:200
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:192
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:29
uint16_t temperature
Definition sun_gtil2.cpp:12