[nextion] Add command queuing to prevent command loss when spacing is active (#9139)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
Edward Firmo 2025-06-20 08:38:40 +02:00 committed by GitHub
parent 4d0f8528d2
commit eb97781f68
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 90 additions and 0 deletions

View File

@ -325,8 +325,31 @@ void Nextion::loop() {
this->nextion_reports_is_setup_ = true;
}
}
#ifdef USE_NEXTION_COMMAND_SPACING
// Try to send any pending commands if spacing allows
this->process_pending_in_queue_();
#endif // USE_NEXTION_COMMAND_SPACING
}
#ifdef USE_NEXTION_COMMAND_SPACING
void Nextion::process_pending_in_queue_() {
if (this->nextion_queue_.empty() || !this->command_pacer_.can_send()) {
return;
}
// Check if first item in queue has a pending command
auto *front_item = this->nextion_queue_.front();
if (front_item && !front_item->pending_command.empty()) {
if (this->send_command_(front_item->pending_command)) {
// Command sent successfully, clear the pending command
front_item->pending_command.clear();
ESP_LOGVV(TAG, "Pending command sent: %s", front_item->component->get_variable_name().c_str());
}
}
}
#endif // USE_NEXTION_COMMAND_SPACING
bool Nextion::remove_from_q_(bool report_empty) {
if (this->nextion_queue_.empty()) {
if (report_empty) {
@ -1034,9 +1057,42 @@ void Nextion::add_no_result_to_queue_with_command_(const std::string &variable_n
if (this->send_command_(command)) {
this->add_no_result_to_queue_(variable_name);
#ifdef USE_NEXTION_COMMAND_SPACING
} else {
// Command blocked by spacing, add to queue WITH the command for retry
this->add_no_result_to_queue_with_pending_command_(variable_name, command);
#endif // USE_NEXTION_COMMAND_SPACING
}
}
#ifdef USE_NEXTION_COMMAND_SPACING
void Nextion::add_no_result_to_queue_with_pending_command_(const std::string &variable_name,
const std::string &command) {
#ifdef USE_NEXTION_MAX_QUEUE_SIZE
if (this->max_queue_size_ > 0 && this->nextion_queue_.size() >= this->max_queue_size_) {
ESP_LOGW(TAG, "Queue full (%zu), drop: %s", this->nextion_queue_.size(), variable_name.c_str());
return;
}
#endif
RAMAllocator<nextion::NextionQueue> allocator;
nextion::NextionQueue *nextion_queue = allocator.allocate(1);
if (nextion_queue == nullptr) {
ESP_LOGW(TAG, "Queue alloc failed");
return;
}
new (nextion_queue) nextion::NextionQueue();
nextion_queue->component = new nextion::NextionComponentBase;
nextion_queue->component->set_variable_name(variable_name);
nextion_queue->queue_time = millis();
nextion_queue->pending_command = command; // Store command for retry
this->nextion_queue_.push_back(nextion_queue);
ESP_LOGVV(TAG, "Queue with pending command: %s", variable_name.c_str());
}
#endif // USE_NEXTION_COMMAND_SPACING
bool Nextion::add_no_result_to_queue_with_ignore_sleep_printf_(const std::string &variable_name, const char *format,
...) {
if ((!this->is_setup() && !this->ignore_is_setup_))

View File

@ -1309,9 +1309,23 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
#ifdef USE_NEXTION_MAX_QUEUE_SIZE
size_t max_queue_size_{0};
#endif // USE_NEXTION_MAX_QUEUE_SIZE
#ifdef USE_NEXTION_COMMAND_SPACING
NextionCommandPacer command_pacer_{0};
/**
* @brief Process any commands in the queue that are pending due to command spacing
*
* This method checks if the first item in the nextion_queue_ has a pending command
* that was previously blocked by command spacing. If spacing now allows and a
* pending command exists, it attempts to send the command. Once successfully sent,
* the pending command is cleared and the queue item continues normal processing.
*
* Called from loop() to retry sending commands that were delayed by spacing.
*/
void process_pending_in_queue_();
#endif // USE_NEXTION_COMMAND_SPACING
std::deque<NextionQueue *> nextion_queue_;
std::deque<NextionQueue *> waveform_queue_;
uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag);
@ -1348,6 +1362,23 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
__attribute__((format(printf, 3, 4)));
void add_no_result_to_queue_with_command_(const std::string &variable_name, const std::string &command);
#ifdef USE_NEXTION_COMMAND_SPACING
/**
* @brief Add a command to the Nextion queue with a pending command for retry
*
* This method creates a queue entry for a command that was blocked by command spacing.
* The command string is stored in the queue item's pending_command field so it can
* be retried later when spacing allows. This ensures commands are not lost when
* sent too quickly.
*
* If the max_queue_size limit is configured and reached, the command will be dropped.
*
* @param variable_name Name of the variable or component associated with the command
* @param command The actual command string to be sent when spacing allows
*/
void add_no_result_to_queue_with_pending_command_(const std::string &variable_name, const std::string &command);
#endif // USE_NEXTION_COMMAND_SPACING
bool add_no_result_to_queue_with_printf_(const std::string &variable_name, const char *format, ...)
__attribute__((format(printf, 3, 4)));

View File

@ -25,6 +25,9 @@ class NextionQueue {
virtual ~NextionQueue() = default;
NextionComponentBase *component;
uint32_t queue_time = 0;
// Store command for retry if spacing blocked it
std::string pending_command; // Empty if command was sent successfully
};
class NextionComponentBase {