mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	| @@ -36,6 +36,7 @@ static const uint8_t AHT10_INIT_ATTEMPTS = 10; | |||||||
| static const uint8_t AHT10_STATUS_BUSY = 0x80; | static const uint8_t AHT10_STATUS_BUSY = 0x80; | ||||||
|  |  | ||||||
| void AHT10Component::setup() { | void AHT10Component::setup() { | ||||||
|  |   this->read_delay_ = this->humidity_sensor_ != nullptr ? AHT10_HUMIDITY_DELAY : AHT10_DEFAULT_DELAY; | ||||||
|   if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) { |   if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) { | ||||||
|     ESP_LOGE(TAG, "Reset AHT10 failed!"); |     ESP_LOGE(TAG, "Reset AHT10 failed!"); | ||||||
|   } |   } | ||||||
| @@ -83,74 +84,78 @@ void AHT10Component::setup() { | |||||||
|   ESP_LOGV(TAG, "AHT10 initialization"); |   ESP_LOGV(TAG, "AHT10 initialization"); | ||||||
| } | } | ||||||
|  |  | ||||||
| void AHT10Component::update() { | void AHT10Component::restart_read_() { | ||||||
|   if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { |   if (this->read_count_ == AHT10_ATTEMPTS) { | ||||||
|     ESP_LOGE(TAG, "Communication with AHT10 failed!"); |     this->read_count_ = 0; | ||||||
|     this->status_set_warning(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   uint8_t data[6]; |  | ||||||
|   uint8_t delay_ms = AHT10_DEFAULT_DELAY; |  | ||||||
|   if (this->humidity_sensor_ != nullptr) |  | ||||||
|     delay_ms = AHT10_HUMIDITY_DELAY; |  | ||||||
|   bool success = false; |  | ||||||
|   for (int i = 0; i < AHT10_ATTEMPTS; ++i) { |  | ||||||
|     ESP_LOGVV(TAG, "Attempt %d at %6" PRIu32, i, millis()); |  | ||||||
|     delay(delay_ms); |  | ||||||
|     if (this->read(data, 6) != i2c::ERROR_OK) { |  | ||||||
|       ESP_LOGD(TAG, "Communication with AHT10 failed, waiting..."); |  | ||||||
|       continue; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if ((data[0] & 0x80) == 0x80) {  // Bit[7] = 0b1, device is busy |  | ||||||
|       ESP_LOGD(TAG, "AHT10 is busy, waiting..."); |  | ||||||
|     } else if (data[1] == 0x0 && data[2] == 0x0 && (data[3] >> 4) == 0x0) { |  | ||||||
|       // Unrealistic humidity (0x0) |  | ||||||
|       if (this->humidity_sensor_ == nullptr) { |  | ||||||
|         ESP_LOGVV(TAG, "ATH10 Unrealistic humidity (0x0), but humidity is not required"); |  | ||||||
|         break; |  | ||||||
|       } else { |  | ||||||
|         ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying..."); |  | ||||||
|         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; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } else { |  | ||||||
|       // data is valid, we can break the loop |  | ||||||
|       ESP_LOGVV(TAG, "Answer at %6" PRIu32, millis()); |  | ||||||
|       success = true; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   if (!success || (data[0] & 0x80) == 0x80) { |  | ||||||
|     ESP_LOGE(TAG, "Measurements reading timed-out!"); |     ESP_LOGE(TAG, "Measurements reading timed-out!"); | ||||||
|     this->status_set_warning(); |     this->status_set_error(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   this->read_count_++; | ||||||
|  |   this->set_timeout(this->read_delay_, [this]() { this->read_data_(); }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AHT10Component::read_data_() { | ||||||
|  |   uint8_t data[6]; | ||||||
|  |   ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_)); | ||||||
|  |   if (this->read(data, 6) != i2c::ERROR_OK) { | ||||||
|  |     ESP_LOGD(TAG, "Communication with AHT10 failed, waiting..."); | ||||||
|  |     this->restart_read_(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   if ((data[0] & 0x80) == 0x80) {  // Bit[7] = 0b1, device is busy | ||||||
|  |     ESP_LOGD(TAG, "AHT10 is busy, waiting..."); | ||||||
|  |     this->restart_read_(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (data[1] == 0x0 && data[2] == 0x0 && (data[3] >> 4) == 0x0) { | ||||||
|  |     // Unrealistic humidity (0x0) | ||||||
|  |     if (this->humidity_sensor_ == nullptr) { | ||||||
|  |       ESP_LOGV(TAG, "ATH10 Unrealistic humidity (0x0), but humidity is not required"); | ||||||
|  |     } else { | ||||||
|  |       ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying..."); | ||||||
|  |       if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { | ||||||
|  |         ESP_LOGE(TAG, "Communication with AHT10 failed!"); | ||||||
|  |         this->status_set_warning(); | ||||||
|  |       } | ||||||
|  |       this->restart_read_(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_)); | ||||||
|   uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; |   uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; | ||||||
|   uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4; |   uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4; | ||||||
|  |  | ||||||
|   float temperature = ((200.0f * (float) raw_temperature) / 1048576.0f) - 50.0f; |  | ||||||
|   float humidity; |  | ||||||
|   if (raw_humidity == 0) {  // unrealistic value |  | ||||||
|     humidity = NAN; |  | ||||||
|   } else { |  | ||||||
|     humidity = (float) raw_humidity * 100.0f / 1048576.0f; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (this->temperature_sensor_ != nullptr) { |   if (this->temperature_sensor_ != nullptr) { | ||||||
|  |     float temperature = ((200.0f * (float) raw_temperature) / 1048576.0f) - 50.0f; | ||||||
|     this->temperature_sensor_->publish_state(temperature); |     this->temperature_sensor_->publish_state(temperature); | ||||||
|   } |   } | ||||||
|   if (this->humidity_sensor_ != nullptr) { |   if (this->humidity_sensor_ != nullptr) { | ||||||
|  |     float humidity; | ||||||
|  |     if (raw_humidity == 0) {  // unrealistic value | ||||||
|  |       humidity = NAN; | ||||||
|  |     } else { | ||||||
|  |       humidity = (float) raw_humidity * 100.0f / 1048576.0f; | ||||||
|  |     } | ||||||
|     if (std::isnan(humidity)) { |     if (std::isnan(humidity)) { | ||||||
|       ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum"); |       ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum"); | ||||||
|     } |     } | ||||||
|     this->humidity_sensor_->publish_state(humidity); |     this->humidity_sensor_->publish_state(humidity); | ||||||
|   } |   } | ||||||
|   this->status_clear_warning(); |   this->status_clear_warning(); | ||||||
|  |   this->read_count_ = 0; | ||||||
|  | } | ||||||
|  | void AHT10Component::update() { | ||||||
|  |   if (this->read_count_ != 0) | ||||||
|  |     return; | ||||||
|  |   this->start_time_ = millis(); | ||||||
|  |   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; | ||||||
|  |   } | ||||||
|  |   this->restart_read_(); | ||||||
| } | } | ||||||
|  |  | ||||||
| float AHT10Component::get_setup_priority() const { return setup_priority::DATA; } | float AHT10Component::get_setup_priority() const { return setup_priority::DATA; } | ||||||
|   | |||||||
| @@ -26,6 +26,11 @@ class AHT10Component : public PollingComponent, public i2c::I2CDevice { | |||||||
|   sensor::Sensor *temperature_sensor_{nullptr}; |   sensor::Sensor *temperature_sensor_{nullptr}; | ||||||
|   sensor::Sensor *humidity_sensor_{nullptr}; |   sensor::Sensor *humidity_sensor_{nullptr}; | ||||||
|   AHT10Variant variant_{}; |   AHT10Variant variant_{}; | ||||||
|  |   unsigned read_count_{}; | ||||||
|  |   unsigned read_delay_{}; | ||||||
|  |   void read_data_(); | ||||||
|  |   void restart_read_(); | ||||||
|  |   uint32_t start_time_{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace aht10 | }  // namespace aht10 | ||||||
|   | |||||||
| @@ -44,6 +44,11 @@ def default_url(config): | |||||||
|             config[CONF_CSS_URL] = "" |             config[CONF_CSS_URL] = "" | ||||||
|         if not (CONF_JS_URL in config): |         if not (CONF_JS_URL in config): | ||||||
|             config[CONF_JS_URL] = "https://oi.esphome.io/v2/www.js" |             config[CONF_JS_URL] = "https://oi.esphome.io/v2/www.js" | ||||||
|  |     if config[CONF_VERSION] == 3: | ||||||
|  |         if not (CONF_CSS_URL in config): | ||||||
|  |             config[CONF_CSS_URL] = "" | ||||||
|  |         if not (CONF_JS_URL in config): | ||||||
|  |             config[CONF_JS_URL] = "https://oi.esphome.io/v3/www.js" | ||||||
|     return config |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -64,7 +69,7 @@ CONFIG_SCHEMA = cv.All( | |||||||
|         { |         { | ||||||
|             cv.GenerateID(): cv.declare_id(WebServer), |             cv.GenerateID(): cv.declare_id(WebServer), | ||||||
|             cv.Optional(CONF_PORT, default=80): cv.port, |             cv.Optional(CONF_PORT, default=80): cv.port, | ||||||
|             cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, int=True), |             cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, 3, int=True), | ||||||
|             cv.Optional(CONF_CSS_URL): cv.string, |             cv.Optional(CONF_CSS_URL): cv.string, | ||||||
|             cv.Optional(CONF_CSS_INCLUDE): cv.file_, |             cv.Optional(CONF_CSS_INCLUDE): cv.file_, | ||||||
|             cv.Optional(CONF_JS_URL): cv.string, |             cv.Optional(CONF_JS_URL): cv.string, | ||||||
| @@ -152,7 +157,7 @@ async def to_code(config): | |||||||
|     cg.add_define("USE_WEBSERVER") |     cg.add_define("USE_WEBSERVER") | ||||||
|     cg.add_define("USE_WEBSERVER_PORT", config[CONF_PORT]) |     cg.add_define("USE_WEBSERVER_PORT", config[CONF_PORT]) | ||||||
|     cg.add_define("USE_WEBSERVER_VERSION", version) |     cg.add_define("USE_WEBSERVER_VERSION", version) | ||||||
|     if version == 2: |     if version >= 2: | ||||||
|         # Don't compress the index HTML as the data sizes are almost the same. |         # Don't compress the index HTML as the data sizes are almost the same. | ||||||
|         add_resource_as_progmem("INDEX_HTML", build_index_html(config), compress=False) |         add_resource_as_progmem("INDEX_HTML", build_index_html(config), compress=False) | ||||||
|     else: |     else: | ||||||
|   | |||||||
| @@ -358,7 +358,7 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { | |||||||
|   stream->print(F("</article></body></html>")); |   stream->print(F("</article></body></html>")); | ||||||
|   request->send(stream); |   request->send(stream); | ||||||
| } | } | ||||||
| #elif USE_WEBSERVER_VERSION == 2 | #elif USE_WEBSERVER_VERSION >= 2 | ||||||
| void WebServer::handle_index_request(AsyncWebServerRequest *request) { | void WebServer::handle_index_request(AsyncWebServerRequest *request) { | ||||||
|   AsyncWebServerResponse *response = |   AsyncWebServerResponse *response = | ||||||
|       request->beginResponse_P(200, "text/html", ESPHOME_WEBSERVER_INDEX_HTML, ESPHOME_WEBSERVER_INDEX_HTML_SIZE); |       request->beginResponse_P(200, "text/html", ESPHOME_WEBSERVER_INDEX_HTML, ESPHOME_WEBSERVER_INDEX_HTML_SIZE); | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ | |||||||
| #include <freertos/semphr.h> | #include <freertos/semphr.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if USE_WEBSERVER_VERSION == 2 | #if USE_WEBSERVER_VERSION >= 2 | ||||||
| extern const uint8_t ESPHOME_WEBSERVER_INDEX_HTML[] PROGMEM; | extern const uint8_t ESPHOME_WEBSERVER_INDEX_HTML[] PROGMEM; | ||||||
| extern const size_t ESPHOME_WEBSERVER_INDEX_HTML_SIZE; | extern const size_t ESPHOME_WEBSERVER_INDEX_HTML_SIZE; | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| """Constants used by esphome.""" | """Constants used by esphome.""" | ||||||
|  |  | ||||||
| __version__ = "2024.3.0b4" | __version__ = "2024.3.0b5" | ||||||
|  |  | ||||||
| ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" | ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" | ||||||
| VALID_SUBSTITUTIONS_CHARACTERS = ( | VALID_SUBSTITUTIONS_CHARACTERS = ( | ||||||
|   | |||||||
| @@ -141,18 +141,35 @@ bool Component::is_ready() { | |||||||
|          (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_SETUP; |          (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_SETUP; | ||||||
| } | } | ||||||
| bool Component::can_proceed() { return true; } | bool Component::can_proceed() { return true; } | ||||||
| bool Component::status_has_warning() { return this->component_state_ & STATUS_LED_WARNING; } | bool Component::status_has_warning() const { return this->component_state_ & STATUS_LED_WARNING; } | ||||||
| bool Component::status_has_error() { return this->component_state_ & STATUS_LED_ERROR; } | bool Component::status_has_error() const { return this->component_state_ & STATUS_LED_ERROR; } | ||||||
| void Component::status_set_warning() { | void Component::status_set_warning(const char *message) { | ||||||
|  |   // Don't spam the log. This risks missing different warning messages though. | ||||||
|  |   if ((this->component_state_ & STATUS_LED_WARNING) != 0) | ||||||
|  |     return; | ||||||
|   this->component_state_ |= STATUS_LED_WARNING; |   this->component_state_ |= STATUS_LED_WARNING; | ||||||
|   App.app_state_ |= STATUS_LED_WARNING; |   App.app_state_ |= STATUS_LED_WARNING; | ||||||
|  |   ESP_LOGW(this->get_component_source(), "Warning set: %s", message); | ||||||
| } | } | ||||||
| void Component::status_set_error() { | void Component::status_set_error(const char *message) { | ||||||
|  |   if ((this->component_state_ & STATUS_LED_ERROR) != 0) | ||||||
|  |     return; | ||||||
|   this->component_state_ |= STATUS_LED_ERROR; |   this->component_state_ |= STATUS_LED_ERROR; | ||||||
|   App.app_state_ |= STATUS_LED_ERROR; |   App.app_state_ |= STATUS_LED_ERROR; | ||||||
|  |   ESP_LOGE(this->get_component_source(), "Error set: %s", message); | ||||||
|  | } | ||||||
|  | void Component::status_clear_warning() { | ||||||
|  |   if ((this->component_state_ & STATUS_LED_WARNING) == 0) | ||||||
|  |     return; | ||||||
|  |   this->component_state_ &= ~STATUS_LED_WARNING; | ||||||
|  |   ESP_LOGW(this->get_component_source(), "Warning cleared"); | ||||||
|  | } | ||||||
|  | void Component::status_clear_error() { | ||||||
|  |   if ((this->component_state_ & STATUS_LED_ERROR) == 0) | ||||||
|  |     return; | ||||||
|  |   this->component_state_ &= ~STATUS_LED_ERROR; | ||||||
|  |   ESP_LOGE(this->get_component_source(), "Error cleared"); | ||||||
| } | } | ||||||
| void Component::status_clear_warning() { this->component_state_ &= ~STATUS_LED_WARNING; } |  | ||||||
| void Component::status_clear_error() { this->component_state_ &= ~STATUS_LED_ERROR; } |  | ||||||
| void Component::status_momentary_warning(const std::string &name, uint32_t length) { | void Component::status_momentary_warning(const std::string &name, uint32_t length) { | ||||||
|   this->status_set_warning(); |   this->status_set_warning(); | ||||||
|   this->set_timeout(name, length, [this]() { this->status_clear_warning(); }); |   this->set_timeout(name, length, [this]() { this->status_clear_warning(); }); | ||||||
|   | |||||||
| @@ -124,13 +124,13 @@ class Component { | |||||||
|  |  | ||||||
|   virtual bool can_proceed(); |   virtual bool can_proceed(); | ||||||
|  |  | ||||||
|   bool status_has_warning(); |   bool status_has_warning() const; | ||||||
|  |  | ||||||
|   bool status_has_error(); |   bool status_has_error() const; | ||||||
|  |  | ||||||
|   void status_set_warning(); |   void status_set_warning(const char *message = "unspecified"); | ||||||
|  |  | ||||||
|   void status_set_error(); |   void status_set_error(const char *message = "unspecified"); | ||||||
|  |  | ||||||
|   void status_clear_warning(); |   void status_clear_warning(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,6 +23,9 @@ logger: | |||||||
| api: | api: | ||||||
|   reboot_timeout: 10min |   reboot_timeout: 10min | ||||||
|  |  | ||||||
|  | web_server: | ||||||
|  |   version: 3 | ||||||
|  |  | ||||||
| time: | time: | ||||||
|   - platform: sntp |   - platform: sntp | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user