Close

Walkthru neotrellis_keypad module

A project log for NeoTrellis Explorations

Adafruit NeoTrellis is a 4x4 button+Neopixel array that can be chained on i2c bus. I am exploring its programming and uses.

Jerry IsdaleJerry Isdale 07/19/2022 at 19:270 Comments

The neotrellis_keypad.py module encapsulates the actions that happen when a key is pressed. A client application need only call setup_keypad() and then in the forever loop, call trellis.sync().  Internally, the doKey() function is associated with each of 16 keys on the neotrellis, and is activated

After the required imports there are a couple module variables. keyColors is an array of  Color, one for each of the 16 keys (hopefully, we dont check size, etc).  keyAnimations is likewise an array associating each key with an animation. 

The setup_keypad() function fills in the globals and sets all 16 neotrellis keys to call doKey() when they are pressed and again when released.

from adafruit_neotrellis.neotrellis import NeoTrellis
import adafruit_led_animation.color as Color

# local modules
import onboard_neopixel
import neotrellis_animations

keyColors = None
keyAnimations = None

__trellis = None

# could be module but short enough for inline
# arrays to map key index to animation and colors
def setup_keypad(trellis):
    global keyColors
    global keyAnimations
    global __trellis
    __trellis = trellis
    keyColors = neotrellis_animations.rainbowPalette
    keyAnimations = neotrellis_animations.trellisAnimations
    # associate 16 trellis keys with doKey() for both press and release
    for i in range(16):
        # activate rising edge events on all keys; key pressed
        __trellis.activate_key(i, NeoTrellis.EDGE_RISING)
        # activate falling edge events on all keys; key released
        __trellis.activate_key(i, NeoTrellis.EDGE_FALLING)
        # set all keys to trigger the doKey() callback
        __trellis.callbacks[i] = doKey

    # --------------- Ready for Main Loop ------------
    # but first lets print out the key colors
    print("key colors", keyColors)
    for clr in keyColors:
        print(hex(clr), end=", ")
    print("")

The doKey() is a callback function. It is triggered by trellis.sync() and given an event.  The event holds a couple entries of interest: edge and number. Depending on whether event.edge shows key was just pressed or just released, we do different actions.

On key press, we set the onboard_neopixel to the key's associated color - by indexing keyColors[] with the event.number. The current animation is frozen (stops updating on animations.animate() call in forever loop). We black out all 16 pixels and set the key's pixel to its keyColor.  Lastly, we blink the onboard pixel, which introduces a blocking delay.  May want to remove that for a responsive application.

Nothing changes while the key is held down, but when it is released, we set the current_animation to the key's associated keyAnimation. It will be run on then next animate() call in forever loop.

Pretty simple. Fairly straight forward to modify for future functions.  Like, maybe, send a midi note like the Astral TV rPi Pico midi remote did?

# doKey() will be called when button events are received
def doKey(event):
    print("\nKeyEvent: ", str(event), " event number",event.number, " edge:",event.edge)
    if event.edge == NeoTrellis.EDGE_RISING:
        # pressed: toggle, stop/freeze current animation, color my pixel
        onboard_neopixel.on_board_neopixel[0] = keyColors[event.number]
        #toggleOnBoardPixel()
        # freeze current animation, set all to black, just the one to its keyColor
        neotrellis_animations.freeze()
        __trellis.pixels.fill(Color.BLACK)
        __trellis.pixels[event.number] = keyColors[event.number]
        print("pixel color", hex(keyColors[event.number]))
        __trellis.pixels.show()
        # blink onboard with same color
        onboard_neopixel.blinkOnBoardPixel(keyColors[event.number])

    # start animationwhen a falling edge is detected
    elif event.edge == NeoTrellis.EDGE_FALLING:
        #toggleOnBoardPixel()
        onboard_neopixel.on_board_neopixel[0] = Color.BLACK
        __trellis.pixels.fill(Color.BLACK)
        #trellis.pixels[event.number] = Color.BLACK
        neotrellis_animations.set_animation_byIndex(event.number)
        neotrellis_animations.current_animation.resume()
        print("new animation", neotrellis_animations.current_animation)

Discussions