Simple USB Audio Controller in CircuitPython

I have plans to build a multi-function macro keyboard using the new Raspberry Pi Pico RP2040 microcontroller and CircuitPython. While I was waiting for it to arrive, I wanted to figure out how I was going to handle controlling the audio on my computer with a rotary encoder, so I built this simple project using CircuitPython and the QT Py M0 microcontroller. Unfortunately, rotaryio has not been implemented for the RP2040 yet in CircuitPython, so there is a bonus code snippet at the end using a potentiometer to accomplish the same thing for the Pi Pico.

Parts

3D Printed SnapFit Enclosure

I modified the enclosure I made for my Zoom/Teams mute button and computer lock button projects.

CAD files for the QT Py rotary encoder enclosure.

Wiring Diagram

wiring diagram for the QT Py and rotary encoder

Code

The code.py file is also available on GitHub.

import board
import time
import usb_hid
from digitalio import DigitalInOut, Direction, Pull
from rotaryio import IncrementalEncoder
from adafruit_hid.consumer_control_code import ConsumerControlCode
from adafruit_hid.consumer_control import ConsumerControl

# Change the below code for different outcomes
# https://circuitpython.readthedocs.io/projects/hid/en/latest/

# Button Press will mute
BUTTON_CODE = ConsumerControlCode.MUTE

# Rotating the encoder clockwise will increase the volume
INCREMENT_CODE = ConsumerControlCode.VOLUME_INCREMENT

# Rotating the encoder clockwise will decrease teh volume
DECREMENT_CODE = ConsumerControlCode.VOLUME_DECREMENT

# initialize as hid device
consumer_control = ConsumerControl(usb_hid.devices)

# initialize encoder on pins D0 and D1 (QT Py M0)
encoder = IncrementalEncoder(board.D0, board.D1)

# initialize encoder click on pin D2 (QT Py M0)
button = DigitalInOut(board.D2)
button.direction = Direction.INPUT
button.pull = Pull.UP

button_in = False
last_position = None

while True:

    if not button.value and not button_in:
        print("button press")
        button_in = True
        consumer_control.send(BUTTON_CODE)
        time.sleep(.2)

    elif button.value and button_in:
        button_in = False

    elif button.value and not button_in:
        position = encoder.position

        if last_position is not None and position != last_position:

            if position > last_position:
                print("rotate clockwise")
                consumer_control.send(INCREMENT_CODE)

            elif position < last_position:
                print("rotate counter-clockwise")
                consumer_control.send(DECREMENT_CODE)

        last_position = position

Bonus: Pi Pico 2040 Potentiometer

Raspberry Pi Pico 2040 with potentiometer
import board
import time
import usb_hid
from analogio import AnalogIn
from adafruit_hid.consumer_control_code import ConsumerControlCode
from adafruit_hid.consumer_control import ConsumerControl

READ_TIME = .001

def map_function(x, in_min, in_max, out_min, out_max):

  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;


# initialize hid device as consumer control 
consumer_control = ConsumerControl(usb_hid.devices)

# initialize potentiometer (pot) wiper connected to GP26_A0
potentiometer = AnalogIn(board.GP26)  

# intialize the read time
last_read = time.monotonic()

# decrease volume all the way down 
# this allows the volume to be set by the current value of the pot
for i in range(32):
    consumer_control.send(ConsumerControlCode.VOLUME_DECREMENT)


# initalize volume and last position
current_volume = 0
last_position = 0



while True:

    if time.monotonic() - last_read > READ_TIME:
        position = int(map_function(potentiometer.value , 200, 65520, 0, 32))

        if abs(position - last_position) > 1:

            last_position = position

            if current_volume < position:
                while current_volume < position:
                    # Raise volume.
                    print("Volume Up!")
                    consumer_control.send(ConsumerControlCode.VOLUME_INCREMENT)
                    current_volume+= 2
            elif current_volume > position:
                while current_volume > position:
                    # Lower volume.
                    print("Volume Down!")
                    consumer_control.send(ConsumerControlCode.VOLUME_DECREMENT)
                    current_volume -= 2

        # update last_read to current time
        last_read = time.monotonic()

    # handle time.monotonic() overflow
    if time.monotonic() < last_read:
        last_read = time.monotonic()

