11 static const char *
const TAG =
"ms8607";
14 static const uint8_t MS8607_PT_CMD_RESET = 0x1E;
18 static const uint8_t MS8607_PROM_START = 0xA0;
20 static const uint8_t MS8607_PROM_END = 0xAE;
22 static const uint8_t MS8607_PROM_COUNT = (MS8607_PROM_END - MS8607_PROM_START) >> 1;
25 static const uint8_t MS8607_CMD_H_RESET = 0xFE;
27 static const uint8_t MS8607_CMD_H_MEASURE_NO_HOLD = 0xF5;
29 static const float MS8607_H_TEMP_COEFFICIENT = -0.18;
32 static const uint8_t MS8607_CMD_ADC_READ = 0x00;
38 static const uint8_t MS8607_CMD_CONV_D1_OSR_8K = 0x4A;
40 static const uint8_t MS8607_CMD_CONV_D2_OSR_8K = 0x5A;
66 static uint8_t crc4(uint16_t *buffer,
size_t length);
67 static uint8_t hsensor_crc_check(uint16_t value);
70 ESP_LOGCONFIG(TAG,
"Setting up MS8607...");
78 [
this](
const uint8_t remaining_setup_attempts) {
79 ESP_LOGD(TAG,
"Resetting both I2C addresses: 0x%02X, 0x%02X", this->
address_,
84 bool const pt_successful = this->
write_bytes(MS8607_PT_CMD_RESET,
nullptr, 0);
87 if (!(pt_successful && h_successful)) {
88 ESP_LOGE(TAG,
"Resetting I2C devices failed");
89 if (!pt_successful && !h_successful) {
91 }
else if (!pt_successful) {
97 if (remaining_setup_attempts > 0) {
138 ESP_LOGCONFIG(TAG,
"MS8607:");
139 LOG_I2C_DEVICE(
this);
143 ESP_LOGE(TAG,
"Communication with MS8607 failed.");
146 ESP_LOGE(TAG,
"Temperature/Pressure RESET failed");
149 ESP_LOGE(TAG,
"Humidity RESET failed");
152 ESP_LOGE(TAG,
"Temperature/Pressure && Humidity RESET failed");
155 ESP_LOGE(TAG,
"Reading PROM failed");
158 ESP_LOGE(TAG,
"PROM values failed CRC");
162 ESP_LOGE(TAG,
"Error reason unknown %u", static_cast<uint8_t>(this->
error_code_));
166 LOG_UPDATE_INTERVAL(
this);
173 ESP_LOGD(TAG,
"Reading calibration values from PROM");
175 uint16_t buffer[MS8607_PROM_COUNT];
176 bool successful =
true;
178 for (uint8_t idx = 0; idx < MS8607_PROM_COUNT; ++idx) {
179 uint8_t
const address_to_read = MS8607_PROM_START + (idx * 2);
180 successful &= this->
read_byte_16(address_to_read, &buffer[idx]);
184 ESP_LOGE(TAG,
"Reading calibration values from PROM failed");
189 ESP_LOGD(TAG,
"Checking CRC of calibration values from PROM");
190 uint8_t
const expected_crc = (buffer[0] & 0xF000) >> 12;
192 uint8_t
const actual_crc = crc4(buffer, MS8607_PROM_COUNT);
194 if (expected_crc != actual_crc) {
195 ESP_LOGE(TAG,
"Incorrect CRC value. Provided value 0x%01X != calculated value 0x%01X", expected_crc, actual_crc);
206 ESP_LOGD(TAG,
"Finished reading calibration values");
219 static uint8_t crc4(uint16_t *buffer,
size_t length) {
220 uint16_t crc_remainder = 0;
223 auto apply_crc = [&crc_remainder](uint8_t next) {
224 crc_remainder ^= next;
225 for (uint8_t bit = 8; bit > 0; --bit) {
226 if (crc_remainder & 0x8000) {
227 crc_remainder = (crc_remainder << 1) ^ 0x3000;
229 crc_remainder = (crc_remainder << 1);
235 for (
size_t idx = 0; idx <
length; ++idx) {
244 return (crc_remainder >> 12) & 0xF;
256 static uint8_t hsensor_crc_check(uint16_t value) {
257 uint32_t polynom = 0x988000;
258 uint32_t msb = 0x800000;
259 uint32_t mask = 0xFF8000;
260 uint32_t result = (uint32_t) value << 8;
262 while (msb != 0x80) {
265 result = ((result ^ polynom) & mask) | (result & ~mask);
273 return result & 0xFF;
278 if (!this->
write_bytes(MS8607_CMD_CONV_D2_OSR_8K,
nullptr, 0)) {
290 if (!this->
read_bytes(MS8607_CMD_ADC_READ, bytes, 3)) {
295 const uint32_t d2_raw_temperature =
encode_uint32(0, bytes[0], bytes[1], bytes[2]);
300 if (!this->
write_bytes(MS8607_CMD_CONV_D1_OSR_8K,
nullptr, 0)) {
312 if (!this->
read_bytes(MS8607_CMD_ADC_READ, bytes, 3)) {
316 const uint32_t d1_raw_pressure =
encode_uint32(0, bytes[0], bytes[1], bytes[2]);
322 ESP_LOGW(TAG,
"Request to measure humidity failed");
335 ESP_LOGW(TAG,
"Failed to read the measured humidity value");
343 uint8_t
const expected_crc = bytes[2];
344 uint8_t
const actual_crc = hsensor_crc_check(humidity);
345 if (expected_crc != actual_crc) {
346 ESP_LOGE(TAG,
"Incorrect Humidity CRC value. Provided value 0x%01X != calculated value 0x%01X", expected_crc,
351 if (!(humidity & 0x2)) {
353 ESP_LOGE(TAG,
"Humidity status bit was not set to 1?");
358 float const humidity_partial = double(humidity) / (1 << 16);
359 float const humidity_percentage =
lerp(humidity_partial, -6.0, 118.0);
360 float const compensated_humidity_percentage =
361 humidity_percentage + (20 - temperature_float) * MS8607_H_TEMP_COEFFICIENT;
362 ESP_LOGD(TAG,
"Compensated for temperature, humidity=%.2f%%", compensated_humidity_percentage);
384 int64_t pressure_sensitivity =
389 const int64_t d_t_squared = int64_t(d_t) * d_t;
390 int64_t temperature_2 = 0;
391 int32_t pressure_offset_2 = 0;
392 int32_t pressure_sensitivity_2 = 0;
393 if (temperature < 2000) {
395 const int32_t low_temperature_adjustment = (temperature - 2000) * (temperature - 2000) >> 4;
398 temperature_2 = (3 * d_t_squared) >> 33;
400 pressure_offset_2 = 61 * low_temperature_adjustment;
402 pressure_sensitivity_2 = 29 * low_temperature_adjustment;
404 if (temperature < -1500) {
406 const int32_t very_low_temperature_adjustment = (temperature + 1500) * (temperature + 1500);
409 pressure_offset_2 += 17 * very_low_temperature_adjustment;
411 pressure_sensitivity_2 += 9 * very_low_temperature_adjustment;
415 temperature_2 = (5 * d_t_squared) >> 38;
418 temperature -= temperature_2;
419 pressure_offset -= pressure_offset_2;
420 pressure_sensitivity -= pressure_sensitivity_2;
423 const int32_t
pressure = (((d1_raw_pressure * pressure_sensitivity) >> 21) - pressure_offset) >> 15;
425 const float temperature_float = temperature / 100.0f;
426 const float pressure_float = pressure / 100.0f;
427 ESP_LOGD(TAG,
"Temperature=%0.2f°C, Pressure=%0.2fhPa", temperature_float, pressure_float);
bool read_byte_16(uint8_t a_register, uint16_t *data)
This component has not successfully reset the PT & H devices.
Successfully read PROM and ready to update sensors.
void status_set_warning(const char *message="unspecified")
Both the Pressure/Temperature address and the Humidity address failed to reset.
void read_humidity_(float temperature_float)
process async humidity read
uint16_t pressure_sensitivity_temperature_coefficient
Temperature coefficient of pressure sensitivity | TCS. [C3].
uint16_t temperature_coefficient_of_temperature
Temperature coefficient of the temperature | TEMPSENS. [C6].
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
bool read_bytes(uint8_t a_register, uint8_t *data, uint8_t len)
Compat APIs All methods below have been added for compatibility reasons.
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.
float lerp(float completion, float start, float end)
Linearly interpolate between start and end by completion (between 0 and 1).
void request_read_pressure_(uint32_t raw_temperature)
start async pressure read
bool read_bytes_raw(uint8_t *data, uint8_t len)
sensor::Sensor * pressure_sensor_
ErrorCode error_code_
Keep track of the reason why this component failed, to augment the dumped config. ...
uint16_t reference_temperature
Reference temperature | T-REF. [C5].
uint16_t pressure_sensitivity
Pressure sensitivity | SENS-T1. [C1].
void set_retry(const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts, std::function< RetryResult(uint8_t)> &&f, float backoff_increase_factor=1.0f)
Set an retry function with a unique name.
void status_set_error(const char *message="unspecified")
uint16_t pressure_offset
Pressure offset | OFF-T1. [C2].
sensor::Sensor * temperature_sensor_
struct esphome::ms8607::MS8607Component::CalibrationValues calibration_values_
sensor::Sensor * humidity_sensor_
void status_clear_warning()
constexpr14 std::array< uint8_t, sizeof(T)> decode_value(T val)
Decode a value into its constituent bytes (from most to least significant).
Reading the PROM calibration values failed.
void request_read_temperature_()
Start async temperature read.
void publish_state(float state)
Publish a new state to the front-end.
The PROM calibration values failed the CRC check.
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Component hasn't failed (yet?)
uint8_t address_
store the address of the device on the bus
void status_clear_error()
Asking the Pressure/Temperature sensor to reset failed.
void calculate_values_(uint32_t raw_temperature, uint32_t raw_pressure)
use raw temperature & pressure to calculate & publish values
SetupStatus setup_status_
Current step in the multi-step & possibly delayed setup() process.
virtual void mark_failed()
Mark this component as failed.
uint16_t pressure_offset_temperature_coefficient
Temperature coefficient of pressure offset | TCO. [C4].
Asking the Humidity sensor to reset failed.
MS8607HumidityDevice * humidity_device_
I2CDevice object to communicate with secondary I2C address for the humidity sensor.
Implementation of SPI Controller mode.
void dump_config() override
std::vector< uint8_t > bytes
Reset commands succeeded, need to wait >= 15ms to read PROM.
void read_pressure_(uint32_t raw_temperature)
process async pressure read
void request_read_humidity_(float temperature_float)
start async humidity read
void read_temperature_()
Process async temperature read.
bool read_calibration_values_from_prom_()
Read and store the Pressure & Temperature calibration settings from the PROM.
bool write_bytes(uint8_t a_register, const uint8_t *data, uint8_t len, bool stop=true)