10static const char *
const TAG =
"nextion";
34#ifdef USE_NEXTION_COMMAND_SPACING
40 ESP_LOGN(TAG,
"send_command %s", command.c_str());
43 const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF};
46#ifdef USE_NEXTION_COMMAND_SPACING
60 ESP_LOGW(TAG,
"Nextion display set as connected without performing handshake");
89 if (!response.empty() && response[0] == 0x1A) {
91 ESP_LOGD(TAG,
"0x1A error ignored during setup");
94 if (response.empty() || response.find(
"comok") == std::string::npos) {
95#ifdef NEXTION_PROTOCOL_LOG
96 ESP_LOGN(TAG,
"Bad connect request %s", response.c_str());
97 for (
size_t i = 0; i < response.length(); i++) {
98 ESP_LOGN(TAG,
"response %s %d %d %c", response.c_str(), i, response[i], response[i]);
102 ESP_LOGW(TAG,
"Nextion is not connected! ");
108 ESP_LOGI(TAG,
"Nextion is connected");
111 ESP_LOGN(TAG,
"connect request %s", response.c_str());
115 std::vector<std::string> connect_info;
116 while ((start = response.find_first_not_of(
',',
end)) != std::string::npos) {
117 end = response.find(
',', start);
118 connect_info.push_back(response.substr(start,
end - start));
123 ESP_LOGN(TAG,
"Received connect_info %zu", connect_info.size());
130 ESP_LOGE(TAG,
"Nextion returned bad connect value \"%s\"", response.c_str());
149 ESP_LOGCONFIG(TAG,
"Nextion:");
153 ESP_LOGCONFIG(TAG,
" Device Model: %s", this->
device_model_.c_str());
155 ESP_LOGCONFIG(TAG,
" Serial Number: %s", this->
serial_number_.c_str());
156 ESP_LOGCONFIG(TAG,
" Flash Size: %s", this->
flash_size_.c_str());
166 ESP_LOGCONFIG(TAG,
" Wake Up Page: %" PRId16, this->
wake_up_page_);
170 ESP_LOGCONFIG(TAG,
" Start Up Page: %" PRId16, this->
start_up_page_);
173#ifdef USE_NEXTION_COMMAND_SPACING
217 binarysensortype->update_component();
220 sensortype->update_component();
223 switchtype->update_component();
226 textsensortype->update_component();
247 va_start(arg, format);
248 int ret = vsnprintf(buffer,
sizeof(buffer), format, arg);
251 ESP_LOGW(TAG,
"Building command for format '%s' failed!", format);
262#ifdef NEXTION_PROTOCOL_LOG
264 ESP_LOGN(TAG,
"print_queue_members_ (top 10) size %zu", this->
nextion_queue_.size());
265 ESP_LOGN(TAG,
"*******************************************");
272 ESP_LOGN(TAG,
"Nextion queue is null");
274 ESP_LOGN(TAG,
"Nextion queue type: %d:%s , name: %s", i->component->get_queue_type(),
275 i->component->get_queue_type_string().c_str(), i->component->get_variable_name().c_str());
278 ESP_LOGN(TAG,
"*******************************************");
315 ESP_LOGD(TAG,
"Manually set nextion report ready");
324 ESP_LOGE(TAG,
"Nextion queue is empty!");
331 ESP_LOGE(TAG,
"Invalid queue entry!");
337 ESP_LOGN(TAG,
"Removing %s from the queue", component->
get_variable_name().c_str());
364#ifdef USE_NEXTION_COMMAND_SPACING
370 size_t to_process_length = 0;
371 std::string to_process;
373 ESP_LOGN(TAG,
"this->command_data_ %s length %d", this->
command_data_.c_str(), this->command_data_.length());
374#ifdef NEXTION_PROTOCOL_LOG
377 while ((to_process_length = this->
command_data_.find(COMMAND_DELIMITER)) != std::string::npos) {
378 ESP_LOGN(TAG,
"print_queue_members_ size %zu", this->
nextion_queue_.size());
379 while (to_process_length + COMMAND_DELIMITER.length() < this->command_data_.length() &&
380 static_cast<uint8_t
>(this->command_data_[to_process_length + COMMAND_DELIMITER.length()]) == 0xFF) {
382 ESP_LOGN(TAG,
"Add extra 0xFF to process");
387 to_process_length -= 1;
388 to_process = this->
command_data_.substr(1, to_process_length);
392 ESP_LOGW(TAG,
"Nextion reported invalid instruction!");
398 ESP_LOGVV(TAG,
"instruction sent by user was successful");
399 ESP_LOGN(TAG,
"this->nextion_queue_.empty() %s", this->
nextion_queue_.empty() ?
"True" :
"False");
404 ESP_LOGD(TAG,
"Nextion is setup");
409#ifdef USE_NEXTION_COMMAND_SPACING
414 ESP_LOGW(TAG,
"Nextion reported component ID or name invalid!");
418 ESP_LOGW(TAG,
"Nextion reported page ID invalid!");
422 ESP_LOGW(TAG,
"Nextion reported picture ID invalid!");
426 ESP_LOGW(TAG,
"Nextion reported font ID invalid!");
430 ESP_LOGW(TAG,
"Nextion File operation fail!");
433 ESP_LOGW(TAG,
"Nextion Instructions with CRC validation fails their CRC check!");
436 ESP_LOGW(TAG,
"Nextion reported baud rate invalid!");
441 "Nextion reported invalid Waveform ID or Channel # was used but no waveform sensor in queue found!");
446 ESP_LOGW(TAG,
"Nextion reported invalid Waveform ID %d or Channel # %d was used!",
449 ESP_LOGN(TAG,
"Removing waveform from queue with component id %d and waveform id %d",
457 ESP_LOGW(TAG,
"Nextion reported variable name invalid!");
461 ESP_LOGW(TAG,
"Nextion reported variable operation invalid!");
465 ESP_LOGW(TAG,
"Nextion reported failed to assign variable!");
469 ESP_LOGW(TAG,
"Nextion reported operating EEPROM failed!");
472 ESP_LOGW(TAG,
"Nextion reported parameter quantity invalid!");
476 ESP_LOGW(TAG,
"Nextion reported component I/O operation invalid!");
479 ESP_LOGW(TAG,
"Nextion reported undefined escape characters!");
483 ESP_LOGW(TAG,
"Nextion reported too long variable name!");
488 ESP_LOGE(TAG,
"Nextion reported Serial Buffer overflow!");
492 if (to_process_length != 3) {
493 ESP_LOGW(TAG,
"Touch event data is expecting 3, received %zu", to_process_length);
497 uint8_t page_id = to_process[0];
498 uint8_t component_id = to_process[1];
499 uint8_t touch_event = to_process[2];
500 ESP_LOGD(TAG,
"Got touch event:");
501 ESP_LOGD(TAG,
" page_id: %u", page_id);
502 ESP_LOGD(TAG,
" component_id: %u", component_id);
503 ESP_LOGD(TAG,
" event type: %s", touch_event ?
"PRESS" :
"RELEASE");
504 for (
auto *touch : this->
touch_) {
505 touch->process_touch(page_id, component_id, touch_event != 0);
512 if (to_process_length != 1) {
513 ESP_LOGW(TAG,
"New page event data is expecting 1, received %zu", to_process_length);
517 uint8_t page_id = to_process[0];
518 ESP_LOGD(TAG,
"Got new page: %u", page_id);
527 if (to_process_length != 5) {
528 ESP_LOGW(TAG,
"Touch coordinate data is expecting 5, received %zu", to_process_length);
529 ESP_LOGW(TAG,
"%s", to_process.c_str());
533 uint16_t
x = (uint16_t(to_process[0]) << 8) | to_process[1];
534 uint16_t
y = (uint16_t(to_process[2]) << 8) | to_process[3];
535 uint8_t touch_event = to_process[4];
536 ESP_LOGD(TAG,
"Got touch event:");
537 ESP_LOGD(TAG,
" x: %u",
x);
538 ESP_LOGD(TAG,
" y: %u",
y);
539 ESP_LOGD(TAG,
" type: %s", touch_event ?
"PRESS" :
"RELEASE");
550 ESP_LOGW(TAG,
"ERROR: Received string return but the queue is empty");
556 ESP_LOGE(TAG,
"Invalid queue entry!");
563 ESP_LOGE(TAG,
"ERROR: Received string return but next in queue \"%s\" is not a text sensor",
566 ESP_LOGN(TAG,
"Received get_string response: \"%s\" for component id: %s, type: %s", to_process.c_str(),
584 ESP_LOGE(TAG,
"ERROR: Received numeric return but the queue is empty");
588 if (to_process_length == 0) {
589 ESP_LOGE(TAG,
"ERROR: Received numeric return but no data!");
595 for (
int i = 0; i < 4; ++i) {
596 value += to_process[i] << (8 * i);
601 ESP_LOGE(TAG,
"Invalid queue entry!");
610 ESP_LOGE(TAG,
"ERROR: Received numeric return but next in queue \"%s\" is not a valid sensor type %d",
613 ESP_LOGN(TAG,
"Received numeric return for variable %s, queue type %d:%s, value %d",
626 ESP_LOGVV(TAG,
"Received Nextion entering sleep automatically");
633 ESP_LOGVV(TAG,
"Received Nextion leaves sleep automatically");
641 ESP_LOGD(TAG,
"system successful start up %zu", to_process_length);
655 std::string variable_name;
658 auto index = to_process.find(
'\0');
659 if (index == std::string::npos || (to_process_length - index - 1) < 1) {
660 ESP_LOGE(TAG,
"Bad switch component data received for 0x90 event!");
661 ESP_LOGN(TAG,
"to_process %s %zu %d", to_process.c_str(), to_process_length, index);
665 variable_name = to_process.substr(0, index);
668 ESP_LOGN(TAG,
"Got Switch:");
669 ESP_LOGN(TAG,
" variable_name: %s", variable_name.c_str());
670 ESP_LOGN(TAG,
" value: %d", to_process[0] != 0);
673 switchtype->process_bool(variable_name, to_process[index] != 0);
684 std::string variable_name;
686 auto index = to_process.find(
'\0');
687 if (index == std::string::npos || (to_process_length - index - 1) != 4) {
688 ESP_LOGE(TAG,
"Bad sensor component data received for 0x91 event!");
689 ESP_LOGN(TAG,
"to_process %s %zu %d", to_process.c_str(), to_process_length, index);
693 index = to_process.find(
'\0');
694 variable_name = to_process.substr(0, index);
697 for (
int i = 0; i < 4; ++i) {
698 value += to_process[i + index + 1] << (8 * i);
701 ESP_LOGN(TAG,
"Got sensor:");
702 ESP_LOGN(TAG,
" variable_name: %s", variable_name.c_str());
703 ESP_LOGN(TAG,
" value: %d", value);
706 sensor->process_sensor(variable_name, value);
719 std::string variable_name;
720 std::string text_value;
723 auto index = to_process.find(
'\0');
724 if (index == std::string::npos || (to_process_length - index - 1) < 1) {
725 ESP_LOGE(TAG,
"Bad text sensor component data received for 0x92 event!");
726 ESP_LOGN(TAG,
"to_process %s %zu %d", to_process.c_str(), to_process_length, index);
730 variable_name = to_process.substr(0, index);
733 text_value = to_process.substr(index);
735 ESP_LOGN(TAG,
"Got Text Sensor:");
736 ESP_LOGN(TAG,
" variable_name: %s", variable_name.c_str());
737 ESP_LOGN(TAG,
" value: %s", text_value.c_str());
744 textsensortype->process_text(variable_name, text_value);
755 std::string variable_name;
758 auto index = to_process.find(
'\0');
759 if (index == std::string::npos || (to_process_length - index - 1) < 1) {
760 ESP_LOGE(TAG,
"Bad binary sensor component data received for 0x92 event!");
761 ESP_LOGN(TAG,
"to_process %s %zu %d", to_process.c_str(), to_process_length, index);
765 variable_name = to_process.substr(0, index);
768 ESP_LOGN(TAG,
"Got Binary Sensor:");
769 ESP_LOGN(TAG,
" variable_name: %s", variable_name.c_str());
770 ESP_LOGN(TAG,
" value: %d", to_process[index] != 0);
773 binarysensortype->process_bool(&variable_name[0], to_process[index] != 0);
778 ESP_LOGVV(TAG,
"Nextion reported data transmit finished!");
783 ESP_LOGVV(TAG,
"Nextion reported ready for transmit!");
785 ESP_LOGE(TAG,
"No waveforms in queue to send data!");
790 auto *component = nb->component;
791 size_t buffer_to_send = component->get_wave_buffer_size() < 255 ? component->get_wave_buffer_size()
794 this->
write_array(component->get_wave_buffer().data(),
static_cast<int>(buffer_to_send));
796 ESP_LOGN(TAG,
"Nextion sending waveform data for component id %d and waveform id %d, size %zu",
797 component->get_component_id(), component->get_wave_channel_id(), buffer_to_send);
799 component->clear_wave_buffer(buffer_to_send);
805 ESP_LOGW(TAG,
"Received unknown event from nextion: 0x%02X", this->
nextion_event_);
810 this->
command_data_.erase(0, to_process_length + COMMAND_DELIMITER.length() + 1);
817 if (!this->
nextion_queue_.empty() && this->nextion_queue_.front()->queue_time + this->max_q_age_ms_ < ms) {
822 ESP_LOGD(TAG,
"Removing old queue type \"%s\" name \"%s\" queue_time 0",
830 ESP_LOGD(TAG,
"Removing old queue type \"%s\" name \"%s\"", component->
get_queue_type_string().c_str(),
850 ESP_LOGN(TAG,
"Loop End");
860 ESP_LOGN(TAG,
"Received state:");
861 ESP_LOGN(TAG,
" variable: %s", name.c_str());
862 ESP_LOGN(TAG,
" state: %lf",
state);
863 ESP_LOGN(TAG,
" queue type: %d", queue_type);
865 switch (queue_type) {
868 if (name == sensor->get_variable_name()) {
869 sensor->set_state(
state,
true,
true);
877 if (name == sensor->get_variable_name()) {
878 sensor->set_state(
state != 0,
true,
true);
886 if (name == sensor->get_variable_name()) {
887 sensor->set_state(
state != 0,
true,
true);
894 ESP_LOGW(TAG,
"set_nextion_sensor_state does not support a queue type %d", queue_type);
900 ESP_LOGD(TAG,
"Received state:");
901 ESP_LOGD(TAG,
" variable: %s", name.c_str());
902 ESP_LOGD(TAG,
" state: %s",
state.c_str());
905 if (name == sensor->get_variable_name()) {
906 sensor->set_state(
state,
true,
true);
913 ESP_LOGD(TAG,
"all_components_send_state_ ");
915 if (force_update || binarysensortype->get_needs_to_send_update())
916 binarysensortype->send_state_to_nextion();
919 if ((force_update || sensortype->get_needs_to_send_update()) && sensortype->get_wave_chan_id() == 0)
920 sensortype->send_state_to_nextion();
923 if (force_update || switchtype->get_needs_to_send_update())
924 switchtype->send_state_to_nextion();
927 if (force_update || textsensortype->get_needs_to_send_update())
928 textsensortype->send_state_to_nextion();
934 if (binarysensortype->get_variable_name().find(prefix, 0) != std::string::npos)
935 binarysensortype->update_component_settings(
true);
938 if (sensortype->get_variable_name().find(prefix, 0) != std::string::npos)
939 sensortype->update_component_settings(
true);
942 if (switchtype->get_variable_name().find(prefix, 0) != std::string::npos)
943 switchtype->update_component_settings(
true);
946 if (textsensortype->get_variable_name().find(prefix, 0) != std::string::npos)
947 textsensortype->update_component_settings(
true);
954 uint8_t nr_of_ff_bytes = 0;
956 bool exit_flag =
false;
957 bool ff_flag =
false;
961 while ((timeout == 0 && this->
available()) ||
millis() - start <= timeout) {
976 if (nr_of_ff_bytes >= 3)
979 response += (char) c;
981 if (response.find(0x05) != std::string::npos) {
988 if (exit_flag || ff_flag) {
994 response = response.substr(0, response.length() - 3);
996 ret = response.length();
1042 va_start(arg, format);
1043 int ret = vsnprintf(buffer,
sizeof(buffer), format, arg);
1046 ESP_LOGW(TAG,
"Building command for format '%s' failed!", format);
1067 va_start(arg, format);
1068 int ret = vsnprintf(buffer,
sizeof(buffer), format, arg);
1071 ESP_LOGW(TAG,
"Building command for format '%s' failed!", format);
1094 const std::string &variable_name_to_send, int32_t state_value) {
1099 const std::string &variable_name_to_send, int32_t state_value,
1100 bool is_sleep_safe) {
1121 const std::string &variable_name_to_send,
1122 const std::string &state_value) {
1127 const std::string &variable_name_to_send,
1128 const std::string &state_value,
bool is_sleep_safe) {
1133 state_value.c_str());
1184 auto *component = nb->component;
1185 size_t buffer_to_send = component->get_wave_buffer_size() < 255 ? component->get_wave_buffer_size()
1188 std::string command =
"addt " +
to_string(component->get_component_id()) +
"," +
1199void
Nextion::set_wait_for_ack(
bool wait_for_ack) { ESP_LOGE(TAG,
"This command is deprecated"); }
void feed_wdt(uint32_t time=0)
uint8_t get_spacing() const
Get current command spacing.
bool can_send() const
Check if enough time has passed to send next command.
void mark_sent()
Mark a command as sent, updating the timing.
uint8_t get_wave_channel_id()
virtual std::string get_queue_type_string()
virtual void set_state_from_int(int state_value, bool publish, bool send_to_nextion)
std::string get_variable_name()
uint8_t get_component_id()
virtual NextionQueueType get_queue_type()
std::string get_variable_name_to_send()
void set_variable_name(const std::string &variable_name, const std::string &variable_name_to_send="")
virtual void set_state_from_string(const std::string &state_value, bool publish, bool send_to_nextion)
void add_setup_state_callback(std::function< void()> &&callback)
Add a callback to be notified when the nextion completes its initialize setup.
std::vector< NextionComponentBase * > touch_
std::vector< NextionComponentBase * > switchtype_
void add_buffer_overflow_event_callback(std::function< void()> &&callback)
Add a callback to be notified when the nextion reports a buffer overflow.
std::vector< NextionComponentBase * > binarysensortype_
const uint16_t max_q_age_ms_
const uint16_t startup_override_ms_
bool send_command_(const std::string &command)
Manually send a raw command to the display and don't wait for an acknowledgement packet.
std::vector< NextionComponentBase * > textsensortype_
CallbackManager< void(uint8_t)> page_callback_
void check_pending_waveform_()
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_
std::string device_model_
void all_components_send_state_(bool force_update=false)
std::string firmware_version_
void set_nextion_sensor_state(int queue_type, const std::string &name, float state)
Set the nextion sensor state object.
void add_addt_command_to_queue(NextionComponentBase *component) override
Add addt command to the queue.
bool ignore_is_setup_
Sends commands ignoring of the Nextion has been setup.
void add_new_page_callback(std::function< void(uint8_t)> &&callback)
Add a callback to be notified when the nextion changes pages.
void process_nextion_commands_()
void add_to_get_queue(NextionComponentBase *component) override
bool send_command_printf(const char *format,...) __attribute__((format(printf
Manually send a raw formatted command to the display.
std::deque< NextionQueue * > nextion_queue_
bool remove_from_q_(bool report_empty=true)
std::vector< NextionComponentBase * > sensortype_
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)
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.
CallbackManager< void()> setup_callback_
std::string command_data_
optional< float > brightness_
CallbackManager< void()> wake_callback_
bool exit_reparse_on_start_
void add_sleep_state_callback(std::function< void()> &&callback)
Add a callback to be notified of sleep state changes.
bool sent_setup_commands_
bool is_updating() override
Check if the TFT update process is currently running.
uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag)
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.
std::string serial_number_
bool nextion_reports_is_setup_
CallbackManager< void()> sleep_callback_
float get_setup_priority() const override
bool void add_no_result_to_queue_with_command_(const std::string &variable_name, const std::string &command)
void reset_(bool reset_nextion=true)
void update_all_components()
void add_no_result_to_queue_(const std::string &variable_name)
CallbackManager< void(uint8_t, uint8_t, bool)> touch_callback_
void print_queue_members_()
void dump_config() override
NextionCommandPacer command_pacer_
void set_nextion_text_state(const std::string &name, const std::string &state)
std::deque< NextionQueue * > waveform_queue_
bool add_no_result_to_queue_with_ignore_sleep_printf_(const std::string &variable_name, const char *format,...) __attribute__((format(printf
uint32_t touch_sleep_timeout_
void add_wake_state_callback(std::function< void()> &&callback)
Add a callback to be notified of wake state changes.
CallbackManager< void()> buffer_overflow_callback_
bool skip_connection_handshake_
void set_writer(const nextion_writer_t &writer)
void add_no_result_to_queue_with_set(NextionComponentBase *component, int32_t state_value) override
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.
void update_components_by_prefix(const std::string &prefix)
void set_backlight_brightness(float brightness)
Set the brightness of the backlight.
NextionComponentBase * component
value_type const & value() const
void write_str(const char *str)
bool read_byte(uint8_t *data)
void write_array(const uint8_t *data, size_t len)
std::function< void(Nextion &)> nextion_writer_t
ESPDEPRECATED("set_wait_for_ack(bool) is deprecated and has no effect", "v1.20") void Nextion
const float DATA
For components that import data from directly connected sensors like DHT.
Providing packet encoding functions for exchanging data with a remote host.
std::string to_string(int value)
void IRAM_ATTR HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.