From 48858198818e0712b56069f6ca073e04bc88ad50 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 4 Sep 2025 12:21:48 -0500 Subject: [PATCH] use helper --- esphome/components/pcf8574/__init__.py | 1 + esphome/components/pcf8574/pcf8574.cpp | 22 +++++++++++----------- esphome/components/pcf8574/pcf8574.h | 16 ++++++++++------ 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/esphome/components/pcf8574/__init__.py b/esphome/components/pcf8574/__init__.py index ff7c314bcd..f387d0a610 100644 --- a/esphome/components/pcf8574/__init__.py +++ b/esphome/components/pcf8574/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_OUTPUT, ) +AUTO_LOAD = ["gpio_expander"] DEPENDENCIES = ["i2c"] MULTI_CONF = True diff --git a/esphome/components/pcf8574/pcf8574.cpp b/esphome/components/pcf8574/pcf8574.cpp index a75f4f2256..67e84d6629 100644 --- a/esphome/components/pcf8574/pcf8574.cpp +++ b/esphome/components/pcf8574/pcf8574.cpp @@ -17,9 +17,8 @@ void PCF8574Component::setup() { this->read_gpio_(); } void PCF8574Component::loop() { - // Invalidate the cache at the start of each loop. - // The actual read will happen on demand in digital_read() - this->cache_valid_ = false; + // Invalidate the cache at the start of each loop + this->reset_pin_cache_(); } void PCF8574Component::dump_config() { ESP_LOGCONFIG(TAG, "PCF8574:"); @@ -29,20 +28,21 @@ void PCF8574Component::dump_config() { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); } } -bool PCF8574Component::digital_read(uint8_t pin) { - // Read the inputs once per loop on demand and cache the result - if (!this->cache_valid_ && this->read_gpio_()) { - this->cache_valid_ = true; - } - return this->input_mask_ & (1 << pin); +bool PCF8574Component::digital_read(uint8_t pin) { return this->get_pin_value_(pin); } + +bool PCF8574Component::digital_read_hw(uint8_t pin) { + return this->read_gpio_() ? (this->input_mask_ & (1 << pin)) : false; } -void PCF8574Component::digital_write(uint8_t pin, bool value) { + +bool PCF8574Component::digital_read_cache(uint8_t pin) { return this->input_mask_ & (1 << pin); } +void PCF8574Component::digital_write(uint8_t pin, bool value) { this->set_pin_value_(pin, value); } + +void PCF8574Component::digital_write_hw(uint8_t pin, bool value) { if (value) { this->output_mask_ |= (1 << pin); } else { this->output_mask_ &= ~(1 << pin); } - this->write_gpio_(); } void PCF8574Component::pin_mode(uint8_t pin, gpio::Flags flags) { diff --git a/esphome/components/pcf8574/pcf8574.h b/esphome/components/pcf8574/pcf8574.h index 41cb411f28..cb848060aa 100644 --- a/esphome/components/pcf8574/pcf8574.h +++ b/esphome/components/pcf8574/pcf8574.h @@ -3,11 +3,16 @@ #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 pcf8574 { -class PCF8574Component : public Component, public i2c::I2CDevice { +// PCF8574(8 pins)/PCF8575(16 pins) always read/write all pins in a single I2C transaction +// so we use uint16_t as bank type to ensure all pins are in one bank and cached together +class PCF8574Component : public Component, + public i2c::I2CDevice, + public gpio_expander::CachedGpioExpander { public: PCF8574Component() = default; @@ -17,8 +22,6 @@ class PCF8574Component : public Component, public i2c::I2CDevice { void setup() override; /// 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. @@ -30,8 +33,11 @@ class PCF8574Component : public Component, public i2c::I2CDevice { void dump_config() override; protected: - bool read_gpio_(); + 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; + bool read_gpio_(); bool write_gpio_(); /// Mask for the pin mode - 1 means output, 0 means input @@ -40,8 +46,6 @@ class PCF8574Component : public Component, public i2c::I2CDevice { uint16_t output_mask_{0x00}; /// The state read in read_gpio_ - 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}; bool pcf8575_; ///< TRUE->16-channel PCF8575, FALSE->8-channel PCF8574 };