mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 21:44:55 +01:00
commit
be15122e8b
9 changed files with 101 additions and 66 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue