1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-03 16:41:50 +00:00

Compare commits

..

12 Commits

Author SHA1 Message Date
Jesse Hills
f07ea6dcda Add raw bus voltage log 2023-11-10 16:30:15 +13:00
Jesse Hills
01d28ce3fc Add resistance_sampler interface for config validation (#5718) 2023-11-10 11:40:07 +13:00
dependabot[bot]
bc7519f645 Bump zeroconf from 0.120.0 to 0.122.3 (#5715) 2023-11-09 12:26:05 -06:00
J. Nick Koston
28513a0502 Update Dockerfile to use piwheels for armv7 (#5709) 2023-11-09 21:04:39 +13:00
J. Nick Koston
3e3266fa74 Bump aioesphomeapi to 18.2.7 (#5706) 2023-11-09 15:52:08 +13:00
Rodrigo Martín
ce020b1f9f fix: Fix broken bluetooth_proxy and ble_clients after BLE enable/disable (#5704) 2023-11-08 23:35:37 +00:00
J. Nick Koston
d394b957d1 Use piwheels for armv7 docker image builds (#5703) 2023-11-09 11:50:08 +13:00
J. Nick Koston
cf22c55430 Fix static assets cache logic (#5700) 2023-11-08 21:04:01 +00:00
Jesse Hills
511348974e Fix esp32_rmt_led_strip custom timing units (#5696) 2023-11-08 09:01:26 +00:00
Jesse Hills
972598a698 Handle nanoseconds in config (#5695) 2023-11-08 21:34:44 +13:00
Edward Firmo
d81bec860b Nextion support to esp-idf (#5667)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-11-07 19:50:45 -06:00
Jesse Hills
fde7a04ee7 Bump version to 2023.12.0-dev 2023-11-08 13:13:56 +13:00
12 changed files with 398 additions and 88 deletions

View File

@@ -1,65 +1,71 @@
from __future__ import annotations
import asyncio
import logging
from datetime import datetime
from typing import Any
from typing import Optional
from aioesphomeapi import APIClient
from aioesphomeapi.api_pb2 import SubscribeLogsResponse
from aioesphomeapi.log_runner import async_run
from zeroconf.asyncio import AsyncZeroconf
from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__
from esphome.core import CORE
from aioesphomeapi import APIClient, ReconnectLogic, APIConnectionError, LogLevel
import zeroconf
from esphome.const import CONF_KEY, CONF_PORT, CONF_PASSWORD, __version__
from esphome.util import safe_print
from . import CONF_ENCRYPTION
_LOGGER = logging.getLogger(__name__)
async def async_run_logs(config, address):
"""Run the logs command in the event loop."""
conf = config["api"]
port: int = int(conf[CONF_PORT])
password: str = conf[CONF_PASSWORD]
noise_psk: str | None = None
noise_psk: Optional[str] = None
if CONF_ENCRYPTION in conf:
noise_psk = conf[CONF_ENCRYPTION][CONF_KEY]
_LOGGER.info("Starting log output from %s using esphome API", address)
aiozc = AsyncZeroconf()
cli = APIClient(
address,
port,
password,
client_info=f"ESPHome Logs {__version__}",
noise_psk=noise_psk,
zeroconf_instance=aiozc.zeroconf,
)
dashboard = CORE.dashboard
first_connect = True
def on_log(msg: SubscribeLogsResponse) -> None:
"""Handle a new log message."""
time_ = datetime.now()
message: bytes = msg.message
text = message.decode("utf8", "backslashreplace")
if dashboard:
text = text.replace("\033", "\\033")
print(f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}]{text}")
def on_log(msg):
time_ = datetime.now().time().strftime("[%H:%M:%S]")
text = msg.message.decode("utf8", "backslashreplace")
safe_print(time_ + text)
async def on_connect():
nonlocal first_connect
try:
await cli.subscribe_logs(
on_log,
log_level=LogLevel.LOG_LEVEL_VERY_VERBOSE,
dump_config=first_connect,
)
first_connect = False
except APIConnectionError:
cli.disconnect()
async def on_disconnect(expected_disconnect: bool) -> None:
_LOGGER.warning("Disconnected from API")
zc = zeroconf.Zeroconf()
reconnect = ReconnectLogic(
client=cli,
on_connect=on_connect,
on_disconnect=on_disconnect,
zeroconf_instance=zc,
)
await reconnect.start()
stop = await async_run(cli, on_log, aio_zeroconf_instance=aiozc)
try:
while True:
await asyncio.sleep(60)
finally:
await aiozc.async_close()
await stop()
def run_logs(config: dict[str, Any], address: str) -> None:
"""Run the logs command."""
try:
asyncio.run(async_run_logs(config, address))
except KeyboardInterrupt:
pass
await reconnect.stop()
zc.close()
def run_logs(config, address):
asyncio.run(async_run_logs(config, address))

View File

@@ -1,7 +1,7 @@
#include "ina226.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
#include <cinttypes>
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ina226 {
@@ -102,6 +102,7 @@ void INA226Component::update() {
this->status_set_warning();
return;
}
ESP_LOGD(TAG, "Got raw bus voltage: %d", raw_bus_voltage);
float bus_voltage_v = int16_t(raw_bus_voltage) * 0.00125f;
this->bus_voltage_sensor_->publish_state(bus_voltage_v);
}

View File

@@ -68,7 +68,6 @@ void LD2420Component::dump_config() {
ESP_LOGCONFIG(TAG, "LD2420:");
ESP_LOGCONFIG(TAG, " Firmware Version : %7s", this->ld2420_firmware_ver_);
ESP_LOGCONFIG(TAG, "LD2420 Number:");
#ifdef USE_NUMBER
LOG_NUMBER(TAG, " Gate Timeout:", this->gate_timeout_number_);
LOG_NUMBER(TAG, " Gate Max Distance:", this->max_gate_distance_number_);
LOG_NUMBER(TAG, " Gate Min Distance:", this->min_gate_distance_number_);
@@ -77,13 +76,10 @@ void LD2420Component::dump_config() {
LOG_NUMBER(TAG, " Gate Move Threshold:", this->gate_move_threshold_numbers_[gate]);
LOG_NUMBER(TAG, " Gate Still Threshold::", this->gate_still_threshold_numbers_[gate]);
}
#endif
#ifdef USE_BUTTON
LOG_BUTTON(TAG, " Apply Config:", this->apply_config_button_);
LOG_BUTTON(TAG, " Revert Edits:", this->revert_config_button_);
LOG_BUTTON(TAG, " Factory Reset:", this->factory_reset_button_);
LOG_BUTTON(TAG, " Restart Module:", this->restart_module_button_);
#endif
ESP_LOGCONFIG(TAG, "LD2420 Select:");
LOG_SELECT(TAG, " Operating Mode", this->operating_selector_);
if (this->get_firmware_int_(ld2420_firmware_ver_) < CALIBRATE_VERSION_MIN) {
@@ -187,11 +183,9 @@ void LD2420Component::factory_reset_action() {
return;
}
this->set_min_max_distances_timeout(FACTORY_MAX_GATE, FACTORY_MIN_GATE, FACTORY_TIMEOUT);
#ifdef USE_NUMBER
this->gate_timeout_number_->state = FACTORY_TIMEOUT;
this->min_gate_distance_number_->state = FACTORY_MIN_GATE;
this->max_gate_distance_number_->state = FACTORY_MAX_GATE;
#endif
for (uint8_t gate = 0; gate < LD2420_TOTAL_GATES; gate++) {
this->new_config.move_thresh[gate] = FACTORY_MOVE_THRESH[gate];
this->new_config.still_thresh[gate] = FACTORY_STILL_THRESH[gate];

View File

@@ -36,7 +36,7 @@ CONFIG_SCHEMA = (
display.BASIC_DISPLAY_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(Nextion),
cv.Optional(CONF_TFT_URL): cv.All(cv.string, cv.only_with_arduino),
cv.Optional(CONF_TFT_URL): cv.url,
cv.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage,
cv.Optional(CONF_ON_SETUP): automation.validate_automation(
{
@@ -85,10 +85,10 @@ async def to_code(config):
if CONF_TFT_URL in config:
cg.add_define("USE_NEXTION_TFT_UPLOAD")
cg.add(var.set_tft_url(config[CONF_TFT_URL]))
if CORE.is_esp32:
if CORE.is_esp32 and CORE.using_arduino:
cg.add_library("WiFiClientSecure", None)
cg.add_library("HTTPClient", None)
if CORE.is_esp8266:
elif CORE.is_esp8266 and CORE.using_arduino:
cg.add_library("ESP8266HTTPClient", None)
if CONF_TOUCH_SLEEP_TIMEOUT in config:

View File

@@ -128,7 +128,7 @@ void Nextion::dump_config() {
ESP_LOGCONFIG(TAG, " Wake On Touch: %s", this->auto_wake_on_touch_ ? "True" : "False");
if (this->touch_sleep_timeout_ != 0) {
ESP_LOGCONFIG(TAG, " Touch Timeout: %d", this->touch_sleep_timeout_);
ESP_LOGCONFIG(TAG, " Touch Timeout: %" PRIu32, this->touch_sleep_timeout_);
}
if (this->wake_up_page_ != -1) {
@@ -868,6 +868,12 @@ uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool
start = millis();
while ((timeout == 0 && this->available()) || millis() - start <= timeout) {
if (!this->available()) {
App.feed_wdt();
delay(1);
continue;
}
this->read_byte(&c);
if (c == 0xFF) {
nr_of_ff_bytes++;
@@ -886,7 +892,7 @@ uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool
}
}
App.feed_wdt();
delay(1);
delay(2);
if (exit_flag || ff_flag) {
break;

View File

@@ -12,14 +12,18 @@
#include "esphome/components/display/display_color_utils.h"
#ifdef USE_NEXTION_TFT_UPLOAD
#ifdef ARDUINO
#ifdef USE_ESP32
#include <HTTPClient.h>
#endif
#endif // USE_ESP32
#ifdef USE_ESP8266
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>
#endif
#endif
#endif // USE_ESP8266
#elif defined(USE_ESP_IDF)
#include <esp_http_client.h>
#endif // ARDUINO vs ESP-IDF
#endif // USE_NEXTION_TFT_UPLOAD
namespace esphome {
namespace nextion {
@@ -685,16 +689,18 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
#ifdef USE_NEXTION_TFT_UPLOAD
/**
* Set the tft file URL. https seems problamtic with arduino..
* Set the tft file URL. https seems problematic with arduino..
*/
void set_tft_url(const std::string &tft_url) { this->tft_url_ = tft_url; }
#endif
/**
* Upload the tft file and softreset the Nextion
* Upload the tft file and soft reset Nextion
* @return bool True: Transfer completed successfuly, False: Transfer failed.
*/
void upload_tft();
bool upload_tft();
void dump_config() override;
/**
@@ -817,16 +823,16 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
BearSSL::WiFiClientSecure *wifi_client_secure_{nullptr};
WiFiClient *get_wifi_client_();
#endif
int content_length_ = 0;
int tft_size_ = 0;
#ifdef ARDUINO
/**
* will request chunk_size chunks from the web server
* and send each to the nextion
* @param int contentLength Total size of the file
* @param uint32_t chunk_size
* @return true if success, false for failure.
* @param HTTPClient http HTTP client handler.
* @param int range_start Position of next byte to transfer.
* @return position of last byte transferred, -1 for failure.
*/
int content_length_ = 0;
int tft_size_ = 0;
int upload_by_chunks_(HTTPClient *http, int range_start);
bool upload_with_range_(uint32_t range_start, uint32_t range_end);
@@ -839,7 +845,30 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
* @return true if success, false for failure.
*/
bool upload_from_buffer_(const uint8_t *file_buf, size_t buf_size);
void upload_end_();
/**
* Ends the upload process, restart Nextion and, if successful,
* restarts ESP
* @param bool url successful True: Transfer completed successfuly, False: Transfer failed.
* @return bool True: Transfer completed successfuly, False: Transfer failed.
*/
bool upload_end_(bool successful);
#elif defined(USE_ESP_IDF)
/**
* will request 4096 bytes chunks from the web server
* and send each to Nextion
* @param std::string url Full url for download.
* @param int range_start Position of next byte to transfer.
* @return position of last byte transferred, -1 for failure.
*/
int upload_range(const std::string &url, int range_start);
/**
* Ends the upload process, restart Nextion and, if successful,
* restarts ESP
* @param bool url successful True: Transfer completed successfuly, False: Transfer failed.
* @return bool True: Transfer completed successfuly, False: Transfer failed.
*/
bool upload_end(bool successful);
#endif // ARDUINO vs ESP-IDF
#endif // USE_NEXTION_TFT_UPLOAD

View File

@@ -55,7 +55,7 @@ void Nextion::set_protocol_reparse_mode(bool active_mode) {
// Set Colors
void Nextion::set_component_background_color(const char *component, uint32_t color) {
this->add_no_result_to_queue_with_printf_("set_component_background_color", "%s.bco=%d", component, color);
this->add_no_result_to_queue_with_printf_("set_component_background_color", "%s.bco=%" PRIu32, component, color);
}
void Nextion::set_component_background_color(const char *component, const char *color) {
@@ -68,7 +68,8 @@ void Nextion::set_component_background_color(const char *component, Color color)
}
void Nextion::set_component_pressed_background_color(const char *component, uint32_t color) {
this->add_no_result_to_queue_with_printf_("set_component_pressed_background_color", "%s.bco2=%d", component, color);
this->add_no_result_to_queue_with_printf_("set_component_pressed_background_color", "%s.bco2=%" PRIu32, component,
color);
}
void Nextion::set_component_pressed_background_color(const char *component, const char *color) {
@@ -89,7 +90,7 @@ void Nextion::set_component_picc(const char *component, uint8_t pic_id) {
}
void Nextion::set_component_font_color(const char *component, uint32_t color) {
this->add_no_result_to_queue_with_printf_("set_component_font_color", "%s.pco=%d", component, color);
this->add_no_result_to_queue_with_printf_("set_component_font_color", "%s.pco=%" PRIu32, component, color);
}
void Nextion::set_component_font_color(const char *component, const char *color) {
@@ -102,7 +103,7 @@ void Nextion::set_component_font_color(const char *component, Color color) {
}
void Nextion::set_component_pressed_font_color(const char *component, uint32_t color) {
this->add_no_result_to_queue_with_printf_("set_component_pressed_font_color", "%s.pco2=%d", component, color);
this->add_no_result_to_queue_with_printf_("set_component_pressed_font_color", "%s.pco2=%" PRIu32, component, color);
}
void Nextion::set_component_pressed_font_color(const char *component, const char *color) {

View File

@@ -1,5 +1,6 @@
#include "nextion.h"
#ifdef ARDUINO
#ifdef USE_NEXTION_TFT_UPLOAD
#include "esphome/core/application.h"
@@ -128,15 +129,15 @@ int Nextion::upload_by_chunks_(HTTPClient *http, int range_start) {
return range_end + 1;
}
void Nextion::upload_tft() {
bool Nextion::upload_tft() {
if (this->is_updating_) {
ESP_LOGD(TAG, "Currently updating");
return;
return false;
}
if (!network::is_connected()) {
ESP_LOGD(TAG, "network is not connected");
return;
return false;
}
this->is_updating_ = true;
@@ -164,7 +165,7 @@ void Nextion::upload_tft() {
ESP_LOGD(TAG, "connection failed");
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
allocator.deallocate(this->transfer_buffer_, this->transfer_buffer_size_);
return;
return false;
} else {
ESP_LOGD(TAG, "Connected");
}
@@ -192,7 +193,7 @@ void Nextion::upload_tft() {
}
if ((code != 200 && code != 206) || tries > 5) {
this->upload_end_();
return this->upload_end_(false);
}
String content_range_string = http.header("Content-Range");
@@ -203,7 +204,7 @@ void Nextion::upload_tft() {
if (this->content_length_ < 4096) {
ESP_LOGE(TAG, "Failed to get file size");
this->upload_end_();
return this->upload_end_(false);
}
ESP_LOGD(TAG, "Updating Nextion %s...", this->device_model_.c_str());
@@ -246,7 +247,7 @@ void Nextion::upload_tft() {
ESP_LOGD(TAG, "preparation for tft update done");
} else {
ESP_LOGD(TAG, "preparation for tft update failed %d \"%s\"", response[0], response.c_str());
this->upload_end_();
return this->upload_end_(false);
}
// Nextion wants 4096 bytes at a time. Make chunk_size a multiple of 4096
@@ -280,7 +281,7 @@ void Nextion::upload_tft() {
this->transfer_buffer_ = allocator.allocate(chunk_size);
if (!this->transfer_buffer_)
this->upload_end_();
return this->upload_end_(false);
}
this->transfer_buffer_size_ = chunk_size;
@@ -295,7 +296,7 @@ void Nextion::upload_tft() {
result = this->upload_by_chunks_(&http, result);
if (result < 0) {
ESP_LOGD(TAG, "Error updating Nextion!");
this->upload_end_();
return this->upload_end_(false);
}
App.feed_wdt();
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
@@ -303,15 +304,19 @@ void Nextion::upload_tft() {
}
ESP_LOGD(TAG, "Successfully updated Nextion!");
this->upload_end_();
return this->upload_end_(true);
}
void Nextion::upload_end_() {
bool Nextion::upload_end_(bool successful) {
this->is_updating_ = false;
ESP_LOGD(TAG, "Restarting Nextion");
this->soft_reset();
delay(1500); // NOLINT
ESP_LOGD(TAG, "Restarting esphome");
ESP.restart(); // NOLINT(readability-static-accessed-through-instance)
if (successful) {
delay(1500); // NOLINT
ESP_LOGD(TAG, "Restarting esphome");
ESP.restart(); // NOLINT(readability-static-accessed-through-instance)
}
return successful;
}
#ifdef USE_ESP8266
@@ -337,3 +342,4 @@ WiFiClient *Nextion::get_wifi_client_() {
} // namespace esphome
#endif // USE_NEXTION_TFT_UPLOAD
#endif // ARDUINO

View File

@@ -0,0 +1,268 @@
#include "nextion.h"
#ifdef USE_ESP_IDF
#ifdef USE_NEXTION_TFT_UPLOAD
#include "esphome/core/application.h"
#include "esphome/core/defines.h"
#include "esphome/core/util.h"
#include "esphome/core/log.h"
#include "esphome/components/network/util.h"
#include <esp_heap_caps.h>
#include <esp_http_client.h>
namespace esphome {
namespace nextion {
static const char *const TAG = "nextion_upload";
// Followed guide
// https://unofficialnextion.com/t/nextion-upload-protocol-v1-2-the-fast-one/1044/2
int Nextion::upload_range(const std::string &url, int range_start) {
ESP_LOGVV(TAG, "url: %s", url.c_str());
uint range_size = this->tft_size_ - range_start;
ESP_LOGVV(TAG, "tft_size_: %i", this->tft_size_);
ESP_LOGV(TAG, "Available heap: %u", esp_get_free_heap_size());
int range_end = (range_start == 0) ? std::min(this->tft_size_, 16383) : this->tft_size_;
if (range_size <= 0 or range_end <= range_start) {
ESP_LOGE(TAG, "Invalid range");
ESP_LOGD(TAG, "Range start: %i", range_start);
ESP_LOGD(TAG, "Range end: %i", range_end);
ESP_LOGD(TAG, "Range size: %i", range_size);
return -1;
}
esp_http_client_config_t config = {
.url = url.c_str(),
.cert_pem = nullptr,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
char range_header[64];
sprintf(range_header, "bytes=%d-%d", range_start, range_end);
ESP_LOGV(TAG, "Requesting range: %s", range_header);
esp_http_client_set_header(client, "Range", range_header);
ESP_LOGVV(TAG, "Available heap: %u", esp_get_free_heap_size());
ESP_LOGV(TAG, "Opening http connetion");
esp_err_t err;
if ((err = esp_http_client_open(client, 0)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
esp_http_client_cleanup(client);
return -1;
}
ESP_LOGV(TAG, "Fetch content length");
int content_length = esp_http_client_fetch_headers(client);
ESP_LOGV(TAG, "content_length = %d", content_length);
if (content_length <= 0) {
ESP_LOGE(TAG, "Failed to get content length: %d", content_length);
esp_http_client_cleanup(client);
return -1;
}
int total_read_len = 0, read_len;
ESP_LOGV(TAG, "Allocate buffer");
uint8_t *buffer = new uint8_t[4096];
std::string recv_string;
if (buffer == nullptr) {
ESP_LOGE(TAG, "Failed to allocate memory for buffer");
ESP_LOGV(TAG, "Available heap: %u", esp_get_free_heap_size());
} else {
ESP_LOGV(TAG, "Memory for buffer allocated successfully");
while (true) {
App.feed_wdt();
ESP_LOGVV(TAG, "Available heap: %u", esp_get_free_heap_size());
int read_len = esp_http_client_read(client, reinterpret_cast<char *>(buffer), 4096);
ESP_LOGVV(TAG, "Read %d bytes from HTTP client, writing to UART", read_len);
if (read_len > 0) {
this->write_array(buffer, read_len);
ESP_LOGVV(TAG, "Write to UART successful");
this->recv_ret_string_(recv_string, 5000, true);
this->content_length_ -= read_len;
ESP_LOGD(TAG, "Uploaded %0.2f %%, remaining %d bytes",
100.0 * (this->tft_size_ - this->content_length_) / this->tft_size_, this->content_length_);
if (recv_string[0] != 0x05) { // 0x05 == "ok"
ESP_LOGD(
TAG, "recv_string [%s]",
format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
}
// handle partial upload request
if (recv_string[0] == 0x08 && recv_string.size() == 5) {
uint32_t result = 0;
for (int j = 0; j < 4; ++j) {
result += static_cast<uint8_t>(recv_string[j + 1]) << (8 * j);
}
if (result > 0) {
ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result);
this->content_length_ = this->tft_size_ - result;
// Deallocate the buffer when done
delete[] buffer;
ESP_LOGVV(TAG, "Memory for buffer deallocated");
esp_http_client_cleanup(client);
esp_http_client_close(client);
return result;
}
}
recv_string.clear();
} else if (read_len == 0) {
ESP_LOGV(TAG, "End of HTTP response reached");
break; // Exit the loop if there is no more data to read
} else {
ESP_LOGE(TAG, "Failed to read from HTTP client, error code: %d", read_len);
break; // Exit the loop on error
}
}
// Deallocate the buffer when done
delete[] buffer;
ESP_LOGVV(TAG, "Memory for buffer deallocated");
}
esp_http_client_cleanup(client);
esp_http_client_close(client);
return range_end + 1;
}
bool Nextion::upload_tft() {
ESP_LOGD(TAG, "Nextion TFT upload requested");
ESP_LOGD(TAG, "url: %s", this->tft_url_.c_str());
if (this->is_updating_) {
ESP_LOGW(TAG, "Currently updating");
return false;
}
if (!network::is_connected()) {
ESP_LOGE(TAG, "Network is not connected");
return false;
}
this->is_updating_ = true;
// Define the configuration for the HTTP client
ESP_LOGV(TAG, "Establishing connection to HTTP server");
ESP_LOGVV(TAG, "Available heap: %u", esp_get_free_heap_size());
esp_http_client_config_t config = {
.url = this->tft_url_.c_str(),
.cert_pem = nullptr,
.method = HTTP_METHOD_HEAD,
.timeout_ms = 15000,
};
// Initialize the HTTP client with the configuration
ESP_LOGV(TAG, "Initializing HTTP client");
ESP_LOGV(TAG, "Available heap: %u", esp_get_free_heap_size());
esp_http_client_handle_t http = esp_http_client_init(&config);
if (!http) {
ESP_LOGE(TAG, "Failed to initialize HTTP client.");
return this->upload_end(false);
}
// Perform the HTTP request
ESP_LOGV(TAG, "Check if the client could connect");
ESP_LOGV(TAG, "Available heap: %u", esp_get_free_heap_size());
esp_err_t err = esp_http_client_perform(http);
if (err != ESP_OK) {
ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err));
esp_http_client_cleanup(http);
return this->upload_end(false);
}
// Check the HTTP Status Code
int status_code = esp_http_client_get_status_code(http);
ESP_LOGV(TAG, "HTTP Status Code: %d", status_code);
size_t tft_file_size = esp_http_client_get_content_length(http);
ESP_LOGD(TAG, "TFT file size: %zu", tft_file_size);
if (tft_file_size < 4096) {
ESP_LOGE(TAG, "File size check failed. Size: %zu", tft_file_size);
esp_http_client_cleanup(http);
return this->upload_end(false);
} else {
ESP_LOGV(TAG, "File size check passed. Proceeding...");
}
this->content_length_ = tft_file_size;
this->tft_size_ = tft_file_size;
ESP_LOGD(TAG, "Updating Nextion");
// The Nextion will ignore the update command if it is sleeping
this->send_command_("sleep=0");
this->set_backlight_brightness(1.0);
vTaskDelay(pdMS_TO_TICKS(250)); // NOLINT
App.feed_wdt();
char command[128];
// Tells the Nextion the content length of the tft file and baud rate it will be sent at
// Once the Nextion accepts the command it will wait until the file is successfully uploaded
// If it fails for any reason a power cycle of the display will be needed
sprintf(command, "whmi-wris %d,%" PRIu32 ",1", this->content_length_, this->parent_->get_baud_rate());
// Clear serial receive buffer
uint8_t d;
while (this->available()) {
this->read_byte(&d);
};
this->send_command_(command);
std::string response;
ESP_LOGV(TAG, "Waiting for upgrade response");
this->recv_ret_string_(response, 2048, true); // This can take some time to return
// The Nextion display will, if it's ready to accept data, send a 0x05 byte.
ESP_LOGD(TAG, "Upgrade response is [%s]",
format_hex_pretty(reinterpret_cast<const uint8_t *>(response.data()), response.size()).c_str());
if (response.find(0x05) != std::string::npos) {
ESP_LOGV(TAG, "Preparation for tft update done");
} else {
ESP_LOGE(TAG, "Preparation for tft update failed %d \"%s\"", response[0], response.c_str());
esp_http_client_cleanup(http);
return this->upload_end(false);
}
ESP_LOGD(TAG, "Updating tft from \"%s\" with a file size of %d, Heap Size %" PRIu32, this->tft_url_.c_str(),
content_length_, esp_get_free_heap_size());
ESP_LOGV(TAG, "Starting transfer by chunks loop");
int result = 0;
while (content_length_ > 0) {
result = upload_range(this->tft_url_.c_str(), result);
if (result < 0) {
ESP_LOGE(TAG, "Error updating Nextion!");
esp_http_client_cleanup(http);
return this->upload_end(false);
}
App.feed_wdt();
ESP_LOGV(TAG, "Heap Size %" PRIu32 ", Bytes left %d", esp_get_free_heap_size(), content_length_);
}
ESP_LOGD(TAG, "Successfully updated Nextion!");
ESP_LOGD(TAG, "Close HTTP connection");
esp_http_client_close(http);
esp_http_client_cleanup(http);
return upload_end(true);
}
bool Nextion::upload_end(bool successful) {
this->is_updating_ = false;
ESP_LOGD(TAG, "Restarting Nextion");
this->soft_reset();
vTaskDelay(pdMS_TO_TICKS(1500)); // NOLINT
if (successful) {
ESP_LOGD(TAG, "Restarting esphome");
esp_restart(); // NOLINT(readability-static-accessed-through-instance)
}
return successful;
}
} // namespace nextion
} // namespace esphome
#endif // USE_NEXTION_TFT_UPLOAD
#endif // USE_ESP_IDF

View File

@@ -1,6 +1,6 @@
"""Constants used by esphome."""
__version__ = "2023.11.0b4"
__version__ = "2023.12.0-dev"
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
VALID_SUBSTITUTIONS_CHARACTERS = (

View File

@@ -147,13 +147,12 @@ class DashboardImportDiscovery:
class EsphomeZeroconf(Zeroconf):
def resolve_host(self, host: str, timeout: float = 3.0) -> str | None:
def resolve_host(self, host: str, timeout=3.0):
"""Resolve a host name to an IP address."""
name = host.partition(".")[0]
info = HostResolver(ESPHOME_SERVICE_TYPE, f"{name}.{ESPHOME_SERVICE_TYPE}")
if (
info.load_from_cache(self)
or (timeout and info.request(self, timeout * 1000))
) and (addresses := info.ip_addresses_by_version(IPVersion.V4Only)):
info = HostResolver(f"{name}.{ESPHOME_SERVICE_TYPE}", ESPHOME_SERVICE_TYPE)
if (info.load_from_cache(self) or info.request(self, timeout * 1000)) and (
addresses := info.ip_addresses_by_version(IPVersion.V4Only)
):
return str(addresses[0])
return None

View File

@@ -10,8 +10,8 @@ platformio==6.1.11 # When updating platformio, also update Dockerfile
esptool==4.6.2
click==8.1.7
esphome-dashboard==20231107.0
aioesphomeapi==18.4.0
zeroconf==0.123.0
aioesphomeapi==18.2.7
zeroconf==0.122.3
# esp-idf requires this, but doesn't bundle it by default
# https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24