19static bool is_sleep_wake_command(
const NextionComponentBase *
component) {
25static constexpr const char *RAW_GET_NAME =
"raw_get";
27static bool is_raw_get_command(
const NextionComponentBase *
component) {
31static const char *raw_command_name(
const char *command,
const char *name) {
32 return ESPHOME_strncmp_P(command, ESPHOME_PSTR(
"get "), 4) == 0 ? RAW_GET_NAME : name;
36static constexpr uint8_t COMMAND_DELIMITER[3] = {0xFF, 0xFF, 0xFF};
37static constexpr size_t DELIMITER_SIZE =
sizeof(COMMAND_DELIMITER);
58#ifdef USE_NEXTION_COMMAND_SPACING
60 if (!this->
connection_state_.ignore_is_setup_ && !this->command_pacer_.can_send(now)) {
61 ESP_LOGN(TAG,
"Command spacing: delaying '%s'", command.c_str());
66 ESP_LOGN(TAG,
"cmd: %s", command.c_str());
69 const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF};
72#ifdef USE_NEXTION_COMMAND_SPACING
89#ifdef USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
90 ESP_LOGW(TAG,
"Connected (no handshake)");
99#ifdef USE_NEXTION_CONFIG_EXIT_REPARSE_ON_START
113 std::string response;
116 if (!response.empty() && response[0] == 0x1A) {
118 ESP_LOGV(TAG,
"0x1A error ignored (setup)");
121 if (response.empty() || response.find(
"comok") == std::string::npos) {
122#ifdef NEXTION_PROTOCOL_LOG
123 ESP_LOGN(TAG,
"Bad connect: %s", response.c_str());
124 for (
size_t i = 0; i < response.length(); i++) {
125 ESP_LOGN(TAG,
"resp: %s %d %d %c", response.c_str(), i, response[i], response[i]);
129 ESP_LOGW(TAG,
"Not connected");
135 ESP_LOGI(TAG,
"Connected");
138 ESP_LOGN(TAG,
"connect: %s", response.c_str());
142 size_t field_count = 0;
145 auto copy_field = [&](
char *dst,
size_t cap) {
146 size_t len = (
end == std::string::npos ? response.size() :
end) - start;
147 size_t n =
len < cap ?
len : cap;
148 std::memcpy(dst, response.data() + start, n);
151 while ((start = response.find_first_not_of(
',',
end)) != std::string::npos) {
152 end = response.find(
',', start);
153 switch (field_count) {
164 this->
flash_size_ =
static_cast<uint32_t>(std::strtoul(response.data() + start,
nullptr, 10));
174 ESP_LOGN(TAG,
"Connect info: %zu fields", field_count);
176 ESP_LOGE(TAG,
"Bad connect value: '%s'", response.c_str());
189 nb->component->~NextionComponentBase();
190 RAMAllocator<NextionComponentBase>().deallocate(nb->component, 1);
193 RAMAllocator<NextionQueue>().deallocate(nb, 1);
201 this->nextion_queue_.clear();
202#ifdef USE_NEXTION_WAVEFORM
206 this->waveform_queue_.clear();
211 ESP_LOGCONFIG(TAG,
"Nextion:");
213#ifdef USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
214 ESP_LOGCONFIG(TAG,
" Skip handshake: YES");
218 " Device Model: %s\n"
220 " Serial Number: %s\n"
221 " Flash Size: %" PRIu32
" bytes",
224 ESP_LOGCONFIG(TAG,
" Device info: not yet detected");
227#ifdef USE_NEXTION_CONFIG_EXIT_REPARSE_ON_START
228 " Exit reparse: YES\n"
230 " Max queue age: %u ms\n"
231 " Startup override: %u ms\n"
232 " Wake On Touch: %s\n"
233 " Touch Timeout: %" PRIu16,
235 this->touch_sleep_timeout_);
238#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP
243 ESP_LOGCONFIG(TAG,
" Wake Up Page: %u", this->
wake_up_page_);
246#ifdef USE_NEXTION_CONF_START_UP_PAGE
252#ifdef USE_NEXTION_COMMAND_SPACING
256#ifdef USE_NEXTION_MAX_QUEUE_SIZE
259#ifdef USE_NEXTION_TFT_UPLOAD
262 " TFT upload HTTP timeout: %" PRIu16
"ms\n"
263 " TFT upload HTTP retries: %u",
264 this->
tft_url_.c_str(), this->tft_upload_http_timeout_, this->tft_upload_http_retries_);
287 binarysensortype->update_component();
290 sensortype->update_component();
293 switchtype->update_component();
296 textsensortype->update_component();
318 ESP_LOGW(TAG,
"Bad cmd format: '%s'",
format);
326#ifdef NEXTION_PROTOCOL_LOG
328 ESP_LOGN(TAG,
"print_queue_members_ (top 10) size %zu", this->nextion_queue_.size());
329 ESP_LOGN(TAG,
"*******************************************");
331 for (
auto *i : this->nextion_queue_) {
336 ESP_LOGN(TAG,
"Queue null");
338 ESP_LOGN(TAG,
"Queue type: %d:%s, name: %s", i->component->get_queue_type(),
339 i->component->get_queue_type_string(), i->component->get_variable_name().c_str());
342 ESP_LOGN(TAG,
"*******************************************");
350 if (this->
connection_state_.nextion_reports_is_setup_ && !this->connection_state_.sent_setup_commands_) {
359#ifdef USE_NEXTION_CONF_START_UP_PAGE
389 ESP_LOGV(TAG,
"Manual ready set");
394#ifdef USE_NEXTION_COMMAND_SPACING
396#ifdef USE_NEXTION_WAVEFORM
397 if (!this->waveform_queue_.empty()) {
404#ifdef USE_NEXTION_COMMAND_SPACING
406#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP
407 size_t commands_sent = 0;
410 for (
auto *item : this->nextion_queue_) {
411 if (item ==
nullptr || item->pending_command.empty()) {
415#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP
417 ESP_LOGV(TAG,
"Pending cmds: loop limit reached, deferring");
430 item->pending_command.clear();
431 ESP_LOGVV(TAG,
"Pending cmd sent: %s", item->component->get_variable_name().c_str());
437 if (this->nextion_queue_.empty()) {
439 ESP_LOGE(TAG,
"Queue empty");
444 NextionQueue *nb = this->nextion_queue_.front();
445 if (!nb || !nb->component) {
446 ESP_LOGE(TAG,
"Invalid queue");
450 this->nextion_queue_.pop_front();
453 NextionComponentBase *
component = nb->component;
455 ESP_LOGN(TAG,
"Removed: %s",
component->get_variable_name().c_str());
461 this->nextion_queue_.pop_front();
466 auto it = this->nextion_queue_.begin();
467 while (it != this->nextion_queue_.end()) {
468 NextionQueue *nb = *it;
469 if (nb ==
nullptr || nb->component ==
nullptr) {
470 ESP_LOGE(TAG,
"Invalid queue entry");
474 it = this->nextion_queue_.erase(it);
477 NextionComponentBase *
component = nb->component;
479 const bool raw_get = is_raw_get_command(
component);
481 if (!nb->pending_command.empty()) {
482 ESP_LOGV(TAG,
"%s: skipping unsent '%s'", LOG_STR_ARG(response_name),
component->get_variable_name().c_str());
489 ESP_LOGV(TAG,
"%s: skipping NO_RESULT '%s'", LOG_STR_ARG(response_name),
component->get_variable_name().c_str());
498 ESP_LOGV(TAG,
"%s for raw get dropped", LOG_STR_ARG(response_name));
501 ESP_LOGN(TAG,
"Numeric: %s type %d:%s val %d",
component->get_variable_name().c_str(), qtype,
502 component->get_queue_type_string(), resp.int_value);
503 component->set_state_from_int(resp.int_value,
true,
false);
505 ESP_LOGN(TAG,
"String resp: '%s' id: %s type: %s", resp.str_value->c_str(),
507 component->set_state_from_string(*resp.str_value,
true,
false);
509 ESP_LOGE(TAG,
"%s but '%s' invalid type %d", LOG_STR_ARG(response_name),
component->get_variable_name().c_str(),
514 this->nextion_queue_.erase(it);
517 ESP_LOGE(TAG,
"%s but no sent query in queue", LOG_STR_ARG(response_name));
521 NextionQueueResponse resp{};
522 resp.is_string =
false;
523 resp.int_value =
value;
528 NextionQueueResponse resp{};
529 resp.is_string =
true;
530 resp.str_value = &
value;
539 size_t to_read = std::min(avail,
sizeof(buf));
545 this->
command_data_.append(
reinterpret_cast<const char *
>(buf), to_read);
554#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP
555 size_t commands_processed = 0;
558 size_t to_process_length = 0;
559 std::string to_process;
561 ESP_LOGN(TAG,
"command_data_ %s len %d", this->
command_data_.c_str(), this->command_data_.length());
562#ifdef NEXTION_PROTOCOL_LOG
565 while ((to_process_length = this->
command_data_.find(
reinterpret_cast<const char *
>(COMMAND_DELIMITER), 0,
566 DELIMITER_SIZE)) != std::string::npos) {
567#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP
569 ESP_LOGV(TAG,
"Command limit reached, deferring");
573 ESP_LOGN(TAG,
"queue size: %zu", this->nextion_queue_.size());
574 while (to_process_length + DELIMITER_SIZE < this->
command_data_.length() &&
575 static_cast<uint8_t
>(this->command_data_[to_process_length + DELIMITER_SIZE]) == 0xFF) {
577 ESP_LOGN(TAG,
"Add 0xFF");
582 to_process_length -= 1;
583 to_process = this->
command_data_.substr(1, to_process_length);
585 switch (nextion_event) {
587 ESP_LOGW(TAG,
"Invalid instruction");
593 ESP_LOGVV(TAG,
"Cmd OK");
594 ESP_LOGN(TAG,
"this->nextion_queue_.empty() %s", YESNO(this->nextion_queue_.empty()));
598 if (this->nextion_queue_.empty()) {
605 ESP_LOGW(TAG,
"Invalid component ID/name");
609 ESP_LOGW(TAG,
"Invalid page ID");
613 ESP_LOGW(TAG,
"Invalid picture ID");
617 ESP_LOGW(TAG,
"Invalid font ID");
621 ESP_LOGW(TAG,
"File operation failed");
624 ESP_LOGW(TAG,
"CRC validation failed");
627 ESP_LOGW(TAG,
"Invalid baud rate");
630#ifdef USE_NEXTION_WAVEFORM
631 if (this->waveform_queue_.empty()) {
632 ESP_LOGW(TAG,
"Waveform ID/ch used but no sensor queued");
634 auto &nb = this->waveform_queue_.front();
635 NextionComponentBase *
component = nb->component;
636 ESP_LOGW(TAG,
"Invalid waveform ID %d/ch %d",
component->get_component_id(),
638 ESP_LOGN(TAG,
"Remove waveform ID %d/ch %d",
component->get_component_id(),
component->get_wave_channel_id());
640 this->waveform_queue_.pop();
643 ESP_LOGW(TAG,
"Waveform ID/ch error but waveform not enabled");
647 ESP_LOGW(TAG,
"Invalid variable name");
651 ESP_LOGW(TAG,
"Invalid variable operation");
655 ESP_LOGW(TAG,
"Variable assign failed");
659 ESP_LOGW(TAG,
"EEPROM operation failed");
662 ESP_LOGW(TAG,
"Invalid parameter count");
666 ESP_LOGW(TAG,
"Invalid component I/O");
669 ESP_LOGW(TAG,
"Undefined escape chars");
673 ESP_LOGW(TAG,
"Variable name too long");
678 ESP_LOGE(TAG,
"Serial buffer overflow");
682 if (to_process_length != 3) {
683 ESP_LOGW(TAG,
"Incorrect touch len: %zu (need 3)", to_process_length);
687 uint8_t page_id = to_process[0];
688 uint8_t component_id = to_process[1];
689 uint8_t touch_event = to_process[2];
690 ESP_LOGV(TAG,
"Touch %s: page %u comp %u", touch_event ? LOG_STR_LITERAL(
"PRESS") : LOG_STR_LITERAL(
"RELEASE"),
691 page_id, component_id);
692 for (
auto *touch : this->
touch_) {
693 touch->process_touch(page_id, component_id, touch_event != 0);
700 if (to_process_length != 1) {
701 ESP_LOGW(TAG,
"Page event: expect 1, got %zu", to_process_length);
705 uint8_t page_id = to_process[0];
706 ESP_LOGV(TAG,
"New page: %u", page_id);
715 if (to_process_length != 5) {
716 ESP_LOGW(TAG,
"Touch coordinate: expect 5, got %zu", to_process_length);
717 ESP_LOGW(TAG,
"%s", to_process.c_str());
721 const uint16_t
x = (uint16_t(to_process[0]) << 8) | to_process[1];
722 const uint16_t
y = (uint16_t(to_process[2]) << 8) | to_process[3];
723 const uint8_t touch_event = to_process[4];
724 ESP_LOGV(TAG,
"Touch %s at %u,%u", touch_event ? LOG_STR_LITERAL(
"PRESS") : LOG_STR_LITERAL(
"RELEASE"),
x,
y);
734 if (this->nextion_queue_.empty()) {
735 ESP_LOGW(TAG,
"String return but queue is empty");
749 if (this->nextion_queue_.empty()) {
750 ESP_LOGE(TAG,
"Numeric return but queue empty");
754 if (to_process_length < 4) {
755 ESP_LOGE(TAG,
"Numeric return but insufficient data (need 4, got %zu)", to_process_length);
759 int value =
static_cast<int>(
encode_uint32(to_process[3], to_process[2], to_process[1], to_process[0]));
766 ESP_LOGVV(TAG,
"Auto sleep");
773 ESP_LOGVV(TAG,
"Auto wake");
781 ESP_LOGV(TAG,
"System start: %zu", to_process_length);
795 std::string variable_name;
798 auto index = to_process.find(
'\0');
799 if (index == std::string::npos || (to_process_length - index - 1) < 1) {
800 ESP_LOGE(TAG,
"Bad switch data (0x90)");
801 ESP_LOGN(TAG,
"proc: %s %zu %zu", to_process.c_str(), to_process_length, index);
805 variable_name = to_process.substr(0, index);
808 ESP_LOGN(TAG,
"Switch %s: %s", ONOFF(to_process[index] != 0), variable_name.c_str());
810#ifdef USE_NEXTION_TRIGGER_CUSTOM_SWITCH
814 for (
auto *switchtype : this->switchtype_) {
815 switchtype->process_bool(variable_name, to_process[index] != 0);
826 std::string variable_name;
828 auto index = to_process.find(
'\0');
829 if (index == std::string::npos || (to_process_length - index - 1) != 4) {
830 ESP_LOGE(TAG,
"Bad sensor data (0x91)");
831 ESP_LOGN(TAG,
"proc: %s %zu %zu", to_process.c_str(), to_process_length, index);
835 index = to_process.find(
'\0');
836 variable_name = to_process.substr(0, index);
838 int value =
static_cast<int>(
839 encode_uint32(to_process[index + 4], to_process[index + 3], to_process[index + 2], to_process[index + 1]));
841 ESP_LOGN(TAG,
"Sensor: %s=%d", variable_name.c_str(), value);
843#ifdef USE_NEXTION_TRIGGER_CUSTOM_SENSOR
847 for (
auto *sensor : this->sensortype_) {
848 sensor->process_sensor(variable_name, value);
861 std::string variable_name;
862 std::string text_value;
865 auto index = to_process.find(
'\0');
866 if (index == std::string::npos || (to_process_length - index - 1) < 1) {
867 ESP_LOGE(TAG,
"Bad text data (0x92)");
868 ESP_LOGN(TAG,
"proc: %s %zu %zu", to_process.c_str(), to_process_length, index);
872 variable_name = to_process.substr(0, index);
876 text_value = to_process.substr(index, to_process_length - index - 1);
878 ESP_LOGN(TAG,
"Text sensor: %s='%s'", variable_name.c_str(), text_value.c_str());
885#ifdef USE_NEXTION_TRIGGER_CUSTOM_TEXT_SENSOR
889 for (
auto *textsensortype : this->textsensortype_) {
890 textsensortype->process_text(variable_name, text_value);
901 std::string variable_name;
904 auto index = to_process.find(
'\0');
905 if (index == std::string::npos || (to_process_length - index - 1) < 1) {
906 ESP_LOGE(TAG,
"Bad binary data (0x93)");
907 ESP_LOGN(TAG,
"proc: %s %zu %zu", to_process.c_str(), to_process_length, index);
911 variable_name = to_process.substr(0, index);
914 ESP_LOGN(TAG,
"Binary sensor: %s=%s", variable_name.c_str(), ONOFF(to_process[index] != 0));
916#ifdef USE_NEXTION_TRIGGER_CUSTOM_BINARY_SENSOR
920 for (
auto *binarysensortype : this->binarysensortype_) {
921 binarysensortype->process_bool(&variable_name[0], to_process[index] != 0);
926 ESP_LOGVV(TAG,
"Data transmit done");
927#ifdef USE_NEXTION_WAVEFORM
933 ESP_LOGVV(TAG,
"Ready for transmit");
934#ifdef USE_NEXTION_WAVEFORM
935 if (this->waveform_queue_.empty()) {
936 ESP_LOGE(TAG,
"No waveforms queued");
939 auto &nb = this->waveform_queue_.front();
941 size_t buffer_to_send =
component->get_wave_buffer_size() < 255 ?
component->get_wave_buffer_size() : 255;
942 this->
write_array(component->get_wave_buffer().data(),
static_cast<int>(buffer_to_send));
943 ESP_LOGN(TAG,
"Send waveform: component id %d, waveform id %d, size %zu",
component->get_component_id(),
944 component->get_wave_channel_id(), buffer_to_send);
945 component->clear_wave_buffer(buffer_to_send);
947 this->waveform_queue_.pop();
949 ESP_LOGW(TAG,
"Waveform transmit ready but waveform not enabled");
954 ESP_LOGW(TAG,
"Unknown event: 0x%02X", nextion_event);
958 this->
command_data_.erase(0, to_process_length + DELIMITER_SIZE + 1);
961 ESP_LOGN(TAG,
"Loop end");
968 if (this->
max_q_age_ms_ > 0 && !this->nextion_queue_.empty() &&
969 ms - this->nextion_queue_.front()->queue_time > this->max_q_age_ms_) {
970 for (
auto it = this->nextion_queue_.begin(); it != this->nextion_queue_.end();) {
971 if (ms - (*it)->queue_time > this->max_q_age_ms_) {
972 NextionComponentBase *
component = (*it)->component;
973 ESP_LOGV(TAG,
"Remove old queue '%s':'%s'",
component->get_queue_type_string(),
980 it = this->nextion_queue_.erase(it);
994 ESP_LOGN(TAG,
"State: %s=%lf (type %d)", name.c_str(),
state, queue_type);
996 switch (queue_type) {
998 for (
auto *sensor : this->sensortype_) {
999 if (name == sensor->get_variable_name()) {
1000 sensor->set_state(
state,
true,
true);
1007 for (
auto *sensor : this->binarysensortype_) {
1008 if (name == sensor->get_variable_name()) {
1009 sensor->set_state(
state != 0,
true,
true);
1016 for (
auto *sensor : this->switchtype_) {
1017 if (name == sensor->get_variable_name()) {
1018 sensor->set_state(
state != 0,
true,
true);
1025 ESP_LOGW(TAG,
"set_sensor_state: bad type %d", queue_type);
1031 ESP_LOGV(TAG,
"State: %s='%s'", name.c_str(),
state.c_str());
1033 for (
auto *sensor : this->textsensortype_) {
1034 if (name == sensor->get_variable_name()) {
1035 sensor->set_state(
state,
true,
true);
1042 ESP_LOGV(TAG,
"Send states");
1043 for (
auto *binarysensortype : this->binarysensortype_) {
1044 if (force_update || binarysensortype->get_needs_to_send_update())
1045 binarysensortype->send_state_to_nextion();
1047 for (
auto *sensortype : this->sensortype_) {
1048#ifdef USE_NEXTION_WAVEFORM
1049 if ((force_update || sensortype->get_needs_to_send_update()) && sensortype->get_wave_channel_id() == UINT8_MAX) {
1051 if (force_update || sensortype->get_needs_to_send_update()) {
1053 sensortype->send_state_to_nextion();
1056 for (
auto *switchtype : this->switchtype_) {
1057 if (force_update || switchtype->get_needs_to_send_update())
1058 switchtype->send_state_to_nextion();
1060 for (
auto *textsensortype : this->textsensortype_) {
1061 if (force_update || textsensortype->get_needs_to_send_update())
1062 textsensortype->send_state_to_nextion();
1067 for (
auto *binarysensortype : this->binarysensortype_) {
1068 if (binarysensortype->get_variable_name().find(prefix, 0) != std::string::npos)
1069 binarysensortype->update_component_settings(
true);
1071 for (
auto *sensortype : this->sensortype_) {
1072 if (sensortype->get_variable_name().find(prefix, 0) != std::string::npos)
1073 sensortype->update_component_settings(
true);
1075 for (
auto *switchtype : this->switchtype_) {
1076 if (switchtype->get_variable_name().find(prefix, 0) != std::string::npos)
1077 switchtype->update_component_settings(
true);
1079 for (
auto *textsensortype : this->textsensortype_) {
1080 if (textsensortype->get_variable_name().find(prefix, 0) != std::string::npos)
1081 textsensortype->update_component_settings(
true);
1087 uint8_t nr_of_ff_bytes = 0;
1088 bool exit_flag =
false;
1089 bool ff_flag =
false;
1093 while ((timeout == 0 && this->
available()) ||
millis() - start <= timeout) {
1108 if (nr_of_ff_bytes >= 3)
1111 response += (char) c;
1113 if (response.find(0x05) != std::string::npos) {
1120 if (exit_flag || ff_flag) {
1126 response = response.substr(0, response.length() - 3);
1128 return response.length();
1133#ifdef USE_NEXTION_MAX_QUEUE_SIZE
1134 if (this->
max_queue_size_ > 0 && this->nextion_queue_.size() >= this->max_queue_size_) {
1135 ESP_LOGW(TAG,
"Queue full (%zu), drop: %s", this->nextion_queue_.size(), variable_name.c_str());
1140 auto *nextion_queue = RAMAllocator<nextion::NextionQueue>().allocate(1);
1141 if (nextion_queue ==
nullptr) {
1142 ESP_LOGW(TAG,
"Queue alloc failed");
1145 new (nextion_queue) nextion::NextionQueue;
1147 nextion_queue->
component = RAMAllocator<nextion::NextionComponentBase>().allocate(1);
1148 if (nextion_queue->component ==
nullptr) {
1149 ESP_LOGW(TAG,
"Component alloc failed");
1153 new (nextion_queue->component) nextion::NextionComponentBase;
1156 return nextion_queue;
1171 if (nextion_queue ==
nullptr)
1173 this->nextion_queue_.push_back(nextion_queue);
1174 ESP_LOGN(TAG,
"Queue NORESULT: %s", variable_name.c_str());
1195 ESP_LOGV(TAG,
"Queue NORESULT '%s': %s", variable_name.c_str(), command.c_str());
1199#ifdef USE_NEXTION_COMMAND_SPACING
1207#ifdef USE_NEXTION_COMMAND_SPACING
1209 const std::string &command) {
1211 if (nextion_queue ==
nullptr)
1213 nextion_queue->pending_command = command;
1214 this->nextion_queue_.push_back(nextion_queue);
1215 ESP_LOGVV(TAG,
"Queue with pending command: %s", variable_name.c_str());
1230 ESP_LOGW(TAG,
"Bad cmd format: '%s'",
format);
1255 ESP_LOGW(TAG,
"Bad cmd format: '%s'",
format);
1278 const std::string &variable_name_to_send, int32_t state_value) {
1283 const std::string &variable_name_to_send, int32_t state_value,
1284 bool is_sleep_safe) {
1305 const std::string &variable_name_to_send,
1306 const std::string &state_value) {
1311 const std::string &variable_name_to_send,
1312 const std::string &state_value,
bool is_sleep_safe) {
1317 state_value.c_str());
1333#ifdef USE_NEXTION_MAX_QUEUE_SIZE
1334 if (this->
max_queue_size_ > 0 && this->nextion_queue_.size() >= this->max_queue_size_) {
1335 ESP_LOGW(TAG,
"Queue full (%zu), drop GET: %s", this->nextion_queue_.size(),
1336 component->get_variable_name().c_str());
1341 RAMAllocator<nextion::NextionQueue> allocator;
1342 nextion::NextionQueue *nextion_queue = allocator.allocate(1);
1343 if (nextion_queue ==
nullptr) {
1344 ESP_LOGW(TAG,
"Queue alloc failed");
1347 new (nextion_queue) nextion::NextionQueue;
1352 ESP_LOGN(TAG,
"Queue %s: %s",
component->get_queue_type_string(),
component->get_variable_name().c_str());
1354 std::string command =
"get " +
component->get_variable_name_to_send();
1356#ifdef USE_NEXTION_COMMAND_SPACING
1360 nextion_queue->pending_command = command;
1361 this->nextion_queue_.push_back(nextion_queue);
1363 nextion_queue->pending_command.clear();
1367 this->nextion_queue_.push_back(nextion_queue);
1374#ifdef USE_NEXTION_WAVEFORM
1384 RAMAllocator<nextion::NextionQueue> allocator;
1385 nextion::NextionQueue *nextion_queue = allocator.allocate(1);
1386 if (nextion_queue ==
nullptr) {
1387 ESP_LOGW(TAG,
"Queue alloc failed");
1390 new (nextion_queue) nextion::NextionQueue;
1395 if (!this->waveform_queue_.push(nextion_queue)) {
1396 ESP_LOGW(TAG,
"Waveform queue full, drop");
1400 if (this->waveform_queue_.size() == 1)
1405 if (this->waveform_queue_.empty())
1408 auto *nb = this->waveform_queue_.front();
1410 size_t buffer_to_send =
component->get_wave_buffer_size() < 255 ?
component->get_wave_buffer_size() : 255;
1413 buf_append_printf(command,
sizeof(command), 0,
"addt %u,%u,%zu",
component->get_component_id(),
1414 component->get_wave_channel_id(), buffer_to_send);
void feed_wdt()
Feed the task watchdog.
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.
uint8_t get_spacing() const
Get current command spacing.
bool can_send(uint32_t now) const
Check if enough time has passed to send the next command.
void mark_sent(uint32_t now)
Record the transmit timestamp for the most recently sent command.
void set_variable_name(const std::string &variable_name, const std::string &variable_name_to_send="")
std::vector< NextionComponentBase * > touch_
std::vector< NextionComponentBase * > switchtype_
std::vector< NextionComponentBase * > binarysensortype_
StaticRingBuffer< NextionQueue *, 4 > waveform_queue_
Fixed-size ring buffer for waveform queue.
uint16_t max_q_age_ms_
Maximum age for queue items in ms.
bool send_command_(const std::string &command)
Manually send a raw command to the display and don't wait for an acknowledgement packet.
static constexpr size_t NEXTION_MODEL_MAX
Max observed ~18 chars from product numbering rules.
std::vector< NextionComponentBase * > textsensortype_
char firmware_version_[NEXTION_FW_MAX+1]
void purge_stale_queue_entries_()
Drop queue entries older than max_q_age_ms_.
CallbackManager< void(uint8_t)> page_callback_
void check_pending_waveform_()
CallbackManager< void(StringRef, int32_t)> custom_sensor_callback_
void set_wake_up_page(uint8_t wake_up_page=255)
Sets which page Nextion loads when exiting sleep mode.
void set_string_return_(const std::string &value)
NextionQueue * make_no_result_entry_(const std::string &variable_name)
void all_components_send_state_(bool force_update=false)
void set_nextion_sensor_state(int queue_type, const std::string &name, float state)
Set the nextion sensor state object.
char serial_number_[NEXTION_SERIAL_MAX+1]
void add_addt_command_to_queue(NextionComponentBase *component) override
uint32_t flash_size_
Flash size in bytes — plain integer, no string needed.
uint16_t max_commands_per_loop_
uint16_t startup_override_ms_
Timeout before forcing setup complete.
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::list< NextionQueue * > nextion_queue_
void set_auto_wake_on_touch(bool auto_wake_on_touch)
Sets if Nextion should auto-wake from sleep when touch press occurs.
bool remove_from_q_(bool report_empty=true)
std::vector< NextionComponentBase * > sensortype_
uint16_t touch_sleep_timeout_
bool add_no_result_to_queue_with_printf_(const std::string &variable_name, const char *format,...) __attribute__((format(printf
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_
std::string command_data_
optional< float > brightness_
CallbackManager< void()> wake_callback_
void release_queue_entry_(NextionQueue *nb)
struct esphome::nextion::Nextion::@151 connection_state_
Status flags for Nextion display state management.
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 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 void add_no_result_to_queue_with_command_(const std::string &variable_name, const std::string &command)
CallbackManager< void(StringRef, bool)> custom_binary_sensor_callback_
bool send_command(const char *command)
Manually send a raw command to the display.
void set_numeric_return_(int value)
CallbackManager< void()> sleep_callback_
void reset_(bool reset_nextion=true)
void update_all_components()
void process_pending_in_queue_()
Process any commands in the queue that are pending due to command spacing.
static constexpr size_t NEXTION_FW_MAX
'S' prefix + integer (e.g. 'S99' or 123)
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 deliver_queue_response_(const LogString *response_name, const NextionQueueResponse &resp)
Deliver a 0x70/0x71 response to the first query in the queue that was sent and expects a value,...
void set_nextion_text_state(const std::string &name, const std::string &state)
bool add_no_result_to_queue_with_ignore_sleep_printf_(const std::string &variable_name, const char *format,...) __attribute__((format(printf
CallbackManager< void()> buffer_overflow_callback_
void set_writer(const nextion_writer_t &writer)
char device_model_[NEXTION_MODEL_MAX+1]
CallbackManager< void(StringRef, StringRef)> custom_text_sensor_callback_
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.
void add_no_result_to_queue_with_set(NextionComponentBase *component, int32_t state_value) override
static constexpr size_t NEXTION_SERIAL_MAX
Consistently 16 hex chars across all documented examples.
CallbackManager< void(StringRef, bool)> custom_switch_callback_
void update_components_by_prefix(const std::string &prefix)
uint32_t tft_upload_watchdog_timeout_
WDT timeout in ms (0 = no adjustment)
void set_backlight_brightness(float brightness)
Set the brightness of the backlight.
NextionComponentBase * component
optional< std::array< uint8_t, N > > read_array()
void discard_available()
Read and drop every byte waiting in the receive buffer.
void write_str(const char *str)
bool read_byte(uint8_t *data)
void write_array(const uint8_t *data, size_t len)
const Component * component
ESPHOME_LOG_TAG(TAG, "nextion_binarysensor")
display::DisplayWriter< Nextion > nextion_writer_t
value[LAYOUT.day_index()]
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
size_t size_t const char va_start(args, fmt)
void HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.