NEED HELP WITH PHYTON PROGRAMMING BUTTONS

Hi everyone! I'm currently building the lightsaber prop example with the feather m4 express and prop-maker. I have some doubts about how to program my button in such a way that it contemplates long click short click and multiple clicks.

1) So this are the 3 cases my button should have:

a) When buton is keep pressed for more than 1/2 seconds power-on or power-off the saber.

b) When button is pressed just once fast do the blaster hit effect (sound and flash of light)

c) When buton is pressed 3 times fast do Lockup sound and light effect. And other 3 times to get out of this function.

This is my current code, I progressed a bit with the programming of items a) and b), but I don't know if it's correct. And regarding item c) I don´t know how to do it..
For this I used the time.monotonic() function (I think it's the equivalent of millis() in Python ):

Code: Select all | TOGGLE FULL SIZE
`[...]prev = 0buttonState = 0  # 0 = not pressed   --- 1 = long pressed --- 2 short pressedDURATION_IN_MILLIS = 1000while True:  buttonState = 0  if not switch.value:     # button pressed?    prev = time.monotonic()    buttonState = 1  # long pressed    while((time.monotonic()-prev)<=DURATION_IN_MILLIS)      if switch.value:         buttonState = 2  # short pressed        break    if buttonState == 0  # Nothing is pressed. If on then do idle, hit and swing stuff      if mode >= 1:      # It is ON        x, y, z = accel.acceleration # Read accelerometer        accel_total = x * x + z * z        # (Y axis isn't needed for this, assuming Hallowing is mounted        # sideways to stick.  Also, square root isn't needed, since we're        # just comparing thresholds...use squared values instead, save math.)                              if accel_total > HIT_THRESHOLD:  # Large acceleration = HIT            play_wav(random.choice(hit_sounds))  # Start playing 'hit' sound            led.color = COLOR_HIT  # Set color to hit color            mode = 3  # HIT mode        elif mode == 1 and accel_total > SWING_THRESHOLD:  # Mild = SWING            play_wav(random.choice(swing_sounds))  # Randomly choose from available swing sounds            led.color = COLOR_SWING  # Set color to SWING COLOR            mode = 2  # SWING mode        elif mode == 1:            # Idle color            led.color = COLOR_IDLE        elif mode > 1:  # If in SWING or HIT mode...            if audio.playing:  # And sound currently playing...                if mode == 2:  # If SWING,                    led.color = COLOR_SWING                else:                    led.color = COLOR_HIT  # Set color to hit color            else:  # No sound now, but still SWING or HIT modes                play_wav('idle', loop=True)  # Resume idle sound                mode = 1  # Return to idle mode                      elif buttonState == 1  # Button is pressed long    if mode == 0:                       # If currently off...        enable.value = True        power('on', 1.7, False)         # Power up!        play_wav('idle', loop=True)     # Play background hum sound        mode = 1                        # ON (idle) mode now    else:                               # else is currently on...        power('off', 1.15, True)        # Power down        mode = 0                        # OFF mode now        enable.value = False    while not switch.value:             # Wait for button release        time.sleep(0.2)                 # to avoid repeated triggering                elif buttonState == 2  # Button is pressed short    # This could be used for blaster hit animation and sound    if mode >= 1:        play_wav(random.choice(blaster_sounds))  # Start playing 'blaster hit' sounds        led.color = COLOR_BLASTER`

2) I tried to program the lightsaber on and off animation for a 3 watt high power RGB LED. Is this code ok?

Code: Select all | TOGGLE FULL SIZE
`def power(sound, duration, reverse):    """    Animate 3W LED with accompanying sound effect for power on / off.    @param sound:    sound name (similar format to play_wav() above)    @param duration: estimated duration of sound, in seconds (>0.0)    @param reverse:  if True, do power-off effect (reverses animation)    """        #gc.collect()   # Tidy up RAM now so animation's smoother        play_wav(sound, loop=False)  #PLAY THE ON OR OFF SOUND    if reverse:        LEDPWM(True) #Power Down light animation (fade out)    elif:        LEDPWM(False) #Power Up light animation (fade in)            while audio.playing:     # Wait until audio done        passdef LEDPWM(reverse)           if reverse:         # Fade from full red to nothing        for i in range(255):            led.color = (255-i,0,0)            time.sleep(duration)    else:        # Fade from nothing up to full red.        for i in range(255):            led.color = (i,0,0)            time.sleep(duration)`

