Differentiate Double & Single Click of a button

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Mrfittingin
Posts: 3
Joined: Wed May 27, 2020 7:33 pm

Differentiate Double & Single Click of a button

Post by Mrfittingin » Wed May 27, 2020 7:48 pm

Hey guys
I have started to learn MicroPython recently, there is one problem I struggled for a while, I have been searching for solutions online and still have no clew what to do. Please help, Thanks.
This is the code, I have used aswitch.py module, I wish to achieve when I am double click the button, only the Yellow LED lights up( the Blue LED has no reaction while there is a double click of the button). and When this is long press, only the Green LED lights up. ( the Blue LED has no reaction while there is a long press of the button)
How should I change the Code to reach this function?

Code: Select all

from pyb import LED
from machine import Pin
import uasyncio as asyncio
from aswitch import Pushbutton

def toggle(led):
    led.toggle()

async def my_app():
    await asyncio.sleep(600)

pin = Pin('X1', Pin.IN, Pin.PULL_UP)  # Pushbutton to gnd
blue = LED(4)
yellow = LED(3)
green = LED(2)

pb = Pushbutton(pin)

pb.press_func(toggle, (blue,))  # Note how function and args are passed
pb.double_func(toggle, (yellow,))  # Note how function and args are passed
pb.long_func(toggle, (green,))  # Note how function and args are passed

loop = asyncio.get_event_loop()
loop.run_until_complete(my_app())  # Run main application code

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: Differentiate Double & Single Click of a button

Post by kevinkk525 » Wed May 27, 2020 9:18 pm

pb = Pushbutton(pin, suppress=True)

Should solve your problem.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

Mrfittingin
Posts: 3
Joined: Wed May 27, 2020 7:33 pm

Re: Differentiate Double & Single Click of a button

Post by Mrfittingin » Thu May 28, 2020 12:17 pm

Hey Kiven

Thank you for you help, I have added pb = Pushbutton(pin, suppress=True) into my code, but it did not work as I expected, the blue light always light up when the first click was pushed of the double click (same for the long press as well).

I wonder if there is any delay function or time frame interval function to let the full signal to go through, then start to process it?

I pasted the code down below.

Thank you!

Code: Select all

from pyb import LED
from machine import Pin
import uasyncio as asyncio
from aswitch import Pushbutton

def toggle(led):
    led.toggle()

async def my_app():
    await asyncio.sleep(600)

pin = Pin('X1', Pin.IN, Pin.PULL_UP)  # Pushbutton to gnd
blue = LED(4)
yellow = LED(3)
green = LED(2)

pb = Pushbutton(pin, suppress=True)


pb.double_func(toggle, (yellow,))  # Note how function and args are passed
pb.long_func(toggle, (green,))  # Note how function and args are passed

pb.press_func(toggle, (blue,))  # Note how function and args are passed

loop = asyncio.get_event_loop()
loop.run_until_complete(my_app())  # Run main application code

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Differentiate Double & Single Click of a button

Post by pythoncoder » Fri May 29, 2020 10:20 am

@Mrfittingin I think you have misunderstood the docs.

For a callback which occurs only on a single short press, you need to assign it to release_func and set suppress=True. As you have found, press_func still occurs on initial button press; this is by design. The reasoning is explained in the above doc. Note that response is necessarily delayed: this is also explained in the doc.
Peter Hinch
Index to my micropython libraries.

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: Differentiate Double & Single Click of a button

Post by kevinkk525 » Fri May 29, 2020 10:37 am

oh yes, thanks @pythoncoder. I missed the detail about having to use the release_func
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

Mrfittingin
Posts: 3
Joined: Wed May 27, 2020 7:33 pm

Re: Differentiate Double & Single Click of a button

Post by Mrfittingin » Mon Jun 01, 2020 2:24 pm

Thank you so much for your help, problem solved!

aerolite
Posts: 3
Joined: Fri Mar 05, 2021 2:42 am

Re: Differentiate Double & Single Click of a button

Post by aerolite » Fri Mar 05, 2021 2:51 am

