diff --git a/esphome/components/tca9555/__init__.py b/esphome/components/tca9555/__init__.py index f42e0fe398..5f571fcea6 100644 --- a/esphome/components/tca9555/__init__.py +++ b/esphome/components/tca9555/__init__.py @@ -5,6 +5,7 @@ import esphome.config_validation as cv from esphome.const import ( CONF_ID, CONF_INPUT, + CONF_INTERRUPT_PIN, CONF_INVERTED, CONF_MODE, CONF_NUMBER, @@ -27,6 +28,7 @@ CONFIG_SCHEMA = ( cv.Schema( { cv.Required(CONF_ID): cv.declare_id(TCA9555Component), + cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema, } ) .extend(cv.COMPONENT_SCHEMA) @@ -38,6 +40,8 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) + if interrupt_pin := config.get(CONF_INTERRUPT_PIN): + cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) def validate_mode(value): diff --git a/esphome/components/tca9555/tca9555.cpp b/esphome/components/tca9555/tca9555.cpp index 79c5253898..3eb794df44 100644 --- a/esphome/components/tca9555/tca9555.cpp +++ b/esphome/components/tca9555/tca9555.cpp @@ -24,9 +24,18 @@ void TCA9555Component::setup() { this->mark_failed(); return; } + + if (this->interrupt_pin_ != nullptr) { + this->interrupt_pin_->setup(); + this->interrupt_pin_->attach_interrupt(&TCA9555Component::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE); + this->set_invalidate_on_read_(false); + } + this->disable_loop(); } +void IRAM_ATTR TCA9555Component::gpio_intr(TCA9555Component *arg) { arg->enable_loop_soon_any_context(); } void TCA9555Component::dump_config() { ESP_LOGCONFIG(TAG, "TCA9555:"); + LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); LOG_I2C_DEVICE(this) if (this->is_failed()) { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); @@ -36,6 +45,9 @@ void TCA9555Component::pin_mode(uint8_t pin, gpio::Flags flags) { if (flags == gpio::FLAG_INPUT) { // Set mode mask bit this->mode_mask_ |= 1 << pin; + if (this->interrupt_pin_ == nullptr) { + this->enable_loop(); + } } else if (flags == gpio::FLAG_OUTPUT) { // Clear mode mask bit this->mode_mask_ &= ~(1 << pin); @@ -43,7 +55,12 @@ void TCA9555Component::pin_mode(uint8_t pin, gpio::Flags flags) { // Write GPIO to enable input mode this->write_gpio_modes_(); } -void TCA9555Component::loop() { this->reset_pin_cache_(); } +void TCA9555Component::loop() { + this->reset_pin_cache_(); + if (this->interrupt_pin_ != nullptr) { + this->disable_loop(); + } +} bool TCA9555Component::read_gpio_outputs_() { if (this->is_failed()) diff --git a/esphome/components/tca9555/tca9555.h b/esphome/components/tca9555/tca9555.h index 9f7273b1e7..d4d070013c 100644 --- a/esphome/components/tca9555/tca9555.h +++ b/esphome/components/tca9555/tca9555.h @@ -24,7 +24,10 @@ class TCA9555Component : public Component, void loop() override; + void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } + protected: + static void IRAM_ATTR gpio_intr(TCA9555Component *arg); bool digital_read_hw(uint8_t pin) override; bool digital_read_cache(uint8_t pin) override; void digital_write_hw(uint8_t pin, bool value) override; @@ -39,6 +42,8 @@ class TCA9555Component : public Component, bool read_gpio_modes_(); bool write_gpio_modes_(); bool read_gpio_outputs_(); + + InternalGPIOPin *interrupt_pin_{nullptr}; }; /// Helper class to expose a TCA9555 pin as an internal input GPIO pin. diff --git a/tests/components/tca9555/common.yaml b/tests/components/tca9555/common.yaml index 82b4c959d8..d1a68c575a 100644 --- a/tests/components/tca9555/common.yaml +++ b/tests/components/tca9555/common.yaml @@ -2,6 +2,10 @@ tca9555: - id: tca9555_hub i2c_id: i2c_bus address: 0x21 + - id: tca9555_hub_int + i2c_id: i2c_bus + address: 0x22 + interrupt_pin: ${interrupt_pin} binary_sensor: - platform: gpio diff --git a/tests/components/tca9555/test.esp32-idf.yaml b/tests/components/tca9555/test.esp32-idf.yaml index b47e39c389..8c3b341dce 100644 --- a/tests/components/tca9555/test.esp32-idf.yaml +++ b/tests/components/tca9555/test.esp32-idf.yaml @@ -1,3 +1,6 @@ +substitutions: + interrupt_pin: GPIO15 + packages: i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml diff --git a/tests/components/tca9555/test.esp8266-ard.yaml b/tests/components/tca9555/test.esp8266-ard.yaml index 4a98b9388a..69b243bfd8 100644 --- a/tests/components/tca9555/test.esp8266-ard.yaml +++ b/tests/components/tca9555/test.esp8266-ard.yaml @@ -1,3 +1,6 @@ +substitutions: + interrupt_pin: GPIO15 + packages: i2c: !include ../../test_build_components/common/i2c/esp8266-ard.yaml diff --git a/tests/components/tca9555/test.rp2040-ard.yaml b/tests/components/tca9555/test.rp2040-ard.yaml index 319a7c71a6..b8ad1e4792 100644 --- a/tests/components/tca9555/test.rp2040-ard.yaml +++ b/tests/components/tca9555/test.rp2040-ard.yaml @@ -1,3 +1,6 @@ +substitutions: + interrupt_pin: GPIO2 + packages: i2c: !include ../../test_build_components/common/i2c/rp2040-ard.yaml