esphome / issues

Issue Tracker for ESPHome
https://esphome.io/
290 stars 36 forks source link

GPIOs on multiple I2C GPIO expanders stop working #4182

Open justlikeef opened 1 year ago

justlikeef commented 1 year ago

The problem

I have two different i2c GPIO expanders (MCP23017 and PCF8575) that are behaving in the same manner. I have also tried with multiple esp32 boards (Olimex POE using wired ethernet and generic WROOM DevkitC using wireless) and have the same result.

All expansion GPIOs are configured in output mode and inverted.

  1. After boot, I seem to have control over some, but not all of them. In the web interface, after selecting them several times sometimes they will start working.
  2. After differing amounts of time, the GPIOs will start turning on an off on their own.
  3. Although the switches in the web interface say they are turning the switch on and off, I don't see a change in the physical pin state.
  4. After differing amounts of time, turning specific switches on and off in the web interface will cause random pins to turn on and off. eg. changing the state of the switch associated with pin 5 will turn on and off pins 6 and 7

I am currently testing with a very simple sketch using Arduino IDE that initializes the 8575, does some bit banging, then lets it sit. So far I have seen none of the strange pin state changes with this sketch as when I'm running ESPHome.

Which version of ESPHome has the issue?

v2023.1.0-dev

What type of installation are you using?

Home Assistant Add-on

Which version of Home Assistant has the issue?

2023.2.4

What platform are you using?

ESP32

Board

Olimex POE and Generic DevKit-C

Component causing the issue

i2c MCP23017 PCF8575 gpio

Example YAML snippet

esphome:
  name: water-controller-dev-01

esp32:
  board: esp32-poe

logger:

api:
  encryption:
    key: "94Zmm6a/gNJdnhY9RcwTN/mETVqQLh1RtQSIGM2uc7U="

ota:
  password: "22799c627062be8ad8d23d1071008b88"

ethernet:
  type: LAN8720
  mdc_pin: GPIO23
  mdio_pin: GPIO18
  clk_mode: GPIO17_OUT
  phy_addr: 0
  power_pin: GPIO12    

web_server:
  port: 80
  include_internal: true
  ota: false

text_sensor:
  - platform: template
    name: uptime_human_readable
    id: uptime_human_readable
    icon: mdi:clock-start
    update_interval: 60s

i2c:
  - id: bus_a
    sda: 13
    scl: 16
    scan: true

pcf8574:
  - id: 'i2c_gpiox_01'
    address: 0x20
    pcf8575: true
  - id: 'i2c_gpiox_02'
    address: 0x21
    pcf8575: true

switch:
  - platform: gpio
    name: "Valve1 Open"
    id: valve1_open
    pin:
      pcf8574: i2c_gpiox_01
      number: 0
      mode:
        output: true
      inverted: true
    interlock: [valve1_close]
    restore_mode: ALWAYS_OFF
  - platform: gpio
    name: "Valve1 Close"
    id: valve1_close
    pin:
      pcf8574: i2c_gpiox_01
      number: 1
      mode:
        output: true
      inverted: true
    interlock: [valve1_open]
    restore_mode: ALWAYS_ON
  - platform: gpio
    name: "Valve2 Open"
    id: valve2_open
    pin:
      pcf8574: i2c_gpiox_01
      number: 2
      mode:
        output: true
      inverted: true
    interlock: [valve2_close]
    restore_mode: ALWAYS_OFF
  - platform: gpio
    name: "Valve2 Close"
    id: valve2_close
    pin:
      pcf8574: i2c_gpiox_01
      number: 3
      mode:
        output: true
      inverted: true
    interlock: [valve2_open]
    restore_mode: ALWAYS_ON
  - platform: gpio
    name: "Valve3 Open"
    id: valve3_open
    pin:
      pcf8574: i2c_gpiox_01
      number: 4
      mode:
        output: true
      inverted: true
    interlock: [valve3_close]
    restore_mode: ALWAYS_OFF
  - platform: gpio
    name: "Valve3 Close"
    id: valve3_close
    pin:
      pcf8574: i2c_gpiox_01
      number: 5
      mode:
        output: true
      inverted: true
    interlock: [valve3_open]
    restore_mode: ALWAYS_ON
  - platform: gpio
    name: "Valve4 Open"
    id: valve4_open
    pin:
      pcf8574: i2c_gpiox_01
      number: 6
      mode:
        output: true
      inverted: true
    interlock: [valve4_close]
    restore_mode: ALWAYS_OFF
  - platform: gpio
    name: "Valve4 Close"
    id: valve4_close
    pin:
      pcf8574: i2c_gpiox_01
      number: 7
      mode:
        output: true
      inverted: true
    interlock: [valve4_open]
    restore_mode: ALWAYS_ON
  - platform: gpio
    name: "Valve5 Open"
    id: valve5_open
    pin:
      pcf8574: i2c_gpiox_01
      number: 8
      mode:
        output: true
      inverted: true
    interlock: [valve5_close]
    restore_mode: ALWAYS_OFF
  - platform: gpio
    name: "Valve5 Close"
    id: valve5_close
    pin:
      pcf8574: i2c_gpiox_01
      number: 9
      mode:
        output: true
      inverted: true
    interlock: [valve5_open]
    restore_mode: ALWAYS_ON
  - platform: gpio
    name: "Valve6 Open"
    id: valve6_open
    pin:
      pcf8574: i2c_gpiox_01
      number: 10
      mode:
        output: true
      inverted: true
    interlock: [valve6_close]
    restore_mode: ALWAYS_OFF
  - platform: gpio
    name: "Valve6 Close"
    id: valve6_close
    pin:
      pcf8574: i2c_gpiox_01
      number: 11
      mode:
        output: true
      inverted: true
    interlock: [valve6_open]
    restore_mode: ALWAYS_ON
  - platform: gpio
    name: "Valve7 Open"
    id: valve7_open
    pin:
      pcf8574: i2c_gpiox_01
      number: 12
      mode:
        output: true
      inverted: true
    interlock: [valve7_close]
    restore_mode: ALWAYS_OFF
  - platform: gpio
    name: "Valve7 Close"
    id: valve7_close
    pin:
      pcf8574: i2c_gpiox_01
      number: 13
      mode:
        output: true
      inverted: true
    interlock: [valve7_open]
    restore_mode: ALWAYS_ON
  - platform: gpio
    name: "Valve8 Open"
    id: valve8_open
    pin:
      pcf8574: i2c_gpiox_01
      number: 14
      mode:
        output: true
      inverted: true
    interlock: [valve8_close]
    restore_mode: ALWAYS_OFF
  - platform: gpio
    name: "Valve8 Close"
    id: valve8_close
    pin:
      pcf8574: i2c_gpiox_01
      number: 15
      mode:
        output: true
      inverted: true
    interlock: [valve8_open]
    restore_mode: ALWAYS_ON
  - platform: safe_mode
    name: use_safe_mode

sensor:
  - platform: uptime
    name: uptime_sensor
    id: uptime_sensor
    update_interval: 15s
    internal: true
    on_raw_value:
      then:
        - text_sensor.template.publish:
            id: uptime_human_readable
            state: !lambda |-
                      int seconds = round(id(uptime_sensor).raw_state);
                      int days = seconds / (24 * 3600);
                      seconds = seconds % (24 * 3600);
                      int hours = seconds / 3600;
                      seconds = seconds % 3600;
                      int minutes = seconds /  60;
                      seconds = seconds % 60;
                      return (
                        (days ? to_string(days)+":" : "00:") +
                        (hours ? to_string(hours)+":" : "00:") +
                        (minutes ? to_string(minutes)+":" : "00:") +
                        (to_string(seconds))
                      ).c_str();

button:
  - platform: restart
    name: "reset/restart_ESP/MCU"
    entity_category: diagnostic

Anything in the logs that might be useful for us?

Nothing in the logs to indicate a state change

Additional information

No response

justlikeef commented 1 year ago

After running the simple diagnostic sketch for more than 24 hours, I can verify that all the GPIOs are functioning as expected. There are no strange state changes or other weird behavior as there are when running the Esphome firmware. Since the same behavior occurs with multiple i2c GPIO expander chips, I would think it is likely either within the i2c or gpio components.

justlikeef commented 1 year ago

I'm not a C programmer, so please forgive me if this is not right. I'll be happy to do whatever needs to be done to troubleshoot this issue...

I've added some basic logging code to the pin setup and attached a log of what I am getting. I see no TX log entries, which I think I should be seeing based on the code in i2c_bus_esp_idf line 164:

ESP_LOGVV(TAG, "0x%02X TX %s", address, debug_hex.c_str());

nor do I see logging from the code I added:

void PCF8574Component::pin_mode(uint8_t pin, gpio::Flags flags) {
  if (flags == gpio::FLAG_INPUT) {
    ESP_LOGCONFIG(TAG, "Pin Mode: Input");
    // Clear mode mask bit
    this->mode_mask_ &= ~(1 << pin);
    // Write GPIO to enable input mode
    this->write_gpio_();
  } else if (flags == gpio::FLAG_OUTPUT) {
    ESP_LOGCONFIG(TAG, "Pin Mode: Output");
    // Set mode mask bit
    this->mode_mask_ |= 1 << pin;
  }
}

logs_water-controller-dev-01_logs (6).txt

justlikeef commented 1 year ago

teraterm.log

justlikeef commented 1 year ago

teraterm1.log

justlikeef commented 1 year ago

Two logs with slightly different results, but the same behavior. After some time of running (45 minutes to an hour in this case for both logs), there start to be problems controlling the switches. The values of the sensors are wrong from the beginning. Nothing jumps out that I can see.

If I run a very simple sketch that either allows me to either read the current status of or turn the gpios on and off, I don't have any issues after running for 48 or more hours, so I don't think it's the electronics.