Open drain output and binary sensor at the same pin

Hello,

I’d like to build an interface for Velux KLI312 to control some windows blinds.

There are plenty of tutorials avaiable how to take the signals from that device. Basically there is a node with a pullup resistor, that is pulled to ground when the button is pressed.

It can be controlled from esphome by connecting an open drain output to this node as well.

However, I would also like to catch the manual button presses, so the position of the blinds can be tracked with cover time based addon.

It seems to be not allowed to have a binary_sensor and a switch on the same pin. It must be possible though, as it is the same as would happen in a I2C bus. Maybe use it as an output and for the short moment of pulling down, while otherwise using it as input?

How can I do that?

Thanks!

PS: here is my current code, where I am using two separate pins for this purpose:

switch:
  - platform: gpio
    pin: 
      number: GPIO1  #TX
      inverted: True
      mode: OUTPUT_OPEN_DRAIN
    id: "switch_auf"
    name: "Switch Auf"
    on_turn_on:
      - delay: 200ms
      - switch.turn_off: switch_auf

binary_sensor:  
  - platform: gpio
    pin: 
      number: GPIO3  #RX
      inverted: true
      mode:
        input: true
    id: "sensor_auf"
    name: "Sensor Auf"
    filters:
      - delayed_on: 10ms
      - delayed_off: 10ms
´´´

“It’s not allowed” isn’t very informative. Always show log output rather than just comments like “it doesn’t work”.

I’ll guess that it is “pin xx is used in multiple places” or similar. You can add allow_other_uses: true to the pin definitions. It might then work providing the pin mode does get set to output.

Alternatively, just bridge your pins 1 and 3, so one is the input and one is the output.

Either way you will get the binary sensor triggered when the button is pressed, whether by your device or the actual button.

The exact error is as you guessed:

INFO ESPHome 2024.12.4
INFO Reading configuration /config/esphome/velux-jalousie-badezimmer.yaml...
Failed config

switch.gpio: [source /config/esphome/velux-jalousie-badezimmer.yaml:35]
  
  Pin 1 is used in multiple places.
  platform: gpio
  pin: 
    number: 1
    inverted: True
    mode: 
      output: True
      open_drain: True
      input: False
      pullup: False
      pulldown: False
      analog: False
  id: switch_auf
binary_sensor.gpio: [source /config/esphome/velux-jalousie-badezimmer.yaml:68]
  
  Pin 1 is used in multiple places.
  platform: gpio
  pin: 
    number: 1
    inverted: True
    mode: 
      input: True
      output: False
      open_drain: False
      pullup: False
      pulldown: False
      analog: False
  id: sensor_auf

allow_other_uses seems to at least allow it to compile, i will try if it actually does what it should. Thank you.

Short on the board I would rather not do, as on the small boards the number of outputs is limited and I need a few pins to automate what I would like to do.

I tried now to load the firmware to the board and check the behaviour, but it does not work as expected.

I would think that something like setting the board the output before outputing, then setting it back to input after a delay is necessary.

Anyway, I resorted to shorting two pins together and using one as opendrain output, the other one as input.

Works for me, but I can imagine it would still be useful to have this ability.

Esphome pin mode also gives option INPUT_OUTPUT_OPEN_DRAIN, no idea how it’s implemented though. Neither if usage of TX pin can cause some conflicts and how is the circuit of your board between TX pin and CH340.

I have been trying put together a similar solution for anohter setup, posted about it here:

Didn’t get any hints but worked my way to be able to change pinmode at runtime and execute reads and write in sequence to the same pin, maybe you could have use for my code:

binary_sensor:
- platform: gpio
  name: "ingang5"
  id: in5
  pin:
    id: in_pin_5
    number: GPIO5
    allow_other_uses: true
    mode: INPUT_PULLUP
    inverted: true

output:
- platform: gpio
  id: out5
  pin:
    id: out_pin_5
    number: GPIO5
    allow_other_uses: true
    inverted: true

button:
- platform: template
  name: "toggel pin 5"
  on_press:
    - logger.log: Button Pressed

    - lambda: |-
        id(out_pin_5)->pin_mode(gpio::FLAG_OUTPUT);
        id(out5)->setup();
    - output.turn_on: out5

    - delay: 10ms

    - lambda: |-
        id(in_pin_5)->pin_mode(gpio::FLAG_INPUT);
        id(in5)->setup();
1 Like

Thank you, I think that is exactly what I needed. I did not try it as I found another way to achieve what I want, but I mark your code as solution!

1 Like

I built this one that does what you want, works well for me and includes PCB design and 3D case.