-
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathnspanel_esphome_addon_upload_tft.yaml
More file actions
371 lines (337 loc) · 14.2 KB
/
nspanel_esphome_addon_upload_tft.yaml
File metadata and controls
371 lines (337 loc) · 14.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
#####################################################################################################
##### NSPanel Easy - https://github.com/edwardtfn/NSPanel-Easy #####
#####################################################################################################
##### 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 ##################
nextion_update_base_url: "https://raw.githubusercontent.com/edwardtfn/NSPanel-Easy/"
nextion_update_url: "${nextion_update_base_url}/main/hmi/nspanel_blank.tft"
upload_tft_automatically: true
upload_tft_baud_rate: 115200
upload_tft_wait_ms_after_boot: 300000 # 5min
##############################################
TAG_UPLOAD_TFT: "nspanel.addon.upload_tft"
esphome:
platformio_options:
build_flags:
- -D NSPANEL_EASY_ADDON_UPLOAD_TFT
- -D NSPANEL_EASY_ADDON_UPLOAD_TFT_AUTOMATICALLY=${1 if upload_tft_automatically else 0}
# yamllint disable rule:comments-indentation
api:
actions:
##### TFT File Update Service: `upload_tft`
# Updates the panel's TFT file remotely from a specified URL or the default location, requiring the "Upload TFT" add-on.
# Usage: Essential for applying custom TFT designs or updates, especially when direct repository access is unavailable.
#
# Parameters:
# - `url` (string): URL for the TFT file. If "default" or empty, uses the URL from "Update TFT - Display Model" in Home Assistant settings.
#
# Example:
# service: esphome.<your_panel_name>_upload_tft
# data:
# url: "http://homeassistant.local:8123/local/custom_tft_file.tft" # Custom or default URL to the TFT file
#
# [!NOTE]
# Utilize "default" to automatically use the URL associated with the display model set in Home Assistant.
#
# [!ATTENTION]
# Requires the "Upload TFT" add-on for functionality.
- action: upload_tft
variables:
url: string
then:
- lambda: |-
if (!system_flags.tft_upload_active) {
tft_upload_manual_request = true;
upload_tft->execute(url.c_str());
}
button:
##### UPDATE TFT DISPLAY #####
- id: tft_update
name: Update TFT display
platform: template
icon: mdi:file-sync
entity_category: config
on_press:
then:
- lambda: |-
tft_upload_manual_request = true;
upload_tft->execute("");
display:
- id: !extend disp1
tft_url: ${nextion_update_url}
exit_reparse_on_start: true
globals:
- id: first_time_synced_ms
type: uint32_t
restore_value: false
initial_value: '0'
nspanel_easy:
lwip_tcp_mss: 1400
task_wdt_timeout_s: 30
script:
- id: !extend check_versions
then:
- lambda: |-
// Automatic upload is enabled
#if NSPANEL_EASY_ADDON_UPLOAD_TFT_AUTOMATICALLY
// Return if sensor has value and versions match (no update needed)
if (version_tft == ${min_tft_version}) {
ESP_LOGV("${TAG_UPLOAD_TFT}", "Same version");
return;
}
// Only proceed when a standard TFT is selected (indices 1+)
if (tft_file_model->active_index().value_or(0) == 0) {
ESP_LOGV("${TAG_UPLOAD_TFT}", "No standard TFT selected");
return;
}
ESP_LOGI("${TAG_UPLOAD_TFT}", "Auto updating TFT from '%" PRIu8 "' to '${min_tft_version}'", version_tft);
upload_tft->execute("");
#else // Automatic upload is disabled
ESP_LOGV("${TAG_UPLOAD_TFT}", "Auto updating is disabled");
return;
#endif // NSPANEL_EASY_ADDON_UPLOAD_TFT_AUTOMATICALLY
- id: !extend dump_config
then:
- lambda: |-
if (system_flags.tft_upload_active)
ESP_LOGW("${TAG_UPLOAD_TFT}", "TFT upload in progress");
ESP_LOGCONFIG("${TAG_UPLOAD_TFT}", "Add-on Upload TFT:");
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) // Code for ESPHome newer than v2025.11.0
ESP_LOGCONFIG("${TAG_UPLOAD_TFT}", " File model: %s", tft_file_model->current_option());
#else
ESP_LOGCONFIG("${TAG_UPLOAD_TFT}", " File model: %s", tft_file_model->state.c_str());
#endif
ESP_LOGCONFIG("${TAG_UPLOAD_TFT}", " Valid TFT: %s", YESNO((display_mode > 0 and display_mode < 4)));
- id: nextion_status
mode: restart
then:
- lambda: |-
ESP_LOGD("${TAG_UPLOAD_TFT}", "Nextion status:");
ESP_LOGD("${TAG_UPLOAD_TFT}", " Is detected: %s", YESNO(disp1->is_detected()));
ESP_LOGD("${TAG_UPLOAD_TFT}", " Is setup: %s", YESNO(disp1->is_setup()));
ESP_LOGD("${TAG_UPLOAD_TFT}", " Queue size: %d", disp1->queue_size());
- id: nextion_upload
mode: single
then:
- lambda: |-
ESP_LOGD("${TAG_UPLOAD_TFT}", "Waiting for empty UART and Nextion queues");
- wait_until:
condition:
- lambda: return (disp1->queue_size() < 1) and (tf_uart->available() < 1);
timeout: 10s
- delay: 2s
- lambda: |-
ESP_LOGD("${TAG_UPLOAD_TFT}", "Starting TFT upload");
tft_upload_result = disp1->upload_tft(${upload_tft_baud_rate}, !disp1->is_setup());
ESP_LOGV("${TAG_UPLOAD_TFT}", "TFT upload: %s", YESNO(tft_upload_result));
- id: !extend stop_all
then:
- lambda: |-
nextion_status->stop();
- id: upload_tft
mode: single
parameters:
url: string
then:
- lambda: |-
ESP_LOGI("${TAG_UPLOAD_TFT}", "Upload TFT sequence started");
- while:
condition:
- lambda: return not tft_upload_manual_request;
- lambda: return (uint32_t)(millis() - tft_upload_first_time_synced_ms) < ${upload_tft_wait_ms_after_boot};
then:
- lambda: |-
const uint32_t elapsed = (uint32_t)(millis() - tft_upload_first_time_synced_ms);
const uint32_t target = ${upload_tft_wait_ms_after_boot};
ESP_LOGD("${TAG_UPLOAD_TFT}", "Waiting after time sync: %u / %u ms elapsed (%.1f%%)",
elapsed, target, (elapsed * 100.0f) / target);
- delay: 15s
# Make sure the screen is ON
- if:
condition:
- switch.is_off: screen_power
then:
- switch.turn_on: screen_power
- delay: 5s
- lambda: |-
ESP_LOGD("${TAG_UPLOAD_TFT}", "Set Nextion unavailable for blueprint calls");
nextion_init->publish_state(false);
ESP_LOGD("${TAG_UPLOAD_TFT}", "Preparing for upload");
// Then start the upload
nextion_status->execute();
system_flags.tft_upload_active = true;
ESP_LOGD("${TAG_UPLOAD_TFT}", "Starting the upload script");
ESP_LOGV("${TAG_UPLOAD_TFT}", " Valid TFT: %s", YESNO((display_mode > 0 and display_mode < 4)));
ESP_LOGV("${TAG_UPLOAD_TFT}", " Baud rate: %" PRIu32, tf_uart->get_baud_rate());
// Calculate URL if needed
std::string resolved_url = url;
// Trim whitespace (both ends) for comparisons, but keep original casing
auto startPos = resolved_url.find_first_not_of(" \t");
auto endPos = resolved_url.find_last_not_of(" \t");
std::string trimmed = (startPos == std::string::npos)
? ""
: resolved_url.substr(startPos, endPos - startPos + 1);
std::string normalized = trimmed;
std::transform(normalized.begin(), normalized.end(), normalized.begin(),
[](unsigned char c){ return std::tolower(c); });
// Calculate URL if empty or "default"
if (normalized.empty() || normalized == "default") {
auto idx_opt = tft_file_model->active_index();
if (!idx_opt.has_value()) {
resolved_url = "${nextion_update_url}"; // Fallback if no valid index
} else {
const int idx = idx_opt.value();
if (idx == 0) {
resolved_url = "${nextion_update_url}";
} else if (idx >= 1 && idx <= 7) {
static const char* const FILENAME_PARTS[] = {
"blank", "eu", "us", "us_land", "CJK_eu", "CJK_us", "CJK_us_land"
};
resolved_url = std::string("${nextion_update_base_url}") +
"v${version}/hmi/nspanel_" +
FILENAME_PARTS[idx-1] + ".tft";
} else {
resolved_url = "${nextion_update_url}";
}
}
} else {
resolved_url = trimmed;
}
ESP_LOGV("${TAG_UPLOAD_TFT}", " Upload URL: %s", resolved_url.c_str());
disp1->set_tft_url(resolved_url.c_str());
- delay: 2s
- lambda: |-
ESP_LOGD("${TAG_UPLOAD_TFT}", "Stopping other scripts");
stop_all->execute();
- script.wait: stop_all
- wait_until:
condition:
- lambda: return (!(display_mode > 0 and display_mode < 4));
timeout: 1s
# Stop Bluetooth stack if present
- lambda: |-
// Stop Bluetooth stack to free memory for TFT upload
#ifdef USE_ESP32_BLE
ESP_LOGI("${TAG_UPLOAD_TFT}", "Stopping Bluetooth stack to free memory for TFT upload");
ESP_LOGI("${TAG_UPLOAD_TFT}", "Free heap before: %u bytes, largest block: %u bytes",
esp_get_free_heap_size(), heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
App.feed_wdt();
if (esp32_ble::global_ble != nullptr) {
ESP_LOGI("${TAG_UPLOAD_TFT}", "Disabling BLE stack");
esp32_ble::global_ble->disable();
}
#endif // USE_ESP32_BLE
- wait_until:
condition:
- lambda: |-
// Wait up to 5s to the stack being disabled
#ifdef USE_ESP32_BLE
return (esp32_ble::global_ble == nullptr || !esp32_ble::global_ble->is_active());
#else
return true;
#endif // USE_ESP32_BLE
timeout: 5s
- lambda: |-
// Release BT memory back to the heap — not done by disable().
// Required to reclaim RAM for the TFT upload.
#ifdef USE_BLUETOOTH_PROXY
App.feed_wdt();
ESP_LOGD("${TAG_UPLOAD_TFT}", "Releasing Bluetooth memory (BTDM)");
esp_err_t err = esp_bt_controller_mem_release(ESP_BT_MODE_BTDM);
if (err == ESP_OK) {
ESP_LOGI("${TAG_UPLOAD_TFT}", "Bluetooth memory released successfully");
} else {
ESP_LOGW("${TAG_UPLOAD_TFT}", "Bluetooth memory release failed: %s", esp_err_to_name(err));
}
#endif // USE_BLUETOOTH_PROXY
#ifdef USE_ESP32_BLE
ESP_LOGI("${TAG_UPLOAD_TFT}", "Free heap after: %u bytes, largest block: %u bytes",
esp_get_free_heap_size(), heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
#endif // USE_ESP32_BLE
### Attempt twice
- script.execute: upload_tft_sequence_attempt
- script.wait: upload_tft_sequence_attempt
### Restart Nextion and attempt twice again
- lambda: |-
ESP_LOGD("${TAG_UPLOAD_TFT}", "Restarting Nextion display");
screen_power->turn_off();
- delay: 2s
- switch.turn_on: screen_power
- delay: 5s
- script.execute: upload_tft_sequence_attempt
- script.wait: upload_tft_sequence_attempt
### All tries failed ###
- lambda: |-
ESP_LOGE("${TAG_UPLOAD_TFT}", "TFT upload failed");
ESP_LOGD("${TAG_UPLOAD_TFT}", "Turn off Nextion and restart ESPHome");
screen_power->turn_off();
// Restart ESPHome
App.safe_reboot();
- id: upload_tft_sequence_attempt
mode: single
then:
- lambda: |-
nextion_status->execute();
- repeat:
count: 2
then:
# First attempt
- script.execute: upload_tft_attempt
- script.wait: upload_tft_attempt
- delay: 5s
- id: upload_tft_attempt
mode: single
then:
- logger.log: "Attempting to upload TFT"
- lambda: tft_upload_attempt++;
- lambda: |-
char update_msg[128];
sprintf(update_msg, "Attempt #%d", tft_upload_attempt);
tft_upload_result = false;
ESP_LOGD("${TAG_UPLOAD_TFT}", update_msg);
- delay: 1s
- script.execute: nextion_upload
- script.wait: nextion_upload
- lambda: |-
char update_msg[128];
sprintf(update_msg, "Attempt #%d returned: %s", tft_upload_attempt,
tft_upload_result ? "Success!" : "FAILED");
ESP_LOGD("${TAG_UPLOAD_TFT}", update_msg);
ESP_LOGI("addon_upload_tft.script.upload_tft_attempt", "Restarting ESPHome");
App.safe_reboot();
select:
- id: tft_file_model
name: Update TFT display - Model
platform: template
options:
- "Use nextion_update_url"
- "NSPanel Blank"
- "NSPanel EU"
- "NSPanel US"
- "NSPanel US Landscape"
- "NSPanel EU (CJK languages)"
- "NSPanel US (CJK languages)"
- "NSPanel US Landscape (CJK languages)"
initial_option: "NSPanel Blank"
optimistic: true
restore_value: true
internal: false
entity_category: config
disabled_by_default: false
icon: mdi:file-sync
update_interval: never
time:
- id: !extend time_provider
on_time_sync:
then:
- lambda: |-
if (tft_upload_first_time_synced_ms > 0) return; // First time sync already registered
tft_upload_first_time_synced_ms = millis();
...