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/ble_client/* @buxtronix | ||||||
| esphome/components/bme680_bsec/* @trvrnrth | esphome/components/bme680_bsec/* @trvrnrth | ||||||
| esphome/components/canbus/* @danielschramm @mvturnho | esphome/components/canbus/* @danielschramm @mvturnho | ||||||
|  | esphome/components/cap1188/* @MrEditor97 | ||||||
| esphome/components/captive_portal/* @OttoWinter | esphome/components/captive_portal/* @OttoWinter | ||||||
| esphome/components/ccs811/* @habbie | esphome/components/ccs811/* @habbie | ||||||
| esphome/components/climate/* @esphome/core | 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: | display: | ||||||
|  |  | ||||||
|  | cap1188: | ||||||
|  |   id: cap1188_component | ||||||
|  |   address: 0x29 | ||||||
|  |   touch_threshold: 0x20 | ||||||
|  |   allow_multiple_touches: true | ||||||
|  |   reset_pin: 14 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user