diff --git a/esphome/components/pca9554/__init__.py b/esphome/components/pca9554/__init__.py index 8572486823..626b08a378 100644 --- a/esphome/components/pca9554/__init__.py +++ b/esphome/components/pca9554/__init__.py @@ -12,6 +12,7 @@ from esphome.const import ( ) CODEOWNERS = ["@hwstar", "@clydebarrow", "@bdraco"] +AUTO_LOAD = ["gpio_expander"] DEPENDENCIES = ["i2c"] MULTI_CONF = True CONF_PIN_COUNT = "pin_count" diff --git a/esphome/components/pca9554/pca9554.cpp b/esphome/components/pca9554/pca9554.cpp index 74be09a748..b0a12b6c45 100644 --- a/esphome/components/pca9554/pca9554.cpp +++ b/esphome/components/pca9554/pca9554.cpp @@ -38,8 +38,8 @@ void PCA9554Component::setup() { void PCA9554Component::loop() { // Invalidate the cache at the start of each loop. - // The actual read will happen on demand in digital_read() - this->cache_valid_ = false; + // The actual read will happen on demand when digital_read() is called + this->reset_pin_cache_(); } void PCA9554Component::dump_config() { @@ -53,15 +53,17 @@ void PCA9554Component::dump_config() { } } -bool PCA9554Component::digital_read(uint8_t pin) { - // Read the inputs once per loop on demand and cache the result - if (!this->cache_valid_ && this->read_inputs_()) { - this->cache_valid_ = true; - } +bool PCA9554Component::digital_read_hw(uint16_t pin) { + // Read all pins from hardware into input_mask_ + return this->read_inputs_(); // Return true if I2C read succeeded, false on error +} + +bool PCA9554Component::digital_read_cache(uint16_t pin) { + // Return the cached pin state from input_mask_ return this->input_mask_ & (1 << pin); } -void PCA9554Component::digital_write(uint8_t pin, bool value) { +void PCA9554Component::digital_write_hw(uint16_t pin, bool value) { if (value) { this->output_mask_ |= (1 << pin); } else { diff --git a/esphome/components/pca9554/pca9554.h b/esphome/components/pca9554/pca9554.h index 3fc4737a4f..dd5154f0a1 100644 --- a/esphome/components/pca9554/pca9554.h +++ b/esphome/components/pca9554/pca9554.h @@ -3,22 +3,21 @@ #include "esphome/core/component.h" #include "esphome/core/hal.h" #include "esphome/components/i2c/i2c.h" +#include "esphome/components/gpio_expander/cached_gpio.h" namespace esphome { namespace pca9554 { -class PCA9554Component : public Component, public i2c::I2CDevice { +class PCA9554Component : public Component, + public i2c::I2CDevice, + public gpio_expander::CachedGpioExpander { public: PCA9554Component() = default; /// Check i2c availability and setup masks void setup() override; - /// Poll for input changes periodically + /// Invalidate cache at start of each loop void loop() override; - /// Helper function to read the value of a pin. - bool digital_read(uint8_t pin); - /// Helper function to write the value of a pin. - void digital_write(uint8_t pin, bool value); /// Helper function to set the pin mode of a pin. void pin_mode(uint8_t pin, gpio::Flags flags); @@ -32,9 +31,13 @@ class PCA9554Component : public Component, public i2c::I2CDevice { protected: bool read_inputs_(); - bool write_register_(uint8_t reg, uint16_t value); + // Virtual methods from CachedGpioExpander + bool digital_read_hw(uint16_t pin) override; + bool digital_read_cache(uint16_t pin) override; + void digital_write_hw(uint16_t pin, bool value) override; + /// number of bits the expander has size_t pin_count_{8}; /// width of registers @@ -45,8 +48,6 @@ class PCA9554Component : public Component, public i2c::I2CDevice { uint16_t output_mask_{0x00}; /// The state of the actual input pin states - 1 means HIGH, 0 means LOW uint16_t input_mask_{0x00}; - /// Cache validity flag - true if we've read inputs this loop cycle - bool cache_valid_{false}; /// Storage for last I2C error seen esphome::i2c::ErrorCode last_error_; };