mirror of
https://github.com/esphome/esphome.git
synced 2025-10-01 09:32:21 +01:00
[pca9554] Migrate to CachedGpioExpander to reduce I2C bus usage (#10571)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
@@ -342,7 +342,7 @@ esphome/components/ota/* @esphome/core
|
|||||||
esphome/components/output/* @esphome/core
|
esphome/components/output/* @esphome/core
|
||||||
esphome/components/packet_transport/* @clydebarrow
|
esphome/components/packet_transport/* @clydebarrow
|
||||||
esphome/components/pca6416a/* @Mat931
|
esphome/components/pca6416a/* @Mat931
|
||||||
esphome/components/pca9554/* @clydebarrow @hwstar
|
esphome/components/pca9554/* @bdraco @clydebarrow @hwstar
|
||||||
esphome/components/pcf85063/* @brogon
|
esphome/components/pcf85063/* @brogon
|
||||||
esphome/components/pcf8563/* @KoenBreeman
|
esphome/components/pcf8563/* @KoenBreeman
|
||||||
esphome/components/pi4ioe5v6408/* @jesserockz
|
esphome/components/pi4ioe5v6408/* @jesserockz
|
||||||
|
@@ -11,7 +11,8 @@ from esphome.const import (
|
|||||||
CONF_OUTPUT,
|
CONF_OUTPUT,
|
||||||
)
|
)
|
||||||
|
|
||||||
CODEOWNERS = ["@hwstar", "@clydebarrow"]
|
CODEOWNERS = ["@hwstar", "@clydebarrow", "@bdraco"]
|
||||||
|
AUTO_LOAD = ["gpio_expander"]
|
||||||
DEPENDENCIES = ["i2c"]
|
DEPENDENCIES = ["i2c"]
|
||||||
MULTI_CONF = True
|
MULTI_CONF = True
|
||||||
CONF_PIN_COUNT = "pin_count"
|
CONF_PIN_COUNT = "pin_count"
|
||||||
|
@@ -37,10 +37,9 @@ void PCA9554Component::setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PCA9554Component::loop() {
|
void PCA9554Component::loop() {
|
||||||
// The read_inputs_() method will cache the input values from the chip.
|
// Invalidate the cache at the start of each loop.
|
||||||
this->read_inputs_();
|
// The actual read will happen on demand when digital_read() is called
|
||||||
// Clear all the previously read flags.
|
this->reset_pin_cache_();
|
||||||
this->was_previously_read_ = 0x00;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCA9554Component::dump_config() {
|
void PCA9554Component::dump_config() {
|
||||||
@@ -54,21 +53,17 @@ void PCA9554Component::dump_config() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PCA9554Component::digital_read(uint8_t pin) {
|
bool PCA9554Component::digital_read_hw(uint8_t pin) {
|
||||||
// Note: We want to try and avoid doing any I2C bus read transactions here
|
// Read all pins from hardware into input_mask_
|
||||||
// to conserve I2C bus bandwidth. So what we do is check to see if we
|
return this->read_inputs_(); // Return true if I2C read succeeded, false on error
|
||||||
// have seen a read during the time esphome is running this loop. If we have,
|
}
|
||||||
// we do an I2C bus transaction to get the latest value. If we haven't
|
|
||||||
// we return a cached value which was read at the time loop() was called.
|
bool PCA9554Component::digital_read_cache(uint8_t pin) {
|
||||||
if (this->was_previously_read_ & (1 << pin))
|
// Return the cached pin state from input_mask_
|
||||||
this->read_inputs_(); // Force a read of a new value
|
|
||||||
// Indicate we saw a read request for this pin in case a
|
|
||||||
// read happens later in the same loop.
|
|
||||||
this->was_previously_read_ |= (1 << pin);
|
|
||||||
return this->input_mask_ & (1 << pin);
|
return this->input_mask_ & (1 << pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCA9554Component::digital_write(uint8_t pin, bool value) {
|
void PCA9554Component::digital_write_hw(uint8_t pin, bool value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
this->output_mask_ |= (1 << pin);
|
this->output_mask_ |= (1 << pin);
|
||||||
} else {
|
} else {
|
||||||
@@ -127,8 +122,7 @@ bool PCA9554Component::write_register_(uint8_t reg, uint16_t value) {
|
|||||||
|
|
||||||
float PCA9554Component::get_setup_priority() const { return setup_priority::IO; }
|
float PCA9554Component::get_setup_priority() const { return setup_priority::IO; }
|
||||||
|
|
||||||
// Run our loop() method very early in the loop, so that we cache read values before
|
// Run our loop() method early to invalidate cache before any other components access the pins
|
||||||
// before other components call our digital_read() method.
|
|
||||||
float PCA9554Component::get_loop_priority() const { return 9.0f; } // Just after WIFI
|
float PCA9554Component::get_loop_priority() const { return 9.0f; } // Just after WIFI
|
||||||
|
|
||||||
void PCA9554GPIOPin::setup() { pin_mode(flags_); }
|
void PCA9554GPIOPin::setup() { pin_mode(flags_); }
|
||||||
|
@@ -3,22 +3,21 @@
|
|||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/components/i2c/i2c.h"
|
#include "esphome/components/i2c/i2c.h"
|
||||||
|
#include "esphome/components/gpio_expander/cached_gpio.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace pca9554 {
|
namespace pca9554 {
|
||||||
|
|
||||||
class PCA9554Component : public Component, public i2c::I2CDevice {
|
class PCA9554Component : public Component,
|
||||||
|
public i2c::I2CDevice,
|
||||||
|
public gpio_expander::CachedGpioExpander<uint16_t, 16> {
|
||||||
public:
|
public:
|
||||||
PCA9554Component() = default;
|
PCA9554Component() = default;
|
||||||
|
|
||||||
/// Check i2c availability and setup masks
|
/// Check i2c availability and setup masks
|
||||||
void setup() override;
|
void setup() override;
|
||||||
/// Poll for input changes periodically
|
/// Invalidate cache at start of each loop
|
||||||
void loop() override;
|
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.
|
/// Helper function to set the pin mode of a pin.
|
||||||
void pin_mode(uint8_t pin, gpio::Flags flags);
|
void pin_mode(uint8_t pin, gpio::Flags flags);
|
||||||
|
|
||||||
@@ -32,9 +31,13 @@ class PCA9554Component : public Component, public i2c::I2CDevice {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool read_inputs_();
|
bool read_inputs_();
|
||||||
|
|
||||||
bool write_register_(uint8_t reg, uint16_t value);
|
bool write_register_(uint8_t reg, uint16_t value);
|
||||||
|
|
||||||
|
// Virtual methods from CachedGpioExpander
|
||||||
|
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;
|
||||||
|
|
||||||
/// number of bits the expander has
|
/// number of bits the expander has
|
||||||
size_t pin_count_{8};
|
size_t pin_count_{8};
|
||||||
/// width of registers
|
/// width of registers
|
||||||
@@ -45,8 +48,6 @@ class PCA9554Component : public Component, public i2c::I2CDevice {
|
|||||||
uint16_t output_mask_{0x00};
|
uint16_t output_mask_{0x00};
|
||||||
/// The state of the actual input pin states - 1 means HIGH, 0 means LOW
|
/// The state of the actual input pin states - 1 means HIGH, 0 means LOW
|
||||||
uint16_t input_mask_{0x00};
|
uint16_t input_mask_{0x00};
|
||||||
/// Flags to check if read previously during this loop
|
|
||||||
uint16_t was_previously_read_ = {0x00};
|
|
||||||
/// Storage for last I2C error seen
|
/// Storage for last I2C error seen
|
||||||
esphome::i2c::ErrorCode last_error_;
|
esphome::i2c::ErrorCode last_error_;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user