mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-29 22:24:26 +00:00 
			
		
		
		
	Fix AHT10 / AHT20 communication (#5198)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -21,36 +21,49 @@ namespace esphome { | ||||
| namespace aht10 { | ||||
|  | ||||
| static const char *const TAG = "aht10"; | ||||
| static const uint8_t AHT10_CALIBRATE_CMD[] = {0xE1}; | ||||
| static const size_t SIZE_CALIBRATE_CMD = 3; | ||||
| static const uint8_t AHT10_CALIBRATE_CMD[] = {0xE1, 0x08, 0x00}; | ||||
| static const uint8_t AHT20_CALIBRATE_CMD[] = {0xBE, 0x08, 0x00}; | ||||
| static const uint8_t AHT10_MEASURE_CMD[] = {0xAC, 0x33, 0x00}; | ||||
| static const uint8_t AHT10_DEFAULT_DELAY = 5;    // ms, for calibration and temperature measurement | ||||
| static const uint8_t AHT10_HUMIDITY_DELAY = 30;  // ms | ||||
| static const uint8_t AHT10_ATTEMPTS = 3;         // safety margin, normally 3 attempts are enough: 3*30=90ms | ||||
| static const uint8_t AHT10_CAL_ATTEMPTS = 10; | ||||
| static const uint8_t AHT10_STATUS_BUSY = 0x80; | ||||
|  | ||||
| void AHT10Component::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up AHT10..."); | ||||
|   const uint8_t *calibrate_cmd; | ||||
|   switch (this->variant_) { | ||||
|     case AHT10Variant::AHT20: | ||||
|       calibrate_cmd = AHT20_CALIBRATE_CMD; | ||||
|       ESP_LOGCONFIG(TAG, "Setting up AHT20"); | ||||
|       break; | ||||
|     case AHT10Variant::AHT10: | ||||
|     default: | ||||
|       calibrate_cmd = AHT10_CALIBRATE_CMD; | ||||
|       ESP_LOGCONFIG(TAG, "Setting up AHT10"); | ||||
|   } | ||||
|  | ||||
|   if (!this->write_bytes(0, AHT10_CALIBRATE_CMD, sizeof(AHT10_CALIBRATE_CMD))) { | ||||
|   if (this->write(calibrate_cmd, SIZE_CALIBRATE_CMD) != i2c::ERROR_OK) { | ||||
|     ESP_LOGE(TAG, "Communication with AHT10 failed!"); | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|   uint8_t data = 0; | ||||
|   if (this->write(&data, 1) != i2c::ERROR_OK) { | ||||
|     ESP_LOGD(TAG, "Communication with AHT10 failed!"); | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|   delay(AHT10_DEFAULT_DELAY); | ||||
|   if (this->read(&data, 1) != i2c::ERROR_OK) { | ||||
|     ESP_LOGD(TAG, "Communication with AHT10 failed!"); | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|   if (this->read(&data, 1) != i2c::ERROR_OK) { | ||||
|     ESP_LOGD(TAG, "Communication with AHT10 failed!"); | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   uint8_t data = AHT10_STATUS_BUSY; | ||||
|   int cal_attempts = 0; | ||||
|   while (data & AHT10_STATUS_BUSY) { | ||||
|     delay(AHT10_DEFAULT_DELAY); | ||||
|     if (this->read(&data, 1) != i2c::ERROR_OK) { | ||||
|       ESP_LOGE(TAG, "Communication with AHT10 failed!"); | ||||
|       this->mark_failed(); | ||||
|       return; | ||||
|     } | ||||
|     ++cal_attempts; | ||||
|     if (cal_attempts > AHT10_CAL_ATTEMPTS) { | ||||
|       ESP_LOGE(TAG, "AHT10 calibration timed out!"); | ||||
|       this->mark_failed(); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   if ((data & 0x68) != 0x08) {  // Bit[6:5] = 0b00, NORMAL mode and Bit[3] = 0b1, CALIBRATED | ||||
|     ESP_LOGE(TAG, "AHT10 calibration failed!"); | ||||
| @@ -62,7 +75,7 @@ void AHT10Component::setup() { | ||||
| } | ||||
|  | ||||
| void AHT10Component::update() { | ||||
|   if (!this->write_bytes(0, AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD))) { | ||||
|   if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { | ||||
|     ESP_LOGE(TAG, "Communication with AHT10 failed!"); | ||||
|     this->status_set_warning(); | ||||
|     return; | ||||
| @@ -89,7 +102,7 @@ void AHT10Component::update() { | ||||
|         break; | ||||
|       } else { | ||||
|         ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying..."); | ||||
|         if (!this->write_bytes(0, AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD))) { | ||||
|         if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { | ||||
|           ESP_LOGE(TAG, "Communication with AHT10 failed!"); | ||||
|           this->status_set_warning(); | ||||
|           return; | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <utility> | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
| @@ -7,12 +9,15 @@ | ||||
| namespace esphome { | ||||
| namespace aht10 { | ||||
|  | ||||
| enum AHT10Variant { AHT10, AHT20 }; | ||||
|  | ||||
| class AHT10Component : public PollingComponent, public i2c::I2CDevice { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void update() override; | ||||
|   void dump_config() override; | ||||
|   float get_setup_priority() const override; | ||||
|   void set_variant(AHT10Variant variant) { this->variant_ = variant; } | ||||
|  | ||||
|   void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } | ||||
|   void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; } | ||||
| @@ -20,6 +25,7 @@ class AHT10Component : public PollingComponent, public i2c::I2CDevice { | ||||
|  protected: | ||||
|   sensor::Sensor *temperature_sensor_{nullptr}; | ||||
|   sensor::Sensor *humidity_sensor_{nullptr}; | ||||
|   AHT10Variant variant_{}; | ||||
| }; | ||||
|  | ||||
| }  // namespace aht10 | ||||
|   | ||||
| @@ -10,6 +10,7 @@ from esphome.const import ( | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     UNIT_PERCENT, | ||||
|     CONF_VARIANT, | ||||
| ) | ||||
|  | ||||
| DEPENDENCIES = ["i2c"] | ||||
| @@ -17,6 +18,12 @@ DEPENDENCIES = ["i2c"] | ||||
| aht10_ns = cg.esphome_ns.namespace("aht10") | ||||
| AHT10Component = aht10_ns.class_("AHT10Component", cg.PollingComponent, i2c.I2CDevice) | ||||
|  | ||||
| AHT10Variant = aht10_ns.enum("AHT10Variant") | ||||
| AHT10_VARIANTS = { | ||||
|     "AHT10": AHT10Variant.AHT10, | ||||
|     "AHT20": AHT10Variant.AHT20, | ||||
| } | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cv.Schema( | ||||
|         { | ||||
| @@ -33,6 +40,9 @@ CONFIG_SCHEMA = ( | ||||
|                 device_class=DEVICE_CLASS_HUMIDITY, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_VARIANT, default="AHT10"): cv.enum( | ||||
|                 AHT10_VARIANTS, upper=True | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.polling_component_schema("60s")) | ||||
| @@ -44,6 +54,7 @@ async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|     await i2c.register_i2c_device(var, config) | ||||
|     cg.add(var.set_variant(config[CONF_VARIANT])) | ||||
|  | ||||
|     if temperature := config.get(CONF_TEMPERATURE): | ||||
|         sens = await sensor.new_sensor(temperature) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user