From e02ee95198bf94b5fc99f01ace8cb2eb9bafad9b Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Sat, 30 Dec 2023 01:59:51 +0100 Subject: [PATCH] Rebuilt Upload TFT Rebuilt again, now based on the ESPHome's Nextion component instead of local code. Still not there yet, specially when Lovelace UI tft is installed, but hopefully this solves #1383 and solves #1491. --- .../nspanel_esphome_addon_upload_tft.yaml | 1254 +++++------------ advanced/esphome/nspanel_esphome_core.yaml | 172 ++- dev/instructions_for_developers.md | 64 + 3 files changed, 502 insertions(+), 988 deletions(-) diff --git a/advanced/esphome/nspanel_esphome_addon_upload_tft.yaml b/advanced/esphome/nspanel_esphome_addon_upload_tft.yaml index cc0d6b1..bd6a917 100644 --- a/advanced/esphome/nspanel_esphome_addon_upload_tft.yaml +++ b/advanced/esphome/nspanel_esphome_addon_upload_tft.yaml @@ -41,7 +41,7 @@ api: clean_url = clean_url.substr(0, endPos + 1); } - if ( clean_url.empty() or clean_url == "default") url = tft_update_url->state; + if (clean_url.empty() or clean_url == "default") url = "${nextion_update_url}"; upload_tft->execute(url.c_str()); button: @@ -55,166 +55,125 @@ button: - lambda: |- static const char *const TAG = "button.tft_update.on_press"; ESP_LOGD(TAG, "Update TFT display button pressed"); - upload_tft->execute(tft_update_url->state.c_str()); + upload_tft->execute("${nextion_update_url}"); display: - id: !extend disp1 tft_url: ${nextion_update_url} exit_reparse_on_start: true +globals: + - id: baud_rate_original + type: uint + restore_value: false + initial_value: '115200' + + - id: baud_rate_target + type: uint + restore_value: false + initial_value: ${upload_tft_baud_rate} + + - id: tft_is_valid + type: bool + restore_value: false + initial_value: 'false' + + - id: tft_upload_try + type: uint + restore_value: false + initial_value: '0' + script: - - id: upload_tft_nextion # NOT IN USE FOR NOW - mode: single + - id: nextion_uart_command + mode: queued parameters: - url: string + command: string then: - lambda: |- - static const char *const TAG = "script.upload_tft_new"; - ESP_LOGVV(TAG, "Starting..."); - id(is_uploading_tft) = true; + static const char *const TAG = "script.nextion_uart_command"; + if (disp1->is_setup()) { + ESP_LOGD(TAG, "Sending `%s` directly to Nextion", command.c_str()); + disp1->send_command_printf(command.c_str()); + } else { + ESP_LOGD(TAG, "Sending `%s` directly to UART", command.c_str()); + tf_uart->write_str(command.c_str()); + const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF}; + tf_uart->write_array(to_send, sizeof(to_send)); + } + App.feed_wdt(); - nextion_status->execute(); - - auto delay_seconds_ = [](int seconds) { - ESP_LOGD(TAG, "Wait %i seconds", seconds); - for (int i = 0; i < (seconds*4); i++) { - #ifdef ARDUINO - delay(250); - #elif defined(USE_ESP_IDF) - vTaskDelay(pdMS_TO_TICKS(250)); - #endif - App.feed_wdt(); + - id: report_upload_progress + mode: restart + parameters: + message: string + then: + - lambda: |- + static const char *const TAG = "script.report_upload_progress"; + ESP_LOGD(TAG, "%s", message.c_str()); + if (id(tft_is_valid)) { + if (page_id->state != 26) { + open_upload_dialog->execute(); } - }; + display_wrapped_text->execute("confirm.body", message.c_str(), 18); + disp1->set_backlight_brightness(1); + App.feed_wdt(); + } - std::string framework = "Unknown"; + - id: nextion_upload + mode: single + then: + - lambda: |- + static const char *const TAG = "script.nextion_upload"; + ESP_LOGD(TAG, "Waiting for empty UART and Nextion queues"); + - wait_until: + condition: + - lambda: !lambda return (disp1->queue_size()<=0); + - lambda: !lambda return (tf_uart->available()<=0); + timeout: 10s + - delay: 2s + - lambda: |- + static const char *const TAG = "script.nextion_upload"; + ESP_LOGD(TAG, "Starting TFT upload..."); + if (disp1->upload_tft()) App.safe_reboot(); + + - id: open_upload_dialog + mode: restart + then: + - lambda: |- + static const char *const TAG = "script.open_upload_dialog"; + ESP_LOGD(TAG, "Showing upload dialog page"); + disp1->goto_page("confirm"); + disp1->hide_component("bt_close"); + disp1->hide_component("bt_accept"); + disp1->hide_component("bt_clear"); + disp1->hide_component("bt_close"); #ifdef ARDUINO - framework = "Arduino"; + disp1->set_component_text_printf("confirm.title", "Upload TFT\\rArduino"); #elif defined(ESP_PLATFORM) - framework = "ESP-IDF"; + disp1->set_component_text_printf("confirm.title", "Upload TFT\\rESP-IDF"); #endif + page_id->update(); - if (disp1->is_setup()) { - disp1->set_backlight_brightness(1); - disp1->set_component_text_printf("confirm.title", "Upload TFT\\r%s", framework.c_str()); - disp1->set_component_text_printf("confirm.body", "Preparing..."); - disp1->goto_page("confirm"); - disp1->hide_component("bt_close"); - disp1->hide_component("bt_accept"); - disp1->hide_component("bt_clear"); - disp1->hide_component("bt_close"); - App.feed_wdt(); - delay_seconds_(1); - display_wrapped_text->execute("confirm.body", "Informing the blueprint that panel is unavailable...", 18); - disp1->hide_component("bt_close"); - App.feed_wdt(); - } - nextion_init->publish_state(false); - App.feed_wdt(); - if (disp1->is_setup()) { - delay_seconds_(1); - display_wrapped_text->execute("confirm.body", "Stopping scripts...", 18); - App.feed_wdt(); - } - stop_all->execute(); - if (disp1->is_setup()) delay_seconds_(1); - App.feed_wdt(); - - ESP_LOGD(TAG, "Try #1 at 921600 bps"); - nextion_status->execute(); - if (disp1->is_setup()) { - display_wrapped_text->execute("confirm.body", "Try #1 at 921600 bps", 18); - App.feed_wdt(); - delay_seconds_(1); - } - //if (disp1->upload_tft(921600)) App.safe_reboot(); - ESP_LOGW(TAG, "Try #1 failed"); - if (disp1->is_setup()) display_wrapped_text->execute("confirm.body", "Try #1 failed", 18); - App.feed_wdt(); - delay_seconds_(5); - ESP_LOGD(TAG, "Try #2 at 921600 bps"); - nextion_status->execute(); - App.feed_wdt(); - if (disp1->is_setup()) display_wrapped_text->execute("confirm.body", "Try #2 at 921600 bps", 18); - //if (disp1->upload_tft(921600)) App.safe_reboot(); - ESP_LOGW(TAG, "Try #2 failed"); - if (disp1->is_setup()) display_wrapped_text->execute("confirm.body", "Try #2 failed", 18); - App.feed_wdt(); - delay_seconds_(5); - ESP_LOGD(TAG, "Try #3 at 115200 bps"); - nextion_status->execute(); - App.feed_wdt(); - if (disp1->is_setup()) display_wrapped_text->execute("confirm.body", "Try #3 at 115200 bps", 18); - //if (disp1->upload_tft(115200)) App.safe_reboot(); - ESP_LOGW(TAG, "Try #3 failed"); - App.feed_wdt(); - if (disp1->is_setup()) { - display_wrapped_text->execute("confirm.body", "Try #3 failed. Restarting display.", 18); - App.feed_wdt(); - delay_seconds_(3); - } - ESP_LOGD(TAG, "Turn off Nextion"); - id(screen_power).turn_off(); - delay_seconds_(2); - ESP_LOGD(TAG, "Turn on Nextion"); - id(screen_power).turn_on(); - delay_seconds_(10); - App.feed_wdt(); - ESP_LOGD(TAG, "Try #4 at 115200 bps"); - nextion_status->execute(); - if (disp1->is_setup()) { - disp1->set_backlight_brightness(1); - disp1->set_component_text_printf("confirm.title", "Upload TFT\\r%s", framework.c_str()); - display_wrapped_text->execute("confirm.body", "Try #4 at 115200 bps", 18); - disp1->goto_page("confirm"); - disp1->hide_component("bt_close"); - disp1->hide_component("bt_accept"); - disp1->hide_component("bt_clear"); - disp1->hide_component("bt_close"); - App.feed_wdt(); - delay_seconds_(1); - } - //if (disp1->upload_tft(115200)) App.safe_reboot(); - ESP_LOGE(TAG, "TFT upload failed"); - if (disp1->is_setup()) display_wrapped_text->execute("confirm.body", "TFT upload failed", 18); - if (disp1->is_setup()) delay_seconds_(2); - ESP_LOGD(TAG, "Turn off Nextion"); - if (disp1->is_setup()) display_wrapped_text->execute("confirm.body", "Restarting...", 18); - if (disp1->is_setup()) delay_seconds_(2); - id(screen_power).turn_off(); - delay_seconds_(2); - ESP_LOGD(TAG, "Turn on Nextion"); - id(screen_power).turn_on(); - ESP_LOGD(TAG, "Restarting ESPHome"); - delay_seconds_(2); - App.safe_reboot(); - - id(is_uploading_tft) = false; - ESP_LOGD(TAG, "Finished!"); - - - id: upload_tft + - id: upload_tft # I've changed this to use ESPHome commands to avoid the parallelism from lambdas mode: single parameters: url: string then: + # Make sure the screen is ON + - if: + condition: + - switch.is_off: screen_power + then: + - switch.turn_on: screen_power + - delay: 5s + # Then start the upload - lambda: |- static const char *const TAG = "script.upload_tft"; ESP_LOGD(TAG, "Starting..."); + id(is_uploading_tft) = true; - char update_msg[128]; - - auto delay_seconds_ = [](int seconds) { - ESP_LOGD(TAG, "Wait %i seconds", seconds); - for (int i = 0; i < (seconds*4); i++) { - #ifdef ARDUINO - delay(250); - #elif defined(USE_ESP_IDF) - vTaskDelay(pdMS_TO_TICKS(250)); - #endif - App.feed_wdt(); - } - }; + nextion_status->execute(); uint32_t supported_baud_rates[] = {2400, 4800, 9600, 19200, 31250, 38400, 57600, 115200, 230400, 250000, 256000, 512000, 921600}; @@ -228,789 +187,262 @@ script: return false; // Return false if not found }; - auto send_nextion_command = [](const std::string &command) -> bool { - static const char *const TAG = "script.upload_tft.send_nextion_command"; - ESP_LOGD(TAG, "Sending: %s", command.c_str()); - tf_uart->write_str(command.c_str()); - const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF}; - tf_uart->write_array(to_send, sizeof(to_send)); - return true; - }; - - std::string framework = "Unknown"; - #ifdef ARDUINO - framework = "Arduino"; - #elif defined(ESP_PLATFORM) - framework = "ESP-IDF"; - #endif - - std::vector buffer_; - - bool is_updating_ = false; - - bool upload_first_chunk_sent_ = false; - - int content_length_ = 0; - int tft_size_ = 0; - - auto set_baud_rate_ = [](int baud_rate) { - #ifdef USE_ARDUINO - auto *uart = reinterpret_cast(tf_uart); - #endif - #ifdef USE_ESP_IDF - auto *uart = reinterpret_cast(tf_uart); - #endif - uart->set_baud_rate(baud_rate); - uart->setup(); - }; - - auto disable_boot_timers_ = [send_nextion_command]() { - ESP_LOGD(TAG, "Disabling timers on boot page"); - send_nextion_command("timer.en=0"); - send_nextion_command("tm_esphome.en=0"); - send_nextion_command("tm_pageid.en=0"); - send_nextion_command("wakeup_timer.en=0"); - // Set Lovelace UI - Just in case - send_nextion_command("tmSleep.en=0"); - send_nextion_command("tMsg1.txt=""Upload TFT"""); - send_nextion_command("tMsg2.txt="""""); - send_nextion_command("tMsg3.txt="""""); - send_nextion_command("dim=1"); - }; - - auto recv_ret_string_ = [](std::string &response, uint32_t timeout, bool recv_flag) -> uint16_t - { - static const char *const TAG = "script.upload_tft.recv_ret_string_"; - uint16_t ret; - uint8_t c = 0; - uint8_t nr_of_ff_bytes = 0; - uint64_t start; - bool exit_flag = false; - bool ff_flag = false; - - start = millis(); - - while ((timeout == 0 && tf_uart->available()) || millis() - start <= timeout) - { - if (!tf_uart->available()) - { - App.feed_wdt(); - continue; - } - - tf_uart->read_byte(&c); - if (c == 0xFF) - { - nr_of_ff_bytes++; - } - else - { - nr_of_ff_bytes = 0; - ff_flag = false; - } - - if (nr_of_ff_bytes >= 3) - ff_flag = true; - - response += (char) c; - if (recv_flag) - { - if (response.find(0x05) != std::string::npos) - { - exit_flag = true; - } - } - App.feed_wdt(); - delay(2); - - if (exit_flag || ff_flag) - { - break; - } - } - - if (ff_flag) - response = response.substr(0, response.length() - 3); // Remove last 3 0xFF - - ret = response.length(); - return ret; - }; - - auto upload_end_ = [&](bool completed) -> bool - { - static const char *const TAG = "script.upload_tft.upload_end_"; - ESP_LOGD(TAG, "Completed: %i", completed ? 1 : 0); - //ESP_LOGD(TAG, "Restarting Nextion"); - //send_nextion_command("rest"); - #ifdef ARDUINO - delay(1500); - #elif defined(ESP_PLATFORM) - //vTaskDelay(pdMS_TO_TICKS(1500)); - #endif - - is_updating_ = false; - if (!completed) ESP_LOGD(TAG, "Nextion TFT upload will try again"); - return completed; - }; - - #ifdef ARDUINO // arduino # To do: Move to Nextion component on ESPHome - size_t transfer_buffer_size_ = 0; - uint8_t *transfer_buffer_{nullptr}; - auto upload_by_chunks_arduino = [&](HTTPClient *http, const std::string &url, int range_start) -> int - { - static const char *const TAG = "script.upload_tft.upload_by_chunks_arduino"; - int range_end; - - if (range_start == 0 && transfer_buffer_size_ > 16384) { // Start small at the first run in case of a big skip - range_end = 16384 - 1; - } else { - range_end = range_start + transfer_buffer_size_ - 1; - } - - if (range_end > tft_size_) - range_end = tft_size_; - - char range_header[64]; - sprintf(range_header, "bytes=%d-%d", range_start, range_end); - - ESP_LOGD(TAG, "Requesting range: %s", range_header); - - int tries = 1; - int code; - bool begin_status; - while (tries <= 10) { - begin_status = http->begin(url.c_str()); - - ++tries; - if (!begin_status) { - ESP_LOGD(TAG, "Connection failed"); - delay(1000); - continue; - }; - - http->addHeader("Range", range_header); - - code = http->GET(); - if (code == 200 || code == 206) { - break; - } - ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s, retries(%d/10)", url.c_str(), - HTTPClient::errorToString(code).c_str(), tries); - http->end(); - delay(1000); - } - - if (tries > 10) { - return -1; - } - - std::string recv_string; - size_t size; - int fetched = 0; - int range = range_end - range_start; - int write_len; - - // fetch next segment from HTTP stream - while (fetched < range) { - size = http->getStreamPtr()->available(); - if (!size) { - App.feed_wdt(); - delay(2); - continue; - } - int c = http->getStreamPtr()->readBytes( - &transfer_buffer_[fetched], ((size > transfer_buffer_size_) ? transfer_buffer_size_ : size)); - fetched += c; - } - http->end(); - ESP_LOGD(TAG, "Fetched %d bytes", fetched); - - // upload fetched segments to the display in 4KB chunks - for (int i = 0; i < range; i += 4096) { - App.feed_wdt(); - write_len = content_length_ < 4096 ? content_length_ : 4096; - tf_uart->write_array(&transfer_buffer_[i], write_len); - content_length_ -= write_len; - ESP_LOGD(TAG, "Uploaded %0.1f %%, remaining %d bytes, heap: %d", - 100.0 * (tft_size_ - content_length_) / tft_size_, - content_length_, ESP.getFreeHeap()); - - if (!upload_first_chunk_sent_) { - upload_first_chunk_sent_ = true; - delay(500); - } - - recv_ret_string_(recv_string, 5000, true); - if (recv_string[0] != 0x05) { // 0x05 == "ok" - ESP_LOGD(TAG, "recv_string [%s]", - format_hex_pretty(reinterpret_cast(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(recv_string[j + 1]) << (8 * j); - } - if (result > 0) { - ESP_LOGD(TAG, "Nextion reported new range %d", result); - content_length_ = tft_size_ - result; - return result; - } - } - - recv_string.clear(); - } - return range_end + 1; - }; - auto upload_tft_ = [&](const std::string &url, unsigned int update_baud_rate_) -> bool - { - static const char *const TAG = "script.upload_tft.upload_tft_arduino"; - ESP_LOGD(TAG, "Nextion TFT upload requested"); - ESP_LOGD(TAG, " url: %s", url.c_str()); - ESP_LOGD(TAG, " baud_rate: %i", update_baud_rate_); - - if (is_updating_) { - ESP_LOGD(TAG, "Currently updating"); - return upload_end_(false); - } - - if (!network::is_connected()) { - ESP_LOGD(TAG, "Network is not connected"); - return upload_end_(false); - } - - if (display_mode->state <= 0) { - ESP_LOGD(TAG, "Setting Nextion protocol reparse mode to passive"); - exit_reparse->execute(); - disable_boot_timers_(); - delay_seconds_(5); - disable_boot_timers_(); - } - - is_updating_ = true; - - HTTPClient http; - http.setTimeout(15000); // Yes 15 seconds.... Helps 8266s along - http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); - bool begin_status = http.begin(url.c_str()); - if (!begin_status) { - is_updating_ = false; - ESP_LOGD(TAG, "Connection failed"); - ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); - allocator.deallocate(transfer_buffer_, transfer_buffer_size_); - return upload_end_(false); - } else { - ESP_LOGD(TAG, "Connected"); - } - - http.addHeader("Range", "bytes=0-255"); - const char *header_names[] = {"Content-Range"}; - http.collectHeaders(header_names, 1); - ESP_LOGD(TAG, "Requesting URL: %s", url.c_str()); - - http.setReuse(true); - // try up to 5 times. DNS sometimes needs a second try or so - int tries = 1; - int code = http.GET(); - delay(100); - - while (code != 200 && code != 206 && tries <= 5) { - ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s, retrying (%d/5)", url.c_str(), - HTTPClient::errorToString(code).c_str(), tries); - - delay(250); - code = http.GET(); - ++tries; - } - - if ((code != 200 && code != 206) || tries > 5) { - return upload_end_(false); - } - - String content_range_string = http.header("Content-Range"); - content_range_string.remove(0, 12); - content_length_ = content_range_string.toInt(); - tft_size_ = content_length_; - http.end(); - - if (content_length_ < 4096) { - ESP_LOGE(TAG, "Failed to get file size"); - return upload_end_(false); - } - - ESP_LOGD(TAG, "Updating Nextion"); - // The Nextion will ignore the update command if it is sleeping - - 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,%d,1", content_length_, update_baud_rate_); - - ESP_LOGD(TAG, "Clear serial receive buffer: %d", tf_uart->available()); - // Clear serial receive buffer - uint8_t d; - while (tf_uart->available()) { - tf_uart->read_byte(&d); - }; - - send_nextion_command(command); - - if (update_baud_rate_ != tf_uart->get_baud_rate()) { - set_baud_rate_(update_baud_rate_); - //tf_uart->set_baud_rate(update_baud_rate_); - //tf_uart->setup(); - //delay_seconds_(2); - } - - ESP_LOGD(TAG, "Waiting for upgrade response"); - std::string response; - recv_ret_string_(response, 5000, 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(response.data()), response.size()).c_str()); - - if (response.find(0x05) != std::string::npos) { - ESP_LOGD(TAG, "Preparation for tft update done"); - } else { - ESP_LOGD(TAG, "Preparation for tft update failed %d \"%s\"", response[0], response.c_str()); - return upload_end_(false); - } - - // Nextion wants 4096 bytes at a time. Make chunk_size a multiple of 4096 - uint32_t chunk_size = 8192; - if (ESP.getFreeHeap() > 81920) { // Ensure some FreeHeap to other things and limit chunk size - chunk_size = ESP.getFreeHeap() - 65536; - chunk_size = int(chunk_size / 4096) * 4096; - chunk_size = chunk_size > ${upload_tft_chunk_size_max} ? ${upload_tft_chunk_size_max} : chunk_size; - } else if (ESP.getFreeHeap() < 32768) { - chunk_size = 4096; - } - - if (transfer_buffer_ == nullptr) { - ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); - ESP_LOGD(TAG, "Allocating buffer size %d, Heap size is %" PRIu32, chunk_size, ESP.getFreeHeap()); - transfer_buffer_ = allocator.allocate(chunk_size); - if (transfer_buffer_ == nullptr) { // Try a smaller size - ESP_LOGD(TAG, "Could not allocate buffer size: %d trying 4096 instead", chunk_size); - chunk_size = 4096; - ESP_LOGD(TAG, "Allocating %d buffer", chunk_size); - transfer_buffer_ = allocator.allocate(chunk_size); - - if (!transfer_buffer_) - { - return upload_end_(false); - } - } - - transfer_buffer_size_ = chunk_size; - } - - ESP_LOGD(TAG, "Updating tft from \"%s\" with a file size of %d using %zu chunksize, Heap Size %" PRIu32, - url.c_str(), content_length_, transfer_buffer_size_, ESP.getFreeHeap()); - - int result = 0; - while (content_length_ > 0) { - result = upload_by_chunks_arduino(&http, url, result); - if (result < 0) { - ESP_LOGD(TAG, "Error updating Nextion!"); - return upload_end_(false); - } - App.feed_wdt(); - ESP_LOGD(TAG, "Heap Size %" PRIu32 ", Bytes left %d", ESP.getFreeHeap(), content_length_); - } - is_updating_ = false; - ESP_LOGD(TAG, "Successfully updated Nextion!"); - - return upload_end_(true); - }; - #elif defined(ESP_PLATFORM) // esp-idf # To do: Move to Nextion component on ESPHome - auto upload_range_esp_idf_ = [&](const std::string &url, int range_start) -> int { - static const char *const TAG = "script.upload_tft.upload_range_esp_idf_"; - ESP_LOGVV(TAG, "url: %s", url.c_str()); - uint range_size_ = tft_size_ - range_start; - ESP_LOGVV(TAG, "tft_size_: %i", tft_size_); - ESP_LOGV(TAG, "Available heap: %u", esp_get_free_heap_size()); - int range_end = (range_start == 0) ? std::min(tft_size_, 16383) : 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(buffer), 4096); - ESP_LOGVV(TAG, "Read %d bytes from HTTP client, writing to UART", read_len); - if (read_len > 0) { - tf_uart->write_array(buffer, read_len); - ESP_LOGVV(TAG, "Write to UART successful"); - recv_ret_string_(recv_string, 5000, true); - content_length_ -= read_len; - ESP_LOGD(TAG, "Uploaded %0.2f %%, remaining %d bytes, heap: %d", - 100.0 * (tft_size_ - content_length_) / tft_size_, - content_length_, esp_get_free_heap_size()); - if (recv_string[0] != 0x05) { // 0x05 == "ok" - ESP_LOGD(TAG, "recv_string [%s]", - format_hex_pretty(reinterpret_cast(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(recv_string[j + 1]) << (8 * j); - } - if (result > 0) { - ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result); - content_length_ = 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; - }; - auto upload_tft_ = [&](const std::string &url, unsigned int update_baud_rate_) -> bool { - static const char *const TAG = "script.upload_tft.upload_tft_esp_idf"; - ESP_LOGD(TAG, "Nextion TFT upload requested"); - ESP_LOGD(TAG, " url: %s", url.c_str()); - ESP_LOGD(TAG, " baud_rate: %i", update_baud_rate_); - - if (is_updating_) { - ESP_LOGW(TAG, "Currently updating"); - return upload_end_(false); - } - - if (!network::is_connected()) { - ESP_LOGE(TAG, "Network is not connected"); - return upload_end_(false); - } - - if (display_mode->state <= 0) { - ESP_LOGD(TAG, "Setting Nextion protocol reparse mode to passive"); - exit_reparse->execute(); - disable_boot_timers_(); - delay_seconds_(5); - disable_boot_timers_(); - } - - 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 = 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 upload_end_(false); // return -1 to indicate an error - } - - // 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 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 upload_end_(false); - } else { - ESP_LOGD(TAG, "File size check passed. Proceeding..."); - } - content_length_ = tft_file_size; - tft_size_ = tft_file_size; - - ESP_LOGD(TAG, "Updating Nextion"); - // The Nextion will ignore the update command if it is sleeping - - 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,%d,1", content_length_, update_baud_rate_); - - // Clear serial receive buffer - uint8_t d; - while (tf_uart->available()) { - tf_uart->read_byte(&d); - }; - - send_nextion_command(command); - - if (update_baud_rate_ != tf_uart->get_baud_rate()) { - set_baud_rate_(update_baud_rate_); - //tf_uart->set_baud_rate(update_baud_rate_); - //tf_uart->setup(); - } - - std::string response; - ESP_LOGD(TAG, "Waiting for upgrade response"); - recv_ret_string_(response, 5000, 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(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 upload_end_(false); - } - - ESP_LOGD(TAG, "Updating tft from \"%s\" with a file size of %d, Heap Size %" PRIu32, - 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_esp_idf_(url.c_str(), result); - if (result < 0) { - ESP_LOGE(TAG, "Error updating Nextion!"); - esp_http_client_cleanup(http); - return upload_end_(false); - } - App.feed_wdt(); - ESP_LOGV(TAG, "Heap Size %" PRIu32 ", Bytes left %d", esp_get_free_heap_size(), content_length_); - } - - is_updating_ = false; - 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); - }; - #endif - // The upload process starts here - disable_boot_timers_(); - nextion_init->publish_state(false); - if (display_mode->state > 0) { - disp1->set_backlight_brightness(1); - disp1->set_component_text_printf("confirm.title", "Upload TFT\\r%s", framework.c_str()); - disp1->set_component_text_printf("confirm.body", "Preparing..."); - disp1->goto_page("confirm"); - disp1->hide_component("bt_close"); - disp1->hide_component("bt_accept"); - disp1->hide_component("bt_clear"); - disp1->hide_component("bt_close"); - delay_seconds_(1); - display_wrapped_text->execute("confirm.body", "Informing the blueprint that panel is unavailable...", 18); - disp1->hide_component("bt_close"); - delay_seconds_(1); - display_wrapped_text->execute("confirm.body", "Stopping scripts...", 18); - } - stop_all->execute(); - if (display_mode->state > 0) delay_seconds_(1); + ESP_LOGD(TAG, "Starting the upload script"); - uint32_t original_baud_rate_ = tf_uart->get_baud_rate(); - if (!is_baud_rate_supported(original_baud_rate_)) original_baud_rate_ = 115200; + // Detect baud rates to be used + id(baud_rate_original) = tf_uart->get_baud_rate(); + if (!is_baud_rate_supported(id(baud_rate_original))) id(baud_rate_original) = 115200; std::string upload_tft_baud_rate_string = "${upload_tft_baud_rate}"; - uint32_t target_upload_baud_rate_ = stoi(upload_tft_baud_rate_string); - if (!is_baud_rate_supported(target_upload_baud_rate_)) target_upload_baud_rate_ = original_baud_rate_; + id(baud_rate_target) = stoi(upload_tft_baud_rate_string); + if (!is_baud_rate_supported(id(baud_rate_target))) id(baud_rate_target) = id(baud_rate_original); - ESP_LOGD(TAG, "Target upload baud rate: %d", target_upload_baud_rate_); - ESP_LOGD(TAG, "Current baud rate: %d", tf_uart->get_baud_rate()); + ESP_LOGD(TAG, " Target upload baud rate: %d bps", id(baud_rate_target)); + ESP_LOGD(TAG, " Current baud rate: %d bps", tf_uart->get_baud_rate()); - sprintf(update_msg, "Try #1 at %d bps", target_upload_baud_rate_); - ESP_LOGD(TAG, update_msg); - if (display_mode->state > 0) { - display_wrapped_text->execute("confirm.body", update_msg, 18); - } - delay_seconds_(1); - if (upload_tft_(url, target_upload_baud_rate_)) App.safe_reboot(); - ESP_LOGW(TAG, "Try #1 failed"); - if (display_mode->state > 0) display_wrapped_text->execute("confirm.body", "Try #1 failed", 18); - delay_seconds_(5); - disable_boot_timers_(); - sprintf(update_msg, "Try #2 at %d bps", target_upload_baud_rate_); - ESP_LOGD(TAG, update_msg); - if (display_mode->state > 0) { - display_wrapped_text->execute("confirm.body", update_msg, 18); - } - delay_seconds_(1); - if (upload_tft_(url, target_upload_baud_rate_)) App.safe_reboot(); - ESP_LOGW(TAG, "Try #2 failed"); - if (display_mode->state > 0) display_wrapped_text->execute("confirm.body", "Try #2 failed", 18); - delay_seconds_(5); - disable_boot_timers_(); - sprintf(update_msg, "Try #3 at %d bps", original_baud_rate_); - ESP_LOGD(TAG, update_msg); - if (display_mode->state > 0) { - display_wrapped_text->execute("confirm.body", update_msg, 18); - } - delay_seconds_(1); - if (upload_tft_(url, original_baud_rate_)) App.safe_reboot(); - ESP_LOGW(TAG, "Try #3 failed"); - if (display_mode->state > 0) { - display_wrapped_text->execute("confirm.body", "Try #3 failed. Restarting display.", 18); - } - delay_seconds_(3); - ESP_LOGD(TAG, "Turn off Nextion"); - id(screen_power).turn_off(); - delay_seconds_(2); - ESP_LOGD(TAG, "Turn on Nextion"); - id(screen_power).turn_on(); - delay_seconds_(2); - disable_boot_timers_(); - send_nextion_command("vis 255,0"); - exit_reparse->execute(); - delay_seconds_(3); - disable_boot_timers_(); - send_nextion_command("vis 255,0"); - delay_seconds_(4); - disable_boot_timers_(); - sprintf(update_msg, "Try #4 at %d bps", original_baud_rate_); - ESP_LOGD(TAG, update_msg); - if (display_mode->state > 0) { - disp1->set_backlight_brightness(1); - disp1->set_component_text_printf("confirm.title", "Upload TFT\\r%s", framework.c_str()); - display_wrapped_text->execute("confirm.body", update_msg, 18); - disp1->goto_page("confirm"); - disp1->hide_component("bt_close"); - disp1->hide_component("bt_accept"); - disp1->hide_component("bt_clear"); - disp1->hide_component("bt_close"); - } - delay_seconds_(1); - if (upload_tft_(url, original_baud_rate_)) App.safe_reboot(); - ESP_LOGW(TAG, "Try #4 failed"); - disable_boot_timers_(); - if (display_mode->state > 0) { - display_wrapped_text->execute("confirm.body", "Try #4 failed.", 18); - delay_seconds_(3); - } - disable_boot_timers_(); - sprintf(update_msg, "Try #5 at %d bps", 115200); - ESP_LOGD(TAG, update_msg); - if (display_mode->state > 0) { - disp1->set_backlight_brightness(1); - disp1->set_component_text_printf("confirm.title", "Upload TFT\\r%s", framework.c_str()); - display_wrapped_text->execute("confirm.body", update_msg, 18); - disp1->goto_page("confirm"); - disp1->hide_component("bt_close"); - disp1->hide_component("bt_accept"); - disp1->hide_component("bt_clear"); - disp1->hide_component("bt_close"); - } - delay_seconds_(1); - if (upload_tft_(url, 115200)) App.safe_reboot(); - ESP_LOGE(TAG, "TFT upload failed"); - if (display_mode->state > 0) display_wrapped_text->execute("confirm.body", "TFT upload failed", 18); - if (display_mode->state > 0) delay_seconds_(2); - ESP_LOGD(TAG, "Turn off Nextion"); - if (display_mode->state > 0) display_wrapped_text->execute("confirm.body", "Restarting...", 18); - if (display_mode->state > 0) delay_seconds_(2); - id(screen_power).turn_off(); - delay_seconds_(2); - ESP_LOGD(TAG, "Turn on Nextion"); - id(screen_power).turn_on(); - ESP_LOGD(TAG, "Restarting ESPHome"); - delay_seconds_(2); - App.safe_reboot(); + // Upload URL + ESP_LOGD(TAG, " Upload URL: %s", url.c_str()); + disp1->set_tft_url(url.c_str()); + nextion_uart_command->execute("bkcmd=3"); + + - lambda: if (id(tft_is_valid)) disp1->goto_page("home"); + - delay: 2s + - script.execute: open_upload_dialog + - script.wait: open_upload_dialog + - lambda: page_id->update(); + - wait_until: + condition: + - lambda: !lambda return (page_id->state == 26); + timeout: 2s + - script.execute: + id: report_upload_progress + message: "Set Nextion unavailable for blueprint calls" + - script.wait: report_upload_progress + - binary_sensor.template.publish: + id: nextion_init + state: false + - script.execute: + id: report_upload_progress + message: "Stopping other scripts" + - script.wait: report_upload_progress + - script.execute: stop_all + - script.wait: stop_all + - wait_until: + condition: + - lambda: !lambda return (!id(tft_is_valid)); + timeout: 1s + + ### Try twice at the target baud rate + - script.execute: nextion_status + - script.wait: nextion_status + - script.execute: + id: report_upload_progress + message: "Setting baud rate" + - script.wait: report_upload_progress + - script.execute: + id: set_baud_rate + baud_rate: !lambda return id(baud_rate_target); + definitive: false + - script.wait: set_baud_rate + - delay: 2s + # Try #1 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + # Try #2 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + + ### Try twice at the original baud rate + - script.execute: nextion_status + - script.wait: nextion_status + - script.execute: + id: report_upload_progress + message: "Setting baud rate" + - script.wait: report_upload_progress + - script.execute: + id: set_baud_rate + baud_rate: !lambda return id(baud_rate_original); + definitive: false + - script.wait: set_baud_rate + - delay: 2s + # Try #3 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + # Try #4 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + + ### Try twice at the Nextion's default baud rate (115200bps) + - script.execute: nextion_status + - script.wait: nextion_status + - script.execute: + id: report_upload_progress + message: "Setting baud rate" + - script.wait: report_upload_progress + - script.execute: + id: set_baud_rate + baud_rate: 115200 + definitive: false + - script.wait: set_baud_rate + - delay: 2s + # Try #5 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + # Try #6 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + + ### Exit reparse and try twice again + - script.execute: nextion_status + - script.wait: nextion_status + - script.execute: + id: report_upload_progress + message: "Exiting reparse mode" + - script.wait: report_upload_progress + - script.execute: exit_reparse + - script.wait: exit_reparse + - delay: 5s + - script.execute: nextion_status + - script.wait: nextion_status + - script.execute: + id: report_upload_progress + message: "Setting baud rate" + - script.wait: report_upload_progress + - script.execute: + id: set_baud_rate + baud_rate: 115200 + definitive: false + - script.wait: set_baud_rate + - delay: 2s + # Try #7 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + # Try #8 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + + ### Then try twice again at 9600bps + - script.execute: nextion_status + - script.wait: nextion_status + - script.execute: + id: report_upload_progress + message: "Setting baud rate" + - script.wait: report_upload_progress + - script.execute: + id: set_baud_rate + baud_rate: 9600 + definitive: false + - script.wait: set_baud_rate + - delay: 2s + # Try #9 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + # Try #10 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + + ### Restart Nextion and try twice again at default baud rate (115200bps) + - script.execute: + id: report_upload_progress + message: "Restarting Nextion display" + - script.wait: report_upload_progress + - wait_until: + condition: + - lambda: !lambda return (!id(tft_is_valid)); + timeout: 3s + - switch.turn_off: screen_power + - delay: 2s + - switch.turn_on: screen_power + - delay: 5s + - script.execute: nextion_status + - script.wait: nextion_status + - script.execute: + id: report_upload_progress + message: "Setting baud rate" + - script.wait: report_upload_progress + - script.execute: + id: set_baud_rate + baud_rate: 115200 + definitive: false + - script.wait: set_baud_rate + - delay: 2s + # Try #11 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + # Try #12 + - script.execute: upload_tft_try + - script.wait: upload_tft_try + - delay: 5s + + ### All tries failed ### + - script.execute: + id: report_upload_progress + message: "TFT upload failed" + - script.wait: report_upload_progress + - wait_until: + condition: + - lambda: !lambda return (!id(tft_is_valid)); + timeout: 5s + - script.execute: + id: report_upload_progress + message: "Turn off Nextion and restart ESPHome" + - script.wait: report_upload_progress + - wait_until: + condition: + - lambda: !lambda return (!id(tft_is_valid)); + timeout: 5s + - switch.turn_off: screen_power + - delay: 2s + # Restart ESPHome + - lambda: !lambda App.safe_reboot(); + + ### This code should never run + - delay: 2s + - lambda: |- + static const char *const TAG = "script.upload_tft"; + ESP_LOGD(TAG, "Finishing..."); id(is_uploading_tft) = false; - ESP_LOGD(TAG, "Finished!"); + screen_power->publish_state(true); + ESP_LOGE(TAG, "TFT upload finished unsuccessfully!"); -text: - - id: tft_update_url - name: ${device_name} Update TFT URL - platform: template - icon: mdi:file-sync - entity_category: config - disabled_by_default: true - restore_value: true - initial_value: ${nextion_update_url} - mode: text - set_action: + - id: upload_tft_try + mode: single + then: + - logger.log: "Trying to upload TFT" + - lambda: !lambda id(tft_upload_try)++; + - lambda: |- + char update_msg[128]; + sprintf(update_msg, "Try #%d at %d bps", id(tft_upload_try), tf_uart->get_baud_rate()); + report_upload_progress->execute(update_msg); + - script.wait: report_upload_progress + - wait_until: + condition: + - lambda: !lambda return (!id(tft_is_valid)); + timeout: 1s + - script.execute: nextion_upload + - script.wait: nextion_upload + - lambda: |- + char update_msg[128]; + sprintf(update_msg, "Try #%d at %d bps failed!", id(tft_upload_try), tf_uart->get_baud_rate()); + report_upload_progress->execute(update_msg); + - script.wait: report_upload_progress + +sensor: + - id: !extend display_mode + on_value: then: - - lambda: |- - static const char *const TAG = "text.tft_update_url.set_action"; - ESP_LOGD(TAG, "Update TFT URL changed: %s", x.c_str()); + lambda: |- + id(tft_is_valid) = (display_mode->state > 0 and display_mode->state < 4); diff --git a/advanced/esphome/nspanel_esphome_core.yaml b/advanced/esphome/nspanel_esphome_core.yaml index b8561c6..f822184 100644 --- a/advanced/esphome/nspanel_esphome_core.yaml +++ b/advanced/esphome/nspanel_esphome_core.yaml @@ -37,59 +37,59 @@ esphome: static const char *const TAG = "on_boot"; ESP_LOGD(TAG, "After boot check-up starting"); set_baud_rate->execute(stoi(baud_rate->state), true); - - wait_until: - condition: - - api.connected: - timeout: 60s - - wait_until: - condition: - - lambda: !lambda return disp1->is_detected(); - timeout: 10s - - lambda: |- - if (!disp1->is_setup()) { - exit_reparse->execute(); - } - - wait_until: - condition: - - lambda: !lambda return disp1->is_setup(); - timeout: 10s - - lambda: |- - static const char *const TAG = "on_boot"; + #- wait_until: + # condition: + # - api.connected: + # timeout: 60s + #- wait_until: + # condition: + # - lambda: !lambda return disp1->is_detected(); + # timeout: 10s + #- lambda: |- + # if (!disp1->is_setup()) { + # exit_reparse->execute(); + # } + #- wait_until: + # condition: + # - lambda: !lambda return disp1->is_setup(); + # timeout: 10s + #- lambda: |- + # static const char *const TAG = "on_boot"; - auto delay_seconds_ = [](int seconds) { - ESP_LOGD(TAG, "Wait %i seconds", seconds); - for (int i = 0; i < (seconds*4); i++) { - #ifdef ARDUINO - delay(250); - #elif defined(USE_ESP_IDF) - vTaskDelay(pdMS_TO_TICKS(250)); - #endif - App.feed_wdt(); - } - }; + # auto delay_seconds_ = [](int seconds) { + # ESP_LOGD(TAG, "Wait %i seconds", seconds); + # for (int i = 0; i < (seconds*4); i++) { + # #ifdef ARDUINO + # delay(250); + # #elif defined(USE_ESP_IDF) + # vTaskDelay(pdMS_TO_TICKS(250)); + # #endif + # App.feed_wdt(); + # } + # }; - nextion_status->execute(); - if (not disp1->is_setup()) { - ESP_LOGE(TAG, "No response from Nextion display"); - ESP_LOGD(TAG, "Turn off Nextion"); - screen_power->turn_off(); - delay_seconds_(2); - ESP_LOGD(TAG, "Turn on Nextion"); - screen_power->turn_on(); - delay_seconds_(5); - nextion_status->execute(); - } - - wait_until: - condition: - - lambda: !lambda return disp1->is_setup(); - timeout: 20s - - lambda: |- - static const char *const TAG = "on_boot"; - nextion_status->execute(); - if (not disp1->is_setup()) { - ESP_LOGE(TAG, "No response from Nextion display"); - } - ESP_LOGD(TAG, "Finished"); + # nextion_status->execute(); + # if (not disp1->is_setup()) { + # ESP_LOGE(TAG, "No response from Nextion display"); + # ESP_LOGD(TAG, "Turn off Nextion"); + # screen_power->turn_off(); + # delay_seconds_(2); + # ESP_LOGD(TAG, "Turn on Nextion"); + # screen_power->turn_on(); + # delay_seconds_(5); + # nextion_status->execute(); + # } + #- wait_until: + # condition: + # - lambda: !lambda return disp1->is_setup(); + # timeout: 20s + #- lambda: |- + # static const char *const TAG = "on_boot"; + # nextion_status->execute(); + # if (not disp1->is_setup()) { + # ESP_LOGE(TAG, "No response from Nextion display"); + # } + # ESP_LOGD(TAG, "Finished"); on_shutdown: then: - switch.turn_off: screen_power @@ -160,6 +160,8 @@ time: - seconds: 0 then: - script.execute: refresh_datetime + - seconds: 30 + then: - script.execute: watchdog on_time_sync: @@ -731,18 +733,23 @@ display: - id: disp1 platform: nextion uart_id: tf_uart - start_up_page: 8 on_setup: - script.execute: setup_sequence on_page: lambda: |- static const char *const TAG = "display.disp1.on_page"; - ESP_LOGD(TAG, "Nextion page changed"); - ESP_LOGD(TAG, "New page: %s (%i)" , id(page_names)[x].c_str(), x); - page_id->update(); - if (current_page->state != id(page_names)[x].c_str()) { - current_page->publish_state(id(page_names)[x].c_str()); - page_changed->execute(id(page_names)[x].c_str()); + if (id(is_uploading_tft)) { + ESP_LOGD(TAG, "Page changed ignored as a TFT upload is in progress"); + } else if (x > id(page_names).size()) { + ESP_LOGW(TAG, "Invalid page index: %i", int(x)); + } else { + ESP_LOGD(TAG, "Nextion page changed"); + ESP_LOGD(TAG, "New page: %s (%i)" , id(page_names)[x].c_str(), x); + page_id->update(); + if (current_page->state != id(page_names)[x].c_str()) { + current_page->publish_state(id(page_names)[x].c_str()); + page_changed->execute(id(page_names)[x].c_str()); + } } on_touch: lambda: |- @@ -1257,8 +1264,8 @@ select: set_action: - lambda: set_baud_rate->execute(stoi(x), true); - - name: ${device_name} Wake-up page - id: wakeup_page_name + - id: wakeup_page_name + name: ${device_name} Wake-up page platform: template options: - buttonpage01 @@ -1300,9 +1307,9 @@ sensor: resistor: 11.2kOhm ##### INTERNAL TEMPERATURE SENSOR, resistance to temperature (calculation) ##### - - name: ${device_name} Temperature + - id: temp_nspanel + name: ${device_name} Temperature platform: ntc - id: temp_nspanel sensor: resistance_sensor unit_of_measurement: ${temp_units} calibration: @@ -1322,9 +1329,9 @@ sensor: - lambda: display_embedded_temp->execute(); ###### Display Brightness GET VALUE FROM NSPanel SLIDER ##### - - name: ${device_name} brightness Slider + - id: brightslider + name: ${device_name} brightness Slider platform: nextion - id: brightslider variable_name: brightslider internal: true on_value: @@ -1336,9 +1343,9 @@ sensor: timer_reset_all->execute("settings"); ###### Display DIM Brightness GET VALUE FROM NSPanel SLIDER ##### - - name: ${device_name} dim brightness slider + - id: dimslider + name: ${device_name} dim brightness slider platform: nextion - id: dimslider variable_name: dimslider internal: true on_value: @@ -1349,8 +1356,8 @@ sensor: - lambda: |- timer_reset_all->execute("settings"); - - name: ${device_name} Page Id - id: page_id + - id: page_id + name: ${device_name} Page Id platform: nextion variable_name: dp precision: 0 @@ -1359,14 +1366,20 @@ sensor: on_value: then: - lambda: |- - if (current_page->state != id(page_names)[x].c_str()) { + static const char *const TAG = "sensor.page_id"; + ESP_LOGD(TAG, "New page Id: %i", int(x)); + if (id(is_uploading_tft)) { + ESP_LOGD(TAG, "Skipping actions as a TFT upload is in progress"); + } else if (x > id(page_names).size()) { + ESP_LOGW(TAG, "Invalid page index: %i", int(x)); + } else if (current_page->state != id(page_names)[x].c_str()) { current_page->publish_state(id(page_names)[x].c_str()); page_changed->execute(id(page_names)[x].c_str()); } ##### Display mode (1 = EU, 2 = US, 3 = US Landscape) - - name: ${device_name} Display mode - id: display_mode + - id: display_mode + name: ${device_name} Display mode platform: nextion variable_name: display_mode precision: 0 @@ -1798,14 +1811,16 @@ script: - logger.log: "Exit reparse" - uart.write: "DRAKJHSUYDGBNCJHGJKSHBDN" - uart.write: [0xFF, 0xFF, 0xFF] + - uart.write: "recmod=0" + - uart.write: [0xFF, 0xFF, 0xFF] + - uart.write: "recmod=0" + - uart.write: [0xFF, 0xFF, 0xFF] - uart.write: "connect" - uart.write: [0xFF, 0xFF, 0xFF] - uart.write: [0xFF, 0xFF] - uart.write: "connect" - uart.write: [0xFF, 0xFF, 0xFF] - - uart.write: "recmod=0" - - uart.write: [0xFF, 0xFF, 0xFF] - - uart.write: "recmod=0" + - uart.write: "bkcmd=3" - uart.write: [0xFF, 0xFF, 0xFF] - id: global_settings @@ -1847,6 +1862,7 @@ script: id(screensaver_display_time_color) = screensaver_time_color; id(is_blueprint_updated) = true; + disp1->send_command_printf("api=1"); // Update home page ESP_LOGV(TAG, "Update home page"); @@ -3013,6 +3029,7 @@ script: } // report API status + bool previous_blueprint_status = id(is_blueprint_updated); bool api_connected = api_server->is_connected(); if (api_connected) { ESP_LOGD(TAG, "API: Connected"); @@ -3071,17 +3088,18 @@ script: else { ESP_LOGW(TAG, " Is setup: False"); ESP_LOGW(TAG, " Is detected: %s", disp1->is_detected() ? "True" : "False"); - exit_reparse->execute(); + //exit_reparse->execute(); } if (nextion_init->state) ESP_LOGD(TAG, " Init: True"); + // Update api value on Nextion + if (id(is_blueprint_updated) != previous_blueprint_status) disp1->send_command_printf("api=%i", id(is_blueprint_updated) ? 1 : 0); else ESP_LOGW(TAG, " Init: False"); if (version_tft->state.empty()) ESP_LOGW(TAG, " TFT: UNKNOWN"); else ESP_LOGD(TAG, " TFT: %s", version_tft->state.c_str()); - // Update api value on Nextion - disp1->send_command_printf("api=%i", id(is_blueprint_updated) ? 1 : 0); + } ESP_LOGV(TAG, "Finished"); diff --git a/dev/instructions_for_developers.md b/dev/instructions_for_developers.md index eda0d51..e3b1f79 100644 --- a/dev/instructions_for_developers.md +++ b/dev/instructions_for_developers.md @@ -1,5 +1,24 @@ # ESPHome +### Logging +Avoid excessive log, or at least avoid excessive log at DEBUG level, but if you look around this project, many of the functionalities will log like this: + +```yaml +sensor: + - id: my_sensor + ... + on_change: + - lambda: |- + static const char *const TAG = "sensor.my_sensor"; + ESP_LOGD(TAG, "New value: %f", x); // No need to log this, use only when needed + if (id(is_uploading_tft)) { + ESP_LOGD(TAG, "Skipping any action as a TFT upload is in progress"); // No need to log this, use only when needed + } else { + // Your code here + } +``` + +### Page opened When a new page is opened, a script name `page_changed` (whith a parameter `page` containing a string with the page name) is called and that one will call a page specific script named `page_`. In addition, pages with multiple pages (entitypageXX, buttonpageXX and weatherXX) will also call a generic page named `page_entitypage`, `page_buttonpage` or `page_weather` with a parameter `page_number` containing the number of the page called. If you want to execute expecific code when a page is opened, you can extend the functionality of that specific page: @@ -21,4 +40,49 @@ script: - id: !extend page_buttonpage02 then: # Code to run when buttonpage02 is opened +``` + +#### Managing conflicts with Upload TFT +The TFT upload is the most resource conmsuming task in this project and should have all the resources available, so when creating something, please take in account: + +#### Stop your scripts before the upload starts +If you create a new script that should be stopped previous a Upload TFT starts, please add your script to the `stop_all` script like this: + +```yaml +script: + - id: !extend stop_all + then: + - script.stop: my_new_script_id +``` + +#### Check for upload status before starting any action +There is a global `is_uploading_tft` which will be true when the upload TFT process starts, so you can use this in your code like this: + +```yaml +sensor: + - id: my_sensor + ... + on_change: + - if: + condition: + - lambda: !lambda return (!id(is_uploading_tft)) + then: + # your code here +``` + +or: + +```yaml +sensor: + - id: my_sensor + ... + on_change: + - lambda: |- + static const char *const TAG = "sensor.my_sensor"; + ESP_LOGD(TAG, "New value: %f", x); // No need to log this, use only when needed + if (id(is_uploading_tft)) { + ESP_LOGD(TAG, "Skipping any action as a TFT upload is in progress"); // No need to log this, use only when needed + } else { + // Your code here + } ``` \ No newline at end of file