ESPHome  2024.12.2
nextion.cpp
Go to the documentation of this file.
1 #include "nextion.h"
2 #include "esphome/core/util.h"
3 #include "esphome/core/log.h"
5 #include <cinttypes>
6 
7 namespace esphome {
8 namespace nextion {
9 
10 static const char *const TAG = "nextion";
11 
13  this->is_setup_ = false;
14  this->ignore_is_setup_ = true;
15 
16  // Wake up the nextion
17  this->send_command_("bkcmd=0");
18  this->send_command_("sleep=0");
19 
20  this->send_command_("bkcmd=0");
21  this->send_command_("sleep=0");
22 
23  // Reboot it
24  this->send_command_("rest");
25 
26  this->ignore_is_setup_ = false;
27 }
28 
29 bool Nextion::send_command_(const std::string &command) {
30  if (!this->ignore_is_setup_ && !this->is_setup()) {
31  return false;
32  }
33 
34  ESP_LOGN(TAG, "send_command %s", command.c_str());
35 
36  this->write_str(command.c_str());
37  const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF};
38  this->write_array(to_send, sizeof(to_send));
39  return true;
40 }
41 
43  if (this->get_is_connected_())
44  return true;
45 
46  // Check if the handshake should be skipped for the Nextion connection
47  if (this->skip_connection_handshake_) {
48  // Log the connection status without handshake
49  ESP_LOGW(TAG, "Nextion display set as connected without performing handshake");
50  // Set the connection status to true
51  this->is_connected_ = true;
52  // Return true indicating the connection is set
53  return true;
54  }
55 
56  if (this->comok_sent_ == 0) {
57  this->reset_(false);
58 
59  this->ignore_is_setup_ = true;
60  this->send_command_("boguscommand=0"); // bogus command. needed sometimes after updating
61  if (this->exit_reparse_on_start_) {
62  this->send_command_("DRAKJHSUYDGBNCJHGJKSHBDN");
63  }
64  this->send_command_("connect");
65 
66  this->comok_sent_ = millis();
67  this->ignore_is_setup_ = false;
68 
69  return false;
70  }
71 
72  if (millis() - 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 during 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 request %s", response.c_str());
86  for (size_t i = 0; i < response.length(); i++) {
87  ESP_LOGN(TAG, "response %s %d %d %c", response.c_str(), i, response[i], response[i]);
88  }
89 #endif
90 
91  ESP_LOGW(TAG, "Nextion is not connected! ");
92  comok_sent_ = 0;
93  return false;
94  }
95 
96  this->ignore_is_setup_ = true;
97  ESP_LOGI(TAG, "Nextion is connected");
98  this->is_connected_ = true;
99 
100  ESP_LOGN(TAG, "connect request %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, "Received connect_info %zu", connect_info.size());
113 
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 {
119  ESP_LOGE(TAG, "Nextion returned bad connect value \"%s\"", response.c_str());
120  }
121 
122  this->ignore_is_setup_ = false;
123  this->dump_config();
124  return true;
125 }
126 
127 void Nextion::reset_(bool reset_nextion) {
128  uint8_t d;
129 
130  while (this->available()) { // Clear receive buffer
131  this->read_byte(&d);
132  };
133  this->nextion_queue_.clear();
134  this->waveform_queue_.clear();
135 }
136 
138  ESP_LOGCONFIG(TAG, "Nextion:");
139  if (this->skip_connection_handshake_) {
140  ESP_LOGCONFIG(TAG, " Skip handshake: %s", YESNO(this->skip_connection_handshake_));
141  } else {
142  ESP_LOGCONFIG(TAG, " Device Model: %s", this->device_model_.c_str());
143  ESP_LOGCONFIG(TAG, " Firmware Version: %s", this->firmware_version_.c_str());
144  ESP_LOGCONFIG(TAG, " Serial Number: %s", this->serial_number_.c_str());
145  ESP_LOGCONFIG(TAG, " Flash Size: %s", this->flash_size_.c_str());
146  }
147  ESP_LOGCONFIG(TAG, " Wake On Touch: %s", YESNO(this->auto_wake_on_touch_));
148  ESP_LOGCONFIG(TAG, " Exit reparse: %s", YESNO(this->exit_reparse_on_start_));
149 
150  if (this->touch_sleep_timeout_ != 0) {
151  ESP_LOGCONFIG(TAG, " Touch Timeout: %" PRIu32, this->touch_sleep_timeout_);
152  }
153 
154  if (this->wake_up_page_ != -1) {
155  ESP_LOGCONFIG(TAG, " Wake Up Page: %" PRId16, this->wake_up_page_);
156  }
157 
158  if (this->start_up_page_ != -1) {
159  ESP_LOGCONFIG(TAG, " Start Up Page: %" PRId16, this->start_up_page_);
160  }
161 }
162 
165  if (!this->is_setup()) {
166  return;
167  }
168  if (this->writer_.has_value()) {
169  (*this->writer_)(*this);
170  }
171 }
172 
173 void Nextion::add_sleep_state_callback(std::function<void()> &&callback) {
174  this->sleep_callback_.add(std::move(callback));
175 }
176 
177 void Nextion::add_wake_state_callback(std::function<void()> &&callback) {
178  this->wake_callback_.add(std::move(callback));
179 }
180 
181 void Nextion::add_setup_state_callback(std::function<void()> &&callback) {
182  this->setup_callback_.add(std::move(callback));
183 }
184 
185 void Nextion::add_new_page_callback(std::function<void(uint8_t)> &&callback) {
186  this->page_callback_.add(std::move(callback));
187 }
188 
189 void Nextion::add_touch_event_callback(std::function<void(uint8_t, uint8_t, bool)> &&callback) {
190  this->touch_callback_.add(std::move(callback));
191 }
192 
193 void Nextion::add_buffer_overflow_event_callback(std::function<void()> &&callback) {
194  this->buffer_overflow_callback_.add(std::move(callback));
195 }
196 
198  if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping())
199  return;
200 
201  for (auto *binarysensortype : this->binarysensortype_) {
202  binarysensortype->update_component();
203  }
204  for (auto *sensortype : this->sensortype_) {
205  sensortype->update_component();
206  }
207  for (auto *switchtype : this->switchtype_) {
208  switchtype->update_component();
209  }
210  for (auto *textsensortype : this->textsensortype_) {
211  textsensortype->update_component();
212  }
213 }
214 
215 bool Nextion::send_command(const char *command) {
216  if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping())
217  return false;
218 
219  if (this->send_command_(command)) {
220  this->add_no_result_to_queue_("send_command");
221  return true;
222  }
223  return false;
224 }
225 
226 bool Nextion::send_command_printf(const char *format, ...) {
227  if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping())
228  return false;
229 
230  char buffer[256];
231  va_list arg;
232  va_start(arg, format);
233  int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
234  va_end(arg);
235  if (ret <= 0) {
236  ESP_LOGW(TAG, "Building command for format '%s' failed!", format);
237  return false;
238  }
239 
240  if (this->send_command_(buffer)) {
241  this->add_no_result_to_queue_("send_command_printf");
242  return true;
243  }
244  return false;
245 }
246 
247 #ifdef NEXTION_PROTOCOL_LOG
249  ESP_LOGN(TAG, "print_queue_members_ (top 10) size %zu", this->nextion_queue_.size());
250  ESP_LOGN(TAG, "*******************************************");
251  int count = 0;
252  for (auto *i : this->nextion_queue_) {
253  if (count++ == 10)
254  break;
255 
256  if (i == nullptr) {
257  ESP_LOGN(TAG, "Nextion queue is null");
258  } else {
259  ESP_LOGN(TAG, "Nextion queue type: %d:%s , name: %s", i->component->get_queue_type(),
260  i->component->get_queue_type_string().c_str(), i->component->get_variable_name().c_str());
261  }
262  }
263  ESP_LOGN(TAG, "*******************************************");
264 }
265 #endif
266 
268  if (!this->check_connect_() || this->is_updating_)
269  return;
270 
271  if (this->nextion_reports_is_setup_ && !this->sent_setup_commands_) {
272  this->ignore_is_setup_ = true;
273  this->sent_setup_commands_ = true;
274  this->send_command_("bkcmd=3"); // Always, returns 0x00 to 0x23 result of serial command.
275 
277 
278  // Check if a startup page has been set and send the command
279  if (this->start_up_page_ != -1) {
280  this->goto_page(this->start_up_page_);
281  }
282 
283  // This could probably be removed from the loop area, as those are redundant.
286 
287  if (this->touch_sleep_timeout_ != 0) {
289  }
290 
291  if (this->wake_up_page_ != -1) {
292  this->set_wake_up_page(this->wake_up_page_);
293  }
294 
295  this->ignore_is_setup_ = false;
296  }
297 
298  this->process_serial_(); // Receive serial data
299  this->process_nextion_commands_(); // Process nextion return commands
300 
301  if (!this->nextion_reports_is_setup_) {
302  if (this->started_ms_ == 0)
303  this->started_ms_ = millis();
304 
305  if (this->started_ms_ + this->startup_override_ms_ < millis()) {
306  ESP_LOGD(TAG, "Manually set nextion report ready");
307  this->nextion_reports_is_setup_ = true;
308  }
309  }
310 }
311 
312 bool Nextion::remove_from_q_(bool report_empty) {
313  if (this->nextion_queue_.empty()) {
314  if (report_empty) {
315  ESP_LOGE(TAG, "Nextion queue is empty!");
316  }
317  return false;
318  }
319 
320  NextionQueue *nb = this->nextion_queue_.front();
321  NextionComponentBase *component = nb->component;
322 
323  ESP_LOGN(TAG, "Removing %s from the queue", component->get_variable_name().c_str());
324 
325  if (component->get_queue_type() == NextionQueueType::NO_RESULT) {
326  if (component->get_variable_name() == "sleep_wake") {
327  this->is_sleeping_ = false;
328  }
329  delete component; // NOLINT(cppcoreguidelines-owning-memory)
330  }
331  delete nb; // NOLINT(cppcoreguidelines-owning-memory)
332  this->nextion_queue_.pop_front();
333  return true;
334 }
335 
337  uint8_t d;
338 
339  while (this->available()) {
340  read_byte(&d);
341  this->command_data_ += d;
342  }
343 }
344 // nextion.tech/instruction-set/
346  if (this->command_data_.empty()) {
347  return;
348  }
349 
350  size_t to_process_length = 0;
351  std::string to_process;
352 
353  ESP_LOGN(TAG, "this->command_data_ %s length %d", this->command_data_.c_str(), this->command_data_.length());
354 #ifdef NEXTION_PROTOCOL_LOG
355  this->print_queue_members_();
356 #endif
357  while ((to_process_length = this->command_data_.find(COMMAND_DELIMITER)) != std::string::npos) {
358  ESP_LOGN(TAG, "print_queue_members_ size %zu", this->nextion_queue_.size());
359  while (to_process_length + COMMAND_DELIMITER.length() < this->command_data_.length() &&
360  static_cast<uint8_t>(this->command_data_[to_process_length + COMMAND_DELIMITER.length()]) == 0xFF) {
361  ++to_process_length;
362  ESP_LOGN(TAG, "Add extra 0xFF to process");
363  }
364 
365  this->nextion_event_ = this->command_data_[0];
366 
367  to_process_length -= 1;
368  to_process = this->command_data_.substr(1, to_process_length);
369 
370  switch (this->nextion_event_) {
371  case 0x00: // instruction sent by user has failed
372  ESP_LOGW(TAG, "Nextion reported invalid instruction!");
373  this->remove_from_q_();
374 
375  break;
376  case 0x01: // instruction sent by user was successful
377 
378  ESP_LOGVV(TAG, "instruction sent by user was successful");
379  ESP_LOGN(TAG, "this->nextion_queue_.empty() %s", this->nextion_queue_.empty() ? "True" : "False");
380 
381  this->remove_from_q_();
382  if (!this->is_setup_) {
383  if (this->nextion_queue_.empty()) {
384  ESP_LOGD(TAG, "Nextion is setup");
385  this->is_setup_ = true;
386  this->setup_callback_.call();
387  }
388  }
389 
390  break;
391  case 0x02: // invalid Component ID or name was used
392  ESP_LOGW(TAG, "Nextion reported component ID or name invalid!");
393  this->remove_from_q_();
394  break;
395  case 0x03: // invalid Page ID or name was used
396  ESP_LOGW(TAG, "Nextion reported page ID invalid!");
397  this->remove_from_q_();
398  break;
399  case 0x04: // invalid Picture ID was used
400  ESP_LOGW(TAG, "Nextion reported picture ID invalid!");
401  this->remove_from_q_();
402  break;
403  case 0x05: // invalid Font ID was used
404  ESP_LOGW(TAG, "Nextion reported font ID invalid!");
405  this->remove_from_q_();
406  break;
407  case 0x06: // File operation fails
408  ESP_LOGW(TAG, "Nextion File operation fail!");
409  break;
410  case 0x09: // Instructions with CRC validation fails their CRC check
411  ESP_LOGW(TAG, "Nextion Instructions with CRC validation fails their CRC check!");
412  break;
413  case 0x11: // invalid Baud rate was used
414  ESP_LOGW(TAG, "Nextion reported baud rate invalid!");
415  break;
416  case 0x12: // invalid Waveform ID or Channel # was used
417  if (this->waveform_queue_.empty()) {
418  ESP_LOGW(TAG,
419  "Nextion reported invalid Waveform ID or Channel # was used but no waveform sensor in queue found!");
420  } else {
421  auto &nb = this->waveform_queue_.front();
422  NextionComponentBase *component = nb->component;
423 
424  ESP_LOGW(TAG, "Nextion reported invalid Waveform ID %d or Channel # %d was used!",
425  component->get_component_id(), component->get_wave_channel_id());
426 
427  ESP_LOGN(TAG, "Removing waveform from queue with component id %d and waveform id %d",
428  component->get_component_id(), component->get_wave_channel_id());
429 
430  delete nb; // NOLINT(cppcoreguidelines-owning-memory)
431  this->waveform_queue_.pop_front();
432  }
433  break;
434  case 0x1A: // variable name invalid
435  ESP_LOGW(TAG, "Nextion reported variable name invalid!");
436  this->remove_from_q_();
437  break;
438  case 0x1B: // variable operation invalid
439  ESP_LOGW(TAG, "Nextion reported variable operation invalid!");
440  this->remove_from_q_();
441  break;
442  case 0x1C: // failed to assign
443  ESP_LOGW(TAG, "Nextion reported failed to assign variable!");
444  this->remove_from_q_();
445  break;
446  case 0x1D: // operate EEPROM failed
447  ESP_LOGW(TAG, "Nextion reported operating EEPROM failed!");
448  break;
449  case 0x1E: // parameter quantity invalid
450  ESP_LOGW(TAG, "Nextion reported parameter quantity invalid!");
451  this->remove_from_q_();
452  break;
453  case 0x1F: // IO operation failed
454  ESP_LOGW(TAG, "Nextion reported component I/O operation invalid!");
455  break;
456  case 0x20: // undefined escape characters
457  ESP_LOGW(TAG, "Nextion reported undefined escape characters!");
458  this->remove_from_q_();
459  break;
460  case 0x23: // too long variable name
461  ESP_LOGW(TAG, "Nextion reported too long variable name!");
462  this->remove_from_q_();
463  break;
464  case 0x24: // Serial Buffer overflow occurs
465  // Buffer will continue to receive the current instruction, all previous instructions are lost.
466  ESP_LOGE(TAG, "Nextion reported Serial Buffer overflow!");
467  this->buffer_overflow_callback_.call();
468  break;
469  case 0x65: { // touch event return data
470  if (to_process_length != 3) {
471  ESP_LOGW(TAG, "Touch event data is expecting 3, received %zu", to_process_length);
472  break;
473  }
474 
475  uint8_t page_id = to_process[0];
476  uint8_t component_id = to_process[1];
477  uint8_t touch_event = to_process[2]; // 0 -> release, 1 -> press
478  ESP_LOGD(TAG, "Got touch event:");
479  ESP_LOGD(TAG, " page_id: %u", page_id);
480  ESP_LOGD(TAG, " component_id: %u", component_id);
481  ESP_LOGD(TAG, " event type: %s", touch_event ? "PRESS" : "RELEASE");
482  for (auto *touch : this->touch_) {
483  touch->process_touch(page_id, component_id, touch_event != 0);
484  }
485  this->touch_callback_.call(page_id, component_id, touch_event != 0);
486  break;
487  }
488  case 0x66: { // Nextion initiated new page event return data.
489  // Also is used for sendme command which we never explicitly initiate
490  if (to_process_length != 1) {
491  ESP_LOGW(TAG, "New page event data is expecting 1, received %zu", to_process_length);
492  break;
493  }
494 
495  uint8_t page_id = to_process[0];
496  ESP_LOGD(TAG, "Got new page: %u", page_id);
497  this->page_callback_.call(page_id);
498  break;
499  }
500  case 0x67: { // Touch Coordinate (awake)
501  break;
502  }
503  case 0x68: { // touch coordinate data (sleep)
504 
505  if (to_process_length != 5) {
506  ESP_LOGW(TAG, "Touch coordinate data is expecting 5, received %zu", to_process_length);
507  ESP_LOGW(TAG, "%s", to_process.c_str());
508  break;
509  }
510 
511  uint16_t x = (uint16_t(to_process[0]) << 8) | to_process[1];
512  uint16_t y = (uint16_t(to_process[2]) << 8) | to_process[3];
513  uint8_t touch_event = to_process[4]; // 0 -> release, 1 -> press
514  ESP_LOGD(TAG, "Got touch event:");
515  ESP_LOGD(TAG, " x: %u", x);
516  ESP_LOGD(TAG, " y: %u", y);
517  ESP_LOGD(TAG, " type: %s", touch_event ? "PRESS" : "RELEASE");
518  break;
519  }
520 
521  // 0x70 0x61 0x62 0x31 0x32 0x33 0xFF 0xFF 0xFF
522  // Returned when using get command for a string.
523  // Each byte is converted to char.
524  // data: ab123
525  case 0x70: // string variable data return
526  {
527  if (this->nextion_queue_.empty()) {
528  ESP_LOGW(TAG, "ERROR: Received string return but the queue is empty");
529  break;
530  }
531 
532  NextionQueue *nb = this->nextion_queue_.front();
533  NextionComponentBase *component = nb->component;
534 
535  if (component->get_queue_type() != NextionQueueType::TEXT_SENSOR) {
536  ESP_LOGE(TAG, "ERROR: Received string return but next in queue \"%s\" is not a text sensor",
537  component->get_variable_name().c_str());
538  } else {
539  ESP_LOGN(TAG, "Received get_string response: \"%s\" for component id: %s, type: %s", to_process.c_str(),
540  component->get_variable_name().c_str(), component->get_queue_type_string().c_str());
541  component->set_state_from_string(to_process, true, false);
542  }
543 
544  delete nb; // NOLINT(cppcoreguidelines-owning-memory)
545  this->nextion_queue_.pop_front();
546 
547  break;
548  }
549  // 0x71 0x01 0x02 0x03 0x04 0xFF 0xFF 0xFF
550  // Returned when get command to return a number
551  // 4 byte 32-bit value in little endian order.
552  // (0x01+0x02*256+0x03*65536+0x04*16777216)
553  // data: 67305985
554  case 0x71: // numeric variable data return
555  {
556  if (this->nextion_queue_.empty()) {
557  ESP_LOGE(TAG, "ERROR: Received numeric return but the queue is empty");
558  break;
559  }
560 
561  if (to_process_length == 0) {
562  ESP_LOGE(TAG, "ERROR: Received numeric return but no data!");
563  break;
564  }
565 
566  int value = 0;
567 
568  for (int i = 0; i < 4; ++i) {
569  value += to_process[i] << (8 * i);
570  }
571 
572  NextionQueue *nb = this->nextion_queue_.front();
573  NextionComponentBase *component = nb->component;
574 
575  if (component->get_queue_type() != NextionQueueType::SENSOR &&
577  component->get_queue_type() != NextionQueueType::SWITCH) {
578  ESP_LOGE(TAG, "ERROR: Received numeric return but next in queue \"%s\" is not a valid sensor type %d",
579  component->get_variable_name().c_str(), component->get_queue_type());
580  } else {
581  ESP_LOGN(TAG, "Received numeric return for variable %s, queue type %d:%s, value %d",
582  component->get_variable_name().c_str(), component->get_queue_type(),
583  component->get_queue_type_string().c_str(), value);
584  component->set_state_from_int(value, true, false);
585  }
586 
587  delete nb; // NOLINT(cppcoreguidelines-owning-memory)
588  this->nextion_queue_.pop_front();
589 
590  break;
591  }
592 
593  case 0x86: { // device automatically enters into sleep mode
594  ESP_LOGVV(TAG, "Received Nextion entering sleep automatically");
595  this->is_sleeping_ = true;
596  this->sleep_callback_.call();
597  break;
598  }
599  case 0x87: // device automatically wakes up
600  {
601  ESP_LOGVV(TAG, "Received Nextion leaves sleep automatically");
602  this->is_sleeping_ = false;
603  this->wake_callback_.call();
604  this->all_components_send_state_(false);
605  break;
606  }
607  case 0x88: // system successful start up
608  {
609  ESP_LOGD(TAG, "system successful start up %zu", to_process_length);
610  this->nextion_reports_is_setup_ = true;
611  break;
612  }
613  case 0x89: { // start SD card upgrade
614  break;
615  }
616  // Data from nextion is
617  // 0x90 - Start
618  // variable length of 0x70 return formatted data (bytes) that contain the variable name: prints "temp1",0
619  // 00 - NULL
620  // 00/01 - Single byte for on/off
621  // FF FF FF - End
622  case 0x90: { // Switched component
623  std::string variable_name;
624 
625  // Get variable name
626  auto index = to_process.find('\0');
627  if (index == std::string::npos || (to_process_length - index - 1) < 1) {
628  ESP_LOGE(TAG, "Bad switch component data received for 0x90 event!");
629  ESP_LOGN(TAG, "to_process %s %zu %d", to_process.c_str(), to_process_length, index);
630  break;
631  }
632 
633  variable_name = to_process.substr(0, index);
634  ++index;
635 
636  ESP_LOGN(TAG, "Got Switch:");
637  ESP_LOGN(TAG, " variable_name: %s", variable_name.c_str());
638  ESP_LOGN(TAG, " value: %d", to_process[0] != 0);
639 
640  for (auto *switchtype : this->switchtype_) {
641  switchtype->process_bool(variable_name, to_process[index] != 0);
642  }
643  break;
644  }
645  // Data from nextion is
646  // 0x91 - Start
647  // variable length of 0x70 return formatted data (bytes) that contain the variable name: prints "temp1",0
648  // 00 - NULL
649  // variable length of 0x71 return data: prints temp1.val,0
650  // FF FF FF - End
651  case 0x91: { // Sensor component
652  std::string variable_name;
653 
654  auto index = to_process.find('\0');
655  if (index == std::string::npos || (to_process_length - index - 1) != 4) {
656  ESP_LOGE(TAG, "Bad sensor component data received for 0x91 event!");
657  ESP_LOGN(TAG, "to_process %s %zu %d", to_process.c_str(), to_process_length, index);
658  break;
659  }
660 
661  index = to_process.find('\0');
662  variable_name = to_process.substr(0, index);
663  // // Get variable name
664  int value = 0;
665  for (int i = 0; i < 4; ++i) {
666  value += to_process[i + index + 1] << (8 * i);
667  }
668 
669  ESP_LOGN(TAG, "Got sensor:");
670  ESP_LOGN(TAG, " variable_name: %s", variable_name.c_str());
671  ESP_LOGN(TAG, " value: %d", value);
672 
673  for (auto *sensor : this->sensortype_) {
674  sensor->process_sensor(variable_name, value);
675  }
676  break;
677  }
678 
679  // Data from nextion is
680  // 0x92 - Start
681  // variable length of 0x70 return formatted data (bytes) that contain the variable name: prints "temp1",0
682  // 00 - NULL
683  // variable length of 0x70 return formatted data (bytes) that contain the text prints temp1.txt,0
684  // 00 - NULL
685  // FF FF FF - End
686  case 0x92: { // Text Sensor Component
687  std::string variable_name;
688  std::string text_value;
689 
690  // Get variable name
691  auto index = to_process.find('\0');
692  if (index == std::string::npos || (to_process_length - index - 1) < 1) {
693  ESP_LOGE(TAG, "Bad text sensor component data received for 0x92 event!");
694  ESP_LOGN(TAG, "to_process %s %zu %d", to_process.c_str(), to_process_length, index);
695  break;
696  }
697 
698  variable_name = to_process.substr(0, index);
699  ++index;
700 
701  text_value = to_process.substr(index);
702 
703  ESP_LOGN(TAG, "Got Text Sensor:");
704  ESP_LOGN(TAG, " variable_name: %s", variable_name.c_str());
705  ESP_LOGN(TAG, " value: %s", text_value.c_str());
706 
707  // NextionTextSensorResponseQueue *nq = new NextionTextSensorResponseQueue;
708  // nq->variable_name = variable_name;
709  // nq->state = text_value;
710  // this->textsensorq_.push_back(nq);
711  for (auto *textsensortype : this->textsensortype_) {
712  textsensortype->process_text(variable_name, text_value);
713  }
714  break;
715  }
716  // Data from nextion is
717  // 0x93 - Start
718  // variable length of 0x70 return formatted data (bytes) that contain the variable name: prints "temp1",0
719  // 00 - NULL
720  // 00/01 - Single byte for on/off
721  // FF FF FF - End
722  case 0x93: { // Binary Sensor component
723  std::string variable_name;
724 
725  // Get variable name
726  auto index = to_process.find('\0');
727  if (index == std::string::npos || (to_process_length - index - 1) < 1) {
728  ESP_LOGE(TAG, "Bad binary sensor component data received for 0x92 event!");
729  ESP_LOGN(TAG, "to_process %s %zu %d", to_process.c_str(), to_process_length, index);
730  break;
731  }
732 
733  variable_name = to_process.substr(0, index);
734  ++index;
735 
736  ESP_LOGN(TAG, "Got Binary Sensor:");
737  ESP_LOGN(TAG, " variable_name: %s", variable_name.c_str());
738  ESP_LOGN(TAG, " value: %d", to_process[index] != 0);
739 
740  for (auto *binarysensortype : this->binarysensortype_) {
741  binarysensortype->process_bool(&variable_name[0], to_process[index] != 0);
742  }
743  break;
744  }
745  case 0xFD: { // data transparent transmit finished
746  ESP_LOGVV(TAG, "Nextion reported data transmit finished!");
747  this->check_pending_waveform_();
748  break;
749  }
750  case 0xFE: { // data transparent transmit ready
751  ESP_LOGVV(TAG, "Nextion reported ready for transmit!");
752  if (this->waveform_queue_.empty()) {
753  ESP_LOGE(TAG, "No waveforms in queue to send data!");
754  break;
755  }
756 
757  auto &nb = this->waveform_queue_.front();
758  auto *component = nb->component;
759  size_t buffer_to_send = component->get_wave_buffer_size() < 255 ? component->get_wave_buffer_size()
760  : 255; // ADDT command can only send 255
761 
762  this->write_array(component->get_wave_buffer().data(), static_cast<int>(buffer_to_send));
763 
764  ESP_LOGN(TAG, "Nextion sending waveform data for component id %d and waveform id %d, size %zu",
765  component->get_component_id(), component->get_wave_channel_id(), buffer_to_send);
766 
767  component->clear_wave_buffer(buffer_to_send);
768  delete nb; // NOLINT(cppcoreguidelines-owning-memory)
769  this->waveform_queue_.pop_front();
770  break;
771  }
772  default:
773  ESP_LOGW(TAG, "Received unknown event from nextion: 0x%02X", this->nextion_event_);
774  break;
775  }
776 
777  // ESP_LOGN(TAG, "nextion_event_ deleting from 0 to %d", to_process_length + COMMAND_DELIMITER.length() + 1);
778  this->command_data_.erase(0, to_process_length + COMMAND_DELIMITER.length() + 1);
779  // App.feed_wdt(); Remove before master merge
780  this->process_serial_();
781  }
782 
783  uint32_t ms = millis();
784 
785  if (!this->nextion_queue_.empty() && this->nextion_queue_.front()->queue_time + this->max_q_age_ms_ < ms) {
786  for (size_t i = 0; i < this->nextion_queue_.size(); i++) {
787  NextionComponentBase *component = this->nextion_queue_[i]->component;
788  if (this->nextion_queue_[i]->queue_time + this->max_q_age_ms_ < ms) {
789  if (this->nextion_queue_[i]->queue_time == 0) {
790  ESP_LOGD(TAG, "Removing old queue type \"%s\" name \"%s\" queue_time 0",
791  component->get_queue_type_string().c_str(), component->get_variable_name().c_str());
792  }
793 
794  if (component->get_variable_name() == "sleep_wake") {
795  this->is_sleeping_ = false;
796  }
797 
798  ESP_LOGD(TAG, "Removing old queue type \"%s\" name \"%s\"", component->get_queue_type_string().c_str(),
799  component->get_variable_name().c_str());
800 
801  if (component->get_queue_type() == NextionQueueType::NO_RESULT) {
802  if (component->get_variable_name() == "sleep_wake") {
803  this->is_sleeping_ = false;
804  }
805  delete component; // NOLINT(cppcoreguidelines-owning-memory)
806  }
807 
808  delete this->nextion_queue_[i]; // NOLINT(cppcoreguidelines-owning-memory)
809 
810  this->nextion_queue_.erase(this->nextion_queue_.begin() + i);
811  i--;
812 
813  } else {
814  break;
815  }
816  }
817  }
818  ESP_LOGN(TAG, "Loop End");
819  // App.feed_wdt(); Remove before master merge
820  this->process_serial_();
821 } // namespace nextion
822 
823 void Nextion::set_nextion_sensor_state(int queue_type, const std::string &name, float state) {
824  this->set_nextion_sensor_state(static_cast<NextionQueueType>(queue_type), name, state);
825 }
826 
827 void Nextion::set_nextion_sensor_state(NextionQueueType queue_type, const std::string &name, float state) {
828  ESP_LOGN(TAG, "Received state:");
829  ESP_LOGN(TAG, " variable: %s", name.c_str());
830  ESP_LOGN(TAG, " state: %lf", state);
831  ESP_LOGN(TAG, " queue type: %d", queue_type);
832 
833  switch (queue_type) {
835  for (auto *sensor : this->sensortype_) {
836  if (name == sensor->get_variable_name()) {
837  sensor->set_state(state, true, true);
838  break;
839  }
840  }
841  break;
842  }
844  for (auto *sensor : this->binarysensortype_) {
845  if (name == sensor->get_variable_name()) {
846  sensor->set_state(state != 0, true, true);
847  break;
848  }
849  }
850  break;
851  }
853  for (auto *sensor : this->switchtype_) {
854  if (name == sensor->get_variable_name()) {
855  sensor->set_state(state != 0, true, true);
856  break;
857  }
858  }
859  break;
860  }
861  default: {
862  ESP_LOGW(TAG, "set_nextion_sensor_state does not support a queue type %d", queue_type);
863  }
864  }
865 }
866 
867 void Nextion::set_nextion_text_state(const std::string &name, const std::string &state) {
868  ESP_LOGD(TAG, "Received state:");
869  ESP_LOGD(TAG, " variable: %s", name.c_str());
870  ESP_LOGD(TAG, " state: %s", state.c_str());
871 
872  for (auto *sensor : this->textsensortype_) {
873  if (name == sensor->get_variable_name()) {
874  sensor->set_state(state, true, true);
875  break;
876  }
877  }
878 }
879 
880 void Nextion::all_components_send_state_(bool force_update) {
881  ESP_LOGD(TAG, "all_components_send_state_ ");
882  for (auto *binarysensortype : this->binarysensortype_) {
883  if (force_update || binarysensortype->get_needs_to_send_update())
884  binarysensortype->send_state_to_nextion();
885  }
886  for (auto *sensortype : this->sensortype_) {
887  if ((force_update || sensortype->get_needs_to_send_update()) && sensortype->get_wave_chan_id() == 0)
888  sensortype->send_state_to_nextion();
889  }
890  for (auto *switchtype : this->switchtype_) {
891  if (force_update || switchtype->get_needs_to_send_update())
892  switchtype->send_state_to_nextion();
893  }
894  for (auto *textsensortype : this->textsensortype_) {
895  if (force_update || textsensortype->get_needs_to_send_update())
896  textsensortype->send_state_to_nextion();
897  }
898 }
899 
900 void Nextion::update_components_by_prefix(const std::string &prefix) {
901  for (auto *binarysensortype : this->binarysensortype_) {
902  if (binarysensortype->get_variable_name().find(prefix, 0) != std::string::npos)
903  binarysensortype->update_component_settings(true);
904  }
905  for (auto *sensortype : this->sensortype_) {
906  if (sensortype->get_variable_name().find(prefix, 0) != std::string::npos)
907  sensortype->update_component_settings(true);
908  }
909  for (auto *switchtype : this->switchtype_) {
910  if (switchtype->get_variable_name().find(prefix, 0) != std::string::npos)
911  switchtype->update_component_settings(true);
912  }
913  for (auto *textsensortype : this->textsensortype_) {
914  if (textsensortype->get_variable_name().find(prefix, 0) != std::string::npos)
915  textsensortype->update_component_settings(true);
916  }
917 }
918 
919 uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag) {
920  uint16_t ret = 0;
921  uint8_t c = 0;
922  uint8_t nr_of_ff_bytes = 0;
923  uint64_t start;
924  bool exit_flag = false;
925  bool ff_flag = false;
926 
927  start = millis();
928 
929  while ((timeout == 0 && this->available()) || millis() - start <= timeout) {
930  if (!this->available()) {
931  App.feed_wdt();
932  delay(1);
933  continue;
934  }
935 
936  this->read_byte(&c);
937  if (c == 0xFF) {
938  nr_of_ff_bytes++;
939  } else {
940  nr_of_ff_bytes = 0;
941  ff_flag = false;
942  }
943 
944  if (nr_of_ff_bytes >= 3)
945  ff_flag = true;
946 
947  response += (char) c;
948  if (recv_flag) {
949  if (response.find(0x05) != std::string::npos) {
950  exit_flag = true;
951  }
952  }
953  App.feed_wdt();
954  delay(2);
955 
956  if (exit_flag || ff_flag) {
957  break;
958  }
959  }
960 
961  if (ff_flag)
962  response = response.substr(0, response.length() - 3); // Remove last 3 0xFF
963 
964  ret = response.length();
965  return ret;
966 }
967 
973 void Nextion::add_no_result_to_queue_(const std::string &variable_name) {
974  // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
975  nextion::NextionQueue *nextion_queue = new nextion::NextionQueue;
976 
977  // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
978  nextion_queue->component = new nextion::NextionComponentBase;
979  nextion_queue->component->set_variable_name(variable_name);
980 
981  nextion_queue->queue_time = millis();
982 
983  this->nextion_queue_.push_back(nextion_queue);
984 
985  ESP_LOGN(TAG, "Add to queue type: NORESULT component %s", nextion_queue->component->get_variable_name().c_str());
986 }
987 
994 void Nextion::add_no_result_to_queue_with_command_(const std::string &variable_name, const std::string &command) {
995  if ((!this->is_setup() && !this->ignore_is_setup_) || command.empty())
996  return;
997 
998  if (this->send_command_(command)) {
999  this->add_no_result_to_queue_(variable_name);
1000  }
1001 }
1002 
1003 bool Nextion::add_no_result_to_queue_with_ignore_sleep_printf_(const std::string &variable_name, const char *format,
1004  ...) {
1005  if ((!this->is_setup() && !this->ignore_is_setup_))
1006  return false;
1007 
1008  char buffer[256];
1009  va_list arg;
1010  va_start(arg, format);
1011  int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
1012  va_end(arg);
1013  if (ret <= 0) {
1014  ESP_LOGW(TAG, "Building command for format '%s' failed!", format);
1015  return false;
1016  }
1017 
1018  this->add_no_result_to_queue_with_command_(variable_name, buffer);
1019  return true;
1020 }
1021 
1029 bool Nextion::add_no_result_to_queue_with_printf_(const std::string &variable_name, const char *format, ...) {
1030  if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping())
1031  return false;
1032 
1033  char buffer[256];
1034  va_list arg;
1035  va_start(arg, format);
1036  int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
1037  va_end(arg);
1038  if (ret <= 0) {
1039  ESP_LOGW(TAG, "Building command for format '%s' failed!", format);
1040  return false;
1041  }
1042 
1043  this->add_no_result_to_queue_with_command_(variable_name, buffer);
1044  return true;
1045 }
1046 
1058  state_value);
1059 }
1060 
1061 void Nextion::add_no_result_to_queue_with_set(const std::string &variable_name,
1062  const std::string &variable_name_to_send, int32_t state_value) {
1063  this->add_no_result_to_queue_with_set_internal_(variable_name, variable_name_to_send, state_value);
1064 }
1065 
1066 void Nextion::add_no_result_to_queue_with_set_internal_(const std::string &variable_name,
1067  const std::string &variable_name_to_send, int32_t state_value,
1068  bool is_sleep_safe) {
1069  if ((!this->is_setup() && !this->ignore_is_setup_) || (!is_sleep_safe && this->is_sleeping()))
1070  return;
1071 
1072  this->add_no_result_to_queue_with_ignore_sleep_printf_(variable_name, "%s=%" PRId32, variable_name_to_send.c_str(),
1073  state_value);
1074 }
1075 
1084 void Nextion::add_no_result_to_queue_with_set(NextionComponentBase *component, const std::string &state_value) {
1086  state_value);
1087 }
1088 void Nextion::add_no_result_to_queue_with_set(const std::string &variable_name,
1089  const std::string &variable_name_to_send,
1090  const std::string &state_value) {
1091  this->add_no_result_to_queue_with_set_internal_(variable_name, variable_name_to_send, state_value);
1092 }
1093 
1094 void Nextion::add_no_result_to_queue_with_set_internal_(const std::string &variable_name,
1095  const std::string &variable_name_to_send,
1096  const std::string &state_value, bool is_sleep_safe) {
1097  if ((!this->is_setup() && !this->ignore_is_setup_) || (!is_sleep_safe && this->is_sleeping()))
1098  return;
1099 
1100  this->add_no_result_to_queue_with_printf_(variable_name, "%s=\"%s\"", variable_name_to_send.c_str(),
1101  state_value.c_str());
1102 }
1103 
1105  if ((!this->is_setup() && !this->ignore_is_setup_))
1106  return;
1107 
1108  // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
1109  nextion::NextionQueue *nextion_queue = new nextion::NextionQueue;
1110 
1111  nextion_queue->component = component;
1112  nextion_queue->queue_time = millis();
1113 
1114  ESP_LOGN(TAG, "Add to queue type: %s component %s", component->get_queue_type_string().c_str(),
1115  component->get_variable_name().c_str());
1116 
1117  std::string command = "get " + component->get_variable_name_to_send();
1118 
1119  if (this->send_command_(command)) {
1120  this->nextion_queue_.push_back(nextion_queue);
1121  }
1122 }
1123 
1133  if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping())
1134  return;
1135 
1136  // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
1137  nextion::NextionQueue *nextion_queue = new nextion::NextionQueue;
1138 
1139  nextion_queue->component = component;
1140  nextion_queue->queue_time = millis();
1141 
1142  this->waveform_queue_.push_back(nextion_queue);
1143  if (this->waveform_queue_.size() == 1)
1144  this->check_pending_waveform_();
1145 }
1146 
1148  if (this->waveform_queue_.empty())
1149  return;
1150 
1151  auto *nb = this->waveform_queue_.front();
1152  auto *component = nb->component;
1153  size_t buffer_to_send = component->get_wave_buffer_size() < 255 ? component->get_wave_buffer_size()
1154  : 255; // ADDT command can only send 255
1155 
1156  std::string command = "addt " + to_string(component->get_component_id()) + "," +
1157  to_string(component->get_wave_channel_id()) + "," + to_string(buffer_to_send);
1158  if (!this->send_command_(command)) {
1159  delete nb; // NOLINT(cppcoreguidelines-owning-memory)
1160  this->waveform_queue_.pop_front();
1161  }
1162 }
1163 
1164 void Nextion::set_writer(const nextion_writer_t &writer) { this->writer_ = writer; }
1165 
1166 ESPDEPRECATED("set_wait_for_ack(bool) is deprecated and has no effect", "v1.20")
1167 void Nextion::set_wait_for_ack(bool wait_for_ack) { ESP_LOGE(TAG, "This command is deprecated"); }
1168 
1169 bool Nextion::is_updating() { return this->is_updating_; }
1170 
1171 } // namespace nextion
1172 } // namespace esphome
void goto_page(const char *page)
Show the page with a given name.
bool ignore_is_setup_
Sends commands ignoring of the Nextion has been setup.
Definition: nextion.h:1232
const uint16_t startup_override_ms_
Definition: nextion.h:1351
void write_str(const char *str)
Definition: uart.h:27
void all_components_send_state_(bool force_update=false)
Definition: nextion.cpp:880
CallbackManager< void(uint8_t)> page_callback_
Definition: nextion.h:1330
CallbackManager< void()> sleep_callback_
Definition: nextion.h:1328
const char * name
Definition: stm32flash.h:78
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
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:185
void write_array(const uint8_t *data, size_t len)
Definition: uart.h:21
void add_wake_state_callback(std::function< void()> &&callback)
Add a callback to be notified of wake state changes.
Definition: nextion.cpp:177
bool send_command(const char *command)
Manually send a raw command to the display.
Definition: nextion.cpp:215
bool send_command_printf(const char *format,...) __attribute__((format(printf
Manually send a raw formatted command to the display.
Definition: nextion.cpp:226
void add_addt_command_to_queue(NextionComponentBase *component) override
Add addt command to the queue.
Definition: nextion.cpp:1132
bool is_updating() override
Check if the TFT update process is currently running.
Definition: nextion.cpp:1169
void add_to_get_queue(NextionComponentBase *component) override
Definition: nextion.cpp:1104
std::vector< NextionComponentBase * > touch_
Definition: nextion.h:1322
optional< nextion_writer_t > writer_
Definition: nextion.h:1334
uint16_t x
Definition: tt21100.cpp:17
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:181
CallbackManager< void()> buffer_overflow_callback_
Definition: nextion.h:1332
const uint16_t max_q_age_ms_
Definition: nextion.h:1352
bool send_command_(const std::string &command)
Manually send a raw command to the display and don&#39;t wait for an acknowledgement packet.
Definition: nextion.cpp:29
float get_setup_priority() const override
Definition: nextion.cpp:163
void setup() override
Definition: nextion.cpp:12
std::string serial_number_
Definition: nextion.h:1339
CallbackManager< void(uint8_t, uint8_t, bool)> touch_callback_
Definition: nextion.h:1331
bool has_value() const
Definition: optional.h:87
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:193
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
void set_exit_reparse_on_start(bool exit_reparse)
Sets if Nextion should exit the active reparse mode before the "connect" command is sent...
uint16_t y
Definition: tt21100.cpp:18
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:1029
void add_sleep_state_callback(std::function< void()> &&callback)
Add a callback to be notified of sleep state changes.
Definition: nextion.cpp:173
virtual void set_state_from_string(const std::string &state_value, bool publish, bool send_to_nextion)
std::string flash_size_
Definition: nextion.h:1340
void set_nextion_sensor_state(int queue_type, const std::string &name, float state)
Set the nextion sensor state object.
Definition: nextion.cpp:823
CallbackManager< void()> setup_callback_
Definition: nextion.h:1327
bool read_byte(uint8_t *data)
Definition: uart.h:29
void set_nextion_text_state(const std::string &name, const std::string &state)
Definition: nextion.cpp:867
void set_wait_for_ack(bool wait_for_ack)
void loop() override
Definition: nextion.cpp:267
std::deque< NextionQueue * > nextion_queue_
Definition: nextion.h:1221
CallbackManager< void()> wake_callback_
Definition: nextion.h:1329
Application App
Global storage of Application pointer - only one Application can exist.
void add_no_result_to_queue_(const std::string &variable_name)
Definition: nextion.cpp:973
std::deque< NextionQueue * > waveform_queue_
Definition: nextion.h:1222
std::string command_data_
Definition: nextion.h:1349
bool remove_from_q_(bool report_empty=true)
Definition: nextion.cpp:312
void set_backlight_brightness(float brightness)
Set the brightness of the backlight.
std::string device_model_
Definition: nextion.h:1337
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:1066
bool add_no_result_to_queue_with_ignore_sleep_printf_(const std::string &variable_name, const char *format,...) __attribute__((format(printf
Definition: nextion.cpp:1003
void set_touch_sleep_timeout(uint16_t timeout)
Set the touch sleep timeout of the display.
std::vector< NextionComponentBase * > textsensortype_
Definition: nextion.h:1325
ESPDEPRECATED("set_wait_for_ack(bool) is deprecated and has no effect", "v1.20") void Nextion
Definition: nextion.cpp:1166
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:189
void set_wake_up_page(uint8_t page_id=255)
Sets which page Nextion loads when exiting sleep mode.
std::vector< NextionComponentBase * > sensortype_
Definition: nextion.h:1324
void dump_config() override
Definition: nextion.cpp:137
std::string to_string(int value)
Definition: helpers.cpp:81
std::vector< NextionComponentBase * > switchtype_
Definition: nextion.h:1323
void set_auto_wake_on_touch(bool auto_wake)
Sets if Nextion should auto-wake from sleep when touch press occurs.
virtual void set_state_from_int(int state_value, bool publish, bool send_to_nextion)
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
bool void add_no_result_to_queue_with_command_(const std::string &variable_name, const std::string &command)
Definition: nextion.cpp:994
void reset_(bool reset_nextion=true)
Definition: nextion.cpp:127
void update_components_by_prefix(const std::string &prefix)
Definition: nextion.cpp:900
void update() override
Definition: nextion.cpp:164
uint8_t end[39]
Definition: sun_gtil2.cpp:31
std::string firmware_version_
Definition: nextion.h:1338
void set_variable_name(const std::string &variable_name, const std::string &variable_name_to_send="")
uint32_t touch_sleep_timeout_
Definition: nextion.h:1240
esphome::sensor::Sensor * sensor
Definition: statsd.h:38
uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag)
Definition: nextion.cpp:919
void add_no_result_to_queue_with_set(NextionComponentBase *component, int32_t state_value) override
Definition: nextion.cpp:1056
std::function< void(Nextion &)> nextion_writer_t
Definition: nextion.h:34
std::vector< NextionComponentBase * > binarysensortype_
Definition: nextion.h:1326
bool state
Definition: fan.h:34
void set_writer(const nextion_writer_t &writer)
Definition: nextion.cpp:1164
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26