diff --git a/esphome/components/sx1509/__init__.py b/esphome/components/sx1509/__init__.py index b61b92fd1e..5b904bb1a6 100644 --- a/esphome/components/sx1509/__init__.py +++ b/esphome/components/sx1509/__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, @@ -75,6 +76,7 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(SX1509Component), cv.Optional(CONF_KEYPAD): cv.Schema(KEYPAD_SCHEMA), + cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema, } ) .extend(cv.COMPONENT_SCHEMA) @@ -86,6 +88,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))) if conf := config.get(CONF_KEYPAD): cg.add(var.set_rows_cols(conf[CONF_KEY_ROWS], conf[CONF_KEY_COLUMNS])) if ( diff --git a/esphome/components/sx1509/sx1509.cpp b/esphome/components/sx1509/sx1509.cpp index 1cdae76eaf..0739fa1ef9 100644 --- a/esphome/components/sx1509/sx1509.cpp +++ b/esphome/components/sx1509/sx1509.cpp @@ -28,10 +28,23 @@ void SX1509Component::setup() { delayMicroseconds(500); if (this->has_keypad_) this->setup_keypad_(); + + if (this->interrupt_pin_ != nullptr) { + this->interrupt_pin_->setup(); + this->interrupt_pin_->attach_interrupt(&SX1509Component::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE); + this->set_invalidate_on_read_(false); + } + // Disable loop until an input pin is configured via pin_mode() + // or keypad is active. For interrupt-driven mode, loop is re-enabled by the ISR. + if (!this->has_keypad_) { + this->disable_loop(); + } } +void IRAM_ATTR SX1509Component::gpio_intr(SX1509Component *arg) { arg->enable_loop_soon_any_context(); } void SX1509Component::dump_config() { ESP_LOGCONFIG(TAG, "SX1509:"); + LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); if (this->is_failed()) { ESP_LOGE(TAG, "Setting up SX1509 failed!"); } @@ -41,6 +54,9 @@ void SX1509Component::dump_config() { void SX1509Component::loop() { // Reset cache at the start of each loop this->reset_pin_cache_(); + if (this->interrupt_pin_ != nullptr && !this->has_keypad_) { + this->disable_loop(); + } if (this->has_keypad_) { if (millis() - this->last_loop_timestamp_ < min_loop_period_) @@ -169,6 +185,9 @@ void SX1509Component::pin_mode(uint8_t pin, gpio::Flags flags) { // Set direction to input this->ddr_mask_ |= (1 << pin); this->write_byte_16(REG_DIR_B, this->ddr_mask_); + if (this->interrupt_pin_ == nullptr) { + this->enable_loop(); + } } } diff --git a/esphome/components/sx1509/sx1509.h b/esphome/components/sx1509/sx1509.h index f98fc0a44f..964a02dd52 100644 --- a/esphome/components/sx1509/sx1509.h +++ b/esphome/components/sx1509/sx1509.h @@ -46,6 +46,7 @@ class SX1509Component : public Component, uint16_t read_key_data(); void set_pin_value(uint8_t pin, uint8_t i_on) { this->write_byte(REG_I_ON[pin], i_on); }; void pin_mode(uint8_t pin, gpio::Flags flags); + void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } uint32_t get_clock() { return this->clk_x_; }; void set_rows_cols(uint8_t rows, uint8_t cols) { this->rows_ = rows; @@ -63,6 +64,8 @@ class SX1509Component : public Component, void setup_led_driver(uint8_t pin); protected: + static void IRAM_ATTR gpio_intr(SX1509Component *arg); + // Virtual methods from CachedGpioExpander bool digital_read_hw(uint8_t pin) override; bool digital_read_cache(uint8_t pin) override; @@ -85,6 +88,7 @@ class SX1509Component : public Component, std::vector keypad_binary_sensors_; std::vector key_triggers_; + InternalGPIOPin *interrupt_pin_{nullptr}; uint32_t last_loop_timestamp_ = 0; const uint32_t min_loop_period_ = 15; // ms diff --git a/tests/components/sx1509/common.yaml b/tests/components/sx1509/common.yaml index cf7e234f09..7bcd565864 100644 --- a/tests/components/sx1509/common.yaml +++ b/tests/components/sx1509/common.yaml @@ -2,6 +2,7 @@ sx1509: - id: sx1509_hub i2c_id: i2c_bus address: 0x3E + interrupt_pin: ${interrupt_pin} keypad: key_rows: 2 key_columns: 2 diff --git a/tests/components/sx1509/test.esp32-idf.yaml b/tests/components/sx1509/test.esp32-idf.yaml index b47e39c389..8c3b341dce 100644 --- a/tests/components/sx1509/test.esp32-idf.yaml +++ b/tests/components/sx1509/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/sx1509/test.esp8266-ard.yaml b/tests/components/sx1509/test.esp8266-ard.yaml index 4a98b9388a..69b243bfd8 100644 --- a/tests/components/sx1509/test.esp8266-ard.yaml +++ b/tests/components/sx1509/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/sx1509/test.rp2040-ard.yaml b/tests/components/sx1509/test.rp2040-ard.yaml index 319a7c71a6..b8ad1e4792 100644 --- a/tests/components/sx1509/test.rp2040-ard.yaml +++ b/tests/components/sx1509/test.rp2040-ard.yaml @@ -1,3 +1,6 @@ +substitutions: + interrupt_pin: GPIO2 + packages: i2c: !include ../../test_build_components/common/i2c/rp2040-ard.yaml