Refactor xpt2046 to be a touchscreen platform (#3793)

This commit is contained in:
NP v/d Spek 2022-10-10 23:10:22 +02:00 committed by GitHub
parent 786c8b6cfe
commit 3c2766448d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 248 additions and 334 deletions

View File

@ -258,4 +258,4 @@ esphome/components/xiaomi_lywsd03mmc/* @ahpohl
esphome/components/xiaomi_mhoc303/* @drug123
esphome/components/xiaomi_mhoc401/* @vevsvevs
esphome/components/xiaomi_rtcgq02lm/* @jesserockz
esphome/components/xpt2046/* @numo68
esphome/components/xpt2046/* @nielsnl68 @numo68

View File

@ -13,7 +13,7 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ["display"]
MULTI_CONF = True
Animation_ = display.display_ns.class_("Animation")
Animation_ = display.display_ns.class_("Animation", espImage.Image_)
ANIMATION_SCHEMA = cv.Schema(
{

View File

@ -1,129 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome import pins
from esphome.components import spi
from esphome.const import CONF_ID, CONF_ON_STATE, CONF_THRESHOLD, CONF_TRIGGER_ID
CODEOWNERS = ["@numo68"]
AUTO_LOAD = ["binary_sensor"]
DEPENDENCIES = ["spi"]
MULTI_CONF = True
CONF_REPORT_INTERVAL = "report_interval"
CONF_CALIBRATION_X_MIN = "calibration_x_min"
CONF_CALIBRATION_X_MAX = "calibration_x_max"
CONF_CALIBRATION_Y_MIN = "calibration_y_min"
CONF_CALIBRATION_Y_MAX = "calibration_y_max"
CONF_DIMENSION_X = "dimension_x"
CONF_DIMENSION_Y = "dimension_y"
CONF_SWAP_X_Y = "swap_x_y"
CONF_IRQ_PIN = "irq_pin"
xpt2046_ns = cg.esphome_ns.namespace("xpt2046")
CONF_XPT2046_ID = "xpt2046_id"
XPT2046Component = xpt2046_ns.class_(
"XPT2046Component", cg.PollingComponent, spi.SPIDevice
CONFIG_SCHEMA = cv.invalid(
"This component sould now be used as platform of the Touchscreen component."
)
XPT2046OnStateTrigger = xpt2046_ns.class_(
"XPT2046OnStateTrigger", automation.Trigger.template(cg.int_, cg.int_, cg.bool_)
)
def validate_xpt2046(config):
if (
abs(
cv.int_(config[CONF_CALIBRATION_X_MAX])
- cv.int_(config[CONF_CALIBRATION_X_MIN])
)
< 1000
):
raise cv.Invalid("Calibration X values difference < 1000")
if (
abs(
cv.int_(config[CONF_CALIBRATION_Y_MAX])
- cv.int_(config[CONF_CALIBRATION_Y_MIN])
)
< 1000
):
raise cv.Invalid("Calibration Y values difference < 1000")
return config
def report_interval(value):
if value == "never":
return 4294967295 # uint32_t max
return cv.positive_time_period_milliseconds(value)
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(XPT2046Component),
cv.Optional(CONF_IRQ_PIN): pins.gpio_input_pin_schema,
cv.Optional(CONF_CALIBRATION_X_MIN, default=0): cv.int_range(
min=0, max=4095
),
cv.Optional(CONF_CALIBRATION_X_MAX, default=4095): cv.int_range(
min=0, max=4095
),
cv.Optional(CONF_CALIBRATION_Y_MIN, default=0): cv.int_range(
min=0, max=4095
),
cv.Optional(CONF_CALIBRATION_Y_MAX, default=4095): cv.int_range(
min=0, max=4095
),
cv.Optional(CONF_DIMENSION_X, default=100): cv.positive_not_null_int,
cv.Optional(CONF_DIMENSION_Y, default=100): cv.positive_not_null_int,
cv.Optional(CONF_THRESHOLD, default=400): cv.int_range(min=0, max=4095),
cv.Optional(CONF_REPORT_INTERVAL, default="never"): report_interval,
cv.Optional(CONF_SWAP_X_Y, default=False): cv.boolean,
cv.Optional(CONF_ON_STATE): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
XPT2046OnStateTrigger
),
}
),
}
)
.extend(cv.polling_component_schema("50ms"))
.extend(spi.spi_device_schema()),
validate_xpt2046,
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await spi.register_spi_device(var, config)
cg.add(var.set_threshold(config[CONF_THRESHOLD]))
cg.add(var.set_report_interval(config[CONF_REPORT_INTERVAL]))
cg.add(var.set_dimensions(config[CONF_DIMENSION_X], config[CONF_DIMENSION_Y]))
cg.add(
var.set_calibration(
config[CONF_CALIBRATION_X_MIN],
config[CONF_CALIBRATION_X_MAX],
config[CONF_CALIBRATION_Y_MIN],
config[CONF_CALIBRATION_Y_MAX],
)
)
if CONF_SWAP_X_Y in config:
cg.add(var.set_swap_x_y(config[CONF_SWAP_X_Y]))
if CONF_IRQ_PIN in config:
pin = await cg.gpio_pin_expression(config[CONF_IRQ_PIN])
cg.add(var.set_irq_pin(pin))
for conf in config.get(CONF_ON_STATE, []):
await automation.build_automation(
var.get_on_state_trigger(),
[(cg.int_, "x"), (cg.int_, "y"), (cg.bool_, "touched")],
conf,
)

View File

@ -1,55 +1,3 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor
from . import (
xpt2046_ns,
XPT2046Component,
CONF_XPT2046_ID,
)
CONF_X_MIN = "x_min"
CONF_X_MAX = "x_max"
CONF_Y_MIN = "y_min"
CONF_Y_MAX = "y_max"
DEPENDENCIES = ["xpt2046"]
XPT2046Button = xpt2046_ns.class_("XPT2046Button", binary_sensor.BinarySensor)
def validate_xpt2046_button(config):
if cv.int_(config[CONF_X_MAX]) < cv.int_(config[CONF_X_MIN]) or cv.int_(
config[CONF_Y_MAX]
) < cv.int_(config[CONF_Y_MIN]):
raise cv.Invalid("x_max is less than x_min or y_max is less than y_min")
return config
CONFIG_SCHEMA = cv.All(
binary_sensor.binary_sensor_schema(XPT2046Button).extend(
{
cv.GenerateID(CONF_XPT2046_ID): cv.use_id(XPT2046Component),
cv.Required(CONF_X_MIN): cv.int_range(min=0, max=4095),
cv.Required(CONF_X_MAX): cv.int_range(min=0, max=4095),
cv.Required(CONF_Y_MIN): cv.int_range(min=0, max=4095),
cv.Required(CONF_Y_MAX): cv.int_range(min=0, max=4095),
}
),
validate_xpt2046_button,
)
async def to_code(config):
var = await binary_sensor.new_binary_sensor(config)
hub = await cg.get_variable(config[CONF_XPT2046_ID])
cg.add(
var.set_area(
config[CONF_X_MIN],
config[CONF_X_MAX],
config[CONF_Y_MIN],
config[CONF_Y_MAX],
)
)
cg.add(hub.register_button(var))
CONFIG_SCHEMA = cv.invalid("Rename this platform component to Touchscreen.")

View File

@ -0,0 +1,116 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import spi, touchscreen
from esphome.const import CONF_ID, CONF_THRESHOLD
CODEOWNERS = ["@numo68", "@nielsnl68"]
DEPENDENCIES = ["spi"]
XPT2046_ns = cg.esphome_ns.namespace("xpt2046")
XPT2046Component = XPT2046_ns.class_(
"XPT2046Component", touchscreen.Touchscreen, cg.PollingComponent, spi.SPIDevice
)
CONF_INTERRUPT_PIN = "interrupt_pin"
CONF_REPORT_INTERVAL = "report_interval"
CONF_CALIBRATION_X_MIN = "calibration_x_min"
CONF_CALIBRATION_X_MAX = "calibration_x_max"
CONF_CALIBRATION_Y_MIN = "calibration_y_min"
CONF_CALIBRATION_Y_MAX = "calibration_y_max"
CONF_SWAP_X_Y = "swap_x_y"
# obsolete Keys
CONF_DIMENSION_X = "dimension_x"
CONF_DIMENSION_Y = "dimension_y"
CONF_IRQ_PIN = "irq_pin"
def validate_xpt2046(config):
if (
abs(
cv.int_(config[CONF_CALIBRATION_X_MAX])
- cv.int_(config[CONF_CALIBRATION_X_MIN])
)
< 1000
):
raise cv.Invalid("Calibration X values difference < 1000")
if (
abs(
cv.int_(config[CONF_CALIBRATION_Y_MAX])
- cv.int_(config[CONF_CALIBRATION_Y_MIN])
)
< 1000
):
raise cv.Invalid("Calibration Y values difference < 1000")
return config
def report_interval(value):
if value == "never":
return 4294967295 # uint32_t max
return cv.positive_time_period_milliseconds(value)
CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(XPT2046Component),
cv.Optional(CONF_INTERRUPT_PIN): cv.All(
pins.internal_gpio_input_pin_schema
),
cv.Optional(CONF_CALIBRATION_X_MIN, default=0): cv.int_range(
min=0, max=4095
),
cv.Optional(CONF_CALIBRATION_X_MAX, default=4095): cv.int_range(
min=0, max=4095
),
cv.Optional(CONF_CALIBRATION_Y_MIN, default=0): cv.int_range(
min=0, max=4095
),
cv.Optional(CONF_CALIBRATION_Y_MAX, default=4095): cv.int_range(
min=0, max=4095
),
cv.Optional(CONF_THRESHOLD, default=400): cv.int_range(min=0, max=4095),
cv.Optional(CONF_REPORT_INTERVAL, default="never"): report_interval,
cv.Optional(CONF_SWAP_X_Y, default=False): cv.boolean,
# obsolete Keys
cv.Optional(CONF_IRQ_PIN): cv.invalid("Rename IRQ_PIN to INTERUPT_PIN"),
cv.Optional(CONF_DIMENSION_X): cv.invalid(
"This key is now obsolete, please remove it"
),
cv.Optional(CONF_DIMENSION_Y): cv.invalid(
"This key is now obsolete, please remove it"
),
},
)
.extend(cv.polling_component_schema("50ms"))
.extend(spi.spi_device_schema()),
).add_extra(validate_xpt2046)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await spi.register_spi_device(var, config)
await touchscreen.register_touchscreen(var, config)
cg.add(var.set_threshold(config[CONF_THRESHOLD]))
cg.add(var.set_report_interval(config[CONF_REPORT_INTERVAL]))
cg.add(var.set_swap_x_y(config[CONF_SWAP_X_Y]))
cg.add(
var.set_calibration(
config[CONF_CALIBRATION_X_MIN],
config[CONF_CALIBRATION_X_MAX],
config[CONF_CALIBRATION_Y_MIN],
config[CONF_CALIBRATION_Y_MAX],
)
)
if CONF_INTERRUPT_PIN in config:
pin = await cg.gpio_pin_expression(config[CONF_INTERRUPT_PIN])
cg.add(var.set_irq_pin(pin))

View File

@ -9,31 +9,38 @@ namespace xpt2046 {
static const char *const TAG = "xpt2046";
void XPT2046TouchscreenStore::gpio_intr(XPT2046TouchscreenStore *store) { store->touch = true; }
void XPT2046Component::setup() {
if (this->irq_pin_ != nullptr) {
// The pin reports a touch with a falling edge. Unfortunately the pin goes also changes state
// while the channels are read and wiring it as an interrupt is not straightforward and would
// need careful masking. A GPIO poll is cheap so we'll just use that.
this->irq_pin_->setup(); // INPUT
this->irq_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
this->irq_pin_->setup();
this->store_.pin = this->irq_pin_->to_isr();
this->irq_pin_->attach_interrupt(XPT2046TouchscreenStore::gpio_intr, &this->store_, gpio::INTERRUPT_FALLING_EDGE);
}
spi_setup();
read_adc_(0xD0); // ADC powerdown, enable PENIRQ pin
}
void XPT2046Component::loop() {
if (this->irq_pin_ != nullptr) {
// Force immediate update if a falling edge (= touched is seen) Ignore if still active
// (that would mean that we missed the release because of a too long update interval)
bool val = this->irq_pin_->digital_read();
if (!val && this->last_irq_ && !this->touched) {
ESP_LOGD(TAG, "Falling penirq edge, forcing update");
update();
}
this->last_irq_ = val;
}
if ((this->irq_pin_ == nullptr) || (!this->store_.touch))
return;
this->store_.touch = false;
check_touch_();
}
void XPT2046Component::update() {
if (this->irq_pin_ == nullptr)
check_touch_();
}
void XPT2046Component::check_touch_() {
int16_t data[6];
bool touch = false;
uint32_t now = millis();
@ -42,13 +49,13 @@ void XPT2046Component::update() {
// In case the penirq pin is present only do the SPI transaction if it reports a touch (is low).
// The touch has to be also confirmed with checking the pressure over threshold
if (this->irq_pin_ == nullptr || !this->irq_pin_->digital_read()) {
if ((this->irq_pin_ == nullptr) || !this->irq_pin_->digital_read()) {
enable();
int16_t z1 = read_adc_(0xB1 /* Z1 */);
int16_t z2 = read_adc_(0xC1 /* Z2 */);
int16_t touch_pressure_1 = read_adc_(0xB1 /* touch_pressure_1 */);
int16_t touch_pressure_2 = read_adc_(0xC1 /* touch_pressure_2 */);
this->z_raw = z1 + 4095 - z2;
this->z_raw = touch_pressure_1 + 4095 - touch_pressure_2;
touch = (this->z_raw >= this->threshold_);
if (touch) {
@ -63,64 +70,73 @@ void XPT2046Component::update() {
data[5] = read_adc_(0x90 /* Y */); // Last Y touch power down
disable();
}
if (touch) {
this->x_raw = best_two_avg(data[0], data[2], data[4]);
this->y_raw = best_two_avg(data[1], data[3], data[5]);
} else {
this->x_raw = this->y_raw = 0;
}
if (touch) {
this->x_raw = best_two_avg(data[0], data[2], data[4]);
this->y_raw = best_two_avg(data[1], data[3], data[5]);
ESP_LOGV(TAG, "Update [x, y] = [%d, %d], z = %d%s", this->x_raw, this->y_raw, this->z_raw, (touch ? " touched" : ""));
ESP_LOGVV(TAG, "Update [x, y] = [%d, %d], z = %d", this->x_raw, this->y_raw, this->z_raw);
if (touch) {
// Normalize raw data according to calibration min and max
TouchPoint touchpoint;
int16_t x_val = normalize(this->x_raw, this->x_raw_min_, this->x_raw_max_);
int16_t y_val = normalize(this->y_raw, this->y_raw_min_, this->y_raw_max_);
touchpoint.x = normalize(this->x_raw, this->x_raw_min_, this->x_raw_max_);
touchpoint.y = normalize(this->y_raw, this->y_raw_min_, this->y_raw_max_);
if (this->swap_x_y_) {
std::swap(x_val, y_val);
}
if (this->swap_x_y_) {
std::swap(touchpoint.x, touchpoint.y);
}
if (this->invert_x_) {
x_val = 0x7fff - x_val;
}
if (this->invert_x_) {
touchpoint.x = 0xfff - touchpoint.x;
}
if (this->invert_y_) {
y_val = 0x7fff - y_val;
}
if (this->invert_y_) {
touchpoint.y = 0xfff - touchpoint.y;
}
x_val = (int16_t)((int) x_val * this->x_dim_ / 0x7fff);
y_val = (int16_t)((int) y_val * this->y_dim_ / 0x7fff);
switch (static_cast<TouchRotation>(this->display_->get_rotation())) {
case ROTATE_0_DEGREES:
break;
case ROTATE_90_DEGREES:
std::swap(touchpoint.x, touchpoint.y);
touchpoint.y = 0xfff - touchpoint.y;
break;
case ROTATE_180_DEGREES:
touchpoint.x = 0xfff - touchpoint.x;
touchpoint.y = 0xfff - touchpoint.y;
break;
case ROTATE_270_DEGREES:
std::swap(touchpoint.x, touchpoint.y);
touchpoint.x = 0xfff - touchpoint.x;
break;
}
if (!this->touched || (now - this->last_pos_ms_) >= this->report_millis_) {
ESP_LOGD(TAG, "Raw [x, y] = [%d, %d], transformed = [%d, %d]", this->x_raw, this->y_raw, x_val, y_val);
touchpoint.x = (int16_t)((int) touchpoint.x * this->display_->get_width() / 0xfff);
touchpoint.y = (int16_t)((int) touchpoint.y * this->display_->get_height() / 0xfff);
this->x = x_val;
this->y = y_val;
this->touched = true;
this->last_pos_ms_ = now;
if (!this->touched || (now - this->last_pos_ms_) >= this->report_millis_) {
ESP_LOGV(TAG, "Touching at [%03X, %03X] => [%3d, %3d]", this->x_raw, this->y_raw, touchpoint.x, touchpoint.y);
this->on_state_trigger_->process(this->x, this->y, true);
for (auto *button : this->buttons_)
button->touch(this->x, this->y);
}
} else {
if (this->touched) {
ESP_LOGD(TAG, "Released [%d, %d]", this->x, this->y);
this->defer([this, touchpoint]() { this->send_touch_(touchpoint); });
this->touched = false;
this->on_state_trigger_->process(this->x, this->y, false);
for (auto *button : this->buttons_)
button->release();
this->x = touchpoint.x;
this->y = touchpoint.y;
this->touched = true;
this->last_pos_ms_ = now;
}
} else {
this->x_raw = this->y_raw = 0;
if (this->touched) {
ESP_LOGV(TAG, "Released [%d, %d]", this->x, this->y);
this->touched = false;
for (auto *listener : this->touch_listeners_)
listener->release();
}
}
}
}
void XPT2046Component::set_calibration(int16_t x_min, int16_t x_max, int16_t y_min, int16_t y_max) {
void XPT2046Component::set_calibration(int16_t x_min, int16_t x_max, int16_t y_min, int16_t y_max) { // NOLINT
this->x_raw_min_ = std::min(x_min, x_max);
this->x_raw_max_ = std::max(x_min, x_max);
this->y_raw_min_ = std::min(y_min, y_max);
@ -137,11 +153,11 @@ void XPT2046Component::dump_config() {
ESP_LOGCONFIG(TAG, " X max: %d", this->x_raw_max_);
ESP_LOGCONFIG(TAG, " Y min: %d", this->y_raw_min_);
ESP_LOGCONFIG(TAG, " Y max: %d", this->y_raw_max_);
ESP_LOGCONFIG(TAG, " X dim: %d", this->x_dim_);
ESP_LOGCONFIG(TAG, " Y dim: %d", this->y_dim_);
if (this->swap_x_y_) {
ESP_LOGCONFIG(TAG, " Swap X/Y");
}
ESP_LOGCONFIG(TAG, " Swap X/Y: %s", YESNO(this->swap_x_y_));
ESP_LOGCONFIG(TAG, " Invert X: %s", YESNO(this->invert_x_));
ESP_LOGCONFIG(TAG, " Invert Y: %s", YESNO(this->invert_y_));
ESP_LOGCONFIG(TAG, " threshold: %d", this->threshold_);
ESP_LOGCONFIG(TAG, " Report interval: %u", this->report_millis_);
@ -150,8 +166,8 @@ void XPT2046Component::dump_config() {
float XPT2046Component::get_setup_priority() const { return setup_priority::DATA; }
int16_t XPT2046Component::best_two_avg(int16_t x, int16_t y, int16_t z) {
int16_t da, db, dc;
int16_t XPT2046Component::best_two_avg(int16_t x, int16_t y, int16_t z) { // NOLINT
int16_t da, db, dc; // NOLINT
int16_t reta = 0;
da = (x > y) ? x - y : y - x;
@ -175,15 +191,15 @@ int16_t XPT2046Component::normalize(int16_t val, int16_t min_val, int16_t max_va
if (val <= min_val) {
ret = 0;
} else if (val >= max_val) {
ret = 0x7fff;
ret = 0xfff;
} else {
ret = (int16_t)((int) 0x7fff * (val - min_val) / (max_val - min_val));
ret = (int16_t)((int) 0xfff * (val - min_val) / (max_val - min_val));
}
return ret;
}
int16_t XPT2046Component::read_adc_(uint8_t ctrl) {
int16_t XPT2046Component::read_adc_(uint8_t ctrl) { // NOLINT
uint8_t data[2];
write_byte(ctrl);
@ -193,25 +209,5 @@ int16_t XPT2046Component::read_adc_(uint8_t ctrl) {
return ((data[0] << 8) | data[1]) >> 3;
}
void XPT2046OnStateTrigger::process(int x, int y, bool touched) { this->trigger(x, y, touched); }
void XPT2046Button::touch(int16_t x, int16_t y) {
bool touched = (x >= this->x_min_ && x <= this->x_max_ && y >= this->y_min_ && y <= this->y_max_);
if (touched) {
this->publish_state(true);
this->state_ = true;
} else {
release();
}
}
void XPT2046Button::release() {
if (this->state_) {
this->publish_state(false);
this->state_ = false;
}
}
} // namespace xpt2046
} // namespace esphome

View File

@ -3,42 +3,31 @@
#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "esphome/components/spi/spi.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/touchscreen/touchscreen.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace xpt2046 {
class XPT2046OnStateTrigger : public Trigger<int, int, bool> {
public:
void process(int x, int y, bool touched);
using namespace touchscreen;
struct XPT2046TouchscreenStore {
volatile bool touch;
ISRInternalGPIOPin pin;
static void gpio_intr(XPT2046TouchscreenStore *store);
};
class XPT2046Button : public binary_sensor::BinarySensor {
public:
/// Set the touch screen area where the button will detect the touch.
void set_area(int16_t x_min, int16_t x_max, int16_t y_min, int16_t y_max) {
this->x_min_ = x_min;
this->x_max_ = x_max;
this->y_min_ = y_min;
this->y_max_ = y_max;
}
void touch(int16_t x, int16_t y);
void release();
protected:
int16_t x_min_, x_max_, y_min_, y_max_;
bool state_{false};
};
class XPT2046Component : public PollingComponent,
class XPT2046Component : public Touchscreen,
public PollingComponent,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_2MHZ> {
public:
/// Set the logical touch screen dimensions.
void set_dimensions(int16_t x, int16_t y) {
this->x_dim_ = x;
this->y_dim_ = y;
this->display_width_ = x;
this->display_height_ = y;
}
/// Set the coordinates for the touch screen edges.
void set_calibration(int16_t x_min, int16_t x_max, int16_t y_min, int16_t y_max);
@ -47,14 +36,12 @@ class XPT2046Component : public PollingComponent,
/// Set the interval to report the touch point perodically.
void set_report_interval(uint32_t interval) { this->report_millis_ = interval; }
uint32_t get_report_interval() { return this->report_millis_; }
/// Set the threshold for the touch detection.
void set_threshold(int16_t threshold) { this->threshold_ = threshold; }
/// Set the pin used to detect the touch.
void set_irq_pin(GPIOPin *pin) { this->irq_pin_ = pin; }
/// Get an access to the on_state automation trigger
XPT2046OnStateTrigger *get_on_state_trigger() const { return this->on_state_trigger_; }
/// Register a virtual button to the component.
void register_button(XPT2046Button *button) { this->buttons_.push_back(button); }
void set_irq_pin(InternalGPIOPin *pin) { this->irq_pin_ = pin; }
void setup() override;
void dump_config() override;
@ -103,21 +90,19 @@ class XPT2046Component : public PollingComponent,
static int16_t normalize(int16_t val, int16_t min_val, int16_t max_val);
int16_t read_adc_(uint8_t ctrl);
void check_touch_();
int16_t threshold_;
int16_t x_raw_min_, x_raw_max_, y_raw_min_, y_raw_max_;
int16_t x_dim_, y_dim_;
bool invert_x_, invert_y_;
bool swap_x_y_;
uint32_t report_millis_;
uint32_t last_pos_ms_{0};
GPIOPin *irq_pin_{nullptr};
bool last_irq_{true};
XPT2046OnStateTrigger *on_state_trigger_{new XPT2046OnStateTrigger()};
std::vector<XPT2046Button *> buttons_{};
InternalGPIOPin *irq_pin_{nullptr};
XPT2046TouchscreenStore store_;
};
} // namespace xpt2046

View File

@ -348,15 +348,16 @@ binary_sensor:
on_state:
then:
- lambda: 'ESP_LOGI("ar1:", "%d", x);'
- platform: xpt2046
xpt2046_id: xpt_touchscreen
- platform: touchscreen
touchscreen_id: xpt_touchscreen
id: touch_key0
x_min: 80
x_max: 160
y_min: 106
y_max: 212
on_state:
- lambda: 'ESP_LOGI("main", "key0: %s", (x ? "touch" : "release"));'
on_press:
- logger.log: Touched
- platform: gpio
name: GPIO SX1509 test
pin:
@ -598,33 +599,6 @@ external_components:
components: [bh1750]
- source: ../esphome/components
components: [sntp]
xpt2046:
id: xpt_touchscreen
cs_pin: 17
irq_pin: 16
update_interval: 50ms
report_interval: 1s
threshold: 400
dimension_x: 240
dimension_y: 320
calibration_x_min: 3860
calibration_x_max: 280
calibration_y_min: 340
calibration_y_max: 3860
swap_x_y: false
on_state:
# yamllint disable rule:line-length
- lambda: |-
ESP_LOGI("main", "args x=%d, y=%d, touched=%s", x, y, (touched ? "touch" : "release"));
ESP_LOGI("main", "member x=%d, y=%d, touched=%d, x_raw=%d, y_raw=%d, z_raw=%d",
id(xpt_touchscreen).x,
id(xpt_touchscreen).y,
(int) id(xpt_touchscreen).touched,
id(xpt_touchscreen).x_raw,
id(xpt_touchscreen).y_raw,
id(xpt_touchscreen).z_raw
);
# yamllint enable rule:line-length
button:
- platform: restart
@ -648,6 +622,25 @@ touchscreen:
format: Touch at (%d, %d)
args: [touch.x, touch.y]
- platform: xpt2046
id: xpt_touchscreen
cs_pin: 17
interrupt_pin: 16
display: inkplate_display
update_interval: 50ms
report_interval: 1s
threshold: 400
calibration_x_min: 3860
calibration_x_max: 280
calibration_y_min: 340
calibration_y_max: 3860
swap_x_y: false
on_touch:
- logger.log:
format: Touch at (%d, %d)
args: [touch.x, touch.y]
- platform: lilygo_t5_47
id: lilygo_touchscreen
interrupt_pin: GPIO36