[nextion] Expose custom protocol frames as automation triggers (#13248)

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
Edward Firmo
2026-04-08 00:13:58 +02:00
committed by GitHub
parent 5d31f4aeba
commit ee7b38504b
7 changed files with 164 additions and 1 deletions
+3
View File
@@ -1,5 +1,8 @@
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/string_ref.h"
#include "nextion.h"
namespace esphome::nextion {
@@ -19,6 +19,10 @@ CONF_MAX_COMMANDS_PER_LOOP = "max_commands_per_loop"
CONF_MAX_QUEUE_AGE = "max_queue_age"
CONF_MAX_QUEUE_SIZE = "max_queue_size"
CONF_ON_BUFFER_OVERFLOW = "on_buffer_overflow"
CONF_ON_CUSTOM_BINARY_SENSOR = "on_custom_binary_sensor"
CONF_ON_CUSTOM_SENSOR = "on_custom_sensor"
CONF_ON_CUSTOM_SWITCH = "on_custom_switch"
CONF_ON_CUSTOM_TEXT_SENSOR = "on_custom_text_sensor"
CONF_ON_PAGE = "on_page"
CONF_ON_SETUP = "on_setup"
CONF_ON_SLEEP = "on_sleep"
+41
View File
@@ -20,6 +20,10 @@ from .base_component import (
CONF_MAX_QUEUE_AGE,
CONF_MAX_QUEUE_SIZE,
CONF_ON_BUFFER_OVERFLOW,
CONF_ON_CUSTOM_BINARY_SENSOR,
CONF_ON_CUSTOM_SENSOR,
CONF_ON_CUSTOM_SWITCH,
CONF_ON_CUSTOM_TEXT_SENSOR,
CONF_ON_PAGE,
CONF_ON_SETUP,
CONF_ON_SLEEP,
@@ -88,6 +92,12 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_MAX_COMMANDS_PER_LOOP): cv.uint16_t,
cv.Optional(CONF_MAX_QUEUE_SIZE): cv.positive_int,
cv.Optional(CONF_ON_BUFFER_OVERFLOW): automation.validate_automation({}),
cv.Optional(CONF_ON_CUSTOM_BINARY_SENSOR): automation.validate_automation(
{}
),
cv.Optional(CONF_ON_CUSTOM_SENSOR): automation.validate_automation({}),
cv.Optional(CONF_ON_CUSTOM_SWITCH): automation.validate_automation({}),
cv.Optional(CONF_ON_CUSTOM_TEXT_SENSOR): automation.validate_automation({}),
cv.Optional(CONF_ON_PAGE): automation.validate_automation({}),
cv.Optional(CONF_ON_SETUP): automation.validate_automation({}),
cv.Optional(CONF_ON_SLEEP): automation.validate_automation({}),
@@ -163,8 +173,36 @@ _CALLBACK_AUTOMATIONS = (
automation.CallbackAutomation(
CONF_ON_BUFFER_OVERFLOW, "add_buffer_overflow_event_callback"
),
automation.CallbackAutomation(
CONF_ON_CUSTOM_BINARY_SENSOR,
"add_custom_binary_sensor_callback",
[(cg.StringRef, "key"), (cg.bool_, "value")],
),
automation.CallbackAutomation(
CONF_ON_CUSTOM_SENSOR,
"add_custom_sensor_callback",
[(cg.StringRef, "key"), (cg.int32, "value")],
),
automation.CallbackAutomation(
CONF_ON_CUSTOM_SWITCH,
"add_custom_switch_callback",
[(cg.StringRef, "key"), (cg.bool_, "value")],
),
automation.CallbackAutomation(
CONF_ON_CUSTOM_TEXT_SENSOR,
"add_custom_text_sensor_callback",
[(cg.StringRef, "key"), (cg.StringRef, "value")],
),
)
# Map custom trigger config keys to their conditional defines
_CUSTOM_TRIGGER_DEFINES = {
CONF_ON_CUSTOM_BINARY_SENSOR: "USE_NEXTION_TRIGGER_CUSTOM_BINARY_SENSOR",
CONF_ON_CUSTOM_SENSOR: "USE_NEXTION_TRIGGER_CUSTOM_SENSOR",
CONF_ON_CUSTOM_SWITCH: "USE_NEXTION_TRIGGER_CUSTOM_SWITCH",
CONF_ON_CUSTOM_TEXT_SENSOR: "USE_NEXTION_TRIGGER_CUSTOM_TEXT_SENSOR",
}
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
@@ -253,5 +291,8 @@ async def to_code(config):
cg.add(var.set_max_commands_per_loop(max_commands_per_loop))
await display.register_display(var, config)
for conf_key, define_name in _CUSTOM_TRIGGER_DEFINES.items():
if config.get(conf_key):
cg.add_define(define_name)
await automation.build_callback_automations(var, config, _CALLBACK_AUTOMATIONS)
+20
View File
@@ -1,8 +1,11 @@
#include "nextion.h"
#include <cinttypes>
#include "esphome/core/application.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include "esphome/core/string_ref.h"
#include "esphome/core/util.h"
namespace esphome::nextion {
@@ -715,6 +718,10 @@ void Nextion::process_nextion_commands_() {
ESP_LOGN(TAG, "Switch %s: %s", ONOFF(to_process[index] != 0), variable_name.c_str());
#ifdef USE_NEXTION_TRIGGER_CUSTOM_SWITCH
this->custom_switch_callback_.call(StringRef(variable_name), to_process[index] != 0);
#endif // USE_NEXTION_TRIGGER_CUSTOM_SWITCH
for (auto *switchtype : this->switchtype_) {
switchtype->process_bool(variable_name, to_process[index] != 0);
}
@@ -744,6 +751,10 @@ void Nextion::process_nextion_commands_() {
ESP_LOGN(TAG, "Sensor: %s=%d", variable_name.c_str(), value);
#ifdef USE_NEXTION_TRIGGER_CUSTOM_SENSOR
this->custom_sensor_callback_.call(StringRef(variable_name), value);
#endif // USE_NEXTION_TRIGGER_CUSTOM_SENSOR
for (auto *sensor : this->sensortype_) {
sensor->process_sensor(variable_name, value);
}
@@ -781,6 +792,11 @@ void Nextion::process_nextion_commands_() {
// nq->variable_name = variable_name;
// nq->state = text_value;
// this->textsensorq_.push_back(nq);
#ifdef USE_NEXTION_TRIGGER_CUSTOM_TEXT_SENSOR
this->custom_text_sensor_callback_.call(StringRef(variable_name), StringRef(text_value));
#endif // USE_NEXTION_TRIGGER_CUSTOM_TEXT_SENSOR
for (auto *textsensortype : this->textsensortype_) {
textsensortype->process_text(variable_name, text_value);
}
@@ -808,6 +824,10 @@ void Nextion::process_nextion_commands_() {
ESP_LOGN(TAG, "Binary sensor: %s=%s", variable_name.c_str(), ONOFF(to_process[index] != 0));
#ifdef USE_NEXTION_TRIGGER_CUSTOM_BINARY_SENSOR
this->custom_binary_sensor_callback_.call(StringRef(variable_name), to_process[index] != 0);
#endif // USE_NEXTION_TRIGGER_CUSTOM_BINARY_SENSOR
for (auto *binarysensortype : this->binarysensortype_) {
binarysensortype->process_bool(&variable_name[0], to_process[index] != 0);
}
+66
View File
@@ -7,6 +7,7 @@
#include "esphome/components/display/display_color_utils.h"
#include "esphome/components/uart/uart.h"
#include "esphome/core/defines.h"
#include "esphome/core/string_ref.h"
#include "esphome/core/time.h"
#ifdef USE_NEXTION_WAVEFORM
@@ -1183,6 +1184,59 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
this->buffer_overflow_callback_.add(std::forward<F>(callback));
}
// Callbacks for Nextion "custom protocol" frames (0x90..0x93)
#ifdef USE_NEXTION_TRIGGER_CUSTOM_BINARY_SENSOR
/** Add a callback to be notified when Nextion sends a custom binary sensor protocol frame (0x93).
*
* This callback is invoked when a Nextion custom binary sensor frame is received,
* providing the component name as the key and the decoded boolean value.
*
* @param callback The void(const StringRef &key, bool value) callback.
*/
template<typename F> void add_custom_binary_sensor_callback(F &&callback) {
this->custom_binary_sensor_callback_.add(std::forward<F>(callback));
}
#endif // USE_NEXTION_TRIGGER_CUSTOM_BINARY_SENSOR
#ifdef USE_NEXTION_TRIGGER_CUSTOM_SENSOR
/** Add a callback to be notified when Nextion sends a custom sensor protocol frame (0x91).
*
* This callback is invoked when a Nextion custom sensor frame is received,
* providing the component name as the key and the decoded integer value.
*
* @param callback The void(StringRef key, int32_t value) callback.
*/
template<typename F> void add_custom_sensor_callback(F &&callback) {
this->custom_sensor_callback_.add(std::forward<F>(callback));
}
#endif // USE_NEXTION_TRIGGER_CUSTOM_SENSOR
#ifdef USE_NEXTION_TRIGGER_CUSTOM_SWITCH
/** Add a callback to be notified when Nextion sends a custom switch protocol frame (0x90).
*
* This callback is invoked when a Nextion custom switch frame is received,
* providing the component name as the key and the decoded boolean value.
*
* @param callback The void(const StringRef &key, bool value) callback.
*/
template<typename F> void add_custom_switch_callback(F &&callback) {
this->custom_switch_callback_.add(std::forward<F>(callback));
}
#endif // USE_NEXTION_TRIGGER_CUSTOM_SWITCH
#ifdef USE_NEXTION_TRIGGER_CUSTOM_TEXT_SENSOR
/** Add a callback to be notified when Nextion sends a custom text sensor protocol frame (0x92).
*
* This callback is invoked when a Nextion custom text sensor frame is received,
* providing the component name as the key and the decoded text value.
*
* @param callback The void(const StringRef &key, const StringRef &value) callback.
*/
template<typename F> void add_custom_text_sensor_callback(F &&callback) {
this->custom_text_sensor_callback_.add(std::forward<F>(callback));
}
#endif // USE_NEXTION_TRIGGER_CUSTOM_TEXT_SENSOR
void update_all_components();
/**
@@ -1535,6 +1589,18 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
CallbackManager<void(uint8_t)> page_callback_{};
CallbackManager<void(uint8_t, uint8_t, bool)> touch_callback_{};
CallbackManager<void()> buffer_overflow_callback_{};
#ifdef USE_NEXTION_TRIGGER_CUSTOM_BINARY_SENSOR
CallbackManager<void(StringRef, bool)> custom_binary_sensor_callback_{};
#endif // USE_NEXTION_TRIGGER_CUSTOM_BINARY_SENSOR
#ifdef USE_NEXTION_TRIGGER_CUSTOM_SENSOR
CallbackManager<void(StringRef, int32_t)> custom_sensor_callback_{};
#endif // USE_NEXTION_TRIGGER_CUSTOM_SENSOR
#ifdef USE_NEXTION_TRIGGER_CUSTOM_SWITCH
CallbackManager<void(StringRef, bool)> custom_switch_callback_{};
#endif // USE_NEXTION_TRIGGER_CUSTOM_SWITCH
#ifdef USE_NEXTION_TRIGGER_CUSTOM_TEXT_SENSOR
CallbackManager<void(StringRef, StringRef)> custom_text_sensor_callback_{};
#endif // USE_NEXTION_TRIGGER_CUSTOM_TEXT_SENSOR
nextion_writer_t writer_;
optional<float> brightness_;
+4
View File
@@ -123,6 +123,10 @@
#define USE_NEXTION_MAX_COMMANDS_PER_LOOP
#define USE_NEXTION_MAX_QUEUE_SIZE
#define USE_NEXTION_TFT_UPLOAD
#define USE_NEXTION_TRIGGER_CUSTOM_BINARY_SENSOR
#define USE_NEXTION_TRIGGER_CUSTOM_SENSOR
#define USE_NEXTION_TRIGGER_CUSTOM_SWITCH
#define USE_NEXTION_TRIGGER_CUSTOM_TEXT_SENSOR
#define USE_NEXTION_WAVEFORM
#define USE_NUMBER
#define USE_OUTPUT
+26 -1
View File
@@ -286,6 +286,31 @@ display:
on_buffer_overflow:
then:
logger.log: "Nextion reported a buffer overflow!"
on_custom_text_sensor:
then:
- lambda: |-
// key: StringRef, value: StringRef
if (key == "csv") {
// parse value here, or forward to your own component
ESP_LOGD("nextion.csv", "Got CSV: %s", value.c_str());
}
on_custom_sensor:
then:
- lambda: |-
// key: StringRef, value: int32_t
if (key == "temperature_raw") {
ESP_LOGD("nextion.custom", "%s=%d", key.c_str(), value);
}
on_custom_binary_sensor:
then:
- lambda: |-
if (key == "btn1") {
ESP_LOGD("nextion.btn", "btn1=%s", ONOFF(value));
}
on_custom_switch:
then:
- lambda: |-
ESP_LOGD("nextion.sw", "%s=%s", key.c_str(), ONOFF(value));
on_page:
then:
lambda: 'ESP_LOGD("display","Display shows new page %u", x);'
@@ -304,8 +329,8 @@ display:
on_wake:
then:
lambda: 'ESP_LOGD("display","Display woke up");'
update_interval: 5s
start_up_page: 1
startup_override_ms: 10000ms # Wait 10s for display ready
touch_sleep_timeout: 3
update_interval: 5s
wake_up_page: 2