COVID-19 Vaccination Displays using CircuitPython

I built a scrolling COVID-19 Vaccination display for both the Adafruit MatrixPortal M4 and the Adafruit MagTag using CircuitPython, and data from Our World in Data and the CDC.

Data

Our World in Data has aggregated massive data sets related to COVID-19. The vaccination data subset is available in a GitHub repository in csv format. The Matrix Portal is using data from this repository.

Our complete COVID-19 dataset is a collection of the COVID-19 data maintained by Our World in Data. It is updated daily and includes data on confirmed cases, deaths, hospitalizations, and testing, as well as other variables of potential interest.

The Center for Disease offers a much more limited data set that includes information for each state and the country as a whole in JSON format. The MagTag has been updated to use the data directly from the CDC

Code

MagTag

https://gist.github.com/jfurcean/bfcafc200a433f2d31b736d41d9202e8

MatrixPortal

https://gist.github.com/jfurcean/dbf1608188c9fcfcf942c7489c22a3d0

Computer Lock Button Using CircuitPython

What happened at the Capitol on January 6, 2021 will go down as a dark day in American history. There are many potential cybersecurity issues related to this incident. Images from inside the Capitol showed at least one computer left unlocked. “We can use this as a learning moment”, as Rachel Tobac, an information security leader, points out in her twitter thread below.

I thought a quick exercise in using this as a learning moment would be to modify my recent Zoom/Microsoft Teams mute button project to create a simple and easy to use computer lock button.

Parts

Wiring

The fritzing schematic is below. Please note that the button I used didn’t have a NC connector, but I couldn’t find a similar part in the fritzing library.

Code

I simplified my code from the Zoom/Microsoft Teams mute button project for this to make it easy and simple to use. The specific kbd.send line will need to be uncommented depending on the operating system. Save the below code as code.py to your QT Py CIRCUITPY drive.

https://gist.github.com/jfurcean/7f5637721bd4e30792e560399ee8888d

Zoom/Microsoft Teams Mute Button using CircuitPython

I wanted to create a simple project using Adafruit’s new QT Py microcontroller and CircuitPython. I decided to make a simple mute button for video conference tools since I spend a lot of my work hours in meetings using either Microsoft Teams or Zoom. There have been many of these made since the start of the pandemic, including the PyRuler version featured in an Adafruit learn guide, but I wanted to make a smaller single button version that could work with multiple applications.

Parts

3D Printed SnapFit Enclosure

I followed Noé Ruiz (@ecken) Layer by Layer tutorial below to make a circular SnapFit case to hold my project (STL/Fusion360 Files). There are several things that could be improved in this design, but it is a start. The Fusion360 file has User Parameters if you want to change the diameter or the height of the enclosure. I printed my enclosure using semi transparent PETG to enable the user to easily see the color of the onboard neopixle. This is helpful for knowing what application/shortcut is active.

Wiring

The fritzing schematic is below. Please note that the button I used didn’t have a NC connector, but I couldn’t find a similar part in the fritzing library.

Code

Below is the code for this project. Modify the controller_buttons variable to add or remove applications and shortcuts. The current code is made to work using Microsoft Teams and Zoom on a Mac. The keycode for each application/shortcut would need to be modified if you are using Windows or Linux. The color updates the neopixle on the QT Py to allow the user to know which application/shortcut is active. I used purple for Teams and blue for zoom.

https://gist.github.com/jfurcean/b2834bc05f5599a23253b392075b390d

Please see Adafruit’s Primary Guide for setting up the QT Py with CircuitPython. You will need to copy the following CircuitPython library files over to your QT Py as well.

  • adafruit_hid/keyboard
  • adafruit_hid/keyboard_layout_us
  • adafruit_hid/keycode
  • neopixel

The strip_xattr.sh script is very helpful if you run into problems copying the required library files over to the QT Py on a Mac. For more information about this issue see the Adafruit Forum post from user aaaidan.

Use

  1. Plug it into your computer.
  2. Press the button to activate the active application’s keyboard shortcut
  3. In order to change the keyboard shortcut that is active, hold down the button until the onboard neopixel changes colors

