##################################################################################################### ##### NSPANEL ESPHOME created by Blackymas - https://github.com/Blackymas/NSPanel_HA_Blueprint ##### ##### TFT Upload engine ##### ##### PLEASE only make changes if it is necessary and also the required knowledge is available. ##### ##### For normal use with the Blueprint, no changes are necessary. ##### ##################################################################################################### ##### ATTENTION: This will add advanced elements to the core system and requires the core part. ##### ##################################################################################################### --- substitutions: ################## Defaults ################## # Just in case user forgets to set something # nextion_update_url: "http://github.com/Blackymas/NSPanel_HA_Blueprint/raw/main/custom_configuration/nspanel_eu.tft" nextion_blank_url: "http://github.com/Blackymas/NSPanel_HA_Blueprint/raw/main/custom_configuration/nspanel_blank.tft" ############################################## ##### DON'T CHANGE THIS ##### upload_tft_chunk_size_max: "32768" upload_tft_baud_rate: "0" ############################# api: services: ##### SERVICE TO UPDATE THE TFT FILE from URL ##### ##### It will use the default url if url is empty or "default" - service: upload_tft_url variables: url: string then: - lambda: |- static const char *const TAG = "service.upload_tft_url"; ESP_LOGVV(TAG, "Starting..."); std::string clean_url = url; // Convert to lowercase std::transform(clean_url.begin(), clean_url.end(), clean_url.begin(), [](unsigned char c){ return std::tolower(c); }); // Trim trailing spaces auto endPos = clean_url.find_last_not_of(" \t"); if (std::string::npos != endPos) { clean_url = clean_url.substr(0, endPos + 1); } if (clean_url.empty() or clean_url == "default") url = "${nextion_update_url}"; upload_tft->execute(url.c_str()); button: ##### UPDATE TFT DISPLAY ##### - id: tft_update name: ${device_name} Update TFT display platform: template icon: mdi:file-sync entity_category: config on_press: - lambda: |- static const char *const TAG = "button.tft_update.on_press"; ESP_LOGD(TAG, "Update TFT display button pressed"); 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: nextion_uart_command mode: queued parameters: command: string then: - lambda: |- 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(); - 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(); } - 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 disp1->set_component_text_printf("confirm.title", "Upload TFT\\rArduino"); #elif defined(ESP_PLATFORM) disp1->set_component_text_printf("confirm.title", "Upload TFT\\rESP-IDF"); #endif page_id->update(); - 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; nextion_status->execute(); uint32_t supported_baud_rates[] = {2400, 4800, 9600, 19200, 31250, 38400, 57600, 115200, 230400, 250000, 256000, 512000, 921600}; auto is_baud_rate_supported = [supported_baud_rates](uint32_t baud_rate_requested) -> bool { size_t size = sizeof(supported_baud_rates) / sizeof(supported_baud_rates[0]); for (size_t i = 0; i < size; ++i) { if (supported_baud_rates[i] == baud_rate_requested) { return true; } } return false; // Return false if not found }; // The upload process starts here ESP_LOGD(TAG, "Starting the upload script"); // 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}"; 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 bps", id(baud_rate_target)); ESP_LOGD(TAG, " Current baud rate: %d bps", tf_uart->get_baud_rate()); // 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; screen_power->publish_state(true); ESP_LOGE(TAG, "TFT upload finished unsuccessfully!"); - 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: |- id(tft_is_valid) = (display_mode->state > 0 and display_mode->state < 4);