mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 00:18:11 +01:00
Touchscreen component and driver fixes (#5997)
* Introduce calibration settings for all touchscreen drivers. this will override the common values. The x,y coordinates only calculated when the right calibrations are set. * resolve issues reported by CI * remove unneeded spaces and newlines * Forgot to remove some obsolete code * remove get_setup_priority from xpt2046 * remove media_player changes. * media_player: removed to much, * Update suggestions * referd back the `get_setup_priority` removal so it can be moved into a othe PR. * tt21100: restore init read * fix spacing * load native display dimensions instead of using internal dimensons. and load it only onse on setup * moved `update_touches()` to protexted section * adding Clydes PR#6049 * add multitouch test script * Update all Touchscreen replacing `get_*_internal` to `get_native_*` * fixed some CI recomendations * couple of fixes * make sure the display is running before touchscreen is setup * fix clang * revert back last changes * xpt2046: change log level for testing * logging information * add test file * fix polling issue with the for example the xpt2046 * fixed some CI issues * fixed some CI issues * restore mirror parameter discriptions * same for the swap_xy * same for the transform * remove the above const from const.py * and put the above const bacl const.py * Merge branch 'nvds-touchscreen-fix1' of https://github.com/nielsnl68/esphome into nvds-touchscreen-fix1 * and put the above const bacl const.py * [tt21100] making interupt pin optional * [tt21100] making interupt pin optional (now complete) * update the display part based on @clyde' s changes. * fix issue with ft6x36 touvhscreen * reverd back touch check. add comment * add some extra checks to the ft6x36 * add an other log and a typo fixed * okay an other fix. * add an extra check like others do and fix data type * [ft6336] fix update race when ts is touched. * [touchscreen] update some log's with a verbose level. * fix clang issues * fix the clang issues * fix the clang issues * fix virtual issue. * fix the clang issues * an other clang issues * remove anti-aliased fonts support. It does not belong here. * remove anti-aliased fonts support. It does not belong here. * rename test script * Moving the test files to there right location. * rename the test files * clean up the code * add a new line * clang fixings * clang fixings * remove comment * remove comment * Update esphome/components/touchscreen/__init__.py Co-authored-by: guillempages <guillempages@users.noreply.github.com> * Update esphome/components/touchscreen/__init__.py Co-authored-by: guillempages <guillempages@users.noreply.github.com> * Update esphome/components/touchscreen/__init__.py Co-authored-by: guillempages <guillempages@users.noreply.github.com> * Update esphome/components/touchscreen/touchscreen.cpp * Update esphome/components/touchscreen/touchscreen.cpp * [ft63x6] add threshold --------- Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Co-authored-by: guillempages <guillempages@users.noreply.github.com>
This commit is contained in:
parent
c43c9ad1c5
commit
5393a09872
21 changed files with 422 additions and 157 deletions
|
@ -175,10 +175,15 @@ class Display : public PollingComponent {
|
|||
/// Clear the entire screen by filling it with OFF pixels.
|
||||
void clear();
|
||||
|
||||
/// Get the width of the image in pixels with rotation applied.
|
||||
virtual int get_width() = 0;
|
||||
/// Get the height of the image in pixels with rotation applied.
|
||||
virtual int get_height() = 0;
|
||||
/// Get the calculated width of the display in pixels with rotation applied.
|
||||
virtual int get_width() { return this->get_width_internal(); }
|
||||
/// Get the calculated height of the display in pixels with rotation applied.
|
||||
virtual int get_height() { return this->get_height_internal(); }
|
||||
|
||||
/// Get the native (original) width of the display in pixels.
|
||||
int get_native_width() { return this->get_width_internal(); }
|
||||
/// Get the native (original) height of the display in pixels.
|
||||
int get_native_height() { return this->get_height_internal(); }
|
||||
|
||||
/// Set a single pixel at the specified coordinates to default color.
|
||||
inline void draw_pixel_at(int x, int y) { this->draw_pixel_at(x, y, COLOR_ON); }
|
||||
|
@ -538,6 +543,9 @@ class Display : public PollingComponent {
|
|||
void do_update_();
|
||||
void clear_clipping_();
|
||||
|
||||
virtual int get_height_internal() = 0;
|
||||
virtual int get_width_internal() = 0;
|
||||
|
||||
/**
|
||||
* This method fills a triangle using only integer variables by using a
|
||||
* modified bresenham algorithm.
|
||||
|
|
|
@ -22,9 +22,6 @@ class DisplayBuffer : public Display {
|
|||
/// Set a single pixel at the specified coordinates to the given color.
|
||||
void draw_pixel_at(int x, int y, Color color) override;
|
||||
|
||||
virtual int get_height_internal() = 0;
|
||||
virtual int get_width_internal() = 0;
|
||||
|
||||
protected:
|
||||
virtual void draw_absolute_pixel_internal(int x, int y, Color color) = 0;
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ void EKTF2232Touchscreen::setup() {
|
|||
|
||||
// Get touch resolution
|
||||
uint8_t received[4];
|
||||
if (this->x_raw_max_ == this->x_raw_min_) {
|
||||
this->write(GET_X_RES, 4);
|
||||
if (this->read(received, 4)) {
|
||||
ESP_LOGE(TAG, "Failed to read X resolution!");
|
||||
|
@ -42,7 +43,9 @@ void EKTF2232Touchscreen::setup() {
|
|||
return;
|
||||
}
|
||||
this->x_raw_max_ = ((received[2])) | ((received[3] & 0xf0) << 4);
|
||||
}
|
||||
|
||||
if (this->y_raw_max_ == this->y_raw_min_) {
|
||||
this->write(GET_Y_RES, 4);
|
||||
if (this->read(received, 4)) {
|
||||
ESP_LOGE(TAG, "Failed to read Y resolution!");
|
||||
|
@ -51,7 +54,7 @@ void EKTF2232Touchscreen::setup() {
|
|||
return;
|
||||
}
|
||||
this->y_raw_max_ = ((received[2])) | ((received[3] & 0xf0) << 4);
|
||||
|
||||
}
|
||||
this->set_power_state(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,14 @@ class FT5x06Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice
|
|||
return;
|
||||
}
|
||||
// reading the chip registers to get max x/y does not seem to work.
|
||||
this->x_raw_max_ = this->display_->get_width();
|
||||
this->y_raw_max_ = this->display_->get_height();
|
||||
if (this->display_ != nullptr) {
|
||||
if (this->x_raw_max_ == this->x_raw_min_) {
|
||||
this->x_raw_max_ = this->display_->get_native_width();
|
||||
}
|
||||
if (this->y_raw_max_ == this->y_raw_min_) {
|
||||
this->x_raw_max_ = this->display_->get_native_height();
|
||||
}
|
||||
}
|
||||
esph_log_config(TAG, "FT5x06 Touchscreen setup complete");
|
||||
}
|
||||
|
||||
|
|
|
@ -12,21 +12,23 @@
|
|||
// Reference: https://focuslcds.com/content/FT6236.pdf
|
||||
namespace esphome {
|
||||
namespace ft63x6 {
|
||||
static const uint8_t FT6X36_ADDR_DEVICE_MODE = 0x00;
|
||||
|
||||
static const uint8_t FT63X6_ADDR_TD_STATUS = 0x02;
|
||||
static const uint8_t FT63X6_ADDR_TOUCH1_STATE = 0x03;
|
||||
static const uint8_t FT63X6_ADDR_TOUCH1_X = 0x03;
|
||||
static const uint8_t FT63X6_ADDR_TOUCH1_ID = 0x05;
|
||||
static const uint8_t FT63X6_ADDR_TOUCH1_Y = 0x05;
|
||||
static const uint8_t FT63X6_ADDR_TOUCH1_WEIGHT = 0x07;
|
||||
static const uint8_t FT63X6_ADDR_TOUCH1_MISC = 0x08;
|
||||
static const uint8_t FT6X36_ADDR_THRESHHOLD = 0x80;
|
||||
static const uint8_t FT6X36_ADDR_TOUCHRATE_ACTIVE = 0x88;
|
||||
static const uint8_t FT63X6_ADDR_CHIP_ID = 0xA3;
|
||||
|
||||
static const uint8_t FT63X6_ADDR_TOUCH2_STATE = 0x09;
|
||||
static const uint8_t FT63X6_ADDR_TOUCH2_X = 0x09;
|
||||
static const uint8_t FT63X6_ADDR_TOUCH2_ID = 0x0B;
|
||||
static const uint8_t FT63X6_ADDR_TOUCH2_Y = 0x0B;
|
||||
|
||||
static const char *const TAG = "FT63X6Touchscreen";
|
||||
static const char *const TAG = "FT63X6";
|
||||
|
||||
void FT63X6Touchscreen::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up FT63X6Touchscreen Touchscreen...");
|
||||
ESP_LOGCONFIG(TAG, "Setting up FT63X6 Touchscreen...");
|
||||
if (this->interrupt_pin_ != nullptr) {
|
||||
this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||
this->interrupt_pin_->setup();
|
||||
|
@ -35,9 +37,8 @@ void FT63X6Touchscreen::setup() {
|
|||
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->setup();
|
||||
}
|
||||
|
||||
this->hard_reset_();
|
||||
}
|
||||
|
||||
// Get touch resolution
|
||||
if (this->x_raw_max_ == this->x_raw_min_) {
|
||||
|
@ -46,6 +47,15 @@ void FT63X6Touchscreen::setup() {
|
|||
if (this->y_raw_max_ == this->y_raw_min_) {
|
||||
this->y_raw_max_ = 480;
|
||||
}
|
||||
uint8_t chip_id = this->read_byte_(FT63X6_ADDR_CHIP_ID);
|
||||
if (chip_id != 0) {
|
||||
ESP_LOGI(TAG, "FT6336U touch driver started chipid: %d", chip_id);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "FT6336U touch driver failed to start");
|
||||
}
|
||||
this->write_byte(FT6X36_ADDR_DEVICE_MODE, 0x00);
|
||||
this->write_byte(FT6X36_ADDR_THRESHHOLD, this->threshold_);
|
||||
this->write_byte(FT6X36_ADDR_TOUCHRATE_ACTIVE, 0x0E);
|
||||
}
|
||||
|
||||
void FT63X6Touchscreen::hard_reset_() {
|
||||
|
@ -65,28 +75,61 @@ void FT63X6Touchscreen::dump_config() {
|
|||
}
|
||||
|
||||
void FT63X6Touchscreen::update_touches() {
|
||||
uint8_t data[15];
|
||||
uint16_t touch_id, x, y;
|
||||
|
||||
if (!this->read_bytes(0x00, (uint8_t *) data, 15)) {
|
||||
ESP_LOGE(TAG, "Failed to read touch data");
|
||||
this->skip_update_ = true;
|
||||
uint8_t touches = this->read_touch_number_();
|
||||
if ((touches == 0x00) || (touches == 0xff)) {
|
||||
// ESP_LOGD(TAG, "No touches detected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (((data[FT63X6_ADDR_TOUCH1_STATE] >> 6) & 0x01) == 0) {
|
||||
touch_id = data[FT63X6_ADDR_TOUCH1_ID] >> 4; // id1 = 0 or 1
|
||||
x = encode_uint16(data[FT63X6_ADDR_TOUCH1_X] & 0x0F, data[FT63X6_ADDR_TOUCH1_X + 1]);
|
||||
y = encode_uint16(data[FT63X6_ADDR_TOUCH1_Y] & 0x0F, data[FT63X6_ADDR_TOUCH1_Y + 1]);
|
||||
this->add_raw_touch_position_(touch_id, x, y);
|
||||
ESP_LOGV(TAG, "Touches found: %d", touches);
|
||||
|
||||
for (auto point = 0; point < touches; point++) {
|
||||
if (((this->read_touch_event_(point)) & 0x01) == 0) { // checking event flag bit 6 if it is null
|
||||
touch_id = this->read_touch_id_(point); // id1 = 0 or 1
|
||||
x = this->read_touch_x_(point);
|
||||
y = this->read_touch_y_(point);
|
||||
if ((x == 0) && (y == 0)) {
|
||||
ESP_LOGW(TAG, "Reporting a (0,0) touch on %d", touch_id);
|
||||
}
|
||||
if (((data[FT63X6_ADDR_TOUCH2_STATE] >> 6) & 0x01) == 0) {
|
||||
touch_id = data[FT63X6_ADDR_TOUCH2_ID] >> 4; // id1 = 0 or 1
|
||||
x = encode_uint16(data[FT63X6_ADDR_TOUCH2_X] & 0x0F, data[FT63X6_ADDR_TOUCH2_X + 1]);
|
||||
y = encode_uint16(data[FT63X6_ADDR_TOUCH2_Y] & 0x0F, data[FT63X6_ADDR_TOUCH2_Y + 1]);
|
||||
this->add_raw_touch_position_(touch_id, x, y);
|
||||
this->add_raw_touch_position_(touch_id, x, y, this->read_touch_weight_(point));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t FT63X6Touchscreen::read_touch_number_() { return this->read_byte_(FT63X6_ADDR_TD_STATUS) & 0x0F; }
|
||||
// Touch 1 functions
|
||||
uint16_t FT63X6Touchscreen::read_touch_x_(uint8_t touch) {
|
||||
uint8_t read_buf[2];
|
||||
read_buf[0] = this->read_byte_(FT63X6_ADDR_TOUCH1_X + (touch * 6));
|
||||
read_buf[1] = this->read_byte_(FT63X6_ADDR_TOUCH1_X + 1 + (touch * 6));
|
||||
return ((read_buf[0] & 0x0f) << 8) | read_buf[1];
|
||||
}
|
||||
uint16_t FT63X6Touchscreen::read_touch_y_(uint8_t touch) {
|
||||
uint8_t read_buf[2];
|
||||
read_buf[0] = this->read_byte_(FT63X6_ADDR_TOUCH1_Y + (touch * 6));
|
||||
read_buf[1] = this->read_byte_(FT63X6_ADDR_TOUCH1_Y + 1 + (touch * 6));
|
||||
return ((read_buf[0] & 0x0f) << 8) | read_buf[1];
|
||||
}
|
||||
uint8_t FT63X6Touchscreen::read_touch_event_(uint8_t touch) {
|
||||
return this->read_byte_(FT63X6_ADDR_TOUCH1_X + (touch * 6)) >> 6;
|
||||
}
|
||||
uint8_t FT63X6Touchscreen::read_touch_id_(uint8_t touch) {
|
||||
return this->read_byte_(FT63X6_ADDR_TOUCH1_ID + (touch * 6)) >> 4;
|
||||
}
|
||||
uint8_t FT63X6Touchscreen::read_touch_weight_(uint8_t touch) {
|
||||
return this->read_byte_(FT63X6_ADDR_TOUCH1_WEIGHT + (touch * 6));
|
||||
}
|
||||
uint8_t FT63X6Touchscreen::read_touch_misc_(uint8_t touch) {
|
||||
return this->read_byte_(FT63X6_ADDR_TOUCH1_MISC + (touch * 6)) >> 4;
|
||||
}
|
||||
|
||||
uint8_t FT63X6Touchscreen::read_byte_(uint8_t addr) {
|
||||
uint8_t byte = 0;
|
||||
this->read_byte(addr, &byte);
|
||||
return byte;
|
||||
}
|
||||
|
||||
} // namespace ft63x6
|
||||
} // namespace esphome
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace ft63x6 {
|
|||
|
||||
using namespace touchscreen;
|
||||
|
||||
static const uint8_t FT6X36_DEFAULT_THRESHOLD = 22;
|
||||
|
||||
class FT63X6Touchscreen : public Touchscreen, public i2c::I2CDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
|
@ -23,18 +25,26 @@ class FT63X6Touchscreen : public Touchscreen, public i2c::I2CDevice {
|
|||
|
||||
void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; }
|
||||
void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; }
|
||||
void set_threshold(uint8_t threshold) { this->threshold_ = threshold; }
|
||||
|
||||
protected:
|
||||
void hard_reset_();
|
||||
uint8_t read_byte_(uint8_t addr);
|
||||
void update_touches() override;
|
||||
|
||||
InternalGPIOPin *interrupt_pin_{nullptr};
|
||||
GPIOPin *reset_pin_{nullptr};
|
||||
uint8_t threshold_{FT6X36_DEFAULT_THRESHOLD};
|
||||
|
||||
uint8_t read_touch_count_();
|
||||
uint16_t read_touch_coordinate_(uint8_t coordinate);
|
||||
uint8_t read_touch_id_(uint8_t id_address);
|
||||
uint8_t read_touch_number_();
|
||||
|
||||
uint16_t read_touch_x_(uint8_t touch);
|
||||
uint16_t read_touch_y_(uint8_t touch);
|
||||
uint8_t read_touch_event_(uint8_t touch);
|
||||
uint8_t read_touch_id_(uint8_t touch);
|
||||
uint8_t read_touch_weight_(uint8_t touch);
|
||||
uint8_t read_touch_misc_(uint8_t touch);
|
||||
|
||||
uint8_t read_byte_(uint8_t addr);
|
||||
};
|
||||
|
||||
} // namespace ft63x6
|
||||
|
|
|
@ -3,7 +3,7 @@ import esphome.config_validation as cv
|
|||
|
||||
from esphome import pins
|
||||
from esphome.components import i2c, touchscreen
|
||||
from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN
|
||||
from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN, CONF_THRESHOLD
|
||||
|
||||
CODEOWNERS = ["@gpambrozio"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
@ -26,6 +26,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend(
|
|||
pins.internal_gpio_input_pin_schema
|
||||
),
|
||||
cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
|
||||
cv.Optional(CONF_THRESHOLD): cv.uint8_t,
|
||||
}
|
||||
).extend(i2c.i2c_device_schema(0x38))
|
||||
)
|
||||
|
|
|
@ -48,9 +48,13 @@ void GT911Touchscreen::setup() {
|
|||
if (err == i2c::ERROR_OK) {
|
||||
err = this->read(data, sizeof(data));
|
||||
if (err == i2c::ERROR_OK) {
|
||||
if (this->x_raw_max_ == this->x_raw_min_) {
|
||||
this->x_raw_max_ = encode_uint16(data[1], data[0]);
|
||||
}
|
||||
if (this->y_raw_max_ == this->y_raw_min_) {
|
||||
this->y_raw_max_ = encode_uint16(data[3], data[2]);
|
||||
esph_log_d(TAG, "Read max_x/max_y %d/%d", this->x_raw_max_, this->y_raw_max_);
|
||||
}
|
||||
esph_log_d(TAG, "calibration max_x/max_y %d/%d", this->x_raw_max_, this->y_raw_max_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,9 +38,14 @@ void LilygoT547Touchscreen::setup() {
|
|||
}
|
||||
|
||||
this->write_register(POWER_REGISTER, WAKEUP_CMD, 1);
|
||||
|
||||
this->x_raw_max_ = this->get_width_();
|
||||
this->y_raw_max_ = this->get_height_();
|
||||
if (this->display_ != nullptr) {
|
||||
if (this->x_raw_max_ == this->x_raw_min_) {
|
||||
this->x_raw_max_ = this->display_->get_native_width();
|
||||
}
|
||||
if (this->y_raw_max_ == this->y_raw_min_) {
|
||||
this->x_raw_max_ = this->display_->get_native_height();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LilygoT547Touchscreen::update_touches() {
|
||||
|
|
|
@ -3,14 +3,17 @@ import esphome.codegen as cg
|
|||
|
||||
from esphome.components import display
|
||||
from esphome import automation
|
||||
|
||||
from esphome.const import (
|
||||
CONF_ON_TOUCH,
|
||||
CONF_ON_RELEASE,
|
||||
CONF_SWAP_XY,
|
||||
CONF_MIRROR_X,
|
||||
CONF_MIRROR_Y,
|
||||
CONF_SWAP_XY,
|
||||
CONF_TRANSFORM,
|
||||
CONF_CALIBRATION,
|
||||
)
|
||||
|
||||
from esphome.core import coroutine_with_priority
|
||||
|
||||
CODEOWNERS = ["@jesserockz", "@nielsnl68"]
|
||||
|
@ -34,6 +37,56 @@ CONF_ON_UPDATE = "on_update"
|
|||
CONF_TOUCH_TIMEOUT = "touch_timeout"
|
||||
|
||||
|
||||
CONF_X_MIN = "x_min"
|
||||
CONF_X_MAX = "x_max"
|
||||
CONF_Y_MIN = "y_min"
|
||||
CONF_Y_MAX = "y_max"
|
||||
|
||||
|
||||
def validate_calibration(config):
|
||||
if CONF_CALIBRATION in config:
|
||||
calibration_config = config[CONF_CALIBRATION]
|
||||
if (
|
||||
cv.int_([CONF_X_MIN]) != 0
|
||||
and cv.int_(calibration_config[CONF_X_MAX]) != 0
|
||||
and abs(
|
||||
cv.int_(calibration_config[CONF_X_MIN])
|
||||
- cv.int_(calibration_config[CONF_X_MAX])
|
||||
)
|
||||
< 10
|
||||
):
|
||||
raise cv.Invalid("Calibration X values difference must be more than 10")
|
||||
|
||||
if (
|
||||
cv.int_(calibration_config[CONF_Y_MIN]) != 0
|
||||
and cv.int_(calibration_config[CONF_Y_MAX]) != 0
|
||||
and abs(
|
||||
cv.int_(calibration_config[CONF_Y_MIN])
|
||||
- cv.int_(calibration_config[CONF_Y_MAX])
|
||||
)
|
||||
< 10
|
||||
):
|
||||
raise cv.Invalid("Calibration Y values difference must be more than 10")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def calibration_schema(default_max_values):
|
||||
return cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_X_MIN, default=0): cv.int_range(min=0, max=4095),
|
||||
cv.Optional(CONF_X_MAX, default=default_max_values): cv.int_range(
|
||||
min=0, max=4095
|
||||
),
|
||||
cv.Optional(CONF_Y_MIN, default=0): cv.int_range(min=0, max=4095),
|
||||
cv.Optional(CONF_Y_MAX, default=default_max_values): cv.int_range(
|
||||
min=0, max=4095
|
||||
),
|
||||
},
|
||||
validate_calibration,
|
||||
)
|
||||
|
||||
|
||||
def touchscreen_schema(default_touch_timeout):
|
||||
return cv.Schema(
|
||||
{
|
||||
|
@ -49,6 +102,7 @@ def touchscreen_schema(default_touch_timeout):
|
|||
cv.positive_time_period_milliseconds,
|
||||
cv.Range(max=cv.TimePeriod(milliseconds=65535)),
|
||||
),
|
||||
cv.Optional(CONF_CALIBRATION): calibration_schema(0),
|
||||
cv.Optional(CONF_ON_TOUCH): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_ON_UPDATE): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_ON_RELEASE): automation.validate_automation(single=True),
|
||||
|
@ -74,6 +128,17 @@ async def register_touchscreen(var, config):
|
|||
cg.add(var.set_mirror_x(transform[CONF_MIRROR_X]))
|
||||
cg.add(var.set_mirror_y(transform[CONF_MIRROR_Y]))
|
||||
|
||||
if CONF_CALIBRATION in config:
|
||||
calibration_config = config[CONF_CALIBRATION]
|
||||
cg.add(
|
||||
var.set_calibration(
|
||||
calibration_config[CONF_X_MIN],
|
||||
calibration_config[CONF_X_MAX],
|
||||
calibration_config[CONF_Y_MIN],
|
||||
calibration_config[CONF_Y_MAX],
|
||||
)
|
||||
)
|
||||
|
||||
if CONF_ON_TOUCH in config:
|
||||
await automation.build_automation(
|
||||
var.get_touch_trigger(),
|
||||
|
|
|
@ -13,6 +13,15 @@ void Touchscreen::attach_interrupt_(InternalGPIOPin *irq_pin, esphome::gpio::Int
|
|||
irq_pin->attach_interrupt(TouchscreenInterrupt::gpio_intr, &this->store_, type);
|
||||
this->store_.init = true;
|
||||
this->store_.touched = false;
|
||||
ESP_LOGD(TAG, "Attach Touch Interupt");
|
||||
}
|
||||
|
||||
void Touchscreen::call_setup() {
|
||||
if (this->display_ != nullptr) {
|
||||
this->display_width_ = this->display_->get_native_width();
|
||||
this->display_height_ = this->display_->get_native_height();
|
||||
}
|
||||
PollingComponent::call_setup();
|
||||
}
|
||||
|
||||
void Touchscreen::update() {
|
||||
|
@ -20,19 +29,22 @@ void Touchscreen::update() {
|
|||
this->store_.touched = true;
|
||||
} else {
|
||||
// no need to poll if we have interrupts.
|
||||
ESP_LOGW(TAG, "Touch Polling Stopped. You can safely remove the 'update_interval:' variable from the YAML file.");
|
||||
this->stop_poller();
|
||||
}
|
||||
}
|
||||
|
||||
void Touchscreen::loop() {
|
||||
if (this->store_.touched) {
|
||||
ESP_LOGVV(TAG, "<< Do Touch loop >>");
|
||||
this->first_touch_ = this->touches_.empty();
|
||||
this->need_update_ = false;
|
||||
this->was_touched_ = this->is_touched_;
|
||||
this->is_touched_ = false;
|
||||
this->skip_update_ = false;
|
||||
for (auto &tp : this->touches_) {
|
||||
if (tp.second.state == STATE_PRESSED || tp.second.state == STATE_UPDATED) {
|
||||
tp.second.state = tp.second.state | STATE_RELEASING;
|
||||
tp.second.state |= STATE_RELEASING;
|
||||
} else {
|
||||
tp.second.state = STATE_RELEASED;
|
||||
}
|
||||
|
@ -42,7 +54,7 @@ void Touchscreen::loop() {
|
|||
this->update_touches();
|
||||
if (this->skip_update_) {
|
||||
for (auto &tp : this->touches_) {
|
||||
tp.second.state = tp.second.state & -STATE_RELEASING;
|
||||
tp.second.state &= ~STATE_RELEASING;
|
||||
}
|
||||
} else {
|
||||
this->store_.touched = false;
|
||||
|
@ -65,11 +77,13 @@ void Touchscreen::add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_r
|
|||
} else {
|
||||
tp = this->touches_[id];
|
||||
tp.state = STATE_UPDATED;
|
||||
tp.y_prev = tp.y;
|
||||
tp.x_prev = tp.x;
|
||||
}
|
||||
tp.x_raw = x_raw;
|
||||
tp.y_raw = y_raw;
|
||||
tp.z_raw = z_raw;
|
||||
|
||||
if (this->x_raw_max_ != this->x_raw_min_ and this->y_raw_max_ != this->y_raw_min_) {
|
||||
x = this->normalize_(x_raw, this->x_raw_min_, this->x_raw_max_, this->invert_x_);
|
||||
y = this->normalize_(y_raw, this->y_raw_min_, this->y_raw_max_, this->invert_y_);
|
||||
|
||||
|
@ -77,9 +91,11 @@ void Touchscreen::add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_r
|
|||
std::swap(x, y);
|
||||
}
|
||||
|
||||
tp.x = (uint16_t) ((int) x * this->get_width_() / 0x1000);
|
||||
tp.y = (uint16_t) ((int) y * this->get_height_() / 0x1000);
|
||||
|
||||
tp.x = (uint16_t) ((int) x * this->display_width_ / 0x1000);
|
||||
tp.y = (uint16_t) ((int) y * this->display_height_ / 0x1000);
|
||||
} else {
|
||||
tp.state |= STATE_CALIBRATE;
|
||||
}
|
||||
if (tp.state == STATE_PRESSED) {
|
||||
tp.x_org = tp.x;
|
||||
tp.y_org = tp.y;
|
||||
|
@ -94,7 +110,20 @@ void Touchscreen::add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_r
|
|||
}
|
||||
|
||||
void Touchscreen::send_touches_() {
|
||||
TouchPoints_t touches;
|
||||
for (auto tp : this->touches_) {
|
||||
ESP_LOGV(TAG, "Touch status: %d/%d: raw:(%4d,%4d,%4d) calc:(%3d,%4d)", tp.second.id, tp.second.state,
|
||||
tp.second.x_raw, tp.second.y_raw, tp.second.z_raw, tp.second.x, tp.second.y);
|
||||
touches.push_back(tp.second);
|
||||
}
|
||||
if (this->need_update_ || (!this->is_touched_ && this->was_touched_)) {
|
||||
this->update_trigger_.trigger(touches);
|
||||
for (auto *listener : this->touch_listeners_) {
|
||||
listener->update(touches);
|
||||
}
|
||||
}
|
||||
if (!this->is_touched_) {
|
||||
if (this->was_touched_) {
|
||||
if (this->touch_timeout_ > 0) {
|
||||
this->cancel_timeout(TAG);
|
||||
}
|
||||
|
@ -102,11 +131,9 @@ void Touchscreen::send_touches_() {
|
|||
for (auto *listener : this->touch_listeners_)
|
||||
listener->release();
|
||||
this->touches_.clear();
|
||||
} else {
|
||||
TouchPoints_t touches;
|
||||
for (auto tp : this->touches_) {
|
||||
touches.push_back(tp.second);
|
||||
this->was_touched_ = false;
|
||||
}
|
||||
} else {
|
||||
if (this->first_touch_) {
|
||||
TouchPoint tp = this->touches_.begin()->second;
|
||||
this->touch_trigger_.trigger(tp, touches);
|
||||
|
@ -114,12 +141,6 @@ void Touchscreen::send_touches_() {
|
|||
listener->touch(tp);
|
||||
}
|
||||
}
|
||||
if (this->need_update_) {
|
||||
this->update_trigger_.trigger(touches);
|
||||
for (auto *listener : this->touch_listeners_) {
|
||||
listener->update(touches);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ static const uint8_t STATE_RELEASED = 0x00;
|
|||
static const uint8_t STATE_PRESSED = 0x01;
|
||||
static const uint8_t STATE_UPDATED = 0x02;
|
||||
static const uint8_t STATE_RELEASING = 0x04;
|
||||
static const uint8_t STATE_CALIBRATE = 0x07;
|
||||
|
||||
struct TouchPoint {
|
||||
uint8_t id;
|
||||
|
@ -68,8 +69,6 @@ class Touchscreen : public PollingComponent {
|
|||
|
||||
void register_listener(TouchListener *listener) { this->touch_listeners_.push_back(listener); }
|
||||
|
||||
virtual void update_touches() = 0;
|
||||
|
||||
optional<TouchPoint> get_touch() { return this->touches_.begin()->second; }
|
||||
|
||||
TouchPoints_t get_touches() {
|
||||
|
@ -82,6 +81,7 @@ class Touchscreen : public PollingComponent {
|
|||
|
||||
void update() override;
|
||||
void loop() override;
|
||||
void call_setup() override;
|
||||
|
||||
protected:
|
||||
/// Call this function to send touch points to the `on_touch` listener and the binary_sensors.
|
||||
|
@ -90,17 +90,17 @@ class Touchscreen : public PollingComponent {
|
|||
|
||||
void add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_raw, int16_t z_raw = 0);
|
||||
|
||||
virtual void update_touches() = 0;
|
||||
|
||||
void send_touches_();
|
||||
|
||||
int16_t normalize_(int16_t val, int16_t min_val, int16_t max_val, bool inverted = false);
|
||||
|
||||
uint16_t get_width_() { return this->display_->get_width(); }
|
||||
|
||||
uint16_t get_height_() { return this->display_->get_height(); }
|
||||
|
||||
display::Display *display_{nullptr};
|
||||
|
||||
int16_t x_raw_min_{0}, x_raw_max_{0}, y_raw_min_{0}, y_raw_max_{0};
|
||||
int16_t display_width_{0}, display_height_{0};
|
||||
|
||||
uint16_t touch_timeout_{0};
|
||||
bool invert_x_{false}, invert_y_{false}, swap_x_y_{false};
|
||||
|
||||
|
@ -115,6 +115,7 @@ class Touchscreen : public PollingComponent {
|
|||
bool first_touch_{true};
|
||||
bool need_update_{false};
|
||||
bool is_touched_{false};
|
||||
bool was_touched_{false};
|
||||
bool skip_update_{false};
|
||||
};
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend(
|
|||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(TT21100Touchscreen),
|
||||
cv.Required(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema,
|
||||
cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema,
|
||||
cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
|
||||
}
|
||||
).extend(i2c.i2c_device_schema(0x24))
|
||||
|
@ -32,6 +32,7 @@ async def to_code(config):
|
|||
await touchscreen.register_touchscreen(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
if CONF_INTERRUPT_PIN in config:
|
||||
interrupt_pin = await cg.gpio_pin_expression(config[CONF_INTERRUPT_PIN])
|
||||
cg.add(var.set_interrupt_pin(interrupt_pin))
|
||||
|
||||
|
|
|
@ -50,10 +50,11 @@ void TT21100Touchscreen::setup() {
|
|||
ESP_LOGCONFIG(TAG, "Setting up TT21100 Touchscreen...");
|
||||
|
||||
// Register interrupt pin
|
||||
if (this->interrupt_pin_ != nullptr) {
|
||||
this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||
this->interrupt_pin_->setup();
|
||||
|
||||
this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE);
|
||||
}
|
||||
|
||||
// Perform reset if necessary
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
|
@ -62,8 +63,14 @@ void TT21100Touchscreen::setup() {
|
|||
}
|
||||
|
||||
// Update display dimensions if they were updated during display setup
|
||||
this->x_raw_max_ = this->get_width_();
|
||||
this->y_raw_max_ = this->get_height_();
|
||||
if (this->display_ != nullptr) {
|
||||
if (this->x_raw_max_ == this->x_raw_min_) {
|
||||
this->x_raw_max_ = this->display_->get_native_width();
|
||||
}
|
||||
if (this->y_raw_max_ == this->y_raw_min_) {
|
||||
this->x_raw_max_ = this->display_->get_native_height();
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger initial read to activate the interrupt
|
||||
this->store_.touched = true;
|
||||
|
|
|
@ -15,35 +15,11 @@ XPT2046Component = XPT2046_ns.class_(
|
|||
spi.SPIDevice,
|
||||
)
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
touchscreen.TOUCHSCREEN_SCHEMA.extend(
|
||||
cv.Schema(
|
||||
|
@ -52,42 +28,41 @@ CONFIG_SCHEMA = cv.All(
|
|||
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(
|
||||
touchscreen.CONF_CALIBRATION
|
||||
): touchscreen.calibration_schema(4095),
|
||||
cv.Optional(CONF_CALIBRATION_X_MIN): cv.invalid(
|
||||
"Deprecated: use the new 'calibration' configuration variable"
|
||||
),
|
||||
cv.Optional(CONF_CALIBRATION_X_MAX): cv.invalid(
|
||||
"Deprecated: use the new 'calibration' configuration variable"
|
||||
),
|
||||
cv.Optional(CONF_CALIBRATION_Y_MIN): cv.invalid(
|
||||
"Deprecated: use the new 'calibration' configuration variable"
|
||||
),
|
||||
cv.Optional(CONF_CALIBRATION_Y_MAX): cv.invalid(
|
||||
"Deprecated: use the new 'calibration' configuration variable"
|
||||
),
|
||||
cv.Optional(CONF_CALIBRATION_Y_MAX): cv.invalid(
|
||||
"Deprecated: use the new 'calibration' configuration variable"
|
||||
),
|
||||
cv.Optional("report_interval"): cv.invalid(
|
||||
"Deprecated: use the 'update_interval' configuration variable"
|
||||
),
|
||||
},
|
||||
)
|
||||
).extend(spi.spi_device_schema()),
|
||||
validate_xpt2046,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await touchscreen.register_touchscreen(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_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))
|
||||
|
|
|
@ -32,9 +32,8 @@ void XPT2046Component::update_touches() {
|
|||
|
||||
int16_t touch_pressure_1 = this->read_adc_(0xB1 /* touch_pressure_1 */);
|
||||
int16_t touch_pressure_2 = this->read_adc_(0xC1 /* touch_pressure_2 */);
|
||||
ESP_LOGVV(TAG, "touch_pressure %d, %d", touch_pressure_1, touch_pressure_2);
|
||||
z_raw = touch_pressure_1 + 0Xfff - touch_pressure_2;
|
||||
|
||||
ESP_LOGVV(TAG, "Touchscreen Update z = %d", z_raw);
|
||||
touch = (z_raw >= this->threshold_);
|
||||
if (touch) {
|
||||
read_adc_(0xD1 /* X */); // dummy Y measure, 1st is always noisy
|
||||
|
@ -53,7 +52,7 @@ void XPT2046Component::update_touches() {
|
|||
x_raw = best_two_avg(data[1], data[3], data[5]);
|
||||
y_raw = best_two_avg(data[0], data[2], data[4]);
|
||||
|
||||
ESP_LOGV(TAG, "Touchscreen Update [%d, %d], z = %d", x_raw, y_raw, z_raw);
|
||||
ESP_LOGD(TAG, "Touchscreen Update [%d, %d], z = %d", x_raw, y_raw, z_raw);
|
||||
|
||||
this->add_raw_touch_position_(0, x_raw, y_raw, z_raw);
|
||||
}
|
||||
|
@ -77,7 +76,7 @@ void XPT2046Component::dump_config() {
|
|||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
float XPT2046Component::get_setup_priority() const { return setup_priority::DATA; }
|
||||
// float XPT2046Component::get_setup_priority() const { return setup_priority::DATA; }
|
||||
|
||||
int16_t XPT2046Component::best_two_avg(int16_t value1, int16_t value2, int16_t value3) {
|
||||
int16_t delta_a, delta_b, delta_c;
|
||||
|
|
|
@ -23,7 +23,7 @@ class XPT2046Component : public Touchscreen,
|
|||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
// float get_setup_priority() const override;
|
||||
|
||||
protected:
|
||||
static int16_t best_two_avg(int16_t value1, int16_t value2, int16_t value3);
|
||||
|
|
38
tests/components/ft63x6/test.esp32.yaml
Normal file
38
tests/components/ft63x6/test.esp32.yaml
Normal file
|
@ -0,0 +1,38 @@
|
|||
spi:
|
||||
clk_pin: 14
|
||||
mosi_pin: 13
|
||||
|
||||
i2c:
|
||||
sda: GPIO18
|
||||
scl: GPIO19
|
||||
|
||||
display:
|
||||
- id: my_display
|
||||
platform: ili9xxx
|
||||
dimensions: 480x320
|
||||
model: ST7796
|
||||
cs_pin: 15
|
||||
dc_pin: 21
|
||||
reset_pin: 22
|
||||
transform:
|
||||
swap_xy: true
|
||||
mirror_x: true
|
||||
mirror_y: true
|
||||
auto_clear_enabled: false
|
||||
|
||||
touchscreen:
|
||||
- platform: ft63x6
|
||||
interrupt_pin: GPIO39
|
||||
transform:
|
||||
swap_xy: true
|
||||
mirror_x: false
|
||||
mirror_y: true
|
||||
on_touch:
|
||||
- logger.log:
|
||||
format: tp touched
|
||||
on_update:
|
||||
- logger.log:
|
||||
format: to updated
|
||||
on_release:
|
||||
- logger.log:
|
||||
format: to released
|
43
tests/components/tt21100/test.esp32-s2.yaml
Normal file
43
tests/components/tt21100/test.esp32-s2.yaml
Normal file
|
@ -0,0 +1,43 @@
|
|||
i2c:
|
||||
sda: GPIO8
|
||||
scl: GPIO18
|
||||
|
||||
spi:
|
||||
clk_pin: 7
|
||||
mosi_pin: 11
|
||||
miso_pin: 9
|
||||
|
||||
display:
|
||||
- platform: ili9xxx
|
||||
id: my_display
|
||||
model: ili9341
|
||||
cs_pin: 5
|
||||
dc_pin: 12
|
||||
reset_pin: 33
|
||||
auto_clear_enabled: false
|
||||
data_rate: 40MHz
|
||||
dimensions: 320x240
|
||||
update_interval: never
|
||||
transform:
|
||||
mirror_y: false
|
||||
mirror_x: false
|
||||
swap_xy: true
|
||||
|
||||
touchscreen:
|
||||
- platform: tt21100
|
||||
address: 0x24
|
||||
interrupt_pin: GPIO3
|
||||
on_touch:
|
||||
- logger.log: "Touchscreen:: Touched"
|
||||
|
||||
binary_sensor:
|
||||
- platform: tt21100
|
||||
index: 0
|
||||
name: "Home"
|
||||
|
||||
- platform: touchscreen
|
||||
name: FanLo
|
||||
x_min: 0
|
||||
x_max: 105
|
||||
y_min: 0
|
||||
y_max: 80
|
37
tests/components/xpt2046/test.esp32-s2.yaml
Normal file
37
tests/components/xpt2046/test.esp32-s2.yaml
Normal file
|
@ -0,0 +1,37 @@
|
|||
spi:
|
||||
clk_pin: 7
|
||||
mosi_pin: 11
|
||||
miso_pin: 9
|
||||
|
||||
display:
|
||||
- platform: ili9xxx
|
||||
id: my_display
|
||||
model: ili9341
|
||||
cs_pin: 5
|
||||
dc_pin: 12
|
||||
reset_pin: 33
|
||||
auto_clear_enabled: false
|
||||
data_rate: 40MHz
|
||||
dimensions: 320x240
|
||||
update_interval: never
|
||||
transform:
|
||||
mirror_y: false
|
||||
mirror_x: false
|
||||
swap_xy: true
|
||||
|
||||
touchscreen:
|
||||
- platform: xpt2046
|
||||
display: my_display
|
||||
id: my_toucher
|
||||
update_interval: 50ms
|
||||
cs_pin: 18
|
||||
threshold: 300
|
||||
calibration:
|
||||
x_min: 210
|
||||
x_max: 3890
|
||||
y_min: 170
|
||||
y_max: 3730
|
||||
transform:
|
||||
mirror_x: false
|
||||
mirror_y: true
|
||||
swap_xy: true
|
|
@ -976,10 +976,11 @@ touchscreen:
|
|||
display: inkplate_display
|
||||
update_interval: 50ms
|
||||
threshold: 400
|
||||
calibration_x_min: 3860
|
||||
calibration_x_max: 280
|
||||
calibration_y_min: 340
|
||||
calibration_y_max: 3860
|
||||
calibration:
|
||||
x_min: 3860
|
||||
x_max: 280
|
||||
y_min: 340
|
||||
y_max: 3860
|
||||
on_touch:
|
||||
- logger.log:
|
||||
format: Touch at (%d, %d)
|
||||
|
|
Loading…
Reference in a new issue