Once you've finished setting up your RP2040 QT Py with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download to your computer as a zipped folder.
# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries # # SPDX-License-Identifier: MIT import board import usb_hid import neopixel from rainbowio import colorwheel from adafruit_debouncer import Button from adafruit_seesaw import seesaw, rotaryio, digitalio from adafruit_hid.consumer_control import ConsumerControl from adafruit_hid.consumer_control_code import ConsumerControlCode from adafruit_hid.keyboard import Keyboard from adafruit_hid.keycode import Keycode enc_inc = ConsumerControlCode.VOLUME_INCREMENT enc_dec = ConsumerControlCode.VOLUME_DECREMENT one_press = ConsumerControlCode.PLAY_PAUSE two_press = ConsumerControlCode.SCAN_NEXT_TRACK three_press = [Keycode.LEFT_CONTROL, Keycode.UP_ARROW] long_press = ConsumerControlCode.MUTE cc = ConsumerControl(usb_hid.devices) kbd = Keyboard(usb_hid.devices) pixel_pin = board.A1 num_pixels = 18 pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=.5, auto_write=True) hue = 0 pixels.fill(colorwheel(hue)) i2c = board.STEMMA_I2C() seesaw = seesaw.Seesaw(i2c, 0x36) seesaw.pin_mode(24, seesaw.INPUT_PULLUP) ss_pin = digitalio.DigitalIO(seesaw, 24) button = Button(ss_pin, long_duration_ms=600) encoder = rotaryio.IncrementalEncoder(seesaw) last_position = 0 while True: position = -encoder.position button.update() if position != last_position: if position > last_position: cc.send(enc_dec) hue = hue - 7 if hue <= 0: hue = hue + 256 else: cc.send(enc_inc) hue = hue + 7 if hue >= 256: hue = hue - 256 pixels.fill(colorwheel(hue)) last_position = position if button.short_count == 1: cc.send(one_press) if button.short_count == 2: cc.send(two_press) if button.short_count == 3: kbd.press(*three_press) kbd.release_all() if button.long_press: cc.send(long_press)
Upload the Code and Libraries to the RP2040 QT Py
After downloading the Project Bundle, plug your RP2040 QT Py into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the Feather's CIRCUITPY drive:
- lib folder
- code.py
Your RP2040 QT Py CIRCUITPY drive should look like this after copying the lib folderĀ and the code.py file.

How the CircuitPython Code Works
At the top of the code are variables for the keycodes that are sent by the media dial. You can update these keycodes if you want the media dial to do different things. By default, turn the encoder increases or decreases volume, one short press sends play/pause, two short presses sends next track, three short presses sends the mission control keyboard short for MacOS and a long press mutes your speaker volume.
enc_inc = ConsumerControlCode.VOLUME_INCREMENT enc_dec = ConsumerControlCode.VOLUME_DECREMENT one_press = ConsumerControlCode.PLAY_PAUSE two_press = ConsumerControlCode.SCAN_NEXT_TRACK three_press = [Keycode.LEFT_CONTROL, Keycode.UP_ARROW] long_press = ConsumerControlCode.MUTE
HID, NeoPixels and seesaw
The Keyboard USB HID device is instantiated, followed by the NeoPixels and seesaw rotary encoder.
cc = ConsumerControl(usb_hid.devices) kbd = Keyboard(usb_hid.devices) pixel_pin = board.A1 num_pixels = 18 pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=.5, auto_write=True) hue = 0 pixels.fill(colorwheel(hue)) i2c = board.STEMMA_I2C() seesaw = seesaw.Seesaw(i2c, 0x36) seesaw.pin_mode(24, seesaw.INPUT_PULLUP) ss_pin = digitalio.DigitalIO(seesaw, 24) button = Button(ss_pin, long_duration_ms=600) encoder = rotaryio.IncrementalEncoder(seesaw) last_position = 0
The Loop
In the loop, the rotary encoder and its switch are monitored for inputs. If the encoder is turned, then the volume is increased or decreased. The NeoPixels will cycle through the colorwheel colors.
if position != last_position: if position > last_position: cc.send(enc_dec) hue = hue - 7 if hue <= 0: hue = hue + 256 else: cc.send(enc_inc) hue = hue + 7 if hue >= 256: hue = hue - 256 pixels.fill(colorwheel(hue)) last_position = position
The switch on the encoder is defined as a adafruit_debouncer Button
object, allowing you to define a long press duration and count short presses. When the defined presses are detected in the loop, the associated keycodes are sent.Ā
if button.short_count == 1: cc.send(one_press) if button.short_count == 2: cc.send(two_press) if button.short_count == 3: kbd.press(*three_press) kbd.release_all() if button.long_press: cc.send(long_press)
List of USB HID Keycodes
A list of available keyboard characters and consumer controls are listed in the documentation linked below. Function keys and modifiers can be used to create custom keyboard shortcuts.
Page last edited January 22, 2025
Text editor powered by tinymce.