mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	CAP1188 Capacitive Touch Sensor Support (#2653)
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
							
								
								
									
										45
									
								
								esphome/components/cap1188/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								esphome/components/cap1188/__init__.py
									
									
									
									
									
										Normal 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) | ||||
							
								
								
									
										25
									
								
								esphome/components/cap1188/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								esphome/components/cap1188/binary_sensor.py
									
									
									
									
									
										Normal 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)) | ||||
							
								
								
									
										88
									
								
								esphome/components/cap1188/cap1188.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								esphome/components/cap1188/cap1188.cpp
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										68
									
								
								esphome/components/cap1188/cap1188.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								esphome/components/cap1188/cap1188.h
									
									
									
									
									
										Normal 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 | ||||
| @@ -504,3 +504,9 @@ interval: | ||||
|  | ||||
| display: | ||||
|  | ||||
| cap1188: | ||||
|   id: cap1188_component | ||||
|   address: 0x29 | ||||
|   touch_threshold: 0x20 | ||||
|   allow_multiple_touches: true | ||||
|   reset_pin: 14 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user