Please note that the led on the arcade button is currently set to toggle every time it is pressed. It is up to the user to manually sync it to there current application if they want to use it as an indicator if they are currently muted or not. Comment out the every line that has button_led if you want to use a button that doesn’t have an LED on it. Also, the Teams or Zoom windows has to be in focus for the button to work.

All code and 3D models are available via the Github Repository: https://github.com/jfurcean/CircuitPython-MuteButton

Special Note About Cura

I noticed that my QT Py was constantly resetting/not working while I was working on this project. It turns out that Cura was trying to “talk” to the QT Py and this was preventing it from working. Everything worked as expected once I closed Cura and reset the QT Py. I found this Github issue related to other CircuitPython boards that were having this same issue.

COVID-19 RGB Matrix with CircuitPython

I built a scrolling COVID-19 Tracking RGB using Adafruit’s new MatrixPortal M4, CircuitPython, and the API from The COVID Tracking Project at The Atlantic

Data

The COVID Tracking Project at The Atlantic has a simple API with a robust data set that is published under a Creative Commons CC BY 4.0 license.

We collect, cross-check, and publish COVID-19 data from 56 US states and territories in three main areas: testing, patient outcomes, and, via The COVID Racial Data Tracker, racial and ethnic demographic information. We compile these numbers to provide the most complete picture we can assemble of the US COVID-19 testing effort and the outbreak’s effects on the people and communities it strikes.

The Covid Tracking Project at The Atlantic

CircuitPython Code

The below code is based on the: Example: Simple two-line text scroller

https://gist.github.com/jfurcean/07146f443cfb9f94043d1d0c349a2da7

The Missing Semester of Your CS Education from MIT

MIT just introduced a new course called “The Missing Semester of Your CS Education“. All of the lectures are available on YouTube and course notes are available at their course website. This is going to be a great resource for Computer Science students, Programmers, and Makers all over the world.

Classes teach you all about advanced topics within CS, from operating systems to machine learning, but there’s one critical subject that’s rarely covered, and is instead left to students to figure out on their own: proficiency with their tools. We’ll teach you how to master the command-line, use a powerful text editor, use fancy features of version control systems, and much more!

The Missing Semester of Your CS Education

Installing OctoPi-TFT using the OctoPi Image

This tutorial uses vi to edit files this can be replaced with nano or some other text editor.

Parts

Step 1: Connect the PiTFT to the Pi

You can connect the PiTFT before you start any of the other steps.

Step 2: Install and Configure OctoPrint

Follow the instructions form the OctoPrint website https://octoprint.org/download/

Step 3: Install Raspbian Desktop

sudo /home/pi/scripts/install-desktop

sudo reboot

Step 4: Install Dependencies

sudo apt-get install xinit
sudo apt-get install x11-xserver-utils
sudo apt-get install xserver-xorg-input-evdev

Step 5: Move 40-libinput.conf

sudo mv /usr/share/X11/xorg.conf.d/40-libinput.conf ~/

Step 6: Install PiTFT Drivers

Use the Easy Install method that Adafruit supplies

We’ve created a custom kernel package based of off Notro’s awesome framebuffer work, so you can install it over your existing Raspbian (or derivative) images in just a few commands. Our tutorial shows you how to install the software, as well as calibrate the touchscreen, display images such as from your PiCam and more!

Adafruit
cd ~
wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/adafruit-pitft.sh
chmod +x adafruit-pitft.sh
sudo ./adafruit-pitft.sh
  • For the 3.5″ PiTFT select #4
  • If you want the HDMI port on top like I do select #3
  • Would you like the console to appear on the PiTFT display? No
  • Would you like the HDMI display to mirror to the PiTFT display? Yes

Step 7: Uninstall Lightdm window manager

sudo dpkg -r --force-depends lightdm

Step 8: Install OctoPi-TFT

cd ~
wget https://github.com/darksid3r/OctoPrint-TFT/releases/download/1.1/octoprint-tft_stretch_1.1.git91fa718-1_armhf.deb
sudo dpkg -i octoprint-tft_stretch_1.1.git91fa718-1_armhf.deb

Step 9: Edit OctoPi-TFT Configuration File

Edit you configuration file.

sudo vi /etc/octoprint-tft-environment

