1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-25 21:23:53 +01:00
Files
esphome/esphome/components/touchscreen/__init__.py

159 lines
5.1 KiB
Python

from esphome import automation
import esphome.codegen as cg
from esphome.components import display
import esphome.config_validation as cv
from esphome.const import (
CONF_CALIBRATION,
CONF_DISPLAY,
CONF_MIRROR_X,
CONF_MIRROR_Y,
CONF_ON_RELEASE,
CONF_ON_TOUCH,
CONF_ON_UPDATE,
CONF_SWAP_XY,
CONF_TRANSFORM,
)
from esphome.core import CoroPriority, coroutine_with_priority
CODEOWNERS = ["@jesserockz", "@nielsnl68"]
DEPENDENCIES = ["display"]
IS_PLATFORM_COMPONENT = True
touchscreen_ns = cg.esphome_ns.namespace("touchscreen")
Touchscreen = touchscreen_ns.class_("Touchscreen", cg.PollingComponent)
TouchRotation = touchscreen_ns.enum("TouchRotation")
TouchPoint = touchscreen_ns.struct("TouchPoint")
TouchPoints_t = cg.std_vector.template(TouchPoint)
TouchPoints_t_const_ref = TouchPoints_t.operator("ref").operator("const")
TouchListener = touchscreen_ns.class_("TouchListener")
CONF_TOUCHSCREEN_ID = "touchscreen_id"
CONF_REPORT_INTERVAL = "report_interval" # not used yet:
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(calibration_config):
x_min = calibration_config[CONF_X_MIN]
x_max = calibration_config[CONF_X_MAX]
y_min = calibration_config[CONF_Y_MIN]
y_max = calibration_config[CONF_Y_MAX]
if x_max < x_min:
raise cv.Invalid(
"x_min must be smaller than x_max. To mirror the direction use the 'transform' options"
)
if y_max < y_min:
raise cv.Invalid(
"y_min must be smaller than y_max. To mirror the direction use the 'transform' options"
)
x_delta = x_max - x_min
y_delta = y_max - y_min
if x_delta < 10 or y_delta < 10:
raise cv.Invalid("Calibration value range must be greater than 10")
return calibration_config
CALIBRATION_SCHEMA = cv.All(
cv.Schema(
{
cv.Required(CONF_X_MIN): cv.int_range(min=0, max=4095),
cv.Required(CONF_X_MAX): cv.int_range(min=0, max=4095),
cv.Required(CONF_Y_MIN): cv.int_range(min=0, max=4095),
cv.Required(CONF_Y_MAX): cv.int_range(min=0, max=4095),
}
),
validate_calibration,
)
def touchscreen_schema(default_touch_timeout=cv.UNDEFINED, calibration_required=False):
calibration = (
cv.Required(CONF_CALIBRATION)
if calibration_required
else cv.Optional(CONF_CALIBRATION)
)
return cv.Schema(
{
cv.GenerateID(CONF_DISPLAY): cv.use_id(display.Display),
cv.Optional(CONF_TRANSFORM): cv.Schema(
{
cv.Optional(CONF_SWAP_XY, default=False): cv.boolean,
cv.Optional(CONF_MIRROR_X, default=False): cv.boolean,
cv.Optional(CONF_MIRROR_Y, default=False): cv.boolean,
}
),
cv.Optional(CONF_TOUCH_TIMEOUT, default=default_touch_timeout): cv.All(
cv.positive_time_period_milliseconds,
cv.Range(max=cv.TimePeriod(milliseconds=65535)),
),
calibration: CALIBRATION_SCHEMA,
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),
}
).extend(cv.polling_component_schema("50ms"))
TOUCHSCREEN_SCHEMA = touchscreen_schema(cv.UNDEFINED)
async def register_touchscreen(var, config):
await cg.register_component(var, config)
disp = await cg.get_variable(config[CONF_DISPLAY])
cg.add(var.set_display(disp))
if CONF_TOUCH_TIMEOUT in config:
cg.add(var.set_touch_timeout(config[CONF_TOUCH_TIMEOUT]))
if CONF_TRANSFORM in config:
transform = config[CONF_TRANSFORM]
cg.add(var.set_swap_xy(transform[CONF_SWAP_XY]))
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(),
[(TouchPoint, "touch"), (TouchPoints_t_const_ref, "touches")],
config[CONF_ON_TOUCH],
)
if CONF_ON_UPDATE in config:
await automation.build_automation(
var.get_update_trigger(),
[(TouchPoints_t_const_ref, "touches")],
config[CONF_ON_UPDATE],
)
if CONF_ON_RELEASE in config:
await automation.build_automation(
var.get_release_trigger(),
[],
config[CONF_ON_RELEASE],
)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(touchscreen_ns.using)
cg.add_define("USE_TOUCHSCREEN")