GPIO

GPIO pin as GND and 3v3

You can power sensors and other low-draw components on GPIO pins alone. On the ESP32 the GPIO pins can usually supply up to around or so, but the "real" 3v3 pin can supply more. It's really just doable for some low-power sensors.

As GND

To configure a pin as GND, you just have to define it as an output pin that has not been turned on:

output:
  - platform: gpio
    id: fake_gnd
    pin:
      number: ${gpio}
      mode:
        pulldown: true
        output: true

Somewhat confusingly, the pin must be defined as output. Enable pulldown in the pin config when using it as GND.

As 3v3

There are several ways to configure a GPIO pin as a source. The simplest way is to configure the pin as inverted:

output:
  - platform: gpio
    id: supply_3v3
    pin:
      number: ${gpio}
      inverted: true
      mode:
        # Optionally set the maximum amount of current (esp-idf only)
        drive_strength: 40mA
        pullup: true
        output: true

Enabaling pullup activates the internal pull-up resistor on ESP32 boards, which is a resistor from the GPIO to 3v3.

Using strapping pins

If you are using a strapping pin that changes the boot mode by being pulled HIGH, and you will need to define a on_shutdown automation that turns the pin on.

Since the pin is inverted, you'll need to call turn_on() to turn it off.

Note that if the ESP looses power, there is no guarantee that the pin will be in the correct state on boot. Thus it is safer to configure the pin to be turned on during or after booting, so that it is programmed to be LOW when the ESP32 boots.

If you configure the output without inverted it will be LOW on boot, needing an on_boot automation to turn_on and pull it up to HIGH.

output:
  - platform: gpio
    id: supply_3v3
    pin:
      number: ${gpio}
      mode:
        pullup: true
        output: true

esphome:
  on_boot:
    priority: 90
    #  800: hardware init, vital components
    #  600: most sensors are ready
    #  250: wifi is initialized
    #  200: network connections and the esphome tcp api are set up
    #  100: everything is initialized
    then:
      - output.turn_on: supply

Another way is to just use the pin in an gpio switch:

switch:
  - platform: gpio
    id: supply_3v3
    name: "${hostname} GPIO 3v3"
    pin:
      number: ${gpio}
      mode:
        pullup: true
        output: true

Unless internal is enabled, this will show up and work like a regular switch entity in Home Assistant, so it can be turned on/off at will.

Both of these methods are useful for strapping pins as they avoid setting the state of the pin in flash and do it at runtime instead.

Pull-up and pull-down resistors

A pull-up resistor sits between GPIO and /3V3 and "pulls up to positive", while a pull-down resistor sits between GPIO and GND and "pulls down to negative" instead.

Schematic showing the difference between pull-up and pull-down resistors

Schematic by tom_l on Home Assistant forum8.

ESP32 has internal pull-up/pull-down resistors that do this internally on the board (but ESP8266 does not have them).

binary_sensor:
  - platform: gpio
    id: binary_sensor_gpio
    name: "Press"
    pin:
      number: "${gpio_pin}"
      inverted: true
      mode:
        input: true
        pullup: true
        pulldown: false
    publish_initial_state: true

Configuring the pin with pulldown will activate this internal resistor on the ESP32 and connect the GPIO pin to the (real) GND with a resistance.

References

6

Pull-up and Pull-down resistors - EEPower: primer on pull-up/pull-down resistors and how they are used on MCUs.

7

Powering sensors - Alex Mekkering: Using GPIO pins as 3V3 or GND.