I’m building a simple device with an ESPHome ESP32 as the core. It has a single button and a single status LED phsyically wired to GPIOs - both are working.
Where I’m struggling is with managing the swtich press/clicks. What I want to acheive is a simple latch where the LED turns on when the button is short-pressed, and the LED turns off when the button is long-pressed. Sounds simple, and to some extent it is, I’ve acheived this very easily with:
on_click:
- min_length: 50ms
max_length: 350ms
then:
- output.turn_on: led
- min_length: 2000ms
max_length: 5000ms
then:
- output.turn_off: led
However this isn’t quite what I want, as these on_click actions trigger on the trailing edge it requires the user to know how long to press the buttons for. What I would like is to make it more intuitve, so that as soon as the button is depressed for 50ms the LED lights up, and as soon as it depressed for more than 2000ms it turns off - i.e. the user gets instant feedback that the action has been completed without taking their finger off the button. I appreacite this comes with a complication, because technically depressing the button for 2000+ms is ALSO depressing it for more than 50ms but that is fine, I’m ok for both actions to be triggered by the long press.
Is there a way to do this using on_press? Or will it require a custom lambda? If so… any hints?
Perhaps, but this turned out to be very easy to do with on_press I trigger the first action immediately then wait for the 2s long press timeout and test whether the button is still pressed, and reset conditionally on that. Possibly some race conditions might occur here because if you did mulitple short presses then you might have the switch ON during the test despite it not being a long press, but I don’t think that will be an issue with this use-case.
on_press:
then:
- output.turn_on: led
- delay: 2s
- if:
condition:
binary_sensor.is_on: button
then:
- output.turn_off: led
- logger.log: "LED is Reset"
else:
- logger.log: "LED is Set"
Yep you got it, max_length is optional only because it defaults to 350ms. If your min_length is greater than 350ms then not providing max_length will fail to compile because min_length must be less than max_length.
Hmm - I have been thinking about something like this for a while. Can you combine on_press: with on_click:, so I can have some visible indications PLUS act on different length clicks?
You can, but you have to be aware the on_press action will trigger immediately and the full automation block for the on_press action will run regardless of whether the button is released before it completes.
I realised you can avoid this race condition by just putting a ‘cooldown’ timer on the on_press automation that is longer than the long_press time. This only works if your real-world usecase can tolerate this and isn’t expecting multiple short presses in short space of time. My use case is indicating that someone has deposited a package in a location and I don’t need to know how many packages, and the chances of two packages being dropped by different people in the space of 2 seconds is virtually impossible.
I still didn’t test it, but this probably does not work, because the filter probably already applies to the initial on_press action so the led will not go on at all?
Just for fun one more idea: would it work to create two binary sensors listening to the same input button. The first sensor immediately switches the led on when the button is pressed, and the second sensor switches the led off again when the button is pressed for more than 2 seconds. Something like this:
Just for completeness: in the mean time I did a simple test, and indeed it does work like this.
This was my test set-up, with one momentary push button and one led connected to an ESP8266:
binary_sensor:
- platform: gpio
id: g0
pin:
number: 0
mode: input_pullup
inverted: true
on_press:
- switch.turn_on: led
on_multi_click:
- timing:
- on for at least 1s
then:
- switch.turn_off: led