mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 06:33:51 +00: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:
		| @@ -175,10 +175,15 @@ class Display : public PollingComponent { | |||||||
|   /// Clear the entire screen by filling it with OFF pixels. |   /// Clear the entire screen by filling it with OFF pixels. | ||||||
|   void clear(); |   void clear(); | ||||||
|  |  | ||||||
|   /// Get the width of the image in pixels with rotation applied. |   /// Get the calculated width of the display in pixels with rotation applied. | ||||||
|   virtual int get_width() = 0; |   virtual int get_width() { return this->get_width_internal(); } | ||||||
|   /// Get the height of the image in pixels with rotation applied. |   /// Get the calculated height of the display in pixels with rotation applied. | ||||||
|   virtual int get_height() = 0; |   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. |   /// 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); } |   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 do_update_(); | ||||||
|   void clear_clipping_(); |   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 |    * This method fills a triangle using only integer variables by using a | ||||||
|    * modified bresenham algorithm. |    * modified bresenham algorithm. | ||||||
|   | |||||||
| @@ -22,9 +22,6 @@ class DisplayBuffer : public Display { | |||||||
|   /// Set a single pixel at the specified coordinates to the given color. |   /// Set a single pixel at the specified coordinates to the given color. | ||||||
|   void draw_pixel_at(int x, int y, Color color) override; |   void draw_pixel_at(int x, int y, Color color) override; | ||||||
|  |  | ||||||
|   virtual int get_height_internal() = 0; |  | ||||||
|   virtual int get_width_internal() = 0; |  | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   virtual void draw_absolute_pixel_internal(int x, int y, Color color) = 0; |   virtual void draw_absolute_pixel_internal(int x, int y, Color color) = 0; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -34,24 +34,27 @@ void EKTF2232Touchscreen::setup() { | |||||||
|  |  | ||||||
|   // Get touch resolution |   // Get touch resolution | ||||||
|   uint8_t received[4]; |   uint8_t received[4]; | ||||||
|   this->write(GET_X_RES, 4); |   if (this->x_raw_max_ == this->x_raw_min_) { | ||||||
|   if (this->read(received, 4)) { |     this->write(GET_X_RES, 4); | ||||||
|     ESP_LOGE(TAG, "Failed to read X resolution!"); |     if (this->read(received, 4)) { | ||||||
|     this->interrupt_pin_->detach_interrupt(); |       ESP_LOGE(TAG, "Failed to read X resolution!"); | ||||||
|     this->mark_failed(); |       this->interrupt_pin_->detach_interrupt(); | ||||||
|     return; |       this->mark_failed(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     this->x_raw_max_ = ((received[2])) | ((received[3] & 0xf0) << 4); | ||||||
|   } |   } | ||||||
|   this->x_raw_max_ = ((received[2])) | ((received[3] & 0xf0) << 4); |  | ||||||
|  |  | ||||||
|   this->write(GET_Y_RES, 4); |   if (this->y_raw_max_ == this->y_raw_min_) { | ||||||
|   if (this->read(received, 4)) { |     this->write(GET_Y_RES, 4); | ||||||
|     ESP_LOGE(TAG, "Failed to read Y resolution!"); |     if (this->read(received, 4)) { | ||||||
|     this->interrupt_pin_->detach_interrupt(); |       ESP_LOGE(TAG, "Failed to read Y resolution!"); | ||||||
|     this->mark_failed(); |       this->interrupt_pin_->detach_interrupt(); | ||||||
|     return; |       this->mark_failed(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     this->y_raw_max_ = ((received[2])) | ((received[3] & 0xf0) << 4); | ||||||
|   } |   } | ||||||
|   this->y_raw_max_ = ((received[2])) | ((received[3] & 0xf0) << 4); |  | ||||||
|  |  | ||||||
|   this->set_power_state(true); |   this->set_power_state(true); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -66,8 +66,14 @@ class FT5x06Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     // reading the chip registers to get max x/y does not seem to work. |     // reading the chip registers to get max x/y does not seem to work. | ||||||
|     this->x_raw_max_ = this->display_->get_width(); |     if (this->display_ != nullptr) { | ||||||
|     this->y_raw_max_ = this->display_->get_height(); |       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"); |     esph_log_config(TAG, "FT5x06 Touchscreen setup complete"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,21 +12,23 @@ | |||||||
| // Reference: https://focuslcds.com/content/FT6236.pdf | // Reference: https://focuslcds.com/content/FT6236.pdf | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ft63x6 { | 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_STATE = 0x03; | ||||||
| static const uint8_t FT63X6_ADDR_TOUCH1_X = 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_ID = 0x05; | ||||||
| static const uint8_t FT63X6_ADDR_TOUCH1_Y = 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 char *const TAG = "FT63X6"; | ||||||
| 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"; |  | ||||||
|  |  | ||||||
| void FT63X6Touchscreen::setup() { | void FT63X6Touchscreen::setup() { | ||||||
|   ESP_LOGCONFIG(TAG, "Setting up FT63X6Touchscreen Touchscreen..."); |   ESP_LOGCONFIG(TAG, "Setting up FT63X6 Touchscreen..."); | ||||||
|   if (this->interrupt_pin_ != nullptr) { |   if (this->interrupt_pin_ != nullptr) { | ||||||
|     this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); |     this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); | ||||||
|     this->interrupt_pin_->setup(); |     this->interrupt_pin_->setup(); | ||||||
| @@ -35,10 +37,9 @@ void FT63X6Touchscreen::setup() { | |||||||
|  |  | ||||||
|   if (this->reset_pin_ != nullptr) { |   if (this->reset_pin_ != nullptr) { | ||||||
|     this->reset_pin_->setup(); |     this->reset_pin_->setup(); | ||||||
|  |     this->hard_reset_(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   this->hard_reset_(); |  | ||||||
|  |  | ||||||
|   // Get touch resolution |   // Get touch resolution | ||||||
|   if (this->x_raw_max_ == this->x_raw_min_) { |   if (this->x_raw_max_ == this->x_raw_min_) { | ||||||
|     this->x_raw_max_ = 320; |     this->x_raw_max_ = 320; | ||||||
| @@ -46,6 +47,15 @@ void FT63X6Touchscreen::setup() { | |||||||
|   if (this->y_raw_max_ == this->y_raw_min_) { |   if (this->y_raw_max_ == this->y_raw_min_) { | ||||||
|     this->y_raw_max_ = 480; |     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_() { | void FT63X6Touchscreen::hard_reset_() { | ||||||
| @@ -65,28 +75,61 @@ void FT63X6Touchscreen::dump_config() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void FT63X6Touchscreen::update_touches() { | void FT63X6Touchscreen::update_touches() { | ||||||
|   uint8_t data[15]; |  | ||||||
|   uint16_t touch_id, x, y; |   uint16_t touch_id, x, y; | ||||||
|  |  | ||||||
|   if (!this->read_bytes(0x00, (uint8_t *) data, 15)) { |   uint8_t touches = this->read_touch_number_(); | ||||||
|     ESP_LOGE(TAG, "Failed to read touch data"); |   if ((touches == 0x00) || (touches == 0xff)) { | ||||||
|     this->skip_update_ = true; |     // ESP_LOGD(TAG, "No touches detected"); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (((data[FT63X6_ADDR_TOUCH1_STATE] >> 6) & 0x01) == 0) { |   ESP_LOGV(TAG, "Touches found: %d", touches); | ||||||
|     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]); |   for (auto point = 0; point < touches; point++) { | ||||||
|     y = encode_uint16(data[FT63X6_ADDR_TOUCH1_Y] & 0x0F, data[FT63X6_ADDR_TOUCH1_Y + 1]); |     if (((this->read_touch_event_(point)) & 0x01) == 0) {  // checking event flag bit 6 if it is null | ||||||
|     this->add_raw_touch_position_(touch_id, x, y); |       touch_id = this->read_touch_id_(point);              // id1 = 0 or 1 | ||||||
|   } |       x = this->read_touch_x_(point); | ||||||
|   if (((data[FT63X6_ADDR_TOUCH2_STATE] >> 6) & 0x01) == 0) { |       y = this->read_touch_y_(point); | ||||||
|     touch_id = data[FT63X6_ADDR_TOUCH2_ID] >> 4;  // id1 = 0 or 1 |       if ((x == 0) && (y == 0)) { | ||||||
|     x = encode_uint16(data[FT63X6_ADDR_TOUCH2_X] & 0x0F, data[FT63X6_ADDR_TOUCH2_X + 1]); |         ESP_LOGW(TAG, "Reporting a (0,0) touch on %d", touch_id); | ||||||
|     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 ft63x6 | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -16,6 +16,8 @@ namespace ft63x6 { | |||||||
|  |  | ||||||
| using namespace touchscreen; | using namespace touchscreen; | ||||||
|  |  | ||||||
|  | static const uint8_t FT6X36_DEFAULT_THRESHOLD = 22; | ||||||
|  |  | ||||||
| class FT63X6Touchscreen : public Touchscreen, public i2c::I2CDevice { | class FT63X6Touchscreen : public Touchscreen, public i2c::I2CDevice { | ||||||
|  public: |  public: | ||||||
|   void setup() override; |   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_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } | ||||||
|   void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; } |   void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; } | ||||||
|  |   void set_threshold(uint8_t threshold) { this->threshold_ = threshold; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void hard_reset_(); |   void hard_reset_(); | ||||||
|   uint8_t read_byte_(uint8_t addr); |  | ||||||
|   void update_touches() override; |   void update_touches() override; | ||||||
|  |  | ||||||
|   InternalGPIOPin *interrupt_pin_{nullptr}; |   InternalGPIOPin *interrupt_pin_{nullptr}; | ||||||
|   GPIOPin *reset_pin_{nullptr}; |   GPIOPin *reset_pin_{nullptr}; | ||||||
|  |   uint8_t threshold_{FT6X36_DEFAULT_THRESHOLD}; | ||||||
|  |  | ||||||
|   uint8_t read_touch_count_(); |   uint8_t read_touch_number_(); | ||||||
|   uint16_t read_touch_coordinate_(uint8_t coordinate); |  | ||||||
|   uint8_t read_touch_id_(uint8_t id_address); |   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 | }  // namespace ft63x6 | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ import esphome.config_validation as cv | |||||||
|  |  | ||||||
| from esphome import pins | from esphome import pins | ||||||
| from esphome.components import i2c, touchscreen | 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"] | CODEOWNERS = ["@gpambrozio"] | ||||||
| DEPENDENCIES = ["i2c"] | DEPENDENCIES = ["i2c"] | ||||||
| @@ -26,6 +26,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( | |||||||
|                 pins.internal_gpio_input_pin_schema |                 pins.internal_gpio_input_pin_schema | ||||||
|             ), |             ), | ||||||
|             cv.Optional(CONF_RESET_PIN): pins.gpio_output_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)) |     ).extend(i2c.i2c_device_schema(0x38)) | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -48,9 +48,13 @@ void GT911Touchscreen::setup() { | |||||||
|     if (err == i2c::ERROR_OK) { |     if (err == i2c::ERROR_OK) { | ||||||
|       err = this->read(data, sizeof(data)); |       err = this->read(data, sizeof(data)); | ||||||
|       if (err == i2c::ERROR_OK) { |       if (err == i2c::ERROR_OK) { | ||||||
|         this->x_raw_max_ = encode_uint16(data[1], data[0]); |         if (this->x_raw_max_ == this->x_raw_min_) { | ||||||
|         this->y_raw_max_ = encode_uint16(data[3], data[2]); |           this->x_raw_max_ = encode_uint16(data[1], data[0]); | ||||||
|         esph_log_d(TAG, "Read max_x/max_y %d/%d", this->x_raw_max_, this->y_raw_max_); |         } | ||||||
|  |         if (this->y_raw_max_ == this->y_raw_min_) { | ||||||
|  |           this->y_raw_max_ = encode_uint16(data[3], data[2]); | ||||||
|  |         } | ||||||
|  |         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->write_register(POWER_REGISTER, WAKEUP_CMD, 1); | ||||||
|  |   if (this->display_ != nullptr) { | ||||||
|   this->x_raw_max_ = this->get_width_(); |     if (this->x_raw_max_ == this->x_raw_min_) { | ||||||
|   this->y_raw_max_ = this->get_height_(); |       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() { | void LilygoT547Touchscreen::update_touches() { | ||||||
|   | |||||||
| @@ -3,14 +3,17 @@ import esphome.codegen as cg | |||||||
|  |  | ||||||
| from esphome.components import display | from esphome.components import display | ||||||
| from esphome import automation | from esphome import automation | ||||||
|  |  | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|     CONF_ON_TOUCH, |     CONF_ON_TOUCH, | ||||||
|     CONF_ON_RELEASE, |     CONF_ON_RELEASE, | ||||||
|  |     CONF_SWAP_XY, | ||||||
|     CONF_MIRROR_X, |     CONF_MIRROR_X, | ||||||
|     CONF_MIRROR_Y, |     CONF_MIRROR_Y, | ||||||
|     CONF_SWAP_XY, |  | ||||||
|     CONF_TRANSFORM, |     CONF_TRANSFORM, | ||||||
|  |     CONF_CALIBRATION, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| from esphome.core import coroutine_with_priority | from esphome.core import coroutine_with_priority | ||||||
|  |  | ||||||
| CODEOWNERS = ["@jesserockz", "@nielsnl68"] | CODEOWNERS = ["@jesserockz", "@nielsnl68"] | ||||||
| @@ -34,6 +37,56 @@ CONF_ON_UPDATE = "on_update" | |||||||
| CONF_TOUCH_TIMEOUT = "touch_timeout" | 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): | def touchscreen_schema(default_touch_timeout): | ||||||
|     return cv.Schema( |     return cv.Schema( | ||||||
|         { |         { | ||||||
| @@ -49,6 +102,7 @@ def touchscreen_schema(default_touch_timeout): | |||||||
|                 cv.positive_time_period_milliseconds, |                 cv.positive_time_period_milliseconds, | ||||||
|                 cv.Range(max=cv.TimePeriod(milliseconds=65535)), |                 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_TOUCH): automation.validate_automation(single=True), | ||||||
|             cv.Optional(CONF_ON_UPDATE): 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), |             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_x(transform[CONF_MIRROR_X])) | ||||||
|         cg.add(var.set_mirror_y(transform[CONF_MIRROR_Y])) |         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: |     if CONF_ON_TOUCH in config: | ||||||
|         await automation.build_automation( |         await automation.build_automation( | ||||||
|             var.get_touch_trigger(), |             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); |   irq_pin->attach_interrupt(TouchscreenInterrupt::gpio_intr, &this->store_, type); | ||||||
|   this->store_.init = true; |   this->store_.init = true; | ||||||
|   this->store_.touched = false; |   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() { | void Touchscreen::update() { | ||||||
| @@ -20,19 +29,22 @@ void Touchscreen::update() { | |||||||
|     this->store_.touched = true; |     this->store_.touched = true; | ||||||
|   } else { |   } else { | ||||||
|     // no need to poll if we have interrupts. |     // 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(); |     this->stop_poller(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void Touchscreen::loop() { | void Touchscreen::loop() { | ||||||
|   if (this->store_.touched) { |   if (this->store_.touched) { | ||||||
|  |     ESP_LOGVV(TAG, "<< Do Touch loop >>"); | ||||||
|     this->first_touch_ = this->touches_.empty(); |     this->first_touch_ = this->touches_.empty(); | ||||||
|     this->need_update_ = false; |     this->need_update_ = false; | ||||||
|  |     this->was_touched_ = this->is_touched_; | ||||||
|     this->is_touched_ = false; |     this->is_touched_ = false; | ||||||
|     this->skip_update_ = false; |     this->skip_update_ = false; | ||||||
|     for (auto &tp : this->touches_) { |     for (auto &tp : this->touches_) { | ||||||
|       if (tp.second.state == STATE_PRESSED || tp.second.state == STATE_UPDATED) { |       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 { |       } else { | ||||||
|         tp.second.state = STATE_RELEASED; |         tp.second.state = STATE_RELEASED; | ||||||
|       } |       } | ||||||
| @@ -42,7 +54,7 @@ void Touchscreen::loop() { | |||||||
|     this->update_touches(); |     this->update_touches(); | ||||||
|     if (this->skip_update_) { |     if (this->skip_update_) { | ||||||
|       for (auto &tp : this->touches_) { |       for (auto &tp : this->touches_) { | ||||||
|         tp.second.state = tp.second.state & -STATE_RELEASING; |         tp.second.state &= ~STATE_RELEASING; | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       this->store_.touched = false; |       this->store_.touched = false; | ||||||
| @@ -65,21 +77,25 @@ void Touchscreen::add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_r | |||||||
|   } else { |   } else { | ||||||
|     tp = this->touches_[id]; |     tp = this->touches_[id]; | ||||||
|     tp.state = STATE_UPDATED; |     tp.state = STATE_UPDATED; | ||||||
|  |     tp.y_prev = tp.y; | ||||||
|  |     tp.x_prev = tp.x; | ||||||
|   } |   } | ||||||
|   tp.x_raw = x_raw; |   tp.x_raw = x_raw; | ||||||
|   tp.y_raw = y_raw; |   tp.y_raw = y_raw; | ||||||
|   tp.z_raw = z_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_); | ||||||
|  |  | ||||||
|   x = this->normalize_(x_raw, this->x_raw_min_, this->x_raw_max_, this->invert_x_); |     if (this->swap_x_y_) { | ||||||
|   y = this->normalize_(y_raw, this->y_raw_min_, this->y_raw_max_, this->invert_y_); |       std::swap(x, y); | ||||||
|  |     } | ||||||
|  |  | ||||||
|   if (this->swap_x_y_) { |     tp.x = (uint16_t) ((int) x * this->display_width_ / 0x1000); | ||||||
|     std::swap(x, y); |     tp.y = (uint16_t) ((int) y * this->display_height_ / 0x1000); | ||||||
|  |   } else { | ||||||
|  |     tp.state |= STATE_CALIBRATE; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   tp.x = (uint16_t) ((int) x * this->get_width_() / 0x1000); |  | ||||||
|   tp.y = (uint16_t) ((int) y * this->get_height_() / 0x1000); |  | ||||||
|  |  | ||||||
|   if (tp.state == STATE_PRESSED) { |   if (tp.state == STATE_PRESSED) { | ||||||
|     tp.x_org = tp.x; |     tp.x_org = tp.x; | ||||||
|     tp.y_org = tp.y; |     tp.y_org = tp.y; | ||||||
| @@ -94,19 +110,30 @@ void Touchscreen::add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_r | |||||||
| } | } | ||||||
|  |  | ||||||
| void Touchscreen::send_touches_() { | 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->is_touched_) { | ||||||
|     if (this->touch_timeout_ > 0) { |     if (this->was_touched_) { | ||||||
|       this->cancel_timeout(TAG); |       if (this->touch_timeout_ > 0) { | ||||||
|  |         this->cancel_timeout(TAG); | ||||||
|  |       } | ||||||
|  |       this->release_trigger_.trigger(); | ||||||
|  |       for (auto *listener : this->touch_listeners_) | ||||||
|  |         listener->release(); | ||||||
|  |       this->touches_.clear(); | ||||||
|  |       this->was_touched_ = false; | ||||||
|     } |     } | ||||||
|     this->release_trigger_.trigger(); |  | ||||||
|     for (auto *listener : this->touch_listeners_) |  | ||||||
|       listener->release(); |  | ||||||
|     this->touches_.clear(); |  | ||||||
|   } else { |   } else { | ||||||
|     TouchPoints_t touches; |  | ||||||
|     for (auto tp : this->touches_) { |  | ||||||
|       touches.push_back(tp.second); |  | ||||||
|     } |  | ||||||
|     if (this->first_touch_) { |     if (this->first_touch_) { | ||||||
|       TouchPoint tp = this->touches_.begin()->second; |       TouchPoint tp = this->touches_.begin()->second; | ||||||
|       this->touch_trigger_.trigger(tp, touches); |       this->touch_trigger_.trigger(tp, touches); | ||||||
| @@ -114,12 +141,6 @@ void Touchscreen::send_touches_() { | |||||||
|         listener->touch(tp); |         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_PRESSED = 0x01; | ||||||
| static const uint8_t STATE_UPDATED = 0x02; | static const uint8_t STATE_UPDATED = 0x02; | ||||||
| static const uint8_t STATE_RELEASING = 0x04; | static const uint8_t STATE_RELEASING = 0x04; | ||||||
|  | static const uint8_t STATE_CALIBRATE = 0x07; | ||||||
|  |  | ||||||
| struct TouchPoint { | struct TouchPoint { | ||||||
|   uint8_t id; |   uint8_t id; | ||||||
| @@ -68,8 +69,6 @@ class Touchscreen : public PollingComponent { | |||||||
|  |  | ||||||
|   void register_listener(TouchListener *listener) { this->touch_listeners_.push_back(listener); } |   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; } |   optional<TouchPoint> get_touch() { return this->touches_.begin()->second; } | ||||||
|  |  | ||||||
|   TouchPoints_t get_touches() { |   TouchPoints_t get_touches() { | ||||||
| @@ -82,6 +81,7 @@ class Touchscreen : public PollingComponent { | |||||||
|  |  | ||||||
|   void update() override; |   void update() override; | ||||||
|   void loop() override; |   void loop() override; | ||||||
|  |   void call_setup() override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   /// Call this function to send touch points to the `on_touch` listener and the binary_sensors. |   /// 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); |   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_(); |   void send_touches_(); | ||||||
|  |  | ||||||
|   int16_t normalize_(int16_t val, int16_t min_val, int16_t max_val, bool inverted = false); |   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}; |   display::Display *display_{nullptr}; | ||||||
|  |  | ||||||
|   int16_t x_raw_min_{0}, x_raw_max_{0}, y_raw_min_{0}, y_raw_max_{0}; |   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}; |   uint16_t touch_timeout_{0}; | ||||||
|   bool invert_x_{false}, invert_y_{false}, swap_x_y_{false}; |   bool invert_x_{false}, invert_y_{false}, swap_x_y_{false}; | ||||||
|  |  | ||||||
| @@ -115,6 +115,7 @@ class Touchscreen : public PollingComponent { | |||||||
|   bool first_touch_{true}; |   bool first_touch_{true}; | ||||||
|   bool need_update_{false}; |   bool need_update_{false}; | ||||||
|   bool is_touched_{false}; |   bool is_touched_{false}; | ||||||
|  |   bool was_touched_{false}; | ||||||
|   bool skip_update_{false}; |   bool skip_update_{false}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( | |||||||
|     cv.Schema( |     cv.Schema( | ||||||
|         { |         { | ||||||
|             cv.GenerateID(): cv.declare_id(TT21100Touchscreen), |             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, |             cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, | ||||||
|         } |         } | ||||||
|     ).extend(i2c.i2c_device_schema(0x24)) |     ).extend(i2c.i2c_device_schema(0x24)) | ||||||
| @@ -32,8 +32,9 @@ async def to_code(config): | |||||||
|     await touchscreen.register_touchscreen(var, config) |     await touchscreen.register_touchscreen(var, config) | ||||||
|     await i2c.register_i2c_device(var, config) |     await i2c.register_i2c_device(var, config) | ||||||
|  |  | ||||||
|     interrupt_pin = await cg.gpio_pin_expression(config[CONF_INTERRUPT_PIN]) |     if CONF_INTERRUPT_PIN in config: | ||||||
|     cg.add(var.set_interrupt_pin(interrupt_pin)) |         interrupt_pin = await cg.gpio_pin_expression(config[CONF_INTERRUPT_PIN]) | ||||||
|  |         cg.add(var.set_interrupt_pin(interrupt_pin)) | ||||||
|  |  | ||||||
|     if CONF_RESET_PIN in config: |     if CONF_RESET_PIN in config: | ||||||
|         rts_pin = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) |         rts_pin = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) | ||||||
|   | |||||||
| @@ -50,10 +50,11 @@ void TT21100Touchscreen::setup() { | |||||||
|   ESP_LOGCONFIG(TAG, "Setting up TT21100 Touchscreen..."); |   ESP_LOGCONFIG(TAG, "Setting up TT21100 Touchscreen..."); | ||||||
|  |  | ||||||
|   // Register interrupt pin |   // Register interrupt pin | ||||||
|   this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); |   if (this->interrupt_pin_ != nullptr) { | ||||||
|   this->interrupt_pin_->setup(); |     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); |     this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   // Perform reset if necessary |   // Perform reset if necessary | ||||||
|   if (this->reset_pin_ != nullptr) { |   if (this->reset_pin_ != nullptr) { | ||||||
| @@ -62,8 +63,14 @@ void TT21100Touchscreen::setup() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Update display dimensions if they were updated during display setup |   // Update display dimensions if they were updated during display setup | ||||||
|   this->x_raw_max_ = this->get_width_(); |   if (this->display_ != nullptr) { | ||||||
|   this->y_raw_max_ = this->get_height_(); |     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 |   // Trigger initial read to activate the interrupt | ||||||
|   this->store_.touched = true; |   this->store_.touched = true; | ||||||
|   | |||||||
| @@ -15,35 +15,11 @@ XPT2046Component = XPT2046_ns.class_( | |||||||
|     spi.SPIDevice, |     spi.SPIDevice, | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| CONF_CALIBRATION_X_MIN = "calibration_x_min" | CONF_CALIBRATION_X_MIN = "calibration_x_min" | ||||||
| CONF_CALIBRATION_X_MAX = "calibration_x_max" | CONF_CALIBRATION_X_MAX = "calibration_x_max" | ||||||
| CONF_CALIBRATION_Y_MIN = "calibration_y_min" | CONF_CALIBRATION_Y_MIN = "calibration_y_min" | ||||||
| CONF_CALIBRATION_Y_MAX = "calibration_y_max" | 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( | CONFIG_SCHEMA = cv.All( | ||||||
|     touchscreen.TOUCHSCREEN_SCHEMA.extend( |     touchscreen.TOUCHSCREEN_SCHEMA.extend( | ||||||
|         cv.Schema( |         cv.Schema( | ||||||
| @@ -52,42 +28,41 @@ CONFIG_SCHEMA = cv.All( | |||||||
|                 cv.Optional(CONF_INTERRUPT_PIN): cv.All( |                 cv.Optional(CONF_INTERRUPT_PIN): cv.All( | ||||||
|                     pins.internal_gpio_input_pin_schema |                     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_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()), |     ).extend(spi.spi_device_schema()), | ||||||
|     validate_xpt2046, |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_ID]) |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|     await touchscreen.register_touchscreen(var, config) |  | ||||||
|     await spi.register_spi_device(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_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: |     if CONF_INTERRUPT_PIN in config: | ||||||
|         pin = await cg.gpio_pin_expression(config[CONF_INTERRUPT_PIN]) |         pin = await cg.gpio_pin_expression(config[CONF_INTERRUPT_PIN]) | ||||||
|         cg.add(var.set_irq_pin(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_1 = this->read_adc_(0xB1 /* touch_pressure_1 */); | ||||||
|   int16_t touch_pressure_2 = this->read_adc_(0xC1 /* touch_pressure_2 */); |   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; |   z_raw = touch_pressure_1 + 0Xfff - touch_pressure_2; | ||||||
|  |   ESP_LOGVV(TAG, "Touchscreen Update z = %d", z_raw); | ||||||
|   touch = (z_raw >= this->threshold_); |   touch = (z_raw >= this->threshold_); | ||||||
|   if (touch) { |   if (touch) { | ||||||
|     read_adc_(0xD1 /* X */);  // dummy Y measure, 1st is always noisy |     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]); |     x_raw = best_two_avg(data[1], data[3], data[5]); | ||||||
|     y_raw = best_two_avg(data[0], data[2], data[4]); |     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); |     this->add_raw_touch_position_(0, x_raw, y_raw, z_raw); | ||||||
|   } |   } | ||||||
| @@ -77,7 +76,7 @@ void XPT2046Component::dump_config() { | |||||||
|   LOG_UPDATE_INTERVAL(this); |   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 XPT2046Component::best_two_avg(int16_t value1, int16_t value2, int16_t value3) { | ||||||
|   int16_t delta_a, delta_b, delta_c; |   int16_t delta_a, delta_b, delta_c; | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ class XPT2046Component : public Touchscreen, | |||||||
|  |  | ||||||
|   void setup() override; |   void setup() override; | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|   float get_setup_priority() const override; |   // float get_setup_priority() const override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   static int16_t best_two_avg(int16_t value1, int16_t value2, int16_t value3); |   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 |     display: inkplate_display | ||||||
|     update_interval: 50ms |     update_interval: 50ms | ||||||
|     threshold: 400 |     threshold: 400 | ||||||
|     calibration_x_min: 3860 |     calibration: | ||||||
|     calibration_x_max: 280 |       x_min: 3860 | ||||||
|     calibration_y_min: 340 |       x_max: 280 | ||||||
|     calibration_y_max: 3860 |       y_min: 340 | ||||||
|  |       y_max: 3860 | ||||||
|     on_touch: |     on_touch: | ||||||
|       - logger.log: |       - logger.log: | ||||||
|           format: Touch at (%d, %d) |           format: Touch at (%d, %d) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user