CAP1188 Capacitive Touch Sensor Support (#2653)

This commit is contained in:
Sam Hughes 2021-11-10 17:52:49 +00:00 committed by GitHub
parent 662773b075
commit 710866ff4e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 233 additions and 0 deletions

View file

@ -31,6 +31,7 @@ esphome/components/binary_sensor/* @esphome/core
esphome/components/ble_client/* @buxtronix
esphome/components/bme680_bsec/* @trvrnrth
esphome/components/canbus/* @danielschramm @mvturnho
esphome/components/cap1188/* @MrEditor97
esphome/components/captive_portal/* @OttoWinter
esphome/components/ccs811/* @habbie
esphome/components/climate/* @esphome/core

View file

@ -0,0 +1,45 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c
from esphome.const import CONF_ID, CONF_RESET_PIN
from esphome import pins
CONF_TOUCH_THRESHOLD = "touch_threshold"
CONF_ALLOW_MULTIPLE_TOUCHES = "allow_multiple_touches"
DEPENDENCIES = ["i2c"]
AUTO_LOAD = ["binary_sensor", "output"]
CODEOWNERS = ["@MrEditor97"]
cap1188_ns = cg.esphome_ns.namespace("cap1188")
CONF_CAP1188_ID = "cap1188_id"
CAP1188Component = cap1188_ns.class_("CAP1188Component", cg.Component, i2c.I2CDevice)
MULTI_CONF = True
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(CAP1188Component),
cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_TOUCH_THRESHOLD, default=0x20): cv.int_range(
min=0x01, max=0x80
),
cv.Optional(CONF_ALLOW_MULTIPLE_TOUCHES, default=False): cv.boolean,
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x29))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_touch_threshold(config[CONF_TOUCH_THRESHOLD]))
cg.add(var.set_allow_multiple_touches(config[CONF_ALLOW_MULTIPLE_TOUCHES]))
if CONF_RESET_PIN in config:
pin = await cg.gpio_pin_expression(config[CONF_RESET_PIN])
cg.add(var.set_reset_pin(pin))
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)

View file

@ -0,0 +1,25 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor
from esphome.const import CONF_CHANNEL, CONF_ID
from . import cap1188_ns, CAP1188Component, CONF_CAP1188_ID
DEPENDENCIES = ["cap1188"]
CAP1188Channel = cap1188_ns.class_("CAP1188Channel", binary_sensor.BinarySensor)
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(CAP1188Channel),
cv.GenerateID(CONF_CAP1188_ID): cv.use_id(CAP1188Component),
cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7),
}
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await binary_sensor.register_binary_sensor(var, config)
hub = await cg.get_variable(config[CONF_CAP1188_ID])
cg.add(var.set_channel(config[CONF_CHANNEL]))
cg.add(hub.register_channel(var))

View file

@ -0,0 +1,88 @@
#include "cap1188.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace cap1188 {
static const char *const TAG = "cap1188";
void CAP1188Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up CAP1188...");
// Reset device using the reset pin
if (this->reset_pin_ != nullptr) {
this->reset_pin_->setup();
this->reset_pin_->digital_write(false);
delay(100); // NOLINT
this->reset_pin_->digital_write(true);
delay(100); // NOLINT
this->reset_pin_->digital_write(false);
delay(100); // NOLINT
}
// Check if CAP1188 is actually connected
this->read_byte(CAP1188_PRODUCT_ID, &this->cap1188_product_id_);
this->read_byte(CAP1188_MANUFACTURE_ID, &this->cap1188_manufacture_id_);
this->read_byte(CAP1188_REVISION, &this->cap1188_revision_);
if ((this->cap1188_product_id_ != 0x50) || (this->cap1188_manufacture_id_ != 0x5D)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
// Set sensitivity
uint8_t sensitivity = 0;
this->read_byte(CAP1188_SENSITVITY, &sensitivity);
sensitivity = sensitivity & 0x0f;
this->write_byte(CAP1188_SENSITVITY, sensitivity | this->touch_threshold_);
// Allow multiple touches
this->write_byte(CAP1188_MULTI_TOUCH, this->allow_multiple_touches_);
// Have LEDs follow touches
this->write_byte(CAP1188_LED_LINK, 0xFF);
// Speed up a bit
this->write_byte(CAP1188_STAND_BY_CONFIGURATION, 0x30);
}
void CAP1188Component::dump_config() {
ESP_LOGCONFIG(TAG, "CAP1188:");
LOG_I2C_DEVICE(this);
LOG_PIN(" Reset Pin: ", this->reset_pin_);
ESP_LOGCONFIG(TAG, " Product ID: 0x%x", this->cap1188_product_id_);
ESP_LOGCONFIG(TAG, " Manufacture ID: 0x%x", this->cap1188_manufacture_id_);
ESP_LOGCONFIG(TAG, " Revision ID: 0x%x", this->cap1188_revision_);
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, "Product ID or Manufacture ID of the connected device does not match a known CAP1188.");
break;
case NONE:
default:
break;
}
}
void CAP1188Component::loop() {
uint8_t touched = 0;
this->read_register(CAP1188_SENSOR_INPUT_STATUS, &touched, 1);
if (touched) {
uint8_t data = 0;
this->read_register(CAP1188_MAIN, &data, 1);
data = data & ~CAP1188_MAIN_INT;
this->write_register(CAP1188_MAIN, &data, 2);
}
for (auto *channel : this->channels_) {
channel->process(touched);
}
}
} // namespace cap1188
} // namespace esphome

View file

@ -0,0 +1,68 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/output/binary_output.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
namespace esphome {
namespace cap1188 {
enum {
CAP1188_I2CADDR = 0x29,
CAP1188_SENSOR_INPUT_STATUS = 0x3,
CAP1188_MULTI_TOUCH = 0x2A,
CAP1188_LED_LINK = 0x72,
CAP1188_PRODUCT_ID = 0xFD,
CAP1188_MANUFACTURE_ID = 0xFE,
CAP1188_STAND_BY_CONFIGURATION = 0x41,
CAP1188_REVISION = 0xFF,
CAP1188_MAIN = 0x00,
CAP1188_MAIN_INT = 0x01,
CAP1188_LEDPOL = 0x73,
CAP1188_INTERUPT_REPEAT = 0x28,
CAP1188_SENSITVITY = 0x1f,
};
class CAP1188Channel : public binary_sensor::BinarySensor {
public:
void set_channel(uint8_t channel) { channel_ = channel; }
void process(uint8_t data) { this->publish_state(static_cast<bool>(data & (1 << this->channel_))); }
protected:
uint8_t channel_{0};
};
class CAP1188Component : public Component, public i2c::I2CDevice {
public:
void register_channel(CAP1188Channel *channel) { this->channels_.push_back(channel); }
void set_touch_threshold(uint8_t touch_threshold) { this->touch_threshold_ = touch_threshold; };
void set_allow_multiple_touches(bool allow_multiple_touches) {
this->allow_multiple_touches_ = allow_multiple_touches ? 0x41 : 0x80;
};
void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void loop() override;
protected:
std::vector<CAP1188Channel *> channels_{};
uint8_t touch_threshold_{0x20};
uint8_t allow_multiple_touches_{0x80};
GPIOPin *reset_pin_{nullptr};
uint8_t cap1188_product_id_{0};
uint8_t cap1188_manufacture_id_{0};
uint8_t cap1188_revision_{0};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,
} error_code_{NONE};
};
} // namespace cap1188
} // namespace esphome

View file

@ -504,3 +504,9 @@ interval:
display:
cap1188:
id: cap1188_component
address: 0x29
touch_threshold: 0x20
allow_multiple_touches: true
reset_pin: 14