This is what mine looks like. You will need to change the OCTOPRINT_APIKEY to match yours. It can be found on the settings page in OctoPrint. I also removed the comments from here so it is easier to read.


OCTOPRINT_CONFIG_FILE=

OCTOPRINT_HOST=http://127.0.0.1:5000

OCTOPRINT_APIKEY=YOUR_APIKEY_GOES_HERE

OCTOPRINT_TFT_STYLE_PATH=/opt/octoprint-tft/styles/default/

OCTOPRINT_TFT_RESOLUTION=480x320

Step 10: Reboot & Test

sudo reboot

Step 11: Check /boot/config.txt

You can disregard this step if everything is working as expected. My display resolution wasn’t correct so I had to change the last line of the /boot/config.txt file from hdmi_cvt=720 480 60 1 0 0 0 to hdmi_cvt=480 320 60 1 0 0 0.

sudo vi /boot/config.txt
sudo reboot

Resources

I used these resources to put together this tutorial.

Custom 3 Button CircuitPython Keyboard

Introduction

I have been doing audio editing for side project at work. These are long form audio recordings of an hour or more. I am using Adobe Audition to do my editing. After doing several of these, I noticed that I use two main functions frequently.

  1. ‘Silence’
  2. ‘Ripple Cut’ -> ‘ Time Selection in All Tracks’

The ripple cut function either used a significant number of mouse clicks or keyboard shortcuts that required both hands. There are probably a few different potential solutions to this problem. I could have changed the keyboard shortcuts to something else, but I wanted this to be easy to use and I wanted to be able to use it on any computer.

I recently completed a project that used the PyPortal to send keyboard commands to my computer to open applications. Also, I had purchased an Adafruit Trinket M0 recently and wanted to build a project with it, so I decided to build a mini keyboard that only had a few buttons.

Parts

Schematics

Code

I modified the the Trinket IO Demo code. I removed some stuff that I didn’t need and had to make sure that holding down a key was treated the exact same as a single key press.

https://gist.github.com/jfurcean/711fb3760710c8d064d40500617fd75b

Results

The first button is used for play/pause, the second button is used to do the ripple cut and the third button is used to do the silencing. This tool has made it so much easier to edit audio content.

Update – 18 April 2020

If you liked this, check out this much more detailed project by Glen Akins (@bikerglen)

Ender 3 – 3D Printer & OctoPrint

Background

I recently purchased a Creality Ender 3 3D printer. I bought this for several reasons:

  1. It is very affordable at $229 on Amazon.
  2. It had a lot of good reviews
  3. Is the Most Popular 3D Printer of Spring 2019
  4. There are lots of upgrades/mods for this printer
    1. 35 Must-Have Creality Ender 3 (Pro) Upgrades & Mods in 2019.

OctoPrint

My interest was peaked when I saw the Raspberry Pi upgrade option under the possible upgrades/mods you could do to the Ender 3.

Let’s face it, we can’t be around to supervise our 3D printer 100 percent of the time. That’s why OctoPrint has become the standard for makers who want to monitor and control their 3D printer remotely. To run this terrific web interface, you need to purchase a Raspberry Pi board.


OctoPrint will allow you to control and observe your Creality Ender 3 from within a web browser. It’s 100 percent open source, which has led to a plethora of unique plugins created by the vast community. On the browser, you can watch prints through an embedded webcam feed, control print temperatures, obtain feedback on current print status, and even start and pause your printer no matter where you are.

35 Must-Have Creality Ender 3 (Pro) Upgrades & Mods in 2019.

I had an extra Raspberry Pi laying around and decided to give it a shot. The software that runs on the Pi is called OctoPrint. Installation and configuration is very straight forward and there are lots of help documents and tutorial videos. I am not going to get into any of the setup in this post, but below is the video that I found most helpful.

How to Install Octoprint on a Creality Ender 3

First Print with OctoPrint

I am currently using a simple USB webcam for the OctoPi. I want to upgrade it to use a mounted Raspberry Pi camera so that it follows the printer head. The video below is a time lapse that was captured using OctoPrint of the mount and case for the Pi camera being 3D printed.

Video 3D print of camera holder for Pi Camera and ender