From 1e9e5ca763a4802f3aa310bf788e8fbd2fa0dca1 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 4 Apr 2026 10:05:00 -1000 Subject: [PATCH] Fix pin_interrupt_mode overriding auto-enabled CHANGE interrupt MCP23XXXGPIOPin::setup() calls pin_interrupt_mode(pin, NO_INTERRUPT) after pin_mode() already auto-enabled CHANGE, undoing the auto-enable. Skip the explicit pin_interrupt_mode call when interrupt_pin is configured and the user didn't override the default. --- esphome/components/mcp23xxx_base/mcp23xxx_base.cpp | 7 ++++++- esphome/components/mcp23xxx_base/mcp23xxx_base.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/esphome/components/mcp23xxx_base/mcp23xxx_base.cpp b/esphome/components/mcp23xxx_base/mcp23xxx_base.cpp index 535119fc5c..4c1daac562 100644 --- a/esphome/components/mcp23xxx_base/mcp23xxx_base.cpp +++ b/esphome/components/mcp23xxx_base/mcp23xxx_base.cpp @@ -7,7 +7,12 @@ namespace mcp23xxx_base { template void MCP23XXXGPIOPin::setup() { this->pin_mode(flags_); - this->parent_->pin_interrupt_mode(this->pin_, this->interrupt_mode_); + // When interrupt_pin is configured, pin_mode() already auto-enables CHANGE + // interrupt for input pins, so skip the explicit call if the user didn't + // override the default (NO_INTERRUPT) + if (this->interrupt_mode_ != MCP23XXX_NO_INTERRUPT || this->parent_->get_interrupt_pin() == nullptr) { + this->parent_->pin_interrupt_mode(this->pin_, this->interrupt_mode_); + } } template void MCP23XXXGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } template bool MCP23XXXGPIOPin::digital_read() { diff --git a/esphome/components/mcp23xxx_base/mcp23xxx_base.h b/esphome/components/mcp23xxx_base/mcp23xxx_base.h index 7838e30127..5e2d9e9c68 100644 --- a/esphome/components/mcp23xxx_base/mcp23xxx_base.h +++ b/esphome/components/mcp23xxx_base/mcp23xxx_base.h @@ -16,6 +16,7 @@ template class MCP23XXXBase : public Component, public gpio_expander: void set_open_drain_ints(const bool value) { this->open_drain_ints_ = value; } void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } + InternalGPIOPin *get_interrupt_pin() const { return this->interrupt_pin_; } float get_setup_priority() const override { return setup_priority::IO; } void loop() override {