ESPHome 2025.5.0
Loading...
Searching...
No Matches
touchscreen.cpp
Go to the documentation of this file.
1#include "touchscreen.h"
2
3#include "esphome/core/log.h"
4
5namespace esphome {
6namespace touchscreen {
7
8static const char *const TAG = "touchscreen";
9
11
14 this->store_.init = true;
15 this->store_.touched = false;
16 ESP_LOGD(TAG, "Attach Touch Interupt");
17}
18
20 if (this->display_ != nullptr) {
21 this->display_width_ = this->display_->get_width();
22 this->display_height_ = this->display_->get_height();
23 }
25}
26
28 if (!this->store_.init) {
29 this->store_.touched = true;
30 } else {
31 // no need to poll if we have interrupts.
32 ESP_LOGW(TAG, "Touch Polling Stopped. You can safely remove the 'update_interval:' variable from the YAML file.");
33 this->stop_poller();
34 }
35}
36
38 if (this->store_.touched) {
39 ESP_LOGVV(TAG, "<< Do Touch loop >>");
40 this->first_touch_ = this->touches_.empty();
41 this->need_update_ = false;
42 this->is_touched_ = false;
43 this->skip_update_ = false;
44 for (auto &tp : this->touches_) {
45 if (tp.second.state == STATE_PRESSED || tp.second.state == STATE_UPDATED) {
46 tp.second.state |= STATE_RELEASING;
47 } else {
48 tp.second.state = STATE_RELEASED;
49 }
50 tp.second.x_prev = tp.second.x;
51 tp.second.y_prev = tp.second.y;
52 }
53 // The interrupt flag must be reset BEFORE calling update_touches, otherwise we might miss an interrupt that was
54 // triggered while we were reading touch data.
55 this->store_.touched = false;
56 this->update_touches();
57 if (this->skip_update_) {
58 for (auto &tp : this->touches_) {
59 tp.second.state &= ~STATE_RELEASING;
60 }
61 } else {
62 this->defer([this]() { this->send_touches_(); });
63 if (this->touch_timeout_ > 0) {
64 // Simulate a touch after <this->touch_timeout_> ms. This will reset any existing timeout operation.
65 // This is to detect touch release.
66 if (this->is_touched_) {
67 this->set_timeout(TAG, this->touch_timeout_, [this]() { this->store_.touched = true; });
68 } else {
69 this->cancel_timeout(TAG);
70 }
71 }
72 }
73 }
74}
75
76void Touchscreen::add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_raw, int16_t z_raw) {
77 TouchPoint tp;
78 uint16_t x, y;
79 if (this->swap_x_y_) {
80 std::swap(x_raw, y_raw);
81 }
82 if (this->touches_.count(id) == 0) {
83 tp.state = STATE_PRESSED;
84 tp.id = id;
85 } else {
86 tp = this->touches_[id];
87 tp.state = STATE_UPDATED;
88 tp.y_prev = tp.y;
89 tp.x_prev = tp.x;
90 }
91 tp.x_raw = x_raw;
92 tp.y_raw = y_raw;
93 tp.z_raw = z_raw;
94 if (this->x_raw_max_ != this->x_raw_min_ and this->y_raw_max_ != this->y_raw_min_) {
95 x = this->normalize_(x_raw, this->x_raw_min_, this->x_raw_max_, this->invert_x_);
96 y = this->normalize_(y_raw, this->y_raw_min_, this->y_raw_max_, this->invert_y_);
97
98 tp.x = (uint16_t) ((int) x * this->display_width_ / 0x1000);
99 tp.y = (uint16_t) ((int) y * this->display_height_ / 0x1000);
100 } else {
101 tp.state |= STATE_CALIBRATE;
102 }
103 if (tp.state == STATE_PRESSED) {
104 tp.x_org = tp.x;
105 tp.y_org = tp.y;
106 }
107
108 this->touches_[id] = tp;
109
110 this->is_touched_ = true;
111 if ((tp.x != tp.x_prev) || (tp.y != tp.y_prev)) {
112 this->need_update_ = true;
113 }
114}
115
117 TouchPoints_t touches;
118 ESP_LOGV(TAG, "Touch status: is_touched=%d, was_touched=%d", this->is_touched_, this->was_touched_);
119 for (auto tp : this->touches_) {
120 ESP_LOGV(TAG, "Touch status: %d/%d: raw:(%4d,%4d,%4d) calc:(%3d,%4d)", tp.second.id, tp.second.state,
121 tp.second.x_raw, tp.second.y_raw, tp.second.z_raw, tp.second.x, tp.second.y);
122 touches.push_back(tp.second);
123 }
124 if (this->need_update_ || (!this->is_touched_ && this->was_touched_)) {
125 this->update_trigger_.trigger(touches);
126 for (auto *listener : this->touch_listeners_) {
127 listener->update(touches);
128 }
129 }
130 if (!this->is_touched_) {
131 if (this->was_touched_) {
133 for (auto *listener : this->touch_listeners_)
134 listener->release();
135 this->touches_.clear();
136 }
137 } else {
138 if (this->first_touch_) {
139 TouchPoint tp = this->touches_.begin()->second;
140 this->touch_trigger_.trigger(tp, touches);
141 for (auto *listener : this->touch_listeners_) {
142 listener->touch(tp);
143 }
144 }
145 }
146 this->was_touched_ = this->is_touched_;
147}
148
149int16_t Touchscreen::normalize_(int16_t val, int16_t min_val, int16_t max_val, bool inverted) {
150 int16_t ret;
151
152 if (val <= min_val) {
153 ret = 0;
154 } else if (val >= max_val) {
155 ret = 0xfff;
156 } else {
157 ret = (int16_t) ((int) 0xfff * (val - min_val) / (max_val - min_val));
158 }
159
160 ret = (inverted) ? 0xfff - ret : ret;
161
162 return ret;
163}
164
165} // namespace touchscreen
166} // namespace esphome
bool cancel_timeout(const std::string &name)
Cancel a timeout function.
Definition component.cpp:76
void defer(const std::string &name, std::function< void()> &&f)
Defer a callback to the next loop() call.
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.cpp:72
void attach_interrupt(void(*func)(T *), T *arg, gpio::InterruptType type) const
Definition gpio.h:88
void call_setup() override
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
Definition automation.h:96
virtual int get_height()
Get the calculated height of the display in pixels with rotation applied.
Definition display.h:218
virtual int get_width()
Get the calculated width of the display in pixels with rotation applied.
Definition display.h:216
std::map< uint8_t, TouchPoint > touches_
int16_t normalize_(int16_t val, int16_t min_val, int16_t max_val, bool inverted=false)
void attach_interrupt_(InternalGPIOPin *irq_pin, esphome::gpio::InterruptType type)
Call this function to send touch points to the on_touch listener and the binary_sensors.
std::vector< TouchListener * > touch_listeners_
Trigger< const TouchPoints_t & > update_trigger_
Trigger< TouchPoint, const TouchPoints_t & > touch_trigger_
void add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_raw, int16_t z_raw=0)
uint8_t type
mopeka_std_values val[4]
const char *const TAG
Definition spi.cpp:8
std::vector< TouchPoint > TouchPoints_t
Definition touchscreen.h:30
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
T id(T value)
Helper function to make id(var) known from lambdas work in custom components.
Definition helpers.h:798
static void gpio_intr(TouchscreenInterrupt *store)
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6