mirror of
https://github.com/esphome/esphome.git
synced 2025-07-28 14:16:40 +00:00
[nextion] Adds a command pacer with command_spacing
attribute (#7948)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
6f35d0ac88
commit
8bbc509b0b
@ -7,28 +7,29 @@ from esphome.const import CONF_BACKGROUND_COLOR, CONF_FOREGROUND_COLOR, CONF_VIS
|
|||||||
|
|
||||||
from . import CONF_NEXTION_ID, Nextion
|
from . import CONF_NEXTION_ID, Nextion
|
||||||
|
|
||||||
CONF_VARIABLE_NAME = "variable_name"
|
CONF_AUTO_WAKE_ON_TOUCH = "auto_wake_on_touch"
|
||||||
|
CONF_BACKGROUND_PRESSED_COLOR = "background_pressed_color"
|
||||||
|
CONF_COMMAND_SPACING = "command_spacing"
|
||||||
CONF_COMPONENT_NAME = "component_name"
|
CONF_COMPONENT_NAME = "component_name"
|
||||||
CONF_WAVE_CHANNEL_ID = "wave_channel_id"
|
CONF_EXIT_REPARSE_ON_START = "exit_reparse_on_start"
|
||||||
CONF_WAVE_MAX_VALUE = "wave_max_value"
|
CONF_FONT_ID = "font_id"
|
||||||
CONF_PRECISION = "precision"
|
CONF_FOREGROUND_PRESSED_COLOR = "foreground_pressed_color"
|
||||||
CONF_WAVEFORM_SEND_LAST_VALUE = "waveform_send_last_value"
|
CONF_ON_BUFFER_OVERFLOW = "on_buffer_overflow"
|
||||||
CONF_TFT_URL = "tft_url"
|
CONF_ON_PAGE = "on_page"
|
||||||
|
CONF_ON_SETUP = "on_setup"
|
||||||
CONF_ON_SLEEP = "on_sleep"
|
CONF_ON_SLEEP = "on_sleep"
|
||||||
CONF_ON_WAKE = "on_wake"
|
CONF_ON_WAKE = "on_wake"
|
||||||
CONF_ON_SETUP = "on_setup"
|
CONF_PRECISION = "precision"
|
||||||
CONF_ON_PAGE = "on_page"
|
|
||||||
CONF_ON_BUFFER_OVERFLOW = "on_buffer_overflow"
|
|
||||||
CONF_TOUCH_SLEEP_TIMEOUT = "touch_sleep_timeout"
|
|
||||||
CONF_WAKE_UP_PAGE = "wake_up_page"
|
|
||||||
CONF_START_UP_PAGE = "start_up_page"
|
|
||||||
CONF_AUTO_WAKE_ON_TOUCH = "auto_wake_on_touch"
|
|
||||||
CONF_WAVE_MAX_LENGTH = "wave_max_length"
|
|
||||||
CONF_BACKGROUND_PRESSED_COLOR = "background_pressed_color"
|
|
||||||
CONF_FOREGROUND_PRESSED_COLOR = "foreground_pressed_color"
|
|
||||||
CONF_FONT_ID = "font_id"
|
|
||||||
CONF_EXIT_REPARSE_ON_START = "exit_reparse_on_start"
|
|
||||||
CONF_SKIP_CONNECTION_HANDSHAKE = "skip_connection_handshake"
|
CONF_SKIP_CONNECTION_HANDSHAKE = "skip_connection_handshake"
|
||||||
|
CONF_START_UP_PAGE = "start_up_page"
|
||||||
|
CONF_TFT_URL = "tft_url"
|
||||||
|
CONF_TOUCH_SLEEP_TIMEOUT = "touch_sleep_timeout"
|
||||||
|
CONF_VARIABLE_NAME = "variable_name"
|
||||||
|
CONF_WAKE_UP_PAGE = "wake_up_page"
|
||||||
|
CONF_WAVE_CHANNEL_ID = "wave_channel_id"
|
||||||
|
CONF_WAVE_MAX_LENGTH = "wave_max_length"
|
||||||
|
CONF_WAVE_MAX_VALUE = "wave_max_value"
|
||||||
|
CONF_WAVEFORM_SEND_LAST_VALUE = "waveform_send_last_value"
|
||||||
|
|
||||||
|
|
||||||
def NextionName(value):
|
def NextionName(value):
|
||||||
|
@ -9,16 +9,17 @@ from esphome.const import (
|
|||||||
CONF_ON_TOUCH,
|
CONF_ON_TOUCH,
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE
|
from esphome.core import CORE, TimePeriod
|
||||||
|
|
||||||
from . import Nextion, nextion_ns, nextion_ref
|
from . import Nextion, nextion_ns, nextion_ref
|
||||||
from .base_component import (
|
from .base_component import (
|
||||||
CONF_AUTO_WAKE_ON_TOUCH,
|
CONF_AUTO_WAKE_ON_TOUCH,
|
||||||
|
CONF_COMMAND_SPACING,
|
||||||
CONF_EXIT_REPARSE_ON_START,
|
CONF_EXIT_REPARSE_ON_START,
|
||||||
CONF_ON_BUFFER_OVERFLOW,
|
CONF_ON_BUFFER_OVERFLOW,
|
||||||
CONF_ON_PAGE,
|
|
||||||
CONF_ON_SETUP,
|
CONF_ON_SETUP,
|
||||||
CONF_ON_SLEEP,
|
CONF_ON_SLEEP,
|
||||||
|
CONF_ON_PAGE,
|
||||||
CONF_ON_WAKE,
|
CONF_ON_WAKE,
|
||||||
CONF_SKIP_CONNECTION_HANDSHAKE,
|
CONF_SKIP_CONNECTION_HANDSHAKE,
|
||||||
CONF_START_UP_PAGE,
|
CONF_START_UP_PAGE,
|
||||||
@ -88,6 +89,10 @@ CONFIG_SCHEMA = (
|
|||||||
cv.Optional(CONF_AUTO_WAKE_ON_TOUCH, default=True): cv.boolean,
|
cv.Optional(CONF_AUTO_WAKE_ON_TOUCH, default=True): cv.boolean,
|
||||||
cv.Optional(CONF_EXIT_REPARSE_ON_START, default=False): cv.boolean,
|
cv.Optional(CONF_EXIT_REPARSE_ON_START, default=False): cv.boolean,
|
||||||
cv.Optional(CONF_SKIP_CONNECTION_HANDSHAKE, default=False): cv.boolean,
|
cv.Optional(CONF_SKIP_CONNECTION_HANDSHAKE, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_COMMAND_SPACING): cv.All(
|
||||||
|
cv.positive_time_period_milliseconds,
|
||||||
|
cv.Range(max=TimePeriod(milliseconds=255)),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.extend(cv.polling_component_schema("5s"))
|
.extend(cv.polling_component_schema("5s"))
|
||||||
@ -120,6 +125,10 @@ async def to_code(config):
|
|||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await uart.register_uart_device(var, config)
|
await uart.register_uart_device(var, config)
|
||||||
|
|
||||||
|
if command_spacing := config.get(CONF_COMMAND_SPACING):
|
||||||
|
cg.add_define("USE_NEXTION_COMMAND_SPACING")
|
||||||
|
cg.add(var.set_command_spacing(command_spacing.total_milliseconds))
|
||||||
|
|
||||||
if CONF_BRIGHTNESS in config:
|
if CONF_BRIGHTNESS in config:
|
||||||
cg.add(var.set_brightness(config[CONF_BRIGHTNESS]))
|
cg.add(var.set_brightness(config[CONF_BRIGHTNESS]))
|
||||||
|
|
||||||
|
@ -31,11 +31,22 @@ bool Nextion::send_command_(const std::string &command) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_NEXTION_COMMAND_SPACING
|
||||||
|
if (!this->ignore_is_setup_ && !this->command_pacer_.can_send()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif // USE_NEXTION_COMMAND_SPACING
|
||||||
|
|
||||||
ESP_LOGN(TAG, "send_command %s", command.c_str());
|
ESP_LOGN(TAG, "send_command %s", command.c_str());
|
||||||
|
|
||||||
this->write_str(command.c_str());
|
this->write_str(command.c_str());
|
||||||
const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF};
|
const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF};
|
||||||
this->write_array(to_send, sizeof(to_send));
|
this->write_array(to_send, sizeof(to_send));
|
||||||
|
|
||||||
|
#ifdef USE_NEXTION_COMMAND_SPACING
|
||||||
|
this->command_pacer_.mark_sent();
|
||||||
|
#endif // USE_NEXTION_COMMAND_SPACING
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +169,10 @@ void Nextion::dump_config() {
|
|||||||
if (this->start_up_page_ != -1) {
|
if (this->start_up_page_ != -1) {
|
||||||
ESP_LOGCONFIG(TAG, " Start Up Page: %" PRId16, this->start_up_page_);
|
ESP_LOGCONFIG(TAG, " Start Up Page: %" PRId16, this->start_up_page_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_NEXTION_COMMAND_SPACING
|
||||||
|
ESP_LOGCONFIG(TAG, " Command spacing: %" PRIu8 "ms", this->command_pacer_.get_spacing());
|
||||||
|
#endif // USE_NEXTION_COMMAND_SPACING
|
||||||
}
|
}
|
||||||
|
|
||||||
float Nextion::get_setup_priority() const { return setup_priority::DATA; }
|
float Nextion::get_setup_priority() const { return setup_priority::DATA; }
|
||||||
@ -312,6 +327,11 @@ bool Nextion::remove_from_q_(bool report_empty) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NextionQueue *nb = this->nextion_queue_.front();
|
NextionQueue *nb = this->nextion_queue_.front();
|
||||||
|
if (!nb || !nb->component) {
|
||||||
|
ESP_LOGE(TAG, "Invalid queue entry!");
|
||||||
|
this->nextion_queue_.pop_front();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
NextionComponentBase *component = nb->component;
|
NextionComponentBase *component = nb->component;
|
||||||
|
|
||||||
ESP_LOGN(TAG, "Removing %s from the queue", component->get_variable_name().c_str());
|
ESP_LOGN(TAG, "Removing %s from the queue", component->get_variable_name().c_str());
|
||||||
@ -341,6 +361,12 @@ void Nextion::process_nextion_commands_() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_NEXTION_COMMAND_SPACING
|
||||||
|
if (!this->command_pacer_.can_send()) {
|
||||||
|
return; // Will try again in next loop iteration
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t to_process_length = 0;
|
size_t to_process_length = 0;
|
||||||
std::string to_process;
|
std::string to_process;
|
||||||
|
|
||||||
@ -380,7 +406,9 @@ void Nextion::process_nextion_commands_() {
|
|||||||
this->setup_callback_.call();
|
this->setup_callback_.call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef USE_NEXTION_COMMAND_SPACING
|
||||||
|
this->command_pacer_.mark_sent(); // Here is where we should mark the command as sent
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case 0x02: // invalid Component ID or name was used
|
case 0x02: // invalid Component ID or name was used
|
||||||
ESP_LOGW(TAG, "Nextion reported component ID or name invalid!");
|
ESP_LOGW(TAG, "Nextion reported component ID or name invalid!");
|
||||||
@ -524,6 +552,11 @@ void Nextion::process_nextion_commands_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NextionQueue *nb = this->nextion_queue_.front();
|
NextionQueue *nb = this->nextion_queue_.front();
|
||||||
|
if (!nb || !nb->component) {
|
||||||
|
ESP_LOGE(TAG, "Invalid queue entry!");
|
||||||
|
this->nextion_queue_.pop_front();
|
||||||
|
return;
|
||||||
|
}
|
||||||
NextionComponentBase *component = nb->component;
|
NextionComponentBase *component = nb->component;
|
||||||
|
|
||||||
if (component->get_queue_type() != NextionQueueType::TEXT_SENSOR) {
|
if (component->get_queue_type() != NextionQueueType::TEXT_SENSOR) {
|
||||||
@ -564,6 +597,11 @@ void Nextion::process_nextion_commands_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NextionQueue *nb = this->nextion_queue_.front();
|
NextionQueue *nb = this->nextion_queue_.front();
|
||||||
|
if (!nb || !nb->component) {
|
||||||
|
ESP_LOGE(TAG, "Invalid queue entry!");
|
||||||
|
this->nextion_queue_.pop_front();
|
||||||
|
return;
|
||||||
|
}
|
||||||
NextionComponentBase *component = nb->component;
|
NextionComponentBase *component = nb->component;
|
||||||
|
|
||||||
if (component->get_queue_type() != NextionQueueType::SENSOR &&
|
if (component->get_queue_type() != NextionQueueType::SENSOR &&
|
||||||
|
@ -35,8 +35,54 @@ using nextion_writer_t = std::function<void(Nextion &)>;
|
|||||||
|
|
||||||
static const std::string COMMAND_DELIMITER{static_cast<char>(255), static_cast<char>(255), static_cast<char>(255)};
|
static const std::string COMMAND_DELIMITER{static_cast<char>(255), static_cast<char>(255), static_cast<char>(255)};
|
||||||
|
|
||||||
|
#ifdef USE_NEXTION_COMMAND_SPACING
|
||||||
|
class NextionCommandPacer {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Creates command pacer with initial spacing
|
||||||
|
* @param initial_spacing Initial time between commands in milliseconds
|
||||||
|
*/
|
||||||
|
explicit NextionCommandPacer(uint8_t initial_spacing = 0) : spacing_ms_(initial_spacing) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the minimum time between commands
|
||||||
|
* @param spacing_ms Spacing in milliseconds
|
||||||
|
*/
|
||||||
|
void set_spacing(uint8_t spacing_ms) { spacing_ms_ = spacing_ms; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get current command spacing
|
||||||
|
* @return Current spacing in milliseconds
|
||||||
|
*/
|
||||||
|
uint8_t get_spacing() const { return spacing_ms_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if enough time has passed to send next command
|
||||||
|
* @return true if enough time has passed since last command
|
||||||
|
*/
|
||||||
|
bool can_send() const { return (millis() - last_command_time_) >= spacing_ms_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mark a command as sent, updating the timing
|
||||||
|
*/
|
||||||
|
void mark_sent() { last_command_time_ = millis(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t spacing_ms_;
|
||||||
|
uint32_t last_command_time_{0};
|
||||||
|
};
|
||||||
|
#endif // USE_NEXTION_COMMAND_SPACING
|
||||||
|
|
||||||
class Nextion : public NextionBase, public PollingComponent, public uart::UARTDevice {
|
class Nextion : public NextionBase, public PollingComponent, public uart::UARTDevice {
|
||||||
public:
|
public:
|
||||||
|
#ifdef USE_NEXTION_COMMAND_SPACING
|
||||||
|
/**
|
||||||
|
* @brief Set the command spacing for the display
|
||||||
|
* @param spacing_ms Time in milliseconds between commands
|
||||||
|
*/
|
||||||
|
void set_command_spacing(uint32_t spacing_ms) { this->command_pacer_.set_spacing(spacing_ms); }
|
||||||
|
#endif // USE_NEXTION_COMMAND_SPACING
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the text of a component to a static string.
|
* Set the text of a component to a static string.
|
||||||
* @param component The component name.
|
* @param component The component name.
|
||||||
@ -1227,6 +1273,9 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
|||||||
bool is_connected() { return this->is_connected_; }
|
bool is_connected() { return this->is_connected_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
#ifdef USE_NEXTION_COMMAND_SPACING
|
||||||
|
NextionCommandPacer command_pacer_{0};
|
||||||
|
#endif // USE_NEXTION_COMMAND_SPACING
|
||||||
std::deque<NextionQueue *> nextion_queue_;
|
std::deque<NextionQueue *> nextion_queue_;
|
||||||
std::deque<NextionQueue *> waveform_queue_;
|
std::deque<NextionQueue *> waveform_queue_;
|
||||||
uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag);
|
uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag);
|
||||||
@ -1360,5 +1409,6 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
|||||||
uint32_t started_ms_ = 0;
|
uint32_t started_ms_ = 0;
|
||||||
bool sent_setup_commands_ = false;
|
bool sent_setup_commands_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace nextion
|
} // namespace nextion
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
@ -280,6 +280,7 @@ display:
|
|||||||
- platform: nextion
|
- platform: nextion
|
||||||
id: main_lcd
|
id: main_lcd
|
||||||
update_interval: 5s
|
update_interval: 5s
|
||||||
|
command_spacing: 5ms
|
||||||
on_sleep:
|
on_sleep:
|
||||||
then:
|
then:
|
||||||
lambda: 'ESP_LOGD("display","Display went to sleep");'
|
lambda: 'ESP_LOGD("display","Display went to sleep");'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user