From 8cfbbd23e37ad98c55f4441e6ae28e55a7276de1 Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:20:20 +0100 Subject: [PATCH 01/10] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index b26beec..7ee7f3c 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,12 @@ #### Welcome to the DitroniX Home Asssitant Integration -[![DitroniX WiKi Pages](https://github.com/DitroniX/Home-Assistant-Dev/blob/main/Datasheets%20and%20Information/GitHub%20WiKi.png?raw=true)](https://github.com/DitroniX/Home-Assistant-Dev/wiki) - This repository is for integration of DitroniX boards into Home Assistant using the ESPHome Components. The development and integration repository is work in progress as various projects evolve. It will also expand on route. [![DitroniX Wiki Pages](https://github.com/DitroniX/Home-Assistant-Dev/blob/main/Datasheets%20and%20Information/GitHub%20WiKi.png?raw=true)](https://github.com/DitroniX/Home-Assistant-Dev/wiki) -[![DitroniX Discussions](https://github.com/DitroniX/DitroniX/blob/main/Files/GitHub%20Discussions.png?raw=true)](https://github.com/DitroniX/Home-Assistant-Dev/discussions) #### User contributions From 555fb700d0fb40c074c55f31dc3938ba7079b277 Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:21:23 +0100 Subject: [PATCH 02/10] Add version entry for TCA6408 in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7ee7f3c..8f8073a 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ An example guide has been put together which should help get your boards up and ## Versions + - 260613 - Added TCA6408 for Dev Testing - 260529 - Refresh Information - 251217 - Initial upload of the ATM90E36 Component for EPEM E36. Could also be adapted for IPEM E36 From ad2d9a6911db439acb828fcdf1b0af4fa081d376 Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:25:09 +0100 Subject: [PATCH 03/10] Update tca6408.h --- components/TCA6408/tca6408.h | 91 ++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 51 deletions(-) diff --git a/components/TCA6408/tca6408.h b/components/TCA6408/tca6408.h index 072d7c5..875c7d4 100644 --- a/components/TCA6408/tca6408.h +++ b/components/TCA6408/tca6408.h @@ -1,62 +1,51 @@ -#pragma once - -#include "esphome/components/gpio_expander/cached_gpio.h" -#include "esphome/components/i2c/i2c.h" -#include "esphome/core/component.h" -#include "esphome/core/hal.h" +#include "tca6408.h" +#include "esphome/core/log.h" namespace esphome { namespace tca6408 { -class TCA6408Component : public Component, - public i2c::I2CDevice, - public gpio_expander::CachedGpioExpander { - public: - void setup() override; - void loop() override; - void dump_config() override; - float get_setup_priority() const override { return setup_priority::IO; } +static const char *const TAG = "tca6408"; - void set_address(uint8_t address) { this->address_ = address; } - void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } +static const uint8_t TCA6408_INPUT_PORT = 0x00; +static const uint8_t TCA6408_OUTPUT_PORT = 0x01; +static const uint8_t TCA6408_POLARITY_PORT = 0x02; +static const uint8_t TCA6408_CONFIG_PORT = 0x03; - void set_polarity_inversion(uint8_t pin, bool inverted); +void TCA6408Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up TCA6408..."); - protected: - static void IRAM_ATTR gpio_intr(TCA6408Component *arg); + // Initialize all registers + if (this->write_register(TCA6408_POLARITY_PORT, 0x00) != i2c::ERROR_OK || + this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_) != i2c::ERROR_OK || + !this->read_gpio_outputs_()) { + this->mark_failed(); + return; + } - 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; - void pin_mode(uint8_t pin, gpio::Flags flags) override; + if (this->interrupt_pin_ != nullptr) { + this->interrupt_pin_->setup(); + this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + this->interrupt_pin_->attach_interrupt(&TCA6408Component::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE); + this->set_invalidate_on_read_(false); + ESP_LOGCONFIG(TAG, " Interrupt mode enabled (active-low)"); + } else { + this->enable_loop(); + ESP_LOGCONFIG(TAG, " Polling mode enabled"); + } +} - uint8_t mode_mask_{0xFF}; // 1 = input, 0 = output - uint8_t output_mask_{0x00}; - uint8_t input_mask_{0x00}; - uint8_t polarity_mask_{0x00}; // 1 = inverted +// ... (gpio_intr, loop, dump_config stay the same) - InternalGPIOPin *interrupt_pin_{nullptr}; - bool interrupt_triggered_{false}; -}; +bool TCA6408Component::read_gpio_outputs_() { + if (this->is_failed()) return false; + uint8_t data; + if (this->read_register(TCA6408_OUTPUT_PORT, &data) != i2c::ERROR_OK) { + this->status_set_warning(); + return false; + } + this->output_mask_ = data; + this->status_clear_warning(); + return true; +} -class TCA6408GPIOPin : public gpio::GPIOPin, public Parented { - public: - void setup() override; - void pin_mode(gpio::Flags flags) override; - bool digital_read() override; - void digital_write(bool value) override; - size_t dump_summary(char *buffer, size_t len) const override; - - void set_pin(uint8_t pin) { pin_ = pin; } - void set_inverted(bool inverted); - void set_flags(gpio::Flags flags) { flags_ = flags; } - gpio::Flags get_flags() const override { return flags_; } - - protected: - uint8_t pin_{0}; - bool inverted_{false}; - gpio::Flags flags_{0}; -}; - -} // namespace tca6408 -} // namespace esphome +// Rest of the file remains the same as you have it... From 9dde9dd0fb0966957ad478aa2085463f30370b88 Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:30:29 +0100 Subject: [PATCH 04/10] Update __init__.py --- components/TCA6408/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/TCA6408/__init__.py b/components/TCA6408/__init__.py index 57b1581..3fd6361 100644 --- a/components/TCA6408/__init__.py +++ b/components/TCA6408/__init__.py @@ -13,9 +13,7 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(TCA6408Component), cv.Optional(CONF_ADDRESS, default=0x20): cv.i2c_address, - cv.Optional(CONF_INTERRUPT_PIN): cv.All( - gpio.validate_gpio_pin("internal"), - ), + cv.Optional(CONF_INTERRUPT_PIN): gpio.validate_gpio_pin("internal"), } ) .extend(cv.COMPONENT_SCHEMA) From e4cc031ed53dd6029619c5806774675924fe66f7 Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:33:54 +0100 Subject: [PATCH 05/10] Update __init__.py From 456f8eeca424dfc726d02f70d3ea634c2e830b19 Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:34:26 +0100 Subject: [PATCH 06/10] Update tca6408.cpp --- components/TCA6408/tca6408.cpp | 74 +++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/components/TCA6408/tca6408.cpp b/components/TCA6408/tca6408.cpp index 657f5f2..b240d68 100644 --- a/components/TCA6408/tca6408.cpp +++ b/components/TCA6408/tca6408.cpp @@ -12,11 +12,23 @@ static const uint8_t TCA6408_POLARITY_PORT = 0x02; static const uint8_t TCA6408_CONFIG_PORT = 0x03; void TCA6408Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up TCA6408..."); + ESP_LOGCONFIG(TAG, "Setting up TCA6408 at address 0x%02X...", this->address_); - if (this->write_register(TCA6408_POLARITY_PORT, 0x00) != i2c::ERROR_OK || - this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_) != i2c::ERROR_OK || - !this->read_gpio_outputs_()) { + // Initialize registers to known state + if (this->write_register(TCA6408_POLARITY_PORT, 0x00) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Failed to write polarity register"); + this->mark_failed(); + return; + } + + if (this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Failed to write config register"); + this->mark_failed(); + return; + } + + if (!this->read_gpio_outputs_()) { + ESP_LOGE(TAG, "Failed to read output register"); this->mark_failed(); return; } @@ -24,13 +36,16 @@ void TCA6408Component::setup() { if (this->interrupt_pin_ != nullptr) { this->interrupt_pin_->setup(); this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - this->interrupt_pin_->attach_interrupt(&TCA6408Component::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE); + this->interrupt_pin_->attach_interrupt(&TCA6408Component::gpio_intr, this, + gpio::INTERRUPT_FALLING_EDGE); this->set_invalidate_on_read_(false); - ESP_LOGCONFIG(TAG, " Interrupt mode enabled"); + ESP_LOGCONFIG(TAG, " Interrupt mode enabled (active-low INT)"); } else { this->enable_loop(); ESP_LOGCONFIG(TAG, " Polling mode enabled"); } + + ESP_LOGCONFIG(TAG, " Setup complete"); } void IRAM_ATTR TCA6408Component::gpio_intr(TCA6408Component *arg) { @@ -42,9 +57,11 @@ void TCA6408Component::loop() { if (this->interrupt_triggered_) { this->interrupt_triggered_ = false; - this->digital_read_hw(0); + // Reading input port clears the interrupt on TCA6408 + this->digital_read_hw(0); // pin number is ignored, reads all 8 bits this->reset_pin_cache_(); + // If INT line is high again, disable loop until next interrupt if (this->interrupt_pin_ && this->interrupt_pin_->digital_read()) { this->disable_loop(); } @@ -56,11 +73,13 @@ void TCA6408Component::dump_config() { LOG_I2C_DEVICE(this); ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); + ESP_LOGCONFIG(TAG, " Mode Mask: 0x%02X (1=input)", this->mode_mask_); + ESP_LOGCONFIG(TAG, " Polarity Mask: 0x%02X", this->polarity_mask_); } bool TCA6408Component::read_gpio_outputs_() { if (this->is_failed()) return false; - uint8_t data; + uint8_t data = 0; if (this->read_register(TCA6408_OUTPUT_PORT, &data) != i2c::ERROR_OK) { this->status_set_warning(); return false; @@ -87,9 +106,9 @@ void TCA6408Component::digital_write_hw(uint8_t pin, bool value) { if (this->is_failed()) return; if (value) { - this->output_mask_ |= (1 << pin); + this->output_mask_ |= (1U << pin); } else { - this->output_mask_ &= ~(1 << pin); + this->output_mask_ &= ~(1U << pin); } if (this->write_register(TCA6408_OUTPUT_PORT, this->output_mask_) != i2c::ERROR_OK) { @@ -101,9 +120,9 @@ void TCA6408Component::digital_write_hw(uint8_t pin, bool value) { void TCA6408Component::pin_mode(uint8_t pin, gpio::Flags flags) { if (flags & gpio::FLAG_OUTPUT) { - this->mode_mask_ &= ~(1 << pin); + this->mode_mask_ &= ~(1U << pin); // 0 = output } else { - this->mode_mask_ |= (1 << pin); + this->mode_mask_ |= (1U << pin); // 1 = input if (this->interrupt_pin_ == nullptr) { this->enable_loop(); } @@ -111,24 +130,25 @@ void TCA6408Component::pin_mode(uint8_t pin, gpio::Flags flags) { this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_); } +void TCA6408Component::set_polarity_inversion(uint8_t pin, bool inverted) { + if (inverted) { + this->polarity_mask_ |= (1U << pin); + } else { + this->polarity_mask_ &= ~(1U << pin); + } + this->write_register(TCA6408_POLARITY_PORT, this->polarity_mask_); +} + bool TCA6408Component::digital_read_cache(uint8_t pin) { - bool value = (this->input_mask_ & (1 << pin)) != 0; - if (this->polarity_mask_ & (1 << pin)) { + bool value = (this->input_mask_ & (1U << pin)) != 0; + // Apply hardware polarity inversion if set + if (this->polarity_mask_ & (1U << pin)) { value = !value; } return value; } -void TCA6408Component::set_polarity_inversion(uint8_t pin, bool inverted) { - if (inverted) { - this->polarity_mask_ |= (1 << pin); - } else { - this->polarity_mask_ &= ~(1 << pin); - } - this->write_register(TCA6408_POLARITY_PORT, this->polarity_mask_); -} - -// ==================== TCA6408GPIOPin ==================== +// ====================== TCA6408GPIOPin ====================== void TCA6408GPIOPin::setup() { this->pin_mode(this->flags_); @@ -150,15 +170,15 @@ void TCA6408GPIOPin::pin_mode(gpio::Flags flags) { } bool TCA6408GPIOPin::digital_read() { - return this->parent_->digital_read(this->pin_); + return this->parent_->digital_read(this->pin_) != this->inverted_; } void TCA6408GPIOPin::digital_write(bool value) { - this->parent_->digital_write(this->pin_, value); + this->parent_->digital_write(this->pin_, value != this->inverted_); } size_t TCA6408GPIOPin::dump_summary(char *buffer, size_t len) const { - return snprintf(buffer, len, "%u via TCA6408", this->pin_); + return snprintf(buffer, len, "%u via TCA6408@0x%02X", this->pin_, this->parent_->address_); } } // namespace tca6408 From 8a6ea593dbd2751f9e3212714d5b2e11a9df455d Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:34:45 +0100 Subject: [PATCH 07/10] Update tca6408.h --- components/TCA6408/tca6408.h | 94 +++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 40 deletions(-) diff --git a/components/TCA6408/tca6408.h b/components/TCA6408/tca6408.h index 875c7d4..565a916 100644 --- a/components/TCA6408/tca6408.h +++ b/components/TCA6408/tca6408.h @@ -1,51 +1,65 @@ -#include "tca6408.h" -#include "esphome/core/log.h" +#pragma once + +#include "esphome/components/gpio_expander/cached_gpio.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" +#include "esphome/core/hal.h" namespace esphome { namespace tca6408 { -static const char *const TAG = "tca6408"; +class TCA6408Component : public Component, + public i2c::I2CDevice, + public gpio_expander::CachedGpioExpander { + public: + void setup() override; + void loop() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::IO; } -static const uint8_t TCA6408_INPUT_PORT = 0x00; -static const uint8_t TCA6408_OUTPUT_PORT = 0x01; -static const uint8_t TCA6408_POLARITY_PORT = 0x02; -static const uint8_t TCA6408_CONFIG_PORT = 0x03; + void set_address(uint8_t address) { this->address_ = address; } + void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } -void TCA6408Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up TCA6408..."); + void set_polarity_inversion(uint8_t pin, bool inverted); - // Initialize all registers - if (this->write_register(TCA6408_POLARITY_PORT, 0x00) != i2c::ERROR_OK || - this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_) != i2c::ERROR_OK || - !this->read_gpio_outputs_()) { - this->mark_failed(); - return; - } + protected: + static void IRAM_ATTR gpio_intr(TCA6408Component *arg); - if (this->interrupt_pin_ != nullptr) { - this->interrupt_pin_->setup(); - this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - this->interrupt_pin_->attach_interrupt(&TCA6408Component::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE); - this->set_invalidate_on_read_(false); - ESP_LOGCONFIG(TAG, " Interrupt mode enabled (active-low)"); - } else { - this->enable_loop(); - ESP_LOGCONFIG(TAG, " Polling mode enabled"); - } -} + 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; + void pin_mode(uint8_t pin, gpio::Flags flags) override; -// ... (gpio_intr, loop, dump_config stay the same) + uint8_t mode_mask_{0xFF}; // 1 = input, 0 = output + uint8_t output_mask_{0x00}; + uint8_t input_mask_{0x00}; + uint8_t polarity_mask_{0x00}; // 1 = inverted (for inputs) -bool TCA6408Component::read_gpio_outputs_() { - if (this->is_failed()) return false; - uint8_t data; - if (this->read_register(TCA6408_OUTPUT_PORT, &data) != i2c::ERROR_OK) { - this->status_set_warning(); - return false; - } - this->output_mask_ = data; - this->status_clear_warning(); - return true; -} + InternalGPIOPin *interrupt_pin_{nullptr}; + bool interrupt_triggered_{false}; -// Rest of the file remains the same as you have it... + private: + bool read_gpio_outputs_(); +}; + +class TCA6408GPIOPin : public gpio::GPIOPin, public Parented { + public: + void setup() override; + void pin_mode(gpio::Flags flags) override; + bool digital_read() override; + void digital_write(bool value) override; + size_t dump_summary(char *buffer, size_t len) const override; + + void set_pin(uint8_t pin) { pin_ = pin; } + void set_inverted(bool inverted); + void set_flags(gpio::Flags flags) { flags_ = flags; } + gpio::Flags get_flags() const override { return flags_; } + + protected: + uint8_t pin_{0}; + bool inverted_{false}; + gpio::Flags flags_{0}; +}; + +} // namespace tca6408 +} // namespace esphome From 156435c278edc758ae882d506f1f034ef427485c Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:35:47 +0100 Subject: [PATCH 08/10] Update tca6408.cpp --- components/TCA6408/tca6408.cpp | 61 ++++++++-------------------------- 1 file changed, 14 insertions(+), 47 deletions(-) diff --git a/components/TCA6408/tca6408.cpp b/components/TCA6408/tca6408.cpp index b240d68..2227581 100644 --- a/components/TCA6408/tca6408.cpp +++ b/components/TCA6408/tca6408.cpp @@ -14,21 +14,9 @@ static const uint8_t TCA6408_CONFIG_PORT = 0x03; void TCA6408Component::setup() { ESP_LOGCONFIG(TAG, "Setting up TCA6408 at address 0x%02X...", this->address_); - // Initialize registers to known state - if (this->write_register(TCA6408_POLARITY_PORT, 0x00) != i2c::ERROR_OK) { - ESP_LOGE(TAG, "Failed to write polarity register"); - this->mark_failed(); - return; - } - - if (this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_) != i2c::ERROR_OK) { - ESP_LOGE(TAG, "Failed to write config register"); - this->mark_failed(); - return; - } - - if (!this->read_gpio_outputs_()) { - ESP_LOGE(TAG, "Failed to read output register"); + if (this->write_register(TCA6408_POLARITY_PORT, 0x00) != i2c::ERROR_OK || + this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_) != i2c::ERROR_OK || + !this->read_gpio_outputs_()) { this->mark_failed(); return; } @@ -36,16 +24,13 @@ void TCA6408Component::setup() { if (this->interrupt_pin_ != nullptr) { this->interrupt_pin_->setup(); this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - this->interrupt_pin_->attach_interrupt(&TCA6408Component::gpio_intr, this, - gpio::INTERRUPT_FALLING_EDGE); + this->interrupt_pin_->attach_interrupt(&TCA6408Component::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE); this->set_invalidate_on_read_(false); - ESP_LOGCONFIG(TAG, " Interrupt mode enabled (active-low INT)"); + ESP_LOGCONFIG(TAG, " Interrupt mode enabled (active-low)"); } else { this->enable_loop(); ESP_LOGCONFIG(TAG, " Polling mode enabled"); } - - ESP_LOGCONFIG(TAG, " Setup complete"); } void IRAM_ATTR TCA6408Component::gpio_intr(TCA6408Component *arg) { @@ -56,12 +41,9 @@ void IRAM_ATTR TCA6408Component::gpio_intr(TCA6408Component *arg) { void TCA6408Component::loop() { if (this->interrupt_triggered_) { this->interrupt_triggered_ = false; - - // Reading input port clears the interrupt on TCA6408 - this->digital_read_hw(0); // pin number is ignored, reads all 8 bits + this->digital_read_hw(0); this->reset_pin_cache_(); - // If INT line is high again, disable loop until next interrupt if (this->interrupt_pin_ && this->interrupt_pin_->digital_read()) { this->disable_loop(); } @@ -73,8 +55,6 @@ void TCA6408Component::dump_config() { LOG_I2C_DEVICE(this); ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); - ESP_LOGCONFIG(TAG, " Mode Mask: 0x%02X (1=input)", this->mode_mask_); - ESP_LOGCONFIG(TAG, " Polarity Mask: 0x%02X", this->polarity_mask_); } bool TCA6408Component::read_gpio_outputs_() { @@ -91,7 +71,6 @@ bool TCA6408Component::read_gpio_outputs_() { bool TCA6408Component::digital_read_hw(uint8_t pin) { if (this->is_failed()) return false; - uint8_t data = 0; if (this->read_register(TCA6408_INPUT_PORT, &data) != i2c::ERROR_OK) { this->status_set_warning(); @@ -104,13 +83,11 @@ bool TCA6408Component::digital_read_hw(uint8_t pin) { void TCA6408Component::digital_write_hw(uint8_t pin, bool value) { if (this->is_failed()) return; - if (value) { this->output_mask_ |= (1U << pin); } else { this->output_mask_ &= ~(1U << pin); } - if (this->write_register(TCA6408_OUTPUT_PORT, this->output_mask_) != i2c::ERROR_OK) { this->status_set_warning(); } else { @@ -120,12 +97,10 @@ void TCA6408Component::digital_write_hw(uint8_t pin, bool value) { void TCA6408Component::pin_mode(uint8_t pin, gpio::Flags flags) { if (flags & gpio::FLAG_OUTPUT) { - this->mode_mask_ &= ~(1U << pin); // 0 = output + this->mode_mask_ &= ~(1U << pin); } else { - this->mode_mask_ |= (1U << pin); // 1 = input - if (this->interrupt_pin_ == nullptr) { - this->enable_loop(); - } + this->mode_mask_ |= (1U << pin); + if (this->interrupt_pin_ == nullptr) this->enable_loop(); } this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_); } @@ -141,27 +116,19 @@ void TCA6408Component::set_polarity_inversion(uint8_t pin, bool inverted) { bool TCA6408Component::digital_read_cache(uint8_t pin) { bool value = (this->input_mask_ & (1U << pin)) != 0; - // Apply hardware polarity inversion if set - if (this->polarity_mask_ & (1U << pin)) { - value = !value; - } + if (this->polarity_mask_ & (1U << pin)) value = !value; return value; } -// ====================== TCA6408GPIOPin ====================== - +// TCA6408GPIOPin void TCA6408GPIOPin::setup() { this->pin_mode(this->flags_); - if (this->inverted_) { - this->parent_->set_polarity_inversion(this->pin_, true); - } + if (this->inverted_) this->parent_->set_polarity_inversion(this->pin_, true); } void TCA6408GPIOPin::set_inverted(bool inverted) { this->inverted_ = inverted; - if (this->parent_ != nullptr) { - this->parent_->set_polarity_inversion(this->pin_, inverted); - } + if (this->parent_) this->parent_->set_polarity_inversion(this->pin_, inverted); } void TCA6408GPIOPin::pin_mode(gpio::Flags flags) { @@ -178,7 +145,7 @@ void TCA6408GPIOPin::digital_write(bool value) { } size_t TCA6408GPIOPin::dump_summary(char *buffer, size_t len) const { - return snprintf(buffer, len, "%u via TCA6408@0x%02X", this->pin_, this->parent_->address_); + return snprintf(buffer, len, "%u via TCA6408", this->pin_); } } // namespace tca6408 From 57b960c9f9f6b19ec12afed244d5946fc3cd47f9 Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:36:39 +0100 Subject: [PATCH 09/10] Update tca6408.h --- components/TCA6408/tca6408.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/TCA6408/tca6408.h b/components/TCA6408/tca6408.h index 565a916..b5b1e3f 100644 --- a/components/TCA6408/tca6408.h +++ b/components/TCA6408/tca6408.h @@ -33,7 +33,7 @@ class TCA6408Component : public Component, uint8_t mode_mask_{0xFF}; // 1 = input, 0 = output uint8_t output_mask_{0x00}; uint8_t input_mask_{0x00}; - uint8_t polarity_mask_{0x00}; // 1 = inverted (for inputs) + uint8_t polarity_mask_{0x00}; // 1 = inverted (hardware polarity for inputs) InternalGPIOPin *interrupt_pin_{nullptr}; bool interrupt_triggered_{false}; From 0ef08811b2b6d08a877954530fe100ac06d8f413 Mon Sep 17 00:00:00 2001 From: Dave Williams | DitroniX | G8PUO Date: Sat, 13 Jun 2026 08:38:16 +0100 Subject: [PATCH 10/10] Fix formatting of set_interrupt_pin call