This add-on enables your panel to upload TFT firmware files to the Nextion display, either automatically after boot or manually via a button in Home Assistant.
The Nextion display has its own controller, memory, and firmware. The UI elements and firmware are compiled into a TFT file which must be loaded onto the display for proper functionality. This add-on handles downloading the TFT file from a remote server (or a local URL) and transferring it to the display over serial.
[!NOTE] This add-on is included by default when using the standard
nspanel_esphome.yamlpackage. You only need to reference it explicitly if you are using granular package selection or if you previously removed it (e.g., for memory optimization with Bluetooth Proxy).
When the device boots and connects to Home Assistant, a version check compares the current TFT version on the display with the expected version from the firmware. Depending on your configuration, the add-on will either:
The TFT file URL is resolved in this order:
nextion_update_url is set in your substitutions → use it as-is, bypassing all other logic[!IMPORTANT] The Display model selector (under Configuration on your device’s page in Home Assistant) serves two purposes: it determines which TFT file is downloaded during an upload, and it configures the panel’s runtime behavior (touch calibration, button layout, display orientation). Always keep it set to the option matching your physical hardware.
This add-on is already part of the default nspanel_esphome.yaml package,
so most users do not need to change anything.
If you are using granular package selection, add the reference to the
addon_upload_tft file in your ESPHome settings in the packages section,
after the core and standard packages:
substitutions:
# Settings - Editable values
device_name: "YOUR_NSPANEL_NAME"
friendly_name: "Your panel's friendly name"
wifi_ssid: !secret wifi_ssid
wifi_password: !secret wifi_password
ota_password: "" # Optional: set OTA password, or use ${wifi_password} for backward compatibility (see migration guide)
language: en # Language code - see docs/localization.md for all supported codes
# Add-on configuration (if needed)
## Upload TFT
upload_tft_automatically: true
# Customization area
##### My customization - Start #####
##### My customization - End #####
# Basic and optional configurations
packages:
remote_package:
url: https://github.com/edwardtfn/NSPanel-Easy
ref: latest
refresh: 300s
files:
- nspanel_esphome.yaml # Basic package (already includes this add-on)
# Optional advanced and add-on configurations
# - esphome/nspanel_esphome_addon_climate_cool.yaml
# - esphome/nspanel_esphome_addon_climate_heat.yaml
# - esphome/nspanel_esphome_addon_climate_dual.yaml
# - esphome/nspanel_esphome_addon_cover.yaml
# - esphome/nspanel_esphome_addon_display_light.yaml
If you use granular package selection (individual files instead of nspanel_esphome.yaml),
add the Upload TFT package explicitly:
packages:
remote_package:
url: https://github.com/edwardtfn/NSPanel-Easy
ref: latest
refresh: 300s
files:
- esphome/nspanel_esphome_core.yaml
- esphome/nspanel_esphome_standard.yaml
- esphome/nspanel_esphome_addon_upload_tft.yaml # Upload TFT add-on
The following keys are available to be used in your substitutions:
| Key | Required | Supported values | Default | Description |
| :- | :-: | :-: | :-: | :- |
| upload_tft_automatically | Optional | true or false | true | When enabled, the device will automatically upload the TFT file when a version mismatch is detected after boot. When disabled, you must manually press the “Update TFT display” button in Home Assistant. |
| upload_tft_wait_ms_after_setup | Optional | Positive integer (milliseconds) | 300000 (5 min) | Time to wait after display setup completes before starting an automatic TFT upload. This delay allows the system to stabilize after boot. Reduce for faster updates; increase if you experience boot instability. |
| nextion_update_base_url | Optional | Valid HTTP/HTTPS base URL | https://raw.githubusercontent.com/edwardtfn/NSPanel-Easy/v${version}/hmi | Base URL used when building the TFT download URL automatically. Override this to host TFT files on a local server while still benefiting from automatic model and version selection. |
| nextion_update_url | Optional | Valid HTTP/HTTPS URL | (empty) | Full URL override for the TFT file. When set, this takes absolute priority. The model selector and version logic are completely bypassed and this URL is used as-is. Use only when you need full control over the TFT source, such as for custom TFT files. See important note below. |
| include_action_upload_tft | Optional | true or false | false | When set to true, registers the upload_tft API action, allowing the TFT upload to be triggered from Home Assistant scripts or automations via esphome.<panel>_upload_tft. Disabled by default to reduce memory usage at boot. See important note below. |
| include_button_scan_baud_rate | Optional | true or false | false | When set to true, registers a “Scan baud rate” diagnostic button that probes all Nextion-supported baud rates to find a working rate, then triggers a TFT upload at the discovered rate. Useful for recovering panels that cannot communicate at the configured rate. See important note below. |
nextion_update_url behaviour[!WARNING] Setting
nextion_update_urldisables all automatic URL management. The Display model selector is still used for runtime behavior (touch calibration, button layout), but the TFT file downloaded will always be the one at the URL you specified, regardless of which model is selected or which version is current. You are responsible for keeping this URL pointing to a compatible and up-to-date TFT file.
When nextion_update_url is left empty (the default), the add-on builds the download URL
automatically from the selected Display model and the current firmware version. This is
the recommended configuration for most users.
include_action_upload_tft behaviour[!NOTE] This substitution was introduced to address boot-time memory exhaustion on devices running memory-intensive configurations (e.g. Bluetooth Proxy). Registering API actions consumes heap memory at boot; disabling unused actions recovers that memory.
When set to false (the default), the upload_tft API action is not registered.
All other functionality of this add-on remains fully operational: automatic TFT upload on
version mismatch, the “Update TFT display” button in Home Assistant, and the boot baud
rate scan are all unaffected.
Set this to true only if you need to trigger TFT uploads programmatically from Home
Assistant scripts or automations using the esphome.<panel>_upload_tft service call.
[!IMPORTANT] If you were previously calling
esphome.<panel>_upload_tftfrom an automation or script, addinclude_action_upload_tft: trueto your substitutions to restore that behaviour. This is a breaking change introduced to improve boot stability on memory-constrained devices.
include_button_scan_baud_rate behaviour[!NOTE] The boot process automatically scans baud rates when the display does not respond at the configured rate within a couple of minutes (see Boot baud rate scan below). The diagnostic button described here is a manual fallback for cases where the automatic scan did not run, did not succeed, or where you want to force a rescan without rebooting the panel.
When set to true, this add-on exposes a “Scan baud rate” button. Pressing it:
This add-on extends the Display model selector with additional options beyond the hardware models defined in the base firmware:
| Option | TFT file | Notes |
|---|---|---|
| NSPanel EU | nspanel_landscape.tft |
Standard EU hardware |
| NSPanel US | nspanel_portrait.tft |
Standard US hardware (portrait) |
| NSPanel US Landscape | nspanel_landscape.tft |
US hardware mounted in landscape |
| NSPanel Blank | nspanel_blank.tft |
First-time installation only. See NSPanel Blank |
substitutions:
device_name: "YOUR_NSPANEL_NAME"
friendly_name: "Your panel's friendly name"
wifi_ssid: !secret wifi_ssid
wifi_password: !secret wifi_password
ota_password: "" # Optional: set OTA password, or use ${wifi_password} for backward compatibility (see migration guide)
language: en # Language code - see docs/localization.md for all supported codes
# Upload TFT configuration
upload_tft_automatically: true
upload_tft_wait_ms_after_setup: 120000 # Wait 2 minutes after setup instead of 29s
packages:
remote_package:
url: https://github.com/edwardtfn/NSPanel-Easy
ref: latest
refresh: 300s
files:
- nspanel_esphome.yaml
substitutions:
device_name: "YOUR_NSPANEL_NAME"
friendly_name: "Your panel's friendly name"
wifi_ssid: !secret wifi_ssid
wifi_password: !secret wifi_password
ota_password: "" # Optional: set OTA password, or use ${wifi_password} for backward compatibility (see migration guide)
language: en # Language code - see docs/localization.md for all supported codes
# Disable automatic TFT upload
upload_tft_automatically: false
packages:
remote_package:
url: https://github.com/edwardtfn/NSPanel-Easy
ref: latest
refresh: 300s
files:
- nspanel_esphome.yaml
Use nextion_update_url only when you need to serve a custom or locally hosted TFT file.
For standard setups, the automatic URL resolution based on the Display model selector
is recommended instead.
substitutions:
device_name: "YOUR_NSPANEL_NAME"
friendly_name: "Your panel's friendly name"
wifi_ssid: !secret wifi_ssid
wifi_password: !secret wifi_password
ota_password: "" # Optional: set OTA password, or use ${wifi_password} for backward compatibility (see migration guide)
language: en # Language code - see docs/localization.md for all supported codes
# Use a locally hosted TFT file - bypasses automatic model and version selection
nextion_update_url: "http://homeassistant.local:8123/local/nspanel_landscape.tft"
packages:
remote_package:
url: https://github.com/edwardtfn/NSPanel-Easy
ref: latest
refresh: 300s
files:
- nspanel_esphome.yaml
If your network cannot reach GitHub but you want to keep automatic model and version selection,
override nextion_update_base_url instead of nextion_update_url:
substitutions:
device_name: "YOUR_NSPANEL_NAME"
friendly_name: "Your panel's friendly name"
wifi_ssid: !secret wifi_ssid
wifi_password: !secret wifi_password
ota_password: "" # Optional: set OTA password, or use ${wifi_password} for backward compatibility (see migration guide)
language: en # Language code - see docs/localization.md for all supported codes
# Mirror the TFT files locally and point to your server
nextion_update_base_url: "http://homeassistant.local:8123/local/nspanel-easy/"
packages:
remote_package:
url: https://github.com/edwardtfn/NSPanel-Easy
ref: latest
refresh: 300s
files:
- nspanel_esphome.yaml
When upload_tft_automatically is set to true (the default), the device will:
upload_tft_wait_ms_after_setup) after display setup completes.[!NOTE] The wait period exists to prevent the TFT upload from starting before the boot process has fully completed, as early uploads have been reported to cause issues on some devices. During this time the panel may not behave as expected, since the display is running an incompatible TFT version.
If you prefer not to wait, you can press the “Update TFT display” button in Home Assistant at any time to trigger an immediate upload, bypassing the remaining wait.
To manually trigger a TFT upload:
The TFT upload process requires a significant amount of free memory on the ESP32. If you are running memory-intensive components such as Bluetooth Proxy alongside this add-on, the TFT upload may fail due to insufficient memory.
In such cases, you can temporarily remove memory-heavy components, perform the TFT update, and then re-add them. See the Memory Optimization section in the installation guide for detailed instructions.
If the display does not respond at the configured baud rate (default 921600 bps) within a couple of minutes of boot, the panel automatically scans all Nextion-supported baud rates to find one where the display answers. This recovers panels in the following situations:
When the scan finds a working rate, the panel continues operating at that rate for the current session and triggers a TFT upload. The new TFT enforces the configured rate on its next boot, so subsequent boots return to the configured rate automatically.
If the scan finds no responsive rate, the panel power-cycles the display and repeats the wait-and-scan cycle indefinitely.
The scan typically completes within seconds for known-good displays. Probe timing can
be tuned via the BAUD_RATE_PROBE_MS substitution (default 1500 ms per rate).
See the Hardware UART configuration for details.
For common TFT transfer issues and solutions, see the TFT Transfer Troubleshooting Guide.