Here is the full code for reference:

Code: Select all | TOGGLE FULL SIZE
`# pylint: disable=bare-exceptimport timeimport randomimport mathfrom digitalio import DigitalInOut, Direction, Pullimport audioioimport busioimport boardimport adafruit_rgbledimport adafruit_lis3dhimport gc# CUSTOMIZE YOUR COLOR HERE:# (red, green, blue) -- each 0 (off) to 255 (brightest)#COLOR = (255, 0, 0)  # red#COLOR = (100, 0, 255)  # purple# COLOR = (0, 100, 255) #cyan# "Idle" color is about 4/5 brightness, "swinging" color is full brightness...COLOR_IDLE = (240, 0, 0) # 240 FOR LOWER RED INTENSITYCOLOR_SWING = (255, 0, 0) # 240 FOR FULL RED INTENSITYCOLOR_HIT = (255, 255, 255)  # "hit" color is whiteCOLOR_BLASTER = (0, 0, 255)  # "Blaster hit" color is blue# CUSTOMIZE SENSITIVITY HERE: smaller numbers = more sensitive to motionHIT_THRESHOLD = 350 # 250SWING_THRESHOLD = 125POWER_PIN = board.D10   # TODO: ADAPT FOR ONLY 1 BUTTON, POWER WILL BE ALWAYS ON UNLESS KILL PIN IS INSIDE, MAYBE SOLDER THIS PINSWITCH_PIN = board.D9   enable = DigitalInOut(POWER_PIN)  enable.direction = Direction.OUTPUTenable.value =Falseswitch = DigitalInOut(SWITCH_PIN)switch.direction = Direction.INPUTswitch.pull = Pull.UPred_led = board.D11green_led = board.D12blue_led = board.D13# Create the RGB LED objectled = adafruit_rgbled.RGBLED(red_led, green_led, blue_led)audio = audioio.AudioOut(board.A0)     # Speakermode = 0                               # Initial mode = OFF# time.sleep(0.1)# Set up accelerometer on I2C bus, 4G range:i2c = busio.I2C(board.SCL, board.SDA)accel = adafruit_lis3dh.LIS3DH_I2C(i2c)accel.range = adafruit_lis3dh.RANGE_4_Gdef play_wav(name, loop=False):    """    Play a WAV file in the 'sounds' directory.    @param name: partial file name string, complete name will be built around                 this, e.g. passing 'foo' will play file 'sounds/foo.wav'.    @param loop: if True, sound will repeat indefinitely (until interrupted                 by another sound).    """    print("playing", name)    try:        wave_file = open('sounds/' + name + '.wav', 'rb')        wave = audioio.WaveFile(wave_file)        audio.play(wave, loop=loop)    except:        return        # List of swing wav files without the .wav in the name for use with play_wav()swing_sounds = [    'swing1',    'swing2',    'swing3',    'swing4',    'swing5',    'swing6',    'swing7',    'swing8',]# List of hit wav files without the .wav in the name for use with play_wav()hit_sounds = [    'hit1',    'hit2',    'hit3',    'hit4',    'hit5',    'hit6',    'hit7',    'hit8',]# List of blaster wav files without the .wav in the name for use with play_wav()blaster_sounds = [    'blaster',    'blaster2',    'blaster3',    'blaster4',]def power(sound, duration, reverse):    """    Animate 3W LED with accompanying sound effect for power on / off.    @param sound:    sound name (similar format to play_wav() above)    @param duration: estimated duration of sound, in seconds (>0.0)    @param reverse:  if True, do power-off effect (reverses animation)    """        #gc.collect()   # Tidy up RAM now so animation's smoother        play_wav(sound, loop=False)  #PLAY THE ON OR OFF SOUND    if reverse:        LEDPWM(True) #Power Down light animation (fade out)    elif:        LEDPWM(False) #Power Up light animation (fade in)            while audio.playing:     # Wait until audio done        passdef LEDPWM(reverse)           if reverse:         # Fade from full red to nothing        for i in range(255):            led.color = (255-i,0,0)            time.sleep(duration)    else:        # Fade from nothing up to full red.        for i in range(255):            led.color = (i,0,0)            time.sleep(duration)            #TODO: make it so it would be easy to change colors (for green and blue).# Main program loop, repeats indefinitelywhile True:    if not switch.value:                    # button pressed?        if mode == 0:                       # If currently off...            enable.value = True            power('on', 1.7, False)         # Power up!            play_wav('idle', loop=True)     # Play background hum sound            mode = 1                        # ON (idle) mode now        else:                               # else is currently on...            power('off', 1.15, True)        # Power down            mode = 0                        # OFF mode now            enable.value = False        while not switch.value:             # Wait for button release            time.sleep(0.2)                 # to avoid repeated triggering    elif mode >= 1:                         # If not OFF mode...        x, y, z = accel.acceleration # Read accelerometer        accel_total = x * x + z * z        # (Y axis isn't needed for this, assuming Hallowing is mounted        # sideways to stick.  Also, square root isn't needed, since we're        # just comparing thresholds...use squared values instead, save math.)        if accel_total > HIT_THRESHOLD:  # Large acceleration = HIT            play_wav(random.choice(hit_sounds))  # Start playing 'hit' sound            led.color = COLOR_HIT  # Set color to hit color            mode = 3  # HIT mode        elif mode == 1 and accel_total > SWING_THRESHOLD:  # Mild = SWING            play_wav(random.choice(swing_sounds))  # Randomly choose from available swing sounds            led.color = COLOR_SWING  # Set color to SWING COLOR            mode = 2  # SWING mode        elif mode == 1:            # Idle color            led.color = COLOR_IDLE        elif mode > 1:  # If in SWING or HIT mode...            if audio.playing:  # And sound currently playing...                if mode == 2:  # If SWING,                    led.color = COLOR_SWING                else:                    led.color = COLOR_HIT  # Set color to hit color            else:  # No sound now, but still SWING or HIT modes                play_wav('idle', loop=True)  # Resume idle sound                mode = 1  # Return to idle mode"""#IN PROGRESS Main program loop FOR LONG CLICK AND SHORT CLICKprev = 0buttonState = 0  # 0 = not pressed   --- 1 = long pressed --- 2 short pressedDURATION_IN_MILLIS = 1000while True:  buttonState = 0  if not switch.value:     # button pressed?    prev = time.monotonic()    buttonState = 1  # long pressed    while((time.monotonic()-prev)<=DURATION_IN_MILLIS)      if switch.value:         buttonState = 2  # short pressed        break    if buttonState == 0  # Nothing is pressed. If on then do idle, hit and swing stuff      if mode >= 1:      # It is ON        x, y, z = accel.acceleration # Read accelerometer        accel_total = x * x + z * z        # (Y axis isn't needed for this, assuming Hallowing is mounted        # sideways to stick.  Also, square root isn't needed, since we're        # just comparing thresholds...use squared values instead, save math.)                              if accel_total > HIT_THRESHOLD:  # Large acceleration = HIT            play_wav(random.choice(hit_sounds))  # Start playing 'hit' sound            led.color = COLOR_HIT  # Set color to hit color            mode = 3  # HIT mode        elif mode == 1 and accel_total > SWING_THRESHOLD:  # Mild = SWING            play_wav(random.choice(swing_sounds))  # Randomly choose from available swing sounds            led.color = COLOR_SWING  # Set color to SWING COLOR            mode = 2  # SWING mode        elif mode == 1:            # Idle color            led.color = COLOR_IDLE        elif mode > 1:  # If in SWING or HIT mode...            if audio.playing:  # And sound currently playing...                if mode == 2:  # If SWING,                    led.color = COLOR_SWING                else:                    led.color = COLOR_HIT  # Set color to hit color            else:  # No sound now, but still SWING or HIT modes                play_wav('idle', loop=True)  # Resume idle sound                mode = 1  # Return to idle mode                      elif buttonState == 1  # Button is pressed long    if mode == 0:                       # If currently off...        enable.value = True        power('on', 1.7, False)         # Power up!        play_wav('idle', loop=True)     # Play background hum sound        mode = 1                        # ON (idle) mode now    else:                               # else is currently on...        power('off', 1.15, True)        # Power down        mode = 0                        # OFF mode now        enable.value = False    while not switch.value:             # Wait for button release        time.sleep(0.2)                 # to avoid repeated triggering                elif buttonState == 2  # Button is pressed short    # This could be used for blaster hit animation and sound    if mode >= 1:        play_wav(random.choice(blaster_sounds))  # Start playing 'blaster hit' sounds        led.color = COLOR_BLASTER     """`

