[ns2009] Add Nsiway NS2009 touchscreen controller component (#10597)

Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
tchilov
2026-10-12 12:49:07 -10:00
committed by GitHub
co-authored by J. Nick Koston pre-commit-ci-lite[bot] J. Nick Koston
parent f9f41ef16e
commit 1c315c3bf2
9 changed files with 185 additions and 0 deletions
+2
View File
@@ -413,6 +413,8 @@ esphome/components/noblex/* @AGalfra
esphome/components/noise/* @esphome/core
esphome/components/npi19/* @bakerkj
esphome/components/nrf52/* @tomaszduda23
esphome/components/ns2009/* @tchilov
esphome/components/ns2009/touchscreen/* @tchilov
esphome/components/number/* @esphome/core
esphome/components/one_wire/* @ssieb
esphome/components/online_image/* @clydebarrow @guillempages
+8
View File
@@ -0,0 +1,8 @@
import esphome.config_validation as cv
CODEOWNERS = ["@tchilov"]
DOMAIN = "ns2009"
CONFIG_SCHEMA = cv.invalid(
"This component should be used as platform of the Touchscreen component."
)
@@ -0,0 +1,34 @@
import esphome.codegen as cg
from esphome.components import i2c, touchscreen
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_THRESHOLD
from esphome.types import ConfigType
CODEOWNERS = ["@tchilov"]
DEPENDENCIES = ["i2c"]
ns2009_ns = cg.esphome_ns.namespace("ns2009")
NS2009Component = ns2009_ns.class_(
"NS2009Component",
touchscreen.Touchscreen,
i2c.I2CDevice,
)
CONFIG_SCHEMA = (
touchscreen.touchscreen_schema(calibration_required=True)
.extend(
{
cv.GenerateID(): cv.declare_id(NS2009Component),
cv.Optional(CONF_THRESHOLD, default=40): cv.uint8_t,
}
)
.extend(i2c.i2c_device_schema(0x48))
)
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await i2c.register_i2c_device(var, config)
await touchscreen.register_touchscreen(var, config)
cg.add(var.set_threshold(config[CONF_THRESHOLD]))
@@ -0,0 +1,65 @@
#include "ns2009.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::ns2009 {
ESPHOME_LOG_TAG(TAG, "ns2009");
static constexpr uint8_t GET_X = 0xC0;
static constexpr uint8_t GET_Y = 0xD0;
static constexpr uint8_t GET_Z = 0xE2;
void NS2009Component::setup() {
if (!this->read_byte(GET_Z).has_value()) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
}
}
void NS2009Component::update_touches() {
auto data_z = this->read_byte(GET_Z);
if (!data_z.has_value()) {
ESP_LOGW(TAG, "failed to read %s, skipping update", LOG_STR_LITERAL("pressure"));
this->skip_update_ = true;
return;
}
uint8_t z = *data_z;
if (z <= this->threshold_) {
return;
}
auto x = this->read_axis_(GET_X);
if (!x.has_value()) {
ESP_LOGW(TAG, "failed to read %s, skipping update", LOG_STR_LITERAL("X position"));
this->skip_update_ = true;
return;
}
auto y = this->read_axis_(GET_Y);
if (!y.has_value()) {
ESP_LOGW(TAG, "failed to read %s, skipping update", LOG_STR_LITERAL("Y position"));
this->skip_update_ = true;
return;
}
ESP_LOGV(TAG, "X %4d Y %4d Z %3d", *x, *y, z);
this->add_raw_touch_position_(0, *x, *y, z);
}
optional<uint16_t> NS2009Component::read_axis_(uint8_t cmd) {
auto data = this->read_bytes<2>(cmd);
if (!data.has_value()) {
return {};
}
return encode_uint16((*data)[0], (*data)[1]) >> 4; // 12 bit followed by 4 0's
}
void NS2009Component::dump_config() {
ESP_LOGCONFIG(TAG,
"NS2009 Touchscreen:\n"
" Threshold: %u",
this->threshold_);
LOG_I2C_DEVICE(this);
}
} // namespace esphome::ns2009
@@ -0,0 +1,25 @@
#pragma once
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/touchscreen/touchscreen.h"
namespace esphome::ns2009 {
class NS2009Component : public touchscreen::Touchscreen, public i2c::I2CDevice {
public:
/// Set the threshold for the touch detection.
void set_threshold(uint8_t threshold) { this->threshold_ = threshold; }
void setup() override;
void dump_config() override;
protected:
void update_touches() override;
/// Read a 12 bit axis value, or nothing when the read fails
optional<uint16_t> read_axis_(uint8_t cmd);
/// @brief The threshold at which a touch is registered.
uint8_t threshold_{40};
};
} // namespace esphome::ns2009
+27
View File
@@ -0,0 +1,27 @@
display:
- platform: mipi_spi
model: ILI9341
id: ns_display
dc_pin: ${dc_pin}
cs_pin: ${cs_pin}
color_depth: 8
invert_colors: false
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
touchscreen:
- platform: ns2009
id: ns_touchscreen
i2c_id: i2c_bus
display: ns_display
transform:
mirror_y: true
calibration:
x_min: 400
x_max: 3700
y_min: 300
y_max: 3700
on_touch:
- logger.log:
format: Touch at (%d, %d)
args: [touch.x, touch.y]
@@ -0,0 +1,8 @@
substitutions:
dc_pin: GPIO15
cs_pin: GPIO5
packages:
spi: !include ../../test_build_components/common/spi/esp32-idf.yaml
i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml
ns2009: !include common.yaml
@@ -0,0 +1,8 @@
substitutions:
dc_pin: GPIO3
cs_pin: GPIO1
packages:
spi: !include ../../test_build_components/common/spi/esp8266-ard.yaml
i2c: !include ../../test_build_components/common/i2c/esp8266-ard.yaml
ns2009: !include common.yaml
@@ -0,0 +1,8 @@
substitutions:
dc_pin: GPIO3
cs_pin: GPIO1
packages:
spi: !include ../../test_build_components/common/spi/rp2040-ard.yaml
i2c: !include ../../test_build_components/common/i2c/rp2040-ard.yaml
ns2009: !include common.yaml