Hello, I am new to micropython and have the same question for ESP32 board. Could anyone help me? I am using the M5ATOM stepper https://docs.m5stack.com/#/en/atom/atomic_step_motor I'd like to use single click to control the direction and double click to increase the speed.

thx

Code: Select all

import stepper
import lite
import machine
import time

last_button_press = 0

if (stepper.dcInput() == 0):
    lite.flashRed()
else:
    lite.flashGreen()

def move(irq):
    print(stepper.dcInput(),stepper.EN, stepper.DIR)
    
    if (stepper.dcInput() == 0):
        stepper.enable(False)
        stepper.setSpeed(1)
        lite.flashOFF()
        lite.flashRed()
        return
    
    if (stepper.EN == 0 ):
        stepper.enable()
        lite.flashOFF()
        lite.greenON(1)
    
    if (stepper.DIR == 0):
        stepper.direction(1)
        lite.flashOFF()
        lite.greenON(1)
    else:
        stepper.direction(0)
        lite.flashOFF()
        lite.blueON(1)
        
    print("button pressed"+str(stepper.DIR))

def double_click(inq):
    
    global last_button_press
    
    # Get the current date in milliseconds
    time_ms = time.ticks_ms()
    # Compute the elapsed time since the last interrupt
    delay = time.ticks_diff(time_ms, last_button_press)
    # If the delay is shorter than 200ms (your mileage may vary), consider this as a bounce
    if (delay < 200) :
        return
    # Else, we update the time of the last interrupt
    last_button_press = time_ms
    # If the delay is greater than 500ms (to be adjusted), it is a simple clock
    if delay > 600: # simple click
        move(1)
    else:
        stepper.setSpeed(stepper.SPEED+1)


button = machine.Pin(39, machine.Pin.IN, machine.Pin.PULL_UP)

button.irq(trigger = machine.Pin.IRQ_FALLING, handler = double_click)


User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Differentiate Double & Single Click of a button

Post by pythoncoder » Fri Mar 05, 2021 10:40 am

See this doc which describes a Pushbutton class where you can define callbacks for single and double clicks.
Peter Hinch
Index to my micropython libraries.

aerolite
Posts: 3
Joined: Fri Mar 05, 2021 2:42 am

Re: Differentiate Double & Single Click of a button

Post by aerolite » Mon Mar 29, 2021 1:49 am

Thank you for the information. But I still can't differentiate them. I use press and long function. when I long press the the press function still called. Here is my code and output. single press is good, but long press is not.

Code: Select all

def toggleRed():
    if (lite.lightStat()[0] == 0):
        lite.redON(1)
    else:
        lite.lightOFF(0)

    print( "red", lite.lightStat()[0] )

def toggleGreen():
    if (lite.lightStat()[1] == 0):
        lite.greenON(1)
    else:
        lite.lightOFF(0)
        
    print( "green", lite.lightStat()[1] )

async def my_app():
    await asyncio.sleep(60)  # Dummy

pin = Pin(39, Pin.IN, Pin.PULL_UP)  # Pushbutton to gnd
pb = Pushbutton(pin)
pb.press_func(toggleRed)  # Note how function and args are passed
#pb.double_func(toggleGreen)
pb.long_func(toggleGreen)
asyncio.run(my_app())  # Run main application code
red 64
red 0
red 64
red 0
red 64
red 0
red 64
red 0
red 64
green 64
red 64
green 64
red 64
green 64
red 64
green 64
red 64
green 64

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Differentiate Double & Single Click of a button

Post by pythoncoder » Mon Mar 29, 2021 6:35 am

when I long press the the press function still called.
This is a) inevitable and b) explained in the docs. At the time when you press a button, the driver doesn't yet "know" if the press is going to be a long one. See section 4.1.1, the "suppress" constructor arg.

As for your code, I suggest you start with the demo program making the minimum changes to accommodate ESP32 pin numbers. Then start adapting it for your own ends.
Peter Hinch
Index to my micropython libraries.

Post Reply