This project doesn't require much (any) knowledge of CircuitPython to get up and running, but if you're new to it, and would like to know more, there is a full getting started guide here. There's also a great introduction to the PyRuler here.

If you'd like to edit the code, Adafruit suggests using the Mu editor to edit your code and have an interactive REPL in CircuitPython. You can learn about Mu and installation in this tutorial.

If you haven't already reprogrammed your PyRuler, it should come pre-programmed as a USB HID keyboard that you can try out. Plug the PyRuler into your computer USB port via an A to microB cable. A drive named CIRCUITPY should appear. Open the code.py file on that drive in Mu and change this line:

ENABLE_KEYBOARD = False

to:

ENABLE_KEYBOARD = True

Then when you hit one of the four buttons, it will type Ω, µ, π, or https://www.digikey.com/python (I totally just typed those on my PyRuler!)

Quick Install

Because we already have everything we need to use the PyRuler as an HID keyboard, getting up and running is very simple: 

  • Download the code as a code.py file
  • Plug the PyRuler into the computer with a microUSB power/data cable
  • Once the CIRCUITPY drive appears, just drag the code.py file you downloaded into the CIRCUITPY folder and replace the code.py file that's there
  • The PyRuler should immediately reboot, and start working as a panic button for your video conferences! 
adafruit_products_PyRuler_install.jpg
To install, just download the new code.py file and replace the one on your PyRuler!
import os
import board
from digitalio import DigitalInOut, Direction
import time
import touchio

# Set this to True to turn the touchpads into a keyboard
ENABLE_KEYBOARD = True

# Used if we do HID output, see below
if ENABLE_KEYBOARD:
    from adafruit_hid.keyboard import Keyboard
    from adafruit_hid.keycode import Keycode
    from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
    import usb_hid
    kbd = Keyboard(usb_hid.devices)
    layout = KeyboardLayoutUS(kbd)

#print(dir(board), os.uname()) # Print a little about ourselves

led = DigitalInOut(board.D13)
led.direction = Direction.OUTPUT

touches = [DigitalInOut(board.CAP0)]
for p in (board.CAP1, board.CAP2, board.CAP3):
    touches.append(touchio.TouchIn(p))

leds = []
for p in (board.LED4, board.LED5, board.LED6, board.LED7):
    led = DigitalInOut(p)
    led.direction = Direction.OUTPUT
    led.value = True
    time.sleep(0.25)
    leds.append(led)
for led in leds:
    led.value = False


cap_touches = [False, False, False, False]

def read_caps():
    t0_count = 0
    t0 = touches[0]
    t0.direction = Direction.OUTPUT
    t0.value = True
    t0.direction = Direction.INPUT
    # funky idea but we can 'diy' the one non-hardware captouch device by hand
    # by reading the drooping voltage on a tri-state pin.
    t0_count = t0.value + t0.value + t0.value + t0.value + t0.value + \
               t0.value + t0.value + t0.value + t0.value + t0.value + \
               t0.value + t0.value + t0.value + t0.value + t0.value
    cap_touches[0] = t0_count > 2
    cap_touches[1] = touches[1].raw_value > 3000
    cap_touches[2] = touches[2].raw_value > 3000
    cap_touches[3] = touches[3].raw_value > 3000
    return cap_touches

while True:
    caps = read_caps()
    print(caps)
    # light up the matching LED
    for i,c in enumerate(caps):
        leds[i].value = c
    if caps[0]:
        if ENABLE_KEYBOARD:
            # Zoom
            kbd.press(Keycode.ALT, Keycode.V)
            kbd.release(Keycode.V)
            time.sleep(0.25)
            kbd.press(Keycode.A)
            kbd.release_all()
    if caps[1]:
        if ENABLE_KEYBOARD:
            # Teams
            # Note that video toggle doesn't work in the web app
            kbd.press(Keycode.CONTROL, Keycode.SHIFT, Keycode.M)
            kbd.release(Keycode.M)
            time.sleep(0.5)
            kbd.press(Keycode.O)
            kbd.release_all()
    if caps[2]:
        if ENABLE_KEYBOARD:
            # Skype
            kbd.press(Keycode.CONTROL, Keycode.M)
            kbd.release(Keycode.M)
            time.sleep(0.5)
            kbd.press(Keycode.SHIFT, Keycode.K)
            kbd.release_all()
    if caps[3]:
        if ENABLE_KEYBOARD:
            # Jitsi
            kbd.press(Keycode.M)
            kbd.release(Keycode.M)
            time.sleep(0.5)
            kbd.press(Keycode.V)
            kbd.release_all()
    time.sleep(.2)

More Details

The code is a lightly-modified version of the code that comes on the PyRuler. However, rather than typing the keys for Ω or µ, it presses the combination of hotkeys needed to toggle the camera and microphone in that specific application.

For example, the first button (the Ω) looks like this:

# Zoom
kbd.press(Keycode.ALT, Keycode.V)
kbd.release(Keycode.V)
time.sleep(0.25)
kbd.press(Keycode.A)
kbd.release_all()

In Zoom, the hotkey for for starting/stopping video is Alt-V, and the hotkey for mute/unmute is Alt-A.

In the code, we're just asking it to press the Alt key, press the V key, release the V key, wait a quarter of a second, press the A key, then release all keys.

"But wait!", you ask, "You didn't hit Alt before the A!"

True, but for modifier keys like Alt, they affect all keys pressed while holding them down. They act just like the Shift key, which is just another modifier key. If you hold the Shift key down and START TYPING, all of your letters become capitals - you don't have to press Shift for each one.

The code for Teams looks slightly different:

kbd.press(Keycode.CONTROL, Keycode.SHIFT, Keycode.M)
kbd.release(Keycode.M)
time.sleep(0.5)
kbd.press(Keycode.O)
kbd.release_all()

Here, we have TWO control keys, both Control and Shift before the M and O keys are pressed. (Ctrl-M is for mute/unmute, and Ctrl-O is for starting/stopping video. You can see why these are difficult to remember in all the apps!

The other thing that's different here is the time between the M and O keys being pressed is increased to half a second. While testing the program, I found that some applications didn't respond very well when the keys were pressed too quickly. Sometimes, this would result in just the microphone being muted, but the video remaining on.

adafruit_products_PyRuler_Muted.png
This is a fine situation, but not if you didn't mean for it to happen!

Even worse, as these hotkeys are toggles (they turn things both off and on), if you'd press the button on the PyRuler again, you could unmute the microphone and turn off the video!

Real-world testing is important, and sometimes small tweaks are needed in the code!

This guide was first published on Aug 04, 2020. It was last updated on Aug 04, 2020.

This page (Code) was last updated on Jun 11, 2021.

Text editor powered by tinymce.