8000
Skip to content

[mcp23016] Migrate to CachedGpioExpander to reduce I2C bus usage - #10581

Merged
bdraco merged 2 commits into
devfrom
mcp_23016_gpio_cache
Sep 7, 2025
Merged

[mcp23016] Migrate to CachedGpioExpander to reduce I2C bus usage#10581
bdraco merged 2 commits into
devfrom
mcp_23016_gpio_cache

Conversation

@bdraco
@bdraco bdraco commented Sep 4, 2025
Copy link
Copy Markdown
Member

What does this implement/fix?

This PR migrates the MCP23016 I/O expander component to use the CachedGpioExpander base class, eliminating redundant I2C reads when multiple pins from the same bank are accessed in a single loop cycle.

The MCP23016 component was performing one I2C read transaction for every digital_read() call, even when reading multiple pins from the same 8-bit bank. Since the MCP23016 reads an entire 8-bit bank at once via I2C, this created unnecessary bus traffic when multiple pins from the same bank were read in the same loop cycle.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Code quality improvements to existing code or addition of tests
  • Other

Related issue or feature (if applicable):

Pull request in esphome-docs with documentation (if applicable):

  • N/A (internal optimization, no user-facing changes)

Test Environment

  • ESP32
  • ESP32 IDF
  • ESP8266
  • RP2040
  • BK72xx
  • RTL87xx
  • nRF52840

Note: I don't have MCP23016 hardware available for physical testing. The changes follow the same pattern successfully used in MCP23008/MCP23017 (which already use CachedGpioExpander) and the code compiles successfully. Testing assistance from the community would be appreciated.

Example entry for config.yaml:

# No configuration changes required - this is an internal optimization
i2c:
  sda: GPIO21
  scl: GPIO22

mcp23016:
  - id: mcp23016_hub
    address: 0x20

binary_sensor:
  - platform: gpio
    name: "MCP23016 Input Pin 0"
    pin:
      mcp23016: mcp23016_hub
      number: 0
      mode: INPUT

switch:
  - platform: gpio
    name: "MCP23016 Output Pin 8"
    pin:
      mcp23016: mcp23016_hub
      number: 8
      mode: OUTPUT

Checklist:

  • The code change is tested and works locally.
  • Tests have been added to verify that the new code works (under tests/ folder).

If user exposed functionality or configuration variables are added/changed:

Changes Made

  1. Migrated MCP23016 to CachedGpioExpander base class:

    • MCP23016 now inherits from gpio_expander::CachedGpioExpander<uint8_t, 16>
    • Uses 2 banks of 8 pins each, matching the hardware's bank-separated reading pattern
    • Added AUTO_LOAD = ["gpio_expander"] to Python configuration
  2. Implemented required virtual methods:

    • digital_read_hw(uint8_t pin) - Reads the relevant 8-bit bank (GP0 or GP1) based on pin number, returns true/false for success/failure
    • digital_read_cache(uint8_t pin) - Returns cached pin value from input_mask_
    • digital_write_hw(uint8_t pin, bool value) - Updates output latch register via existing update_reg_() method
  3. Cache management:

    • Added loop() method that calls reset_pin_cache_() to invalidate cache at start of each loop
    • Maintains separate cache validity for each 8-bit bank
    • Follows the same pattern as MCP23008/MCP23017 components without custom loop priority
  4. Preserved existing functionality:

    • Pin mode configuration remains unchanged
    • Output control through OLAT registers unchanged
    • All existing features and error handling preserved

Expected Performance Impact

Based on similar optimizations in other I/O expander components:

  • Reduced I2C bus usage: Multiple reads from the same 8-bit bank within a loop cycle now share a single I2C transaction
  • Lower latency: Cached reads are instantaneous after the first read in a bank
  • Better scalability: Systems with multiple MCP23016 chips or other I2C devices benefit from reduced bus congestion

The optimization is particularly beneficial when:

  • Reading multiple pins from the same bank (pins 0-7 or pins 8-15) in a single loop cycle
  • Using the MCP23016 in mixed input/output configurations
  • Operating in I2C bus-constrained environments

Technical Details

The MCP23016 reads its GPIO banks separately:

  • Bank 0 (pins 0-7): Register GP0 (0x00)
  • Bank 1 (pins 8-15): Register GP1 (0x01)

Using CachedGpioExpander<uint8_t, 16> with 2 banks perfectly matches this hardware pattern:

  • First read in bank 0 fetches all 8 pins via I2C
  • Subsequent reads from bank 0 use cache until next loop
  • Same behavior for bank 1 (pins 8-15)
  • Cache invalidated at start of each loop to ensure fresh data

This approach is identical to the already-proven MCP23017 implementation, which uses the same 2-bank architecture.

@codecov-commenter
codecov-commenter commented Sep 4, 2025
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 60.43%. Comparing base (c7ee727) to head (99ae671).
⚠️ Report is 9 commits behind head on dev.

Additional details and impacted files
@@           Coverage Diff           @@
##              dev   #10581   +/-   ##
=======================================
  Coverage   60.43%   60.43%           
=======================================
  Files          51       51           
  Lines       10482    10482           
  Branches     1400     1400           
=======================================
  Hits         6335     6335           
  Misses       3789     3789           
  Partials      358      358           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
github-actions Bot commented Sep 4, 2025
Copy link
Copy Markdown
Contributor

To use the changes from this PR as an external component, add the following to your ESPHome configuration YAML file:

external_components:
  - source: github://pr#10581
    components: [mcp23016]
    refresh: 1h

(Added by the PR bot)

@bdraco
bdraco marked this pull request as ready for review September 4, 2025 19:22
Copilot AI review requested due to automatic review settings September 4, 2025 19:22
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR migrates the MCP23016 I/O expander component to use the CachedGpioExpander base class to reduce I2C bus traffic by eliminating redundant reads when multiple pins from the same bank are accessed within a single loop cycle.

  • Inherits from CachedGpioExpander<uint8_t, 16> to implement caching for 2 banks of 8 pins each
  • Implements required virtual methods for hardware reads/writes and cache management
  • Adds loop-based cache invalidation to ensure fresh data each cycle

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
esphome/components/mcp23016/mcp23016.h Adds CachedGpioExpander inheritance, new virtual methods, and input cache member variable
esphome/components/mcp23016/mcp23016.cpp Implements caching logic, replaces direct digital_read/write methods, and adds loop method
esphome/components/mcp23016/init.py Adds gpio_expander as auto-loaded dependency

Comment thread esphome/components/mcp23016/mcp23016.cpp
Comment thread esphome/components/mcp23016/mcp23016.cpp Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@bdraco
bdraco commented Sep 7, 2025
Copy link
Copy Markdown
Member Author

thanks

@bdraco
bdraco merged commit 0ff08bb into dev Sep 7, 2025
25 checks passed
@bdraco
bdraco deleted the mcp_23016_gpio_cache branch September 7, 2025 23:26
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 9, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

0