ESPHome 2026.4.3
Loading...
Searching...
No Matches
pcf8574.cpp
Go to the documentation of this file.
1#include "pcf8574.h"
2#include "esphome/core/log.h"
3
4namespace esphome {
5namespace pcf8574 {
6
7static const char *const TAG = "pcf8574";
8
10 if (!this->read_gpio_()) {
11 ESP_LOGE(TAG, "PCF8574 not available under 0x%02X", this->address_);
12 this->mark_failed();
13 return;
14 }
15
16 this->write_gpio_();
17 this->read_gpio_();
18
19 if (this->interrupt_pin_ != nullptr) {
20 this->interrupt_pin_->setup();
22 // Don't invalidate cache on read — only invalidate when interrupt fires
23 this->set_invalidate_on_read_(false);
24 }
25 // Disable loop until an input pin is configured via pin_mode()
26 // For interrupt-driven mode, loop is re-enabled by the ISR
27 // For polling mode, loop is re-enabled when pin_mode() registers an input pin
28 this->disable_loop();
29}
32 // Invalidate the cache so the next digital_read() triggers a fresh I2C read
33 this->reset_pin_cache_();
34 // Only disable the loop once INT has actually gone HIGH. Input transitions that straddle the
35 // I2C read leave INT asserted without re-firing a falling edge, which would strand us with
36 // stale state forever; keep looping until the line is released so we self-heal.
37 if (this->interrupt_pin_ != nullptr && this->interrupt_pin_->digital_read()) {
38 this->disable_loop();
39 }
40}
42 ESP_LOGCONFIG(TAG,
43 "PCF8574:\n"
44 " Is PCF8575: %s",
45 YESNO(this->pcf8575_));
46 LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
47 LOG_I2C_DEVICE(this)
48 if (this->is_failed()) {
49 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
50 }
51}
53 // Read all pins from hardware into input_mask_
54 return this->read_gpio_(); // Return true if I2C read succeeded, false on error
55}
56
57bool PCF8574Component::digital_read_cache(uint8_t pin) { return this->input_mask_ & (1 << pin); }
58
59void PCF8574Component::digital_write_hw(uint8_t pin, bool value) {
60 if (value) {
61 this->output_mask_ |= (1 << pin);
62 } else {
63 this->output_mask_ &= ~(1 << pin);
64 }
65 this->write_gpio_();
66}
68 if (flags == gpio::FLAG_INPUT) {
69 // Clear mode mask bit
70 this->mode_mask_ &= ~(1 << pin);
71 // Write GPIO to enable input mode
72 this->write_gpio_();
73 // Enable polling loop for input pins (not needed for interrupt-driven mode
74 // where the ISR handles re-enabling loop)
75 if (this->interrupt_pin_ == nullptr) {
76 this->enable_loop();
77 }
78 } else if (flags == gpio::FLAG_OUTPUT) {
79 // Set mode mask bit
80 this->mode_mask_ |= 1 << pin;
81 }
82}
84 if (this->is_failed())
85 return false;
86 bool success;
87 uint8_t data[2];
88 if (this->pcf8575_) {
89 success = this->read_bytes_raw(data, 2);
90 this->input_mask_ = (uint16_t(data[1]) << 8) | (uint16_t(data[0]) << 0);
91 } else {
92 success = this->read_bytes_raw(data, 1);
93 this->input_mask_ = data[0];
94 }
95
96 if (!success) {
97 this->status_set_warning();
98 return false;
99 }
100 this->status_clear_warning();
101 return true;
102}
104 if (this->is_failed())
105 return false;
106
107 uint16_t value = 0;
108 // Pins in OUTPUT mode and where pin is HIGH.
109 value |= this->mode_mask_ & this->output_mask_;
110 // Pins in INPUT mode must also be set here
111 value |= ~this->mode_mask_;
112
113 uint8_t data[2];
114 data[0] = value;
115 data[1] = value >> 8;
116 if (this->write(data, this->pcf8575_ ? 2 : 1) != i2c::ERROR_OK) {
117 this->status_set_warning();
118 return false;
119 }
120
121 this->status_clear_warning();
122 return true;
123}
125
128bool PCF8574GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
129void PCF8574GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
130size_t PCF8574GPIOPin::dump_summary(char *buffer, size_t len) const {
131 return buf_append_printf(buffer, len, 0, "%u via PCF8574", this->pin_);
132}
133
134} // namespace pcf8574
135} // namespace esphome
void mark_failed()
Mark this component as failed.
bool is_failed() const
Definition component.h:284
void enable_loop_soon_any_context()
Thread and ISR-safe version of enable_loop() that can be called from any context.
void enable_loop()
Enable this component's loop.
Definition component.h:258
void disable_loop()
Disable this component's loop.
void status_clear_warning()
Definition component.h:306
virtual void setup()=0
virtual bool digital_read()=0
void attach_interrupt(void(*func)(T *), T *arg, gpio::InterruptType type) const
Definition gpio.h:107
bool digital_read(P pin)
Read the state of the given pin.
Definition cached_gpio.h:37
ErrorCode write(const uint8_t *data, size_t len) const
writes an array of bytes to a device using an I2CBus
Definition i2c.h:183
optional< std::array< uint8_t, N > > read_bytes_raw()
Definition i2c.h:230
uint8_t address_
store the address of the device on the bus
Definition i2c.h:270
uint16_t input_mask_
The state read in read_gpio_ - 1 means HIGH, 0 means LOW.
Definition pcf8574.h:47
void setup() override
Check i2c availability and setup masks.
Definition pcf8574.cpp:9
uint16_t mode_mask_
Mask for the pin mode - 1 means output, 0 means input.
Definition pcf8574.h:43
static void IRAM_ATTR gpio_intr(PCF8574Component *arg)
Definition pcf8574.cpp:30
uint16_t output_mask_
The mask to write as output state - 1 means HIGH, 0 means LOW.
Definition pcf8574.h:45
float get_setup_priority() const override
Definition pcf8574.cpp:124
void digital_write_hw(uint8_t pin, bool value) override
Definition pcf8574.cpp:59
void pin_mode(uint8_t pin, gpio::Flags flags)
Helper function to set the pin mode of a pin.
Definition pcf8574.cpp:67
bool digital_read_cache(uint8_t pin) override
Definition pcf8574.cpp:57
InternalGPIOPin * interrupt_pin_
Definition pcf8574.h:49
bool pcf8575_
TRUE->16-channel PCF8575, FALSE->8-channel PCF8574.
Definition pcf8574.h:48
bool digital_read_hw(uint8_t pin) override
Definition pcf8574.cpp:52
void digital_write(bool value) override
Definition pcf8574.cpp:129
void pin_mode(gpio::Flags flags) override
Definition pcf8574.cpp:127
size_t dump_summary(char *buffer, size_t len) const override
Definition pcf8574.cpp:130
PCF8574Component * parent_
Definition pcf8574.h:69
uint16_t flags
@ INTERRUPT_FALLING_EDGE
Definition gpio.h:51
@ FLAG_OUTPUT
Definition gpio.h:28
@ FLAG_INPUT
Definition gpio.h:27
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:14
constexpr float IO
For components that represent GPIO pins like PCF8573.
Definition component.h:38
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:1045