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