Kyuga

Posts: 18
Joined: Sun Jan 26, 2020 6:23 am

Re: NEED HELP WITH PHYTON PROGRAMMING BUTTONS

Have a look at the debouncer module: https://learn.adafruit.com/debouncer-library-python-circuitpython-buttons-sensors. Since that guide was written, timing information has been added to the library and might be just what you need. Here's the example:

Code: Select all | TOGGLE FULL SIZE
`import timeimport boardfrom digitalio import DigitalInOut, Direction, Pullfrom adafruit_debouncer import Debouncerbutton = DigitalInOut(board.D4)button.direction = Direction.INPUTbutton.pull = Pull.UPswitch = Debouncer(button)while True:    switch.update()    if switch.fell:        print('pressed')        print('was released for ', switch.last_duration)    elif switch.rose:        print('released')        print('was pressed for ', switch.last_duration)    else:        print('Stable for ', switch.current_duration)    time.sleep(0.1)`

Dave

dastels

Posts: 1643
Joined: Tue Oct 20, 2015 3:22 pm

Re: NEED HELP WITH PHYTON PROGRAMMING BUTTONS

dastels wrote:Have a look at the debouncer module: https://learn.adafruit.com/debouncer-library-python-circuitpython-buttons-sensors. Since that guide was written, timing information has been added to the library and might be just what you need. Here's the example:

Code: Select all | TOGGLE FULL SIZE
`import timeimport boardfrom digitalio import DigitalInOut, Direction, Pullfrom adafruit_debouncer import Debouncerbutton = DigitalInOut(board.D4)button.direction = Direction.INPUTbutton.pull = Pull.UPswitch = Debouncer(button)while True:    switch.update()    if switch.fell:        print('pressed')        print('was released for ', switch.last_duration)    elif switch.rose:        print('released')        print('was pressed for ', switch.last_duration)    else:        print('Stable for ', switch.current_duration)    time.sleep(0.1)`

Dave

Very interesting! I think that in my case I could simply use the Rose parameter, and check the "switch.current_duration". Maybe something like this:

Code: Select all | TOGGLE FULL SIZE
`import timeimport boardfrom digitalio import DigitalInOut, Direction, Pullfrom adafruit_debouncer import Debouncerbutton = DigitalInOut(board.D4)button.direction = Direction.INPUTbutton.pull = Pull.UPswitch = Debouncer(button)while True:    switch.update()    if switch.rose:  # button released        if switch.last_duration < 0.1  # was pressed for 100 miliseconds, short clic             #Do stuff        elif switch.last_duration >= 1  # was pressed for 1 second, long clic             #Do other stuff    else:        print('Stable for ', switch.current_duration)    time.sleep(0.1)`

Kyuga

Posts: 18
Joined: Sun Jan 26, 2020 6:23 am

Re: NEED HELP WITH PHYTON PROGRAMMING BUTTONS

That would do it.

dastels

Posts: 1643
Joined: Tue Oct 20, 2015 3:22 pm