ESPHome 2026.3.3
Loading...
Searching...
No Matches
nextion.cpp
Go to the documentation of this file.
1#include "nextion.h"
2#include <cinttypes>
5#include "esphome/core/log.h"
6#include "esphome/core/util.h"
7
8namespace esphome {
9namespace nextion {
10
11static const char *const TAG = "nextion";
12
14 this->is_setup_ = false;
15 this->connection_state_.ignore_is_setup_ = true;
16
17 // Wake up the nextion and ensure clean communication state
18 this->send_command_("sleep=0"); // Exit sleep mode if sleeping
19 this->send_command_("bkcmd=0"); // Disable return data during init sequence
20
21 // Reset device for clean state - critical for reliable communication
22 this->send_command_("rest");
23
24 this->connection_state_.ignore_is_setup_ = false;
25}
26
27bool Nextion::send_command_(const std::string &command) {
28 if (!this->connection_state_.ignore_is_setup_ && !this->is_setup()) {
29 return false;
30 }
31
32#ifdef USE_NEXTION_COMMAND_SPACING
33 if (!this->connection_state_.ignore_is_setup_ && !this->command_pacer_.can_send()) {
34 ESP_LOGN(TAG, "Command spacing: delaying command '%s'", command.c_str());
35 return false;
36 }
37#endif // USE_NEXTION_COMMAND_SPACING
38
39 ESP_LOGN(TAG, "cmd: %s", command.c_str());
40
41 this->write_str(command.c_str());
42 const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF};
43 this->write_array(to_send, sizeof(to_send));
44
45 return true;
46}
47
49 if (this->connection_state_.is_connected_)
50 return true;
51
52#ifdef USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
53 ESP_LOGW(TAG, "Connected (no handshake)"); // Log the connection status without handshake
54 this->is_connected_ = true; // Set the connection status to true
55 return true; // Return true indicating the connection is set
56#else // USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
57 if (this->comok_sent_ == 0) {
58 this->reset_(false);
59
60 this->connection_state_.ignore_is_setup_ = true;
61 this->send_command_("boguscommand=0"); // bogus command. needed sometimes after updating
62#ifdef USE_NEXTION_CONFIG_EXIT_REPARSE_ON_START
63 this->send_command_("DRAKJHSUYDGBNCJHGJKSHBDN");
64#endif // USE_NEXTION_CONFIG_EXIT_REPARSE_ON_START
65 this->send_command_("connect");
66
68 this->connection_state_.ignore_is_setup_ = false;
69
70 return false;
71 }
72
73 if (App.get_loop_component_start_time() - this->comok_sent_ <= 500) // Wait 500 ms
74 return false;
75
76 std::string response;
77
78 this->recv_ret_string_(response, 0, false);
79 if (!response.empty() && response[0] == 0x1A) {
80 // Swallow invalid variable name responses that may be caused by the above commands
81 ESP_LOGV(TAG, "0x1A error ignored (setup)");
82 return false;
83 }
84 if (response.empty() || response.find("comok") == std::string::npos) {
85#ifdef NEXTION_PROTOCOL_LOG
86 ESP_LOGN(TAG, "Bad connect: %s", response.c_str());
87 for (size_t i = 0; i < response.length(); i++) {
88 ESP_LOGN(TAG, "resp: %s %d %d %c", response.c_str(), i, response[i], response[i]);
89 }
90#endif // NEXTION_PROTOCOL_LOG
91
92 ESP_LOGW(TAG, "Not connected");
93 comok_sent_ = 0;
94 return false;
95 }
96
97 this->connection_state_.ignore_is_setup_ = true;
98 ESP_LOGI(TAG, "Connected");
99 this->connection_state_.is_connected_ = true;
100
101 ESP_LOGN(TAG, "connect: %s", response.c_str());
102
103 size_t start;
104 size_t end = 0;
105 std::vector<std::string> connect_info;
106 while ((start = response.find_first_not_of(',', end)) != std::string::npos) {
107 end = response.find(',', start);
108 connect_info.push_back(response.substr(start, end - start));
109 }
110
111 this->is_detected_ = (connect_info.size() == 7);
112 if (this->is_detected_) {
113 ESP_LOGN(TAG, "Connect info: %zu", connect_info.size());
114#ifdef USE_NEXTION_CONFIG_DUMP_DEVICE_INFO
115 this->device_model_ = connect_info[2];
116 this->firmware_version_ = connect_info[3];
117 this->serial_number_ = connect_info[5];
118 this->flash_size_ = connect_info[6];
119#else // USE_NEXTION_CONFIG_DUMP_DEVICE_INFO
120 ESP_LOGI(TAG,
121 " Device Model: %s\n"
122 " FW Version: %s\n"
123 " Serial Number: %s\n"
124 " Flash Size: %s\n",
125 connect_info[2].c_str(), connect_info[3].c_str(), connect_info[5].c_str(), connect_info[6].c_str());
126#endif // USE_NEXTION_CONFIG_DUMP_DEVICE_INFO
127 } else {
128 ESP_LOGE(TAG, "Bad connect value: '%s'", response.c_str());
129 }
130
131 this->connection_state_.ignore_is_setup_ = false;
132 this->dump_config();
133 return true;
134#endif // USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
135}
136
137void Nextion::reset_(bool reset_nextion) {
138 uint8_t d;
139
140 while (this->available()) { // Clear receive buffer
141 this->read_byte(&d);
142 };
143 this->nextion_queue_.clear();
144 this->waveform_queue_.clear();
145}
146
148 ESP_LOGCONFIG(TAG, "Nextion:");
149
150#ifdef USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
151 ESP_LOGCONFIG(TAG, " Skip handshake: YES");
152#else // USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
153#ifdef USE_NEXTION_CONFIG_DUMP_DEVICE_INFO
154 ESP_LOGCONFIG(TAG,
155 " Device Model: %s\n"
156 " FW Version: %s\n"
157 " Serial Number: %s\n"
158 " Flash Size: %s\n"
159 " Max queue age: %u ms\n"
160 " Startup override: %u ms\n",
161 this->device_model_.c_str(), this->firmware_version_.c_str(), this->serial_number_.c_str(),
162 this->flash_size_.c_str(), this->max_q_age_ms_, this->startup_override_ms_);
163#endif // USE_NEXTION_CONFIG_DUMP_DEVICE_INFO
164#ifdef USE_NEXTION_CONFIG_EXIT_REPARSE_ON_START
165 ESP_LOGCONFIG(TAG, " Exit reparse: YES\n");
166#endif // USE_NEXTION_CONFIG_EXIT_REPARSE_ON_START
167 ESP_LOGCONFIG(TAG,
168 " Wake On Touch: %s\n"
169 " Touch Timeout: %" PRIu16,
170 YESNO(this->connection_state_.auto_wake_on_touch_), this->touch_sleep_timeout_);
171#endif // USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
172
173#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP
174 ESP_LOGCONFIG(TAG, " Max commands per loop: %u", this->max_commands_per_loop_);
175#endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP
176
177 if (this->wake_up_page_ != 255) {
178 ESP_LOGCONFIG(TAG, " Wake Up Page: %u", this->wake_up_page_);
179 }
180
181#ifdef USE_NEXTION_CONF_START_UP_PAGE
182 if (this->start_up_page_ != 255) {
183 ESP_LOGCONFIG(TAG, " Start Up Page: %u", this->start_up_page_);
184 }
185#endif // USE_NEXTION_CONF_START_UP_PAGE
186
187#ifdef USE_NEXTION_COMMAND_SPACING
188 ESP_LOGCONFIG(TAG, " Cmd spacing: %u ms", this->command_pacer_.get_spacing());
189#endif // USE_NEXTION_COMMAND_SPACING
190
191#ifdef USE_NEXTION_MAX_QUEUE_SIZE
192 ESP_LOGCONFIG(TAG, " Max queue size: %zu", this->max_queue_size_);
193#endif
194#ifdef USE_NEXTION_TFT_UPLOAD
195 ESP_LOGCONFIG(TAG,
196 " TFT URL: %s\n"
197 " TFT upload HTTP timeout: %" PRIu16 "ms\n"
198 " TFT upload HTTP retries: %u",
199 this->tft_url_.c_str(), this->tft_upload_http_timeout_, this->tft_upload_http_retries_);
200#ifdef USE_ESP32
201 if (this->tft_upload_watchdog_timeout_ > 0) {
202 ESP_LOGCONFIG(TAG, " TFT upload WDT timeout: %" PRIu32 "ms", this->tft_upload_watchdog_timeout_);
203 }
204#endif // USE_ESP32
205#endif // USE_NEXTION_TFT_UPLOAD
206}
207
209 if (!this->is_setup()) {
210 return;
211 }
212 if (this->writer_.has_value()) {
213 (*this->writer_)(*this);
214 }
215}
216
217void Nextion::add_sleep_state_callback(std::function<void()> &&callback) {
218 this->sleep_callback_.add(std::move(callback));
219}
220
221void Nextion::add_wake_state_callback(std::function<void()> &&callback) {
222 this->wake_callback_.add(std::move(callback));
223}
224
225void Nextion::add_setup_state_callback(std::function<void()> &&callback) {
226 this->setup_callback_.add(std::move(callback));
227}
228
229void Nextion::add_new_page_callback(std::function<void(uint8_t)> &&callback) {
230 this->page_callback_.add(std::move(callback));
231}
232
233void Nextion::add_touch_event_callback(std::function<void(uint8_t, uint8_t, bool)> &&callback) {
234 this->touch_callback_.add(std::move(callback));
235}
236
237void Nextion::add_buffer_overflow_event_callback(std::function<void()> &&callback) {
238 this->buffer_overflow_callback_.add(std::move(callback));
239}
240
242 if ((!this->is_setup() && !this->connection_state_.ignore_is_setup_) || this->is_sleeping())
243 return;
244
245 for (auto *binarysensortype : this->binarysensortype_) {
246 binarysensortype->update_component();
247 }
248 for (auto *sensortype : this->sensortype_) {
249 sensortype->update_component();
250 }
251 for (auto *switchtype : this->switchtype_) {
252 switchtype->update_component();
253 }
254 for (auto *textsensortype : this->textsensortype_) {
255 textsensortype->update_component();
256 }
257}
258
259bool Nextion::send_command(const char *command) {
260 if ((!this->is_setup() && !this->connection_state_.ignore_is_setup_) || this->is_sleeping())
261 return false;
262
263 if (this->send_command_(command)) {
264 this->add_no_result_to_queue_("send_command");
265 return true;
266 }
267 return false;
268}
269
270bool Nextion::send_command_printf(const char *format, ...) {
271 if ((!this->is_setup() && !this->connection_state_.ignore_is_setup_) || this->is_sleeping())
272 return false;
273
274 char buffer[256];
275 va_list arg;
276 va_start(arg, format);
277 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
278 va_end(arg);
279 if (ret <= 0) {
280 ESP_LOGW(TAG, "Bad cmd format: '%s'", format);
281 return false;
282 }
283
284 if (this->send_command_(buffer)) {
285 this->add_no_result_to_queue_("send_command_printf");
286 return true;
287 }
288 return false;
289}
290
291#ifdef NEXTION_PROTOCOL_LOG
293 ESP_LOGN(TAG, "print_queue_members_ (top 10) size %zu", this->nextion_queue_.size());
294 ESP_LOGN(TAG, "*******************************************");
295 int count = 0;
296 for (auto *i : this->nextion_queue_) {
297 if (count++ == 10)
298 break;
299
300 if (i == nullptr) {
301 ESP_LOGN(TAG, "Queue null");
302 } else {
303 ESP_LOGN(TAG, "Queue type: %d:%s, name: %s", i->component->get_queue_type(),
304 i->component->get_queue_type_string().c_str(), i->component->get_variable_name().c_str());
305 }
306 }
307 ESP_LOGN(TAG, "*******************************************");
308}
309#endif
310
312 if (!this->check_connect_() || this->connection_state_.is_updating_)
313 return;
314
315 if (this->connection_state_.nextion_reports_is_setup_ && !this->connection_state_.sent_setup_commands_) {
316 this->connection_state_.ignore_is_setup_ = true;
317 this->connection_state_.sent_setup_commands_ = true;
318 this->send_command_("bkcmd=3"); // Always, returns 0x00 to 0x23 result of serial command.
319
320 if (this->brightness_.has_value()) {
321 this->set_backlight_brightness(this->brightness_.value());
322 }
323
324#ifdef USE_NEXTION_CONF_START_UP_PAGE
325 // Check if a startup page has been set and send the command
326 if (this->start_up_page_ != 255) {
327 this->goto_page(this->start_up_page_);
328 }
329#endif // USE_NEXTION_CONF_START_UP_PAGE
330
331 if (this->wake_up_page_ != 255) {
332 this->set_wake_up_page(this->wake_up_page_);
333 }
334
335 if (this->touch_sleep_timeout_ != 0) {
337 }
338
339 this->set_auto_wake_on_touch(this->connection_state_.auto_wake_on_touch_);
340
341 this->connection_state_.ignore_is_setup_ = false;
342 }
343
344 this->process_serial_(); // Receive serial data
345 this->process_nextion_commands_(); // Process nextion return commands
346
347 if (!this->connection_state_.nextion_reports_is_setup_) {
348 if (this->started_ms_ == 0)
350
351 if (this->startup_override_ms_ > 0 &&
352 App.get_loop_component_start_time() - this->started_ms_ > this->startup_override_ms_) {
353 ESP_LOGV(TAG, "Manual ready set");
354 this->connection_state_.nextion_reports_is_setup_ = true;
355 }
356 }
357
358#ifdef USE_NEXTION_COMMAND_SPACING
359 // Try to send any pending commands if spacing allows
361#endif // USE_NEXTION_COMMAND_SPACING
362}
363
364#ifdef USE_NEXTION_COMMAND_SPACING
366 if (this->nextion_queue_.empty() || !this->command_pacer_.can_send()) {
367 return;
368 }
369
370 // Check if first item in queue has a pending command
371 auto *front_item = this->nextion_queue_.front();
372 if (front_item && !front_item->pending_command.empty()) {
373 if (this->send_command_(front_item->pending_command)) {
374 // Command sent successfully, clear the pending command
375 front_item->pending_command.clear();
376 ESP_LOGVV(TAG, "Pending command sent: %s", front_item->component->get_variable_name().c_str());
377 }
378 }
379}
380#endif // USE_NEXTION_COMMAND_SPACING
381
382bool Nextion::remove_from_q_(bool report_empty) {
383 if (this->nextion_queue_.empty()) {
384 if (report_empty) {
385 ESP_LOGE(TAG, "Queue empty");
386 }
387 return false;
388 }
389
390 NextionQueue *nb = this->nextion_queue_.front();
391 if (!nb || !nb->component) {
392 ESP_LOGE(TAG, "Invalid queue");
393 this->nextion_queue_.pop_front();
394 return false;
395 }
397
398 ESP_LOGN(TAG, "Removed: %s", component->get_variable_name().c_str());
399
400 if (component->get_queue_type() == NextionQueueType::NO_RESULT) {
401 if (component->get_variable_name() == "sleep_wake") {
402 this->is_sleeping_ = false;
403 }
404 delete component; // NOLINT(cppcoreguidelines-owning-memory)
405 }
406 delete nb; // NOLINT(cppcoreguidelines-owning-memory)
407 this->nextion_queue_.pop_front();
408 return true;
409}
410
412 // Read all available bytes in batches to reduce UART call overhead.
413 size_t avail = this->available();
414 uint8_t buf[64];
415 while (avail > 0) {
416 size_t to_read = std::min(avail, sizeof(buf));
417 if (!this->read_array(buf, to_read)) {
418 break;
419 }
420 avail -= to_read;
421
422 this->command_data_.append(reinterpret_cast<const char *>(buf), to_read);
423 }
424}
425// nextion.tech/instruction-set/
427 if (this->command_data_.empty()) {
428 return;
429 }
430
431#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP
432 size_t commands_processed = 0;
433#endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP
434
435 size_t to_process_length = 0;
436 std::string to_process;
437
438 ESP_LOGN(TAG, "command_data_ %s len %d", this->command_data_.c_str(), this->command_data_.length());
439#ifdef NEXTION_PROTOCOL_LOG
440 this->print_queue_members_();
441#endif
442 while ((to_process_length = this->command_data_.find(COMMAND_DELIMITER)) != std::string::npos) {
443#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP
444 if (++commands_processed > this->max_commands_per_loop_) {
445 ESP_LOGW(TAG, "Command processing limit exceeded");
446 break;
447 }
448#endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP
449 ESP_LOGN(TAG, "queue size: %zu", this->nextion_queue_.size());
450 while (to_process_length + COMMAND_DELIMITER.length() < this->command_data_.length() &&
451 static_cast<uint8_t>(this->command_data_[to_process_length + COMMAND_DELIMITER.length()]) == 0xFF) {
452 ++to_process_length;
453 ESP_LOGN(TAG, "Add 0xFF");
454 }
455
456 const uint8_t nextion_event = this->command_data_[0];
457
458 to_process_length -= 1;
459 to_process = this->command_data_.substr(1, to_process_length);
460
461 switch (nextion_event) {
462 case 0x00: // instruction sent by user has failed
463 ESP_LOGW(TAG, "Invalid instruction");
464 this->remove_from_q_();
465
466 break;
467 case 0x01: // instruction sent by user was successful
468
469 ESP_LOGVV(TAG, "Cmd OK");
470 ESP_LOGN(TAG, "this->nextion_queue_.empty() %s", YESNO(this->nextion_queue_.empty()));
471
472 this->remove_from_q_();
473 if (!this->is_setup_) {
474 if (this->nextion_queue_.empty()) {
475 this->is_setup_ = true;
476 this->setup_callback_.call();
477 }
478 }
479#ifdef USE_NEXTION_COMMAND_SPACING
480 this->command_pacer_.mark_sent(); // Here is where we should mark the command as sent
481 ESP_LOGN(TAG, "Command spacing: marked command sent");
482#endif
483 break;
484 case 0x02: // invalid Component ID or name was used
485 ESP_LOGW(TAG, "Invalid component ID/name");
486 this->remove_from_q_();
487 break;
488 case 0x03: // invalid Page ID or name was used
489 ESP_LOGW(TAG, "Invalid page ID");
490 this->remove_from_q_();
491 break;
492 case 0x04: // invalid Picture ID was used
493 ESP_LOGW(TAG, "Invalid picture ID");
494 this->remove_from_q_();
495 break;
496 case 0x05: // invalid Font ID was used
497 ESP_LOGW(TAG, "Invalid font ID");
498 this->remove_from_q_();
499 break;
500 case 0x06: // File operation fails
501 ESP_LOGW(TAG, "File operation failed");
502 break;
503 case 0x09: // Instructions with CRC validation fails their CRC check
504 ESP_LOGW(TAG, "CRC validation failed");
505 break;
506 case 0x11: // invalid Baud rate was used
507 ESP_LOGW(TAG, "Invalid baud rate");
508 break;
509 case 0x12: // invalid Waveform ID or Channel # was used
510 if (this->waveform_queue_.empty()) {
511 ESP_LOGW(TAG, "Waveform ID/ch used but no sensor queued");
512 } else {
513 auto &nb = this->waveform_queue_.front();
514 NextionComponentBase *component = nb->component;
515
516 ESP_LOGW(TAG, "Invalid waveform ID %d/ch %d", component->get_component_id(),
517 component->get_wave_channel_id());
518
519 ESP_LOGN(TAG, "Remove waveform ID %d/ch %d", component->get_component_id(), component->get_wave_channel_id());
520
521 delete nb; // NOLINT(cppcoreguidelines-owning-memory)
522 this->waveform_queue_.pop_front();
523 }
524 break;
525 case 0x1A: // variable name invalid
526 ESP_LOGW(TAG, "Invalid variable name");
527 this->remove_from_q_();
528 break;
529 case 0x1B: // variable operation invalid
530 ESP_LOGW(TAG, "Invalid variable operation");
531 this->remove_from_q_();
532 break;
533 case 0x1C: // failed to assign
534 ESP_LOGW(TAG, "Variable assign failed");
535 this->remove_from_q_();
536 break;
537 case 0x1D: // operate EEPROM failed
538 ESP_LOGW(TAG, "EEPROM operation failed");
539 break;
540 case 0x1E: // parameter quantity invalid
541 ESP_LOGW(TAG, "Invalid parameter count");
542 this->remove_from_q_();
543 break;
544 case 0x1F: // IO operation failed
545 ESP_LOGW(TAG, "Invalid component I/O");
546 break;
547 case 0x20: // undefined escape characters
548 ESP_LOGW(TAG, "Undefined escape chars");
549 this->remove_from_q_();
550 break;
551 case 0x23: // too long variable name
552 ESP_LOGW(TAG, "Variable name too long");
553 this->remove_from_q_();
554 break;
555 case 0x24: // Serial Buffer overflow occurs
556 // Buffer will continue to receive the current instruction, all previous instructions are lost.
557 ESP_LOGE(TAG, "Serial buffer overflow");
558 this->buffer_overflow_callback_.call();
559 break;
560 case 0x65: { // touch event return data
561 if (to_process_length != 3) {
562 ESP_LOGW(TAG, "Incorrect touch len: %zu (need 3)", to_process_length);
563 break;
564 }
565
566 uint8_t page_id = to_process[0];
567 uint8_t component_id = to_process[1];
568 uint8_t touch_event = to_process[2]; // 0 -> release, 1 -> press
569 ESP_LOGV(TAG, "Touch %s: page %u comp %u", touch_event ? "PRESS" : "RELEASE", page_id, component_id);
570 for (auto *touch : this->touch_) {
571 touch->process_touch(page_id, component_id, touch_event != 0);
572 }
573 this->touch_callback_.call(page_id, component_id, touch_event != 0);
574 break;
575 }
576 case 0x66: { // Nextion initiated new page event return data.
577 // Also is used for sendme command which we never explicitly initiate
578 if (to_process_length != 1) {
579 ESP_LOGW(TAG, "Page event: expect 1, got %zu", to_process_length);
580 break;
581 }
582
583 uint8_t page_id = to_process[0];
584 ESP_LOGV(TAG, "New page: %u", page_id);
585 this->page_callback_.call(page_id);
586 break;
587 }
588 case 0x67: { // Touch Coordinate (awake)
589 break;
590 }
591 case 0x68: { // touch coordinate data (sleep)
592
593 if (to_process_length != 5) {
594 ESP_LOGW(TAG, "Touch coordinate: expect 5, got %zu", to_process_length);
595 ESP_LOGW(TAG, "%s", to_process.c_str());
596 break;
597 }
598
599 const uint16_t x = (uint16_t(to_process[0]) << 8) | to_process[1];
600 const uint16_t y = (uint16_t(to_process[2]) << 8) | to_process[3];
601 const uint8_t touch_event = to_process[4]; // 0 -> release, 1 -> press
602 ESP_LOGV(TAG, "Touch %s at %u,%u", touch_event ? "PRESS" : "RELEASE", x, y);
603 break;
604 }
605
606 // 0x70 0x61 0x62 0x31 0x32 0x33 0xFF 0xFF 0xFF
607 // Returned when using get command for a string.
608 // Each byte is converted to char.
609 // data: ab123
610 case 0x70: // string variable data return
611 {
612 if (this->nextion_queue_.empty()) {
613 ESP_LOGW(TAG, "String return but queue is empty");
614 break;
615 }
616
617 NextionQueue *nb = this->nextion_queue_.front();
618 if (!nb || !nb->component) {
619 ESP_LOGE(TAG, "Invalid queue entry");
620 this->nextion_queue_.pop_front();
621 return;
622 }
624
625 if (component->get_queue_type() != NextionQueueType::TEXT_SENSOR) {
626 ESP_LOGE(TAG, "String return but '%s' not text sensor", component->get_variable_name().c_str());
627 } else {
628 ESP_LOGN(TAG, "String resp: '%s' id: %s type: %s", to_process.c_str(), component->get_variable_name().c_str(),
629 component->get_queue_type_string().c_str());
630 }
631
632 delete nb; // NOLINT(cppcoreguidelines-owning-memory)
633 this->nextion_queue_.pop_front();
634
635 break;
636 }
637 // 0x71 0x01 0x02 0x03 0x04 0xFF 0xFF 0xFF
638 // Returned when get command to return a number
639 // 4 byte 32-bit value in little endian order.
640 // (0x01+0x02*256+0x03*65536+0x04*16777216)
641 // data: 67305985
642 case 0x71: // numeric variable data return
643 {
644 if (this->nextion_queue_.empty()) {
645 ESP_LOGE(TAG, "Numeric return but queue empty");
646 break;
647 }
648
649 if (to_process_length < 4) {
650 ESP_LOGE(TAG, "Numeric return but insufficient data (need 4, got %zu)", to_process_length);
651 break;
652 }
653
654 int value = static_cast<int>(encode_uint32(to_process[3], to_process[2], to_process[1], to_process[0]));
655
656 NextionQueue *nb = this->nextion_queue_.front();
657 if (!nb || !nb->component) {
658 ESP_LOGE(TAG, "Invalid queue");
659 this->nextion_queue_.pop_front();
660 return;
661 }
663
664 if (component->get_queue_type() != NextionQueueType::SENSOR &&
665 component->get_queue_type() != NextionQueueType::BINARY_SENSOR &&
666 component->get_queue_type() != NextionQueueType::SWITCH) {
667 ESP_LOGE(TAG, "Numeric return but '%s' invalid type %d", component->get_variable_name().c_str(),
668 component->get_queue_type());
669 } else {
670 ESP_LOGN(TAG, "Numeric: %s type %d:%s val %d", component->get_variable_name().c_str(),
671 component->get_queue_type(), component->get_queue_type_string().c_str(), value);
672 component->set_state_from_int(value, true, false);
673 }
674
675 delete nb; // NOLINT(cppcoreguidelines-owning-memory)
676 this->nextion_queue_.pop_front();
677
678 break;
679 }
680
681 case 0x86: { // device automatically enters into sleep mode
682 ESP_LOGVV(TAG, "Auto sleep");
683 this->is_sleeping_ = true;
684 this->sleep_callback_.call();
685 break;
686 }
687 case 0x87: // device automatically wakes up
688 {
689 ESP_LOGVV(TAG, "Auto wake");
690 this->is_sleeping_ = false;
691 this->wake_callback_.call();
692 this->all_components_send_state_(false);
693 break;
694 }
695 case 0x88: // system successful start up
696 {
697 ESP_LOGV(TAG, "System start: %zu", to_process_length);
698 this->connection_state_.nextion_reports_is_setup_ = true;
699 break;
700 }
701 case 0x89: { // start SD card upgrade
702 break;
703 }
704 // Data from nextion is
705 // 0x90 - Start
706 // variable length of 0x70 return formatted data (bytes) that contain the variable name: prints "temp1",0
707 // 00 - NULL
708 // 00/01 - Single byte for on/off
709 // FF FF FF - End
710 case 0x90: { // Switched component
711 std::string variable_name;
712
713 // Get variable name
714 auto index = to_process.find('\0');
715 if (index == std::string::npos || (to_process_length - index - 1) < 1) {
716 ESP_LOGE(TAG, "Bad switch data (0x90)");
717 ESP_LOGN(TAG, "proc: %s %zu %d", to_process.c_str(), to_process_length, index);
718 break;
719 }
720
721 variable_name = to_process.substr(0, index);
722 ++index;
723
724 ESP_LOGN(TAG, "Switch %s: %s", ONOFF(to_process[index] != 0), variable_name.c_str());
725
726 for (auto *switchtype : this->switchtype_) {
727 switchtype->process_bool(variable_name, to_process[index] != 0);
728 }
729 break;
730 }
731 // Data from nextion is
732 // 0x91 - Start
733 // variable length of 0x70 return formatted data (bytes) that contain the variable name: prints "temp1",0
734 // 00 - NULL
735 // variable length of 0x71 return data: prints temp1.val,0
736 // FF FF FF - End
737 case 0x91: { // Sensor component
738 std::string variable_name;
739
740 auto index = to_process.find('\0');
741 if (index == std::string::npos || (to_process_length - index - 1) != 4) {
742 ESP_LOGE(TAG, "Bad sensor data (0x91)");
743 ESP_LOGN(TAG, "proc: %s %zu %d", to_process.c_str(), to_process_length, index);
744 break;
745 }
746
747 index = to_process.find('\0');
748 variable_name = to_process.substr(0, index);
749 // // Get variable name
750 int value = static_cast<int>(
751 encode_uint32(to_process[index + 4], to_process[index + 3], to_process[index + 2], to_process[index + 1]));
752
753 ESP_LOGN(TAG, "Sensor: %s=%d", variable_name.c_str(), value);
754
755 for (auto *sensor : this->sensortype_) {
756 sensor->process_sensor(variable_name, value);
757 }
758 break;
759 }
760
761 // Data from nextion is
762 // 0x92 - Start
763 // variable length of 0x70 return formatted data (bytes) that contain the variable name: prints "temp1",0
764 // 00 - NULL
765 // variable length of 0x70 return formatted data (bytes) that contain the text prints temp1.txt,0
766 // 00 - NULL
767 // FF FF FF - End
768 case 0x92: { // Text Sensor Component
769 std::string variable_name;
770 std::string text_value;
771
772 // Get variable name
773 auto index = to_process.find('\0');
774 if (index == std::string::npos || (to_process_length - index - 1) < 1) {
775 ESP_LOGE(TAG, "Bad text data (0x92)");
776 ESP_LOGN(TAG, "proc: %s %zu %d", to_process.c_str(), to_process_length, index);
777 break;
778 }
779
780 variable_name = to_process.substr(0, index);
781 ++index;
782
783 // Get variable value without terminating NUL byte. Length check above ensures substr len >= 0.
784 text_value = to_process.substr(index, to_process_length - index - 1);
785
786 ESP_LOGN(TAG, "Text sensor: %s='%s'", variable_name.c_str(), text_value.c_str());
787
788 // NextionTextSensorResponseQueue *nq = new NextionTextSensorResponseQueue;
789 // nq->variable_name = variable_name;
790 // nq->state = text_value;
791 // this->textsensorq_.push_back(nq);
792 for (auto *textsensortype : this->textsensortype_) {
793 textsensortype->process_text(variable_name, text_value);
794 }
795 break;
796 }
797 // Data from nextion is
798 // 0x93 - Start
799 // variable length of 0x70 return formatted data (bytes) that contain the variable name: prints "temp1",0
800 // 00 - NULL
801 // 00/01 - Single byte for on/off
802 // FF FF FF - End
803 case 0x93: { // Binary Sensor component
804 std::string variable_name;
805
806 // Get variable name
807 auto index = to_process.find('\0');
808 if (index == std::string::npos || (to_process_length - index - 1) < 1) {
809 ESP_LOGE(TAG, "Bad binary data (0x92)");
810 ESP_LOGN(TAG, "proc: %s %zu %d", to_process.c_str(), to_process_length, index);
811 break;
812 }
813
814 variable_name = to_process.substr(0, index);
815 ++index;
816
817 ESP_LOGN(TAG, "Binary sensor: %s=%s", variable_name.c_str(), ONOFF(to_process[index] != 0));
818
819 for (auto *binarysensortype : this->binarysensortype_) {
820 binarysensortype->process_bool(&variable_name[0], to_process[index] != 0);
821 }
822 break;
823 }
824 case 0xFD: { // data transparent transmit finished
825 ESP_LOGVV(TAG, "Data transmit done");
827 break;
828 }
829 case 0xFE: { // data transparent transmit ready
830 ESP_LOGVV(TAG, "Ready for transmit");
831 if (this->waveform_queue_.empty()) {
832 ESP_LOGE(TAG, "No waveforms queued");
833 break;
834 }
835
836 auto &nb = this->waveform_queue_.front();
837 auto *component = nb->component;
838 size_t buffer_to_send = component->get_wave_buffer_size() < 255 ? component->get_wave_buffer_size()
839 : 255; // ADDT command can only send 255
840
841 this->write_array(component->get_wave_buffer().data(), static_cast<int>(buffer_to_send));
842
843 ESP_LOGN(TAG, "Send waveform: component id %d, waveform id %d, size %zu", component->get_component_id(),
844 component->get_wave_channel_id(), buffer_to_send);
845
846 component->clear_wave_buffer(buffer_to_send);
847 delete nb; // NOLINT(cppcoreguidelines-owning-memory)
848 this->waveform_queue_.pop_front();
849 break;
850 }
851 default:
852 ESP_LOGW(TAG, "Unknown event: 0x%02X", nextion_event);
853 break;
854 }
855
856 this->command_data_.erase(0, to_process_length + COMMAND_DELIMITER.length() + 1);
857 }
858
860
861 if (this->max_q_age_ms_ > 0 && !this->nextion_queue_.empty() &&
862 ms - this->nextion_queue_.front()->queue_time > this->max_q_age_ms_) {
863 for (size_t i = 0; i < this->nextion_queue_.size(); i++) {
864 NextionComponentBase *component = this->nextion_queue_[i]->component;
865 if (ms - this->nextion_queue_[i]->queue_time > this->max_q_age_ms_) {
866 if (this->nextion_queue_[i]->queue_time == 0) {
867 ESP_LOGD(TAG, "Remove old queue '%s':'%s' (t=0)", component->get_queue_type_string().c_str(),
868 component->get_variable_name().c_str());
869 }
870
871 if (component->get_variable_name() == "sleep_wake") {
872 this->is_sleeping_ = false;
873 }
874
875 ESP_LOGD(TAG, "Remove old queue '%s':'%s'", component->get_queue_type_string().c_str(),
876 component->get_variable_name().c_str());
877
878 if (component->get_queue_type() == NextionQueueType::NO_RESULT) {
879 if (component->get_variable_name() == "sleep_wake") {
880 this->is_sleeping_ = false;
881 }
882 delete component; // NOLINT(cppcoreguidelines-owning-memory)
883 }
884
885 delete this->nextion_queue_[i]; // NOLINT(cppcoreguidelines-owning-memory)
886
887 this->nextion_queue_.erase(this->nextion_queue_.begin() + i);
888 i--;
889
890 } else {
891 break;
892 }
893 }
894 }
895 ESP_LOGN(TAG, "Loop end");
896 // App.feed_wdt(); Remove before master merge
897 this->process_serial_();
898} // Nextion::process_nextion_commands_()
899
900void Nextion::set_nextion_sensor_state(int queue_type, const std::string &name, float state) {
901 this->set_nextion_sensor_state(static_cast<NextionQueueType>(queue_type), name, state);
902}
903
904void Nextion::set_nextion_sensor_state(NextionQueueType queue_type, const std::string &name, float state) {
905 ESP_LOGN(TAG, "State: %s=%lf (type %d)", name.c_str(), state, queue_type);
906
907 switch (queue_type) {
909 for (auto *sensor : this->sensortype_) {
910 if (name == sensor->get_variable_name()) {
911 sensor->set_state(state, true, true);
912 break;
913 }
914 }
915 break;
916 }
918 for (auto *sensor : this->binarysensortype_) {
919 if (name == sensor->get_variable_name()) {
920 sensor->set_state(state != 0, true, true);
921 break;
922 }
923 }
924 break;
925 }
927 for (auto *sensor : this->switchtype_) {
928 if (name == sensor->get_variable_name()) {
929 sensor->set_state(state != 0, true, true);
930 break;
931 }
932 }
933 break;
934 }
935 default: {
936 ESP_LOGW(TAG, "set_sensor_state: bad type %d", queue_type);
937 }
938 }
939}
940
941void Nextion::set_nextion_text_state(const std::string &name, const std::string &state) {
942 ESP_LOGV(TAG, "State: %s='%s'", name.c_str(), state.c_str());
943
944 for (auto *sensor : this->textsensortype_) {
945 if (name == sensor->get_variable_name()) {
946 sensor->set_state(state, true, true);
947 break;
948 }
949 }
950}
951
952void Nextion::all_components_send_state_(bool force_update) {
953 ESP_LOGV(TAG, "Send states");
954 for (auto *binarysensortype : this->binarysensortype_) {
955 if (force_update || binarysensortype->get_needs_to_send_update())
956 binarysensortype->send_state_to_nextion();
957 }
958 for (auto *sensortype : this->sensortype_) {
959 if ((force_update || sensortype->get_needs_to_send_update()) && sensortype->get_wave_chan_id() == 0)
960 sensortype->send_state_to_nextion();
961 }
962 for (auto *switchtype : this->switchtype_) {
963 if (force_update || switchtype->get_needs_to_send_update())
964 switchtype->send_state_to_nextion();
965 }
966 for (auto *textsensortype : this->textsensortype_) {
967 if (force_update || textsensortype->get_needs_to_send_update())
968 textsensortype->send_state_to_nextion();
969 }
970}
971
972void Nextion::update_components_by_prefix(const std::string &prefix) {
973 for (auto *binarysensortype : this->binarysensortype_) {
974 if (binarysensortype->get_variable_name().find(prefix, 0) != std::string::npos)
975 binarysensortype->update_component_settings(true);
976 }
977 for (auto *sensortype : this->sensortype_) {
978 if (sensortype->get_variable_name().find(prefix, 0) != std::string::npos)
979 sensortype->update_component_settings(true);
980 }
981 for (auto *switchtype : this->switchtype_) {
982 if (switchtype->get_variable_name().find(prefix, 0) != std::string::npos)
983 switchtype->update_component_settings(true);
984 }
985 for (auto *textsensortype : this->textsensortype_) {
986 if (textsensortype->get_variable_name().find(prefix, 0) != std::string::npos)
987 textsensortype->update_component_settings(true);
988 }
989}
990
991uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag) {
992 uint8_t c = 0;
993 uint8_t nr_of_ff_bytes = 0;
994 bool exit_flag = false;
995 bool ff_flag = false;
996
997 const uint32_t start = millis();
998
999 while ((timeout == 0 && this->available()) || millis() - start <= timeout) {
1000 if (!this->available()) {
1001 App.feed_wdt();
1002 delay(1);
1003 continue;
1004 }
1005
1006 this->read_byte(&c);
1007 if (c == 0xFF) {
1008 nr_of_ff_bytes++;
1009 } else {
1010 nr_of_ff_bytes = 0;
1011 ff_flag = false;
1012 }
1013
1014 if (nr_of_ff_bytes >= 3)
1015 ff_flag = true;
1016
1017 response += (char) c;
1018 if (recv_flag) {
1019 if (response.find(0x05) != std::string::npos) {
1020 exit_flag = true;
1021 }
1022 }
1023 App.feed_wdt();
1024 delay(2);
1025
1026 if (exit_flag || ff_flag) {
1027 break;
1028 }
1029 }
1030
1031 if (ff_flag)
1032 response = response.substr(0, response.length() - 3); // Remove last 3 0xFF
1033
1034 return response.length();
1035}
1036
1047void Nextion::add_no_result_to_queue_(const std::string &variable_name) {
1048#ifdef USE_NEXTION_MAX_QUEUE_SIZE
1049 if (this->max_queue_size_ > 0 && this->nextion_queue_.size() >= this->max_queue_size_) {
1050 ESP_LOGW(TAG, "Queue full (%zu), drop: %s", this->nextion_queue_.size(), variable_name.c_str());
1051 return;
1052 }
1053#endif
1054
1056 nextion::NextionQueue *nextion_queue = allocator.allocate(1);
1057 if (nextion_queue == nullptr) {
1058 ESP_LOGW(TAG, "Queue alloc failed");
1059 return;
1060 }
1061 new (nextion_queue) nextion::NextionQueue();
1062
1063 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
1064 nextion_queue->component = new nextion::NextionComponentBase;
1065 nextion_queue->component->set_variable_name(variable_name);
1066
1067 nextion_queue->queue_time = App.get_loop_component_start_time();
1068
1069 this->nextion_queue_.push_back(nextion_queue);
1070
1071 ESP_LOGN(TAG, "Queue NORESULT: %s", nextion_queue->component->get_variable_name().c_str());
1072}
1073
1080void Nextion::add_no_result_to_queue_with_command_(const std::string &variable_name, const std::string &command) {
1081 if ((!this->is_setup() && !this->connection_state_.ignore_is_setup_) || command.empty())
1082 return;
1083
1084 if (this->send_command_(command)) {
1085 this->add_no_result_to_queue_(variable_name);
1086#ifdef USE_NEXTION_COMMAND_SPACING
1087 } else {
1088 // Command blocked by spacing, add to queue WITH the command for retry
1089 this->add_no_result_to_queue_with_pending_command_(variable_name, command);
1090#endif // USE_NEXTION_COMMAND_SPACING
1091 }
1092}
1093
1094#ifdef USE_NEXTION_COMMAND_SPACING
1095void Nextion::add_no_result_to_queue_with_pending_command_(const std::string &variable_name,
1096 const std::string &command) {
1097#ifdef USE_NEXTION_MAX_QUEUE_SIZE
1098 if (this->max_queue_size_ > 0 && this->nextion_queue_.size() >= this->max_queue_size_) {
1099 ESP_LOGW(TAG, "Queue full (%zu), drop: %s", this->nextion_queue_.size(), variable_name.c_str());
1100 return;
1101 }
1102#endif
1103
1105 nextion::NextionQueue *nextion_queue = allocator.allocate(1);
1106 if (nextion_queue == nullptr) {
1107 ESP_LOGW(TAG, "Queue alloc failed");
1108 return;
1109 }
1110 new (nextion_queue) nextion::NextionQueue();
1111
1112 nextion_queue->component = new nextion::NextionComponentBase;
1113 nextion_queue->component->set_variable_name(variable_name);
1114 nextion_queue->queue_time = App.get_loop_component_start_time();
1115 nextion_queue->pending_command = command; // Store command for retry
1116
1117 this->nextion_queue_.push_back(nextion_queue);
1118 ESP_LOGVV(TAG, "Queue with pending command: %s", variable_name.c_str());
1119}
1120#endif // USE_NEXTION_COMMAND_SPACING
1121
1122bool Nextion::add_no_result_to_queue_with_ignore_sleep_printf_(const std::string &variable_name, const char *format,
1123 ...) {
1124 if ((!this->is_setup() && !this->connection_state_.ignore_is_setup_))
1125 return false;
1126
1127 char buffer[256];
1128 va_list arg;
1129 va_start(arg, format);
1130 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
1131 va_end(arg);
1132 if (ret <= 0) {
1133 ESP_LOGW(TAG, "Bad cmd format: '%s'", format);
1134 return false;
1135 }
1136
1137 this->add_no_result_to_queue_with_command_(variable_name, buffer);
1138 return true;
1139}
1140
1148bool Nextion::add_no_result_to_queue_with_printf_(const std::string &variable_name, const char *format, ...) {
1149 if ((!this->is_setup() && !this->connection_state_.ignore_is_setup_) || this->is_sleeping())
1150 return false;
1151
1152 char buffer[256];
1153 va_list arg;
1154 va_start(arg, format);
1155 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
1156 va_end(arg);
1157 if (ret <= 0) {
1158 ESP_LOGW(TAG, "Bad cmd format: '%s'", format);
1159 return false;
1160 }
1161
1162 this->add_no_result_to_queue_with_command_(variable_name, buffer);
1163 return true;
1164}
1165
1176 this->add_no_result_to_queue_with_set(component->get_variable_name(), component->get_variable_name_to_send(),
1177 state_value);
1178}
1179
1180void Nextion::add_no_result_to_queue_with_set(const std::string &variable_name,
1181 const std::string &variable_name_to_send, int32_t state_value) {
1182 this->add_no_result_to_queue_with_set_internal_(variable_name, variable_name_to_send, state_value);
1183}
1184
1185void Nextion::add_no_result_to_queue_with_set_internal_(const std::string &variable_name,
1186 const std::string &variable_name_to_send, int32_t state_value,
1187 bool is_sleep_safe) {
1188 if ((!this->is_setup() && !this->connection_state_.ignore_is_setup_) || (!is_sleep_safe && this->is_sleeping()))
1189 return;
1190
1191 this->add_no_result_to_queue_with_ignore_sleep_printf_(variable_name, "%s=%" PRId32, variable_name_to_send.c_str(),
1192 state_value);
1193}
1194
1204 this->add_no_result_to_queue_with_set(component->get_variable_name(), component->get_variable_name_to_send(),
1205 state_value);
1206}
1207void Nextion::add_no_result_to_queue_with_set(const std::string &variable_name,
1208 const std::string &variable_name_to_send,
1209 const std::string &state_value) {
1210 this->add_no_result_to_queue_with_set_internal_(variable_name, variable_name_to_send, state_value);
1211}
1212
1213void Nextion::add_no_result_to_queue_with_set_internal_(const std::string &variable_name,
1214 const std::string &variable_name_to_send,
1215 const std::string &state_value, bool is_sleep_safe) {
1216 if ((!this->is_setup() && !this->connection_state_.ignore_is_setup_) || (!is_sleep_safe && this->is_sleeping()))
1217 return;
1218
1219 this->add_no_result_to_queue_with_printf_(variable_name, "%s=\"%s\"", variable_name_to_send.c_str(),
1220 state_value.c_str());
1221}
1222
1233 if ((!this->is_setup() && !this->connection_state_.ignore_is_setup_))
1234 return;
1235
1236#ifdef USE_NEXTION_MAX_QUEUE_SIZE
1237 if (this->max_queue_size_ > 0 && this->nextion_queue_.size() >= this->max_queue_size_) {
1238 ESP_LOGW(TAG, "Queue full (%zu), drop GET: %s", this->nextion_queue_.size(),
1239 component->get_variable_name().c_str());
1240 return;
1241 }
1242#endif
1243
1245 nextion::NextionQueue *nextion_queue = allocator.allocate(1);
1246 if (nextion_queue == nullptr) {
1247 ESP_LOGW(TAG, "Queue alloc failed");
1248 return;
1249 }
1250 new (nextion_queue) nextion::NextionQueue();
1251
1252 nextion_queue->component = component;
1253 nextion_queue->queue_time = App.get_loop_component_start_time();
1254
1255 ESP_LOGN(TAG, "Queue %s: %s", component->get_queue_type_string().c_str(), component->get_variable_name().c_str());
1256
1257 std::string command = "get " + component->get_variable_name_to_send();
1258
1259 if (this->send_command_(command)) {
1260 this->nextion_queue_.push_back(nextion_queue);
1261 }
1262}
1263
1273 if ((!this->is_setup() && !this->connection_state_.ignore_is_setup_) || this->is_sleeping())
1274 return;
1275
1277 nextion::NextionQueue *nextion_queue = allocator.allocate(1);
1278 if (nextion_queue == nullptr) {
1279 ESP_LOGW(TAG, "Queue alloc failed");
1280 return;
1281 }
1282 new (nextion_queue) nextion::NextionQueue();
1283
1284 nextion_queue->component = component;
1285 nextion_queue->queue_time = App.get_loop_component_start_time();
1286
1287 this->waveform_queue_.push_back(nextion_queue);
1288 if (this->waveform_queue_.size() == 1)
1290}
1291
1293 if (this->waveform_queue_.empty())
1294 return;
1295
1296 auto *nb = this->waveform_queue_.front();
1297 auto *component = nb->component;
1298 size_t buffer_to_send = component->get_wave_buffer_size() < 255 ? component->get_wave_buffer_size()
1299 : 255; // ADDT command can only send 255
1300
1301 char command[24]; // "addt " + uint8 + "," + uint8 + "," + uint8 + null = max 17 chars
1302 buf_append_printf(command, sizeof(command), 0, "addt %u,%u,%zu", component->get_component_id(),
1303 component->get_wave_channel_id(), buffer_to_send);
1304 if (!this->send_command_(command)) {
1305 delete nb; // NOLINT(cppcoreguidelines-owning-memory)
1306 this->waveform_queue_.pop_front();
1307 }
1308}
1309
1310void Nextion::set_writer(const nextion_writer_t &writer) { this->writer_ = writer; }
1311
1312bool Nextion::is_updating() { return this->connection_state_.is_updating_; }
1313
1314} // namespace nextion
1315} // namespace esphome
void feed_wdt(uint32_t time=0)
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:1899
T * allocate(size_t n)
Definition helpers.h:1916
uint8_t get_spacing() const
Get current command spacing.
Definition nextion.h:53
void mark_sent()
Mark a command as sent, updating the timing.
Definition nextion.h:64
void set_variable_name(const std::string &variable_name, const std::string &variable_name_to_send="")
void add_setup_state_callback(std::function< void()> &&callback)
Add a callback to be notified when the nextion completes its initialize setup.
Definition nextion.cpp:225
std::vector< NextionComponentBase * > touch_
Definition nextion.h:1506
std::vector< NextionComponentBase * > switchtype_
Definition nextion.h:1507
void add_buffer_overflow_event_callback(std::function< void()> &&callback)
Add a callback to be notified when the nextion reports a buffer overflow.
Definition nextion.cpp:237
std::vector< NextionComponentBase * > binarysensortype_
Definition nextion.h:1510
uint16_t max_q_age_ms_
Maximum age for queue items in ms.
Definition nextion.h:1539
bool send_command_(const std::string &command)
Manually send a raw command to the display and don't wait for an acknowledgement packet.
Definition nextion.cpp:27
std::vector< NextionComponentBase * > textsensortype_
Definition nextion.h:1509
CallbackManager< void(uint8_t)> page_callback_
Definition nextion.h:1514
struct esphome::nextion::Nextion::@144 connection_state_
Status flags for Nextion display state management.
void set_wake_up_page(uint8_t wake_up_page=255)
Sets which page Nextion loads when exiting sleep mode.
std::string device_model_
Definition nextion.h:1522
void all_components_send_state_(bool force_update=false)
Definition nextion.cpp:952
std::string firmware_version_
Definition nextion.h:1523
void set_nextion_sensor_state(int queue_type, const std::string &name, float state)
Set the nextion sensor state object.
Definition nextion.cpp:900
void add_addt_command_to_queue(NextionComponentBase *component) override
Add addt command to the queue.
Definition nextion.cpp:1272
void add_new_page_callback(std::function< void(uint8_t)> &&callback)
Add a callback to be notified when the nextion changes pages.
Definition nextion.cpp:229
uint16_t max_commands_per_loop_
Definition nextion.h:1364
nextion_writer_t writer_
Definition nextion.h:1518
uint16_t startup_override_ms_
Timeout before forcing setup complete.
Definition nextion.h:1538
void add_to_get_queue(NextionComponentBase *component) override
Queue a GET command for a component that expects a response from the Nextion display.
Definition nextion.cpp:1232
bool send_command_printf(const char *format,...) __attribute__((format(printf
Manually send a raw formatted command to the display.
Definition nextion.cpp:270
void setup() override
Definition nextion.cpp:13
std::deque< NextionQueue * > nextion_queue_
Definition nextion.h:1386
void loop() override
Definition nextion.cpp:311
void set_auto_wake_on_touch(bool auto_wake_on_touch)
Sets if Nextion should auto-wake from sleep when touch press occurs.
bool remove_from_q_(bool report_empty=true)
Definition nextion.cpp:382
std::vector< NextionComponentBase * > sensortype_
Definition nextion.h:1508
bool void add_no_result_to_queue_with_set_internal_(const std::string &variable_name, const std::string &variable_name_to_send, int32_t state_value, bool is_sleep_safe=false)
Definition nextion.cpp:1185
bool add_no_result_to_queue_with_printf_(const std::string &variable_name, const char *format,...) __attribute__((format(printf
Sends a formatted command to the nextion.
Definition nextion.cpp:1148
void set_touch_sleep_timeout(uint16_t touch_sleep_timeout=0)
Set the touch sleep timeout of the display using the thsp command.
CallbackManager< void()> setup_callback_
Definition nextion.h:1511
std::string command_data_
Definition nextion.h:1535
optional< float > brightness_
Definition nextion.h:1519
CallbackManager< void()> wake_callback_
Definition nextion.h:1513
void add_sleep_state_callback(std::function< void()> &&callback)
Add a callback to be notified of sleep state changes.
Definition nextion.cpp:217
bool is_updating() override
Check if the TFT update process is currently running.
Definition nextion.cpp:1312
uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag)
Definition nextion.cpp:991
void goto_page(const char *page)
Show the page with a given name.
bool send_command(const char *command)
Manually send a raw command to the display.
Definition nextion.cpp:259
std::string serial_number_
Definition nextion.h:1524
CallbackManager< void()> sleep_callback_
Definition nextion.h:1512
bool void add_no_result_to_queue_with_command_(const std::string &variable_name, const std::string &command)
Definition nextion.cpp:1080
void reset_(bool reset_nextion=true)
Definition nextion.cpp:137
void process_pending_in_queue_()
Process any commands in the queue that are pending due to command spacing.
Definition nextion.cpp:365
void add_no_result_to_queue_(const std::string &variable_name)
Add a command to the Nextion queue that expects no response.
Definition nextion.cpp:1047
CallbackManager< void(uint8_t, uint8_t, bool)> touch_callback_
Definition nextion.h:1515
void dump_config() override
Definition nextion.cpp:147
NextionCommandPacer command_pacer_
Definition nextion.h:1371
void set_nextion_text_state(const std::string &name, const std::string &state)
Definition nextion.cpp:941
std::deque< NextionQueue * > waveform_queue_
Definition nextion.h:1387
bool add_no_result_to_queue_with_ignore_sleep_printf_(const std::string &variable_name, const char *format,...) __attribute__((format(printf
Definition nextion.cpp:1122
void update() override
Definition nextion.cpp:208
uint8_t is_connected_
Connection established with Nextion display.
Definition nextion.h:1400
void add_wake_state_callback(std::function< void()> &&callback)
Add a callback to be notified of wake state changes.
Definition nextion.cpp:221
CallbackManager< void()> buffer_overflow_callback_
Definition nextion.h:1516
void set_writer(const nextion_writer_t &writer)
Definition nextion.cpp:1310
void add_no_result_to_queue_with_pending_command_(const std::string &variable_name, const std::string &command)
Add a command to the Nextion queue with a pending command for retry.
Definition nextion.cpp:1095
void add_no_result_to_queue_with_set(NextionComponentBase *component, int32_t state_value) override
Definition nextion.cpp:1175
void add_touch_event_callback(std::function< void(uint8_t, uint8_t, bool)> &&callback)
Add a callback to be notified when Nextion has a touch event.
Definition nextion.cpp:233
void update_components_by_prefix(const std::string &prefix)
Definition nextion.cpp:972
uint32_t tft_upload_watchdog_timeout_
WDT timeout in ms (0 = no adjustment)
Definition nextion.h:1473
void set_backlight_brightness(float brightness)
Set the brightness of the backlight.
optional< std::array< uint8_t, N > > read_array()
Definition uart.h:38
void write_str(const char *str)
Definition uart.h:32
bool read_byte(uint8_t *data)
Definition uart.h:34
void write_array(const uint8_t *data, size_t len)
Definition uart.h:26
const Component * component
Definition component.cpp:37
bool state
Definition fan.h:2
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
const char int const __FlashStringHelper * format
Definition log.h:74
va_end(args)
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition helpers.h:736
size_t size_t const char va_start(args, fmt)
void HOT delay(uint32_t ms)
Definition core.cpp:28
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:26
Application App
Global storage of Application pointer - only one Application can exist.
static void uint32_t
uint8_t end[39]
Definition sun_gtil2.cpp:17
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6