Continuously toggling a GPIO pin?

I’m just getting started with ESPHome but struggling to find the info i need for this simple project.

I would like GPIO Pin 7 (Wemos D1 Mini ESP32 C3) to go high for 5 seconds every minute and loop continuously. This is to drive a small fan (via a transistor) to pull air into a DIY ceiling mounted air quality and temp sensor. This is all based on several I2C sensors which i have working fine.

I tried using a simple Relay command but seems the loop has to be automated within homeassistant somehow, rather than the ESPHome code (as it would if this were a traditional arduino app). I suspect i’ve misunderstood but cannot find what i’m looking for!

Ideally, i would also like to sequence this, so that any of the per minute readings from the I2C sensors occur 20 seconds after the fan stops and the complete 60 second loop restarting. This would be to prevent any false readings while the fan is running.

I did read the following article but non the wiser! Any help appreciated, thank you.

GPIO Switch — ESPHome

1 Like

Can you set the duty cycle though?

Thank you @FloatingBoater, a great help and may do what i need. I have a similar question to @parautenbach - is it possible for on/off period to be different? i.e. 5 seconds high, 55 seconds low…

i assume there’s no possibility of defining where in the overall ‘program’ this happens to ensure the GPIO pin does not go high at the same time the 60s I2C sensor data is requested.

Many thanks

I searched now a bit more out of curiosity, and it doesn’t seem like there’s a straightfoward, built-in way to do this (surprisingly so).

I think you might be able to simulate it with this: Sigma-Delta Output — ESPHome.

Or you could use a GPIO Switch — ESPHome and control it with ESPHome automations.

Making an output component could maybe work too: On for 5s, then off. Turn off with an automation on an interval. Template Output — ESPHome

See in particular also: Automations and Templates — ESPHome.

If all else fails, there’s always External Components — ESPHome. I did a search for matching external components, but couldn’t find any.


I’ve a fully worked ESPhome example of a slow_pwm driving a towel radiator (resistive heater via a Shelly relay), which does have both period (period: 300s) and duty-cycle (level: 40%) control.

The function of the output was checked via an oscilloscope, and the simple hack of defining a separate output pin mirroring the PWM relay - meaning the HASS History showed the exact timing of a Slow_PWM output directly (HASS as the worlds slowest logic analyser!).

The code is complicated by my use of a select to give a drop-down of pre-defined heat levels and a script so a timer is only called ONCE, but in summary…

# Define slow_pwm for heater control
  - platform: slow_pwm
    pin: GPIO26
    #inverted: True
    id: relay0
    period: 300s
    restart_cycle_on_state_change: True

<stuff deleted>

# Define a script to ensure Dry mode timers are only executed ONCE
  - id: dry_script
    mode: single
      - logger.log: "Dry High"
      - output.set_level:
          id: relay0
          level: 100%
      - delay: 30min
      - logger.log: "Dry Medium"
      - output.set_level:
          id: relay0
          level: 40%
      - delay: 90min
      - logger.log: "Dry Off"
      - output.set_level:
          id: relay0
          level: 0%
      - select.set:
          id: heat_mode
          option: "Off"

There’s obviously a lot more in the code, but it’s not made it to GitHub (yet) as I’d need to document it and add safety caveats (Chartered Engineer so need to be careful about liabilities).

If this helps, :heart: this post!

Where do you make the connection between that output with its level and where it’s used by the slow PWM? I really looked hard for anything in the docs regarding a duty cycle.

      - output.set_level:
          id: relay0
          level: 40%
1 Like

Ah, thanks – the ID. TIL.

Thanks for this info, I have been looking for a means to flash some LEDs at a known duty cycle and period for simulating a device for testing and this SlowPWM should do the trick.

The doco for the ‘output’ command does not really say that the ‘output_level_set’ changes the duty cycle so I’m not sure how anyone would know that.

I did some quick testing at 5% and 75% and it looks like it will do what I want.

1 Like

Let’s just say setting the duty cycle took me a few days to get to compile, nevermind actually match my use case!

I even had to use an external YAML linter / parser to troubleshoot this project - config like selectors, PWM, and a single timer instance were all “challenging”.

Glad to see you’ve also cracked the code.

A bit off topic but I have hit a problem with my use for slow_pwm and there has not been much response to my other topic.

When I try I get an error: “This option is not templatable!”

Is there any way to set the period of the slow_pwm component from the value of another control ?