Single GPIO as Input and Output?

I have an ESP32 that drives a controller by active-low, it has a npn transistor, and two external pull resistors to function as both input and output if needed, since it can be externally driven down by a few physical buttons.
Now the question is, how can I set up my ESPHOME config to make the GPIO pins act as both Input as output, or sensing whether it’s driven down, and driving it down via the esp32?

The ESP32 architecture supports this use case, but as far as I am aware nothing supports it on the ESPHome platform.

Never tried anything like this but give it a try.
Set output (switch) as INPUT_OUTPUT_OPEN_DRAIN
Set both input (binary sensor) and output for allow_other_uses: true
Use external pullup.

Not quite the same thing as you are after but I have my VELUX blinds controlled in a similar method using the remote. It uses two GPIO’s one to control and one to sense. Details can be found here including code and Kicad files. Something you may be able to adapt if you have enough GPIO’s.

I’m not the author of this.

I solved it with this post: Open drain output and binary sensor at the same pin - #6 by laschrocket
I had issues at boot with sensors being on so used the initial lambda to on_boot as well. Seems to work so far, no burnt out components yet.
Also added open drain, just in case someone gets the brilliant idea of pushing the button when it happens to be on.

#....
esphome:
  name: name
  friendly_name: friendly_name
  on_boot:
    - priority: -100
      then:
        - lambda: |-
            id(in_pin_18)->pin_mode(gpio::FLAG_INPUT);
            id(sensor_up)->setup();

#....

binary_sensor:
  - platform: gpio
    name: "Up"
    id: sensor_up
    pin:
      id: in_pin_18
      number: 18
      allow_other_uses: true
      mode: INPUT
      inverted: true

output:
  - platform: gpio
    id: button_up
    pin:
      id: out_pin_18
      number: 18
      allow_other_uses: true
      inverted: true

button:
  # Recall Presets
  - platform: template
    id: go_up_now
    name: "go up"
    icon: "mdi:numeric-1-box"
    on_press:
      - lambda: |-
          id(out_pin_18)->pin_mode(gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN);
          id(button_up)->setup();
      - output.turn_on: button_up
      - delay: 4s
      - output.turn_off: button_up
      - delay: 10ms
      - lambda: |-
          id(in_pin_18)->pin_mode(gpio::FLAG_INPUT);
          id(sensor_up)->setup();

1 Like