# CircuitPython Powered AT Hand-Raiser

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/065/128/medium800thumb/trinket_Light3.jpg?1541207849)

Sometimes folks need help doing the simple things that most of us take for granted - that's where Assistive Technology comes into play.&nbsp; For example, ATMakers recently had a college student reach out and ask for help getting her professor's attention in class.

The problem was she has Spinal Muscular Atrophy (SMA) and couldn't raise her hand.&nbsp; So, we created this small Trinket-powered device that attaches to her laptop or tablet and lights up when she wants to participate!

Along the way, we found a fantastic way to control CircuitPython code using nothing more than the USB cord and Windows, Mac or Linux scripts loaded on the Trinket itself.

## Parts List

This project requires just two parts and some 3D printing filament.&nbsp; You'll need a Trinket M0 microcontroller and a good USB Cable.&nbsp; Make sure you've got a data cable, not a charge-only cable, as this project will send data over the USB interface.

For the filament, you'll need a translucent style that allows light to pass through the faceplate.&nbsp; The Natural Translucent PLA listed below is great.&nbsp; For the other pieces, you can use the same filament or something opaque like the "ATMakers Green" filament we chose.

### Adafruit Trinket M0 - for use with CircuitPython & Arduino IDE

[Adafruit Trinket M0 - for use with CircuitPython & Arduino IDE](https://www.adafruit.com/product/3500)
The&nbsp;Adafruit Trinket M0 may be small, but do not be fooled by its size! It's a tiny microcontroller board, built around the Atmel ATSAMD21, a little chip with _a lot_ of power. We wanted to design a microcontroller board that was small enough to fit into any project, and low...

In Stock
[Buy Now](https://www.adafruit.com/product/3500)
[Related Guides to the Product](https://learn.adafruit.com/products/3500/guides)
![Manicured hand holding Trinket M0.](https://cdn-shop.adafruit.com/640x480/3500-04.jpg)

### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

In Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)
![USB cable - USB A to Micro-B - 3 foot long](https://cdn-shop.adafruit.com/640x480/592-01.jpg)

# CircuitPython Powered AT Hand-Raiser

## Printing the Enclosure

The CircuitPython code controls the on-board RGB LED, but without an enclosure that diffuses that light, it doesn't really grab your attention. So, we created a three-piece snap-fit case that holds the Trinket and allows it to hang over the edge of our user's laptop or tablet screen. The case has a translucent front cover that spreads out the light and makes a nice large lighted volume that's easy to see from across the room.

This enclosure is a "snap fit" design, based on the approach that Noe & Pedro Ruiz shared in [their great video last year](https://www.youtube.com/watch?v=VVmOtM60VWw&t=991s). This design leverages those ideas and creates a design that is easy to print, requires no supports, and can be assembled in seconds, all with no tools.

You will need to download three STL files: a backplate for the Trinket, a hanging hook, and a faceplate that must be printed in translucent filament. There are several versions of the hook and faceplate, you only need one:

[Download 3D STL Files](https://www.thingiverse.com/thing:3172905/files)
[Download Fusion 360 Archive](https://www.thingiverse.com/download:5508764)
## Back Plate

**Filename: Snap\_Back.stl**

This part holds the Trinket in place. It's specifically designed to hold the board in place with no screws or tools.

There is only one backplate design, and you can print it in any color you'd like. We've used ATMakers Green.

![trinket_BackPic.png](https://cdn-learn.adafruit.com/assets/assets/000/064/360/medium640/trinket_BackPic.png?1540438777)

## Hanging Hook

**Filename: Snap\_Hanger.stl** &nbsp;

The hook snaps onto the backplate and holds the enclosure onto the screen of a laptop or tablet. This part is configurable in Fusion 360 in the User Parameters screen. You can set the width of the screen you're mounting the device on and how far you'd like the tab to hang down.&nbsp;

![trinket_Hanger.png](https://cdn-learn.adafruit.com/assets/assets/000/064/361/medium640/trinket_Hanger.png?1540438991)

The default is 10mm wide, but if you're not up to editing the file, we've included two alternative widths: 15mm, and 20mm.&nbsp; You only need to print one of the files that start with **Snap\_Hanger**.

## Faceplate

**Filename: Faceplate-Hand.stl**

The faceplate snaps over both of the other two parts and must be printed in filament that allows light through such as a&nbsp;[natural translucent PLA.](https://www.adafruit.com/product/2451)

You only need to print one faceplate - there are four available:

- Handprint
- Adafruit Logo
- ATMakers.org Logo
- and Blank

![trinket_HandPic.png](https://cdn-learn.adafruit.com/assets/assets/000/064/367/medium640/trinket_HandPic.png?1540441289)

## Printing Tips

- **Supports:** All three parts print easily with out any supports, however your software may try to add them on the faceplate.&nbsp; You should disable supports so that they don't make marks on the translucent surface when they break apart.
- **Filament:** For best results, print the parts in similar materials.&nbsp; That is, if you're using a translucent PLA for the faceplate, try to print the other parts in a similar PLA rather than mixing PLA and ABS, etc.&nbsp; We have had excellent results with many styles of PLA and PETG with this design.
- **Resolution:&nbsp;** For the snap-fit to work best, a layer height of .200mm or finer is recommended.&nbsp; These parts do not take long to print and the result is worth the wait.
- **Orientation:** For easiest printing, orient the parts as seen below

![](https://cdn-learn.adafruit.com/assets/assets/000/064/368/medium800/trinket_Orientation.png?1540442530)

# CircuitPython Powered AT Hand-Raiser

## Assembly

https://www.youtube.com/watch?v=yJx9yOcKMSw

Assembling the HandRaiser light is quite simple and requires no tools.&nbsp; Just pop the Trinket into the backplate and snap on the hanger and the cover.

## Firmly press the Trinket M0 onto the backplate.&nbsp;

The board should be oriented so that the USB port is at the bottom of the backplate.&nbsp; The top of the backplate is thinner so that the hanger can snap on - that is where the reset button should go.

> Note: The fit can be snug, and you may have to press one side and then the other, but when complete the board should be secure.

![trinket_Press2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/065/133/medium640/trinket_Press2.jpg?1541213783)

## Snap on the Hanger

While there are several Hanger sizes, they all attach the same way.&nbsp;

Position the hanger as shown and firmly press the snap-fit grooves together.&nbsp;&nbsp;

![trinket_Hanger.jpg](https://cdn-learn.adafruit.com/assets/assets/000/065/131/medium640/trinket_Hanger.jpg?1541213488)

## Choose and Attach Your Cover

We've provide four different covers you can choose: an ATMakers logo, an Adafruit Logo, a hand, and a blank cover.

Once you choose and print the cover, it's a breeze to snap it over the Trinket and onto the Backplate.

&nbsp;

![trinket_IMG_00027.jpg](https://cdn-learn.adafruit.com/assets/assets/000/065/134/medium640/trinket_IMG_00027.jpg?1541213890)

That's all there is to it!&nbsp; Now it's time to program the Trinket and let our users get their teacher's attention.

# CircuitPython Powered AT Hand-Raiser

## Programming the Trinket

To get you started quickly, we've created a single file that contains everything you'll need to program your Trinket M0 and turning it into a HandRaiser.&nbsp; Once that's working you can adjust and customize your device to suit your needs.

[Download the HandRaiser.UF2 File](https://github.com/ATMakersOrg/Little-HandRaiser/raw/master/LittleHandRaiser.UF2)
The **HandiRaiser.UF2** file is a complete image that will program the Trinket and load the support files all in one shot.&nbsp; To load the UF2 file:

1. Plug in the Trinket using the (known-good) Power+Data USB cord
2. [Place the Trinket in Bootloader Mode by double-tapping the Reset Button](https://learn.adafruit.com/adafruit-hallowing/uf2-bootloader-details#entering-bootloader-mode-45-4).&nbsp; (The RGB LED on the Trinket will blink green)
3. Locate the new drive (named **TRINKETBOOT** ) that is created in Bootloader Mode (usually named D:\, E:\ or another letter on Windows).&nbsp; You will know you have the right drive if you see a file named **CURRENT.UF2**
4. Copy the **HandRaiser.UF2** file to that drive.&nbsp; The Trinket will restart and you should see a new drive named **CIRCUITPY.**

Once the process is complete, your HandRaiser should reset and should go into a slowly changing "Wheel" color pattern that goes through all the colors of the spectrum.

![](https://cdn-learn.adafruit.com/assets/assets/000/065/138/medium800thumb/trinket_Light.jpg?1541220562)

Next, let's set this up so that our users can choose the color and pattern they want directly from any computer with a USB port.

# CircuitPython Powered AT Hand-Raiser

## HandRaiser Commands

The HandRaiser works by listening to incoming requests over it's USB Serial connection.&nbsp; That allows any PC, Mac, etc. with a USB Serial (UART) connection to control the device.

For Michelle, that controlling device was her Tobii Speech Generating Device (which is based on a Windows Tablet), but it could just as easily be a Raspberry Pi, Mac, Android or anything with a USB port.

We will share details about how to connect via Windows and Linux later in the guide, but first, let's show what commands are available on the HandRaiser and what they do.

## Shortcuts - Just 4 Colors

This project started with a very simple request: the ability to set her color to red, yellow, green or black.&nbsp; So, those names are special in this project: they simply set the color and make sure the'll stay on that color by switching out of the "wheel" mode.&nbsp; Other modes like "blink" and "ramp" continue to work, the color hue just changes.

## Any Color - #RRGGBB

If you'd like to set any other color, you can send a Hex code, just like in HTML.&nbsp; The Hex code starts with a hashtag, then two letters for Red, Green, and Blue in that order.&nbsp; Just like the standard colors, modes stay the same except for "wheel" which switches to solid.

There are many Hex Code calculators and tools out there, including [this one from W3Schools.](https://www.w3schools.com/colors/colors_hexadecimal.asp "W3Schools Hex Color Calculator")

## Changing Brightness - %0 - %100

To change the brightness of the LED without changing the mode or base color, just send a percent symbol followed by a number between 0 and 100.&nbsp;&nbsp;

## Changing Mode - @modename

Messages that start with an @ symbol trigger a change of mode.&nbsp; Currently there are five modes that change how the HandRaiser's colors change:

- **solid -** &nbsp;Show the target color with no variation or changes.
- **blink -** Alternate between the target color and black every half second (or so)
- **ramp -&nbsp;** Slowly fade between the target color and black every two seconds (or so)
- **beat -&nbsp;** Change the brightness of the target color to match that of a standard heartbeat rythm (experimental)
- **wheel -&nbsp;** Rotate the color of the LED around a color wheel.

## Examples

Here are some examples:

```auto
green
@blink
%50
```

Set the color to red, blinking, and 1/2 full brightness

```auto
#990099
%90
@ramp
```

Set the color to dark purple, 90% brightness and a slow ramp from black to purple and back.

```auto
#FF0000
%100
@beat
```

Make the HandRaiser follow a heartbeat pattern in red with full brightness.

# CircuitPython Powered AT Hand-Raiser

## Windows Shortcuts

The HandRaiser includes a set of Windows Shortcuts that can be used to change the LED just by double clicking them.&nbsp; You'll find them in the **WindowsCommands** folder on the **CIRCUITPY** drive that's created when you plug in the HandRaiser.

These scripts use a language that many of us aren't very familiar with, but that is installed on every modern Windows machine: PowerShell!

![](https://cdn-learn.adafruit.com/assets/assets/000/068/722/medium800/trinket_WindowsCommands.png?1546715882)

The folder has a PowerShell script named "ColorChange.ps1" that connects to the Serial Port on the HandRaiser and sends a message. It also has .BAT files that simply call that file with different messages.

For example, the "red.bat" file has the following text:

```
powershell -executionpolicy bypass -File "ColorChange.ps1" "red"
```

When executed, it calls ColorChange.ps1 and request that it send the code "red" to the Trinket. (the "-executionpolicy bypass" is necessary to run unsigned scripts from the command line)

Let's take a look at the ColorChange.ps1 file and how it works.

```auto
function sendColor($colorName)
{
    $portInfo = ( Get-WmiObject Win32_SerialPort | Where { $_.PNPDeviceID -like '*VID_239A*' } | select -last 1 )
    $port = new-Object System.IO.Ports.SerialPort $portInfo.DeviceID,9600,None,8,one
    $port.open()
    $text = $colorName + "`r"
    $port.Write($text)
    start-sleep -m 50
    $port.ReadExisting()
    $port.Close()
}
if ($args.Length -eq 0)
{
    echo "Usage: ColorChange &lt;color&gt;"
}
else
{
    sendColor($args[0])
}
```

This PowerShell script has a single function sendColor() that takes a string and sends it cleanly to the Trinket over the Serial connection.&nbsp; The critical section begins on line 3:

```auto
    $portInfo = ( Get-WmiObject Win32_SerialPort | Where { $_.PNPDeviceID -like '*VID_239A*' } | select -last 1 )
    $port = new-Object System.IO.Ports.SerialPort $portInfo.DeviceID,9600,None,8,one
    $port.open()
```

Here, PowerShell requests information about the Serial Ports and filters that down to only return those with a Plug and Play DeviceID that includes "VID\_239A" which is Adafruit's identifier.&nbsp; It then selects only the last device (the most recently added device).

This means that if you're connecting multiple Adafruit devices (perhaps a Trinket, Circuit Playground and a Feather) it will always connect to the most recently added device with a Serial Port.

The next line creates a new SerialPort object connecting at 9600 baud and the standard "N-8-1" parity settings.

Then the port is opened so that we can read and write to it.

```auto
    $text = $colorName + "`r"
    $port.Write($text)
```

Next we add a carriage return character to the end of any text passed in.&nbsp; This is because the CircuitPython code running on the Trinket uses that to recognize the end of a a command.

And we use the **Write()** method to send the command and carriage return to the serial port.

```auto
    start-sleep -m 50
    $port.ReadExisting()
    $port.Close()
```

These lines are necessary to get the Trinket to stop listening for the command to perform the action.&nbsp; A short delay (50ms) is added and then the port is read before closing it.

This is a limitation of the **input()** method in CircuitPython and you may have to increase or decrease your delay to match your device.&nbsp; However, we've found the 50ms delay is adequate for the Trinket M0 we're using.

# CircuitPython Powered AT Hand-Raiser

## Linux/Mac Scripts

For those running Mac OS/X, Linux or using a Raspberry Pi, shortcuts like those for Windows are less useful.&nbsp;

Using serial interface programs like Minicom or Screen are great and work wonderfully, however, a simple script that sends commands to the HandRaiser are certainly helpful.

Like on Windows, we'll use a scripting language that is on every major Linux release and in Mac OS/X: the Bash shell.

in the Scripts folder, you'll find a script named **colorChange.sh**.&nbsp; Let's take a look at it.

```auto
#!/bin/bash
# The line above has to be bash (not sh) because we're using the printf builtin

#before we start, make sure we know whether we're under Linux or OS/X (Darwin)
uname -s | grep -i Linux &gt; /dev/null
ISLINUX=$?

#$ISLINUX will be 0 (true) if we're on linux and 1 (false) if we're on mac

#First, get the name of the most recent Adafruit serial device connected
#Conveniently linux helps us by grouping them by manufacturer id
#Mac doesn't so we just take the most recently added serial device overall

if [ "$ISLINUX" -eq 0 ]; then

    DEVNAME=`ls -1t /dev/serial/by-id/ | grep Adafruit | head -1`

    if [[ -z "$DEVNAME" ]]; then
        echo "No Adafruit Device Found"
        exit
    fi

    FULLDEVPATH=/dev/serial/by-id/$DEVNAME
else
    DEVNAME=`ls -1t /dev/cu.usb* | head -1`
    if [[ -z "$DEVNAME" ]]; then
        echo "No Serial Device Found"
        exit
    fi
    FULLDEVPATH=$DEVNAME
fi

#Comment this to remove debug text
echo "Found recent Adafruit device at $FULLDEVPATH"

text=$@

if [[ -z "$text" ]]; then
    echo "Usage: colorChange.sh &lt;Text To Send&gt;"
    exit
fi

#Comment this to remove debug text
echo "Sending text '$text' to serial device"

printf "%b\r" $text &gt; $FULLDEVPATH
#for some reason input() needs to have the serial port READ to return on linux
if [ "$ISLINUX" -eq 0 ]; then
	head -1 $FULLDEVPATH &gt; /dev/null
fi
```

First, we need to find the most recently added Adafruit device with a serial port (just like we did on Windows).&nbsp; How we do this differs depending on whether we're on Linux or Mac OS/X.&nbsp; We determine that by running the command:

```
uname -s | grep -i Linux
```

and saving the return code in the $ISLINUX variable.

## Detecting Boards on Linux

Thankfully, Linux makes this easy by already grouping all of the serial port in a folder named&nbsp; **/dev/serial/by-id/.&nbsp;&nbsp;** Here's a listing:

![](https://cdn-learn.adafruit.com/assets/assets/000/068/724/medium800/trinket_serial.png?1546718181)

As you can see with the HandRaiser attached, there is an entry for a serial device that has an id that includes **Adafruit\_Industries\_LLC\_Trinket\_M0**.&nbsp; We'll use this to find the correct device.

```
DEVNAME=`ls -1t /dev/serial/by-id/ | grep Adafruit | head -1`
```

This command calls the ls command with the -1t option asking for a simple name output in order of modification, sends the output to grep to look for the word "Adafruit" and then takes just the first line by using "head -1".&nbsp; results are stored in the **DEVNAME** variable using backticks (`)

If we don't find one, we exit with an error message.

We build the full pathname to the serial device using this command:

```
FULLDEVPATH=/dev/serial/by-id/$DEVNAME
```
## Detecting Boards under OS/X

If we're on Mac OS/X, we don't have the list by device id, so we just use the list of all serial devices which can be found under **/dev/cu.usb** \* and follow a similar path to determine the **FULLPATH**

```
DEVNAME=`ls -1t /dev/cu.usb* | head -1`
```

In this case, the **FULLDEVPATH** is actually returned directly:

```
FULLDEVPATH=$DEVNAME
```
## Sending the Text using Printf

Next, we read the text from the command line using this line:

```
text=$@
```

That stores the command line arguments (which bash puts in $@) into a variable named **text**.&nbsp; If we don't get any we return with an error.

Finally we need to send the command with a carriage return and read from the serial port to make the Trinket process the command.&nbsp; All of that can be done using these two lines:

```
printf "%q\r" "$text" > $FULLDEVPATH
head -1 $FULLDEVPATH > /dev/null
```

The **printf** call is a bash built-in function that lets you specify formatting characters like the carriage return (\r) easily and to pass through special characters like "%" using the %q option.&nbsp; We send the output directly to the serial port using the redirection operator (\>)

The **head** command reads a single line from the serial port and sends it to **/dev/null** (basically this just ignores the result).

## Using the colorChange.sh Script

To use the **colorChange.sh** script, copy it to your Linux machine and make sure you have permissions to access the serial port.&nbsp; Kattni's guide on using the Serial port can really help here.

Once installed you can use the script like this:

```
./colorChange.sh "red"
```

Set the color to **red**

```
./colorChange.sh "%50"
```

Set the brightness to 50% (note the quotes are required here!)

```
./colorChange.sh "@wheel"
```

Set the device to rotate through the colors

```
./colorChange.sh "#AA00AA"
```

Set the color to **dark purple**.

# CircuitPython Powered AT Hand-Raiser

## CircuitPython Code

The HandRaiser uses CircuitPython to listen for commands on its USB Serial connection and respond by changing its LED's color accordingly.

Let's walk through the code showing how this works:

```auto
import board
import adafruit_dotstar
from time import sleep

import supervisor
```

First we need to import some modules that we'll use.&nbsp; Most of these are common: **board** includes definitions that are specific to the Trinket M0 like pin names,&nbsp; **adafruit\_dotstar** lets use control the single color LED and&nbsp;the&nbsp;**sleep()** function lets us add delays to our loop.

A less common addition is the&nbsp; **supervisor** module.&nbsp; It provides information and control of the Python environment itself.&nbsp; In this case, we want to ask CircuitPython if there is any text available to read from the USB Serial connection (without blocking).&nbsp; Thankfully, there's an attribute (**runtime.serial\_bytes\_available)** on the&nbsp; **supervisor** module r **untime** object that lets us check that.

```auto
def hex2rgb(hex_code):
    red = int("0x"+hex_code[0:2], 16)
    green = int("0x"+hex_code[2:4], 16)
    blue = int("0x"+hex_code[4:6], 16)
    rgb = (red, green, blue)
    return rgb
```

This helper function, **hex2rgb()** is handy to convert Web-style hex color codes to RGB tuples.&nbsp; This lets the controlling computer send commands like "#550000" for dark red or "#FFFF00" for bright yellow.

```auto
beatArray = [0.090909091,0.097902098,0.104895105,0.118881119,0.132867133,0.146853147,
    0.153846154........
```

The&nbsp; **beatArray variable holds an array of sampled values that represent a heartbeat.&nbsp; It supports the "@beat" mode.**

```auto
# When we start up, make the LED black
black = (0, 0, 0)
# the color that's passed in over the text input
targetColor = black

#pos is used for all modes that cycle or progress
#it loops from 0-255 and starts over
pos = 0

#curColor is the color that will be displayed at the end of the main loop
#it is mapped using pos according to the mode
curColor = black
```

Here we set the initial values for the current and target color, position of the color wheel and make a constant color&nbsp; **black** that we'll use for turning off the LED.

```auto
# the mode can be one of 
# solid - just keep the current color
# blink - alternate between black and curColor
# ramp  - transition continuously between black and curColor
# beat - pulse to a recorded heartbeat intensity
# wheel - change hue around the colorwheel (curColor is ignored)

mode='wheel'
```

The&nbsp; **mode** variable keeps track of which type of animation we're running.&nbsp; We'll use it to change the LED color on each pass through the main loop.

```auto
# standard function to rotate around the colorwheel
def wheel(cpos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if cpos &lt; 85:
        return (int(cpos * 3), int(255 - (cpos * 3)), 0)
    elif cpos &lt; 170:
        cpos -= 85
        return (int(255 - (cpos * 3)), 0, int(cpos * 3))
    else:
        cpos -= 170
        return (0, int(cpos * 3), int(255 - cpos * 3))

# We start by turning off pixels
pixels.fill(black)
pixels.show()
```

This code is common to many "blinky" projects from Adafruit - it cycles through the color wheel making a lovely rainbow pattern.&nbsp;

```auto
# Main Loop
while True:
    # Check to see if there's input available (requires CP 4.0 Alpha)
    if supervisor.runtime.serial_bytes_available:
        # read in text (@mode, #RRGGBB, %brightness, standard color)
        # input() will block until a newline is sent
        inText = input().strip()
        # Sometimes Windows sends an extra (or missing) newline - ignore them
        if inText == "":
            continue
```

Once the setup is complete, we have our main loop - this will continue forever, checking for new messages from the controller and changing the LED.

First, it checks with the CircuitPython Supervisor to see if there is any text to read from the USB port.&nbsp; If so, it calls&nbsp;**input()** to read the message (and then strips off any whitespace like newlines or spaces).

Info: 

```auto
# Process the input text - start with the presets (no #,@,etc)
        # We use startswith to not have to worry about CR vs CR+LF differences
        if inText.lower().startswith("red"):
            # set the target color to red
            targetColor = (255, 0, 0)
            # and set the mode to solid if we're in a mode that ignores targetColor
            if mode == "wheel":
                mode="solid"
# Repeat for green, yellow and black...
```

Now that we're processing text, look for standard colors:&nbsp; **red, green, yellow,** and **black**.&nbsp; We set an appropriate color and make the&nbsp; **mode**"solid" if it was set to "wheel".

```auto
# Here we're going to change the mode - which starts w/@
        elif inText.lower().startswith("@"):
            mode= inText[1:]
```

If the incoming message starts with an "@" symbol, change the&nbsp; **mode** to the incoming text.&nbsp; Valid values of&nbsp; **mode** are "solid", "blink", "ramp", "beat", and "wheel".

```auto
# Here we can set the brightness with a "%" symbol
        elif inText.startswith("%"):
            pctText = inText[1:]
            pct = float(pctText)/100.0
            pixels.brightness=pct
```

If the controller sends a message starting with "%" take the number after it as a brightness level (0-100).

```auto
# If we get a hex code set it and go to solid
        elif inText.startswith("#"):
            hexcode = inText[1:]
            targetColor = hex2rgb(hexcode)
            if (mode == "wheel"):
                mode="solid"
```

Here we use the&nbsp;**hex2rgb()** function to convert any incoming #RRGGBB values into a valid color tuple before setting the color.

```auto
# if we get a command we don't understand, set it to gray
        #we should probably just ignore it but this helps debug
        else:
            targetColor =(50, 50, 50)
            if (mode == "wheel"):
                mode="solid"
```

If we get a command but don't understand it, just set the color to medium gray so we have an indicator something's gone wrong.

```auto
else:
        #If no text availble, update the color according to the mode
        if mode == 'blink':
            if curColor == black:
                curColor = targetColor
            else:
                curColor = black
            sleep(.4)
        #        print('.', end='')
            pixels.fill(curColor)
            pixels.show()   
        elif mode == 'wheel':
            sleep(.05)
            pos = (pos + 1) % 255
            pixels.fill(wheel(pos))
            pixels.show()
        elif mode == 'solid':
            pixels.fill(targetColor)
            pixels.show()
        elif mode == 'beat':
            pos = (pos + 5 ) % 106
            scaleAvg = (beatArray[(pos-2)%106] + beatArray[(pos-1)%106] + beatArray[pos] + beatArray[(pos+1)%106] + beatArray[(pos+2)%106])/5
            beatColor = tuple(int(scaleAvg*x) for x in targetColor)
            pixels.fill(beatColor)
            sleep(.025)
            pixels.show()
        elif mode == 'ramp':
            pos = ((pos + 5 ) % 255)
            scaleFactor = (2*abs(pos-127))/255
            beatColor = tuple(int(scaleFactor * x) for x in targetColor)
            pixels.fill(beatColor)
            sleep(.075)
            pixels.show()
```

At this point, we know that we&nbsp; **do not** have an incoming message. So, we just want to update the color of the LED based on the current mode, **sleep()** if appropriate and continue the loop to check for the message again.

Each of the&nbsp; **If/Elif** sections covers a different mode and simply calculates the next color, sets it and sleeps. There are lots of ways to modify these color modes or to add your own!

## Complete Code
https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CircuitPython_AT_Hand_Raiser/code.py


## Featured Products

### Adafruit Trinket M0 - for use with CircuitPython & Arduino IDE

[Adafruit Trinket M0 - for use with CircuitPython & Arduino IDE](https://www.adafruit.com/product/3500)
The&nbsp;Adafruit Trinket M0 may be small, but do not be fooled by its size! It's a tiny microcontroller board, built around the Atmel ATSAMD21, a little chip with _a lot_ of power. We wanted to design a microcontroller board that was small enough to fit into any project, and low...

In Stock
[Buy Now](https://www.adafruit.com/product/3500)
[Related Guides to the Product](https://learn.adafruit.com/products/3500/guides)
### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

In Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)
### PLA Filament for 3D Printers - 1.75mm Natural Translucent - 1KG

[PLA Filament for 3D Printers - 1.75mm Natural Translucent - 1KG](https://www.adafruit.com/product/2451)
Having a 3D printer without filament is sort of like having a regular printer without paper or ink. &nbsp;And while a lot of printers come with some filament there's a good chance you've been printing up a storm and need something new. &nbsp;That's why we've started carrying a...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/2451)
[Related Guides to the Product](https://learn.adafruit.com/products/2451/guides)
### PLA Filament for 3D Printers - 1.75mm Diameter - Green - 1KG

[PLA Filament for 3D Printers - 1.75mm Diameter - Green - 1KG](https://www.adafruit.com/product/2150)
Having a 3D printer without filament is sort of like having a regular printer without paper or ink. &nbsp;And while a lot of printers come with some filament there's a good chance you've been printing up a storm and need something new. That's why we've started carrying a...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/2150)
[Related Guides to the Product](https://learn.adafruit.com/products/2150/guides)
### Circuit Playground Express

[Circuit Playground Express](https://www.adafruit.com/product/3333)
 **Circuit Playground Express** is the next step towards a perfect introduction to electronics and programming. We've taken the original Circuit Playground Classic and made it even better! Not only did we pack even more sensors in, we also made it even easier to...

In Stock
[Buy Now](https://www.adafruit.com/product/3333)
[Related Guides to the Product](https://learn.adafruit.com/products/3333/guides)
### Adafruit Feather M0 Express

[Adafruit Feather M0 Express](https://www.adafruit.com/product/3403)
At the Feather M0's heart is an ATSAMD21G18 ARM Cortex M0+ processor, clocked at 48 MHz and at 3.3V logic, the same one used in the new&nbsp;[Arduino Zero](https://www.adafruit.com/products/2843). This chip has a whopping 256K of FLASH (8x more than the Atmega328 or 32u4) and...

In Stock
[Buy Now](https://www.adafruit.com/product/3403)
[Related Guides to the Product](https://learn.adafruit.com/products/3403/guides)
### Adafruit ItsyBitsy M0 Express - for CircuitPython & Arduino IDE

[Adafruit ItsyBitsy M0 Express - for CircuitPython & Arduino IDE](https://www.adafruit.com/product/3727)
What's smaller than a Feather but larger than a Trinket? It's an **Adafruit ItsyBitsy M0 Express**! Small, powerful, with a rockin' ATSAMD21 Cortex M0 processor running at 48 MHz - this microcontroller board is perfect when you want something very compact, but still...

In Stock
[Buy Now](https://www.adafruit.com/product/3727)
[Related Guides to the Product](https://learn.adafruit.com/products/3727/guides)
### Adafruit METRO M0 Express - designed for CircuitPython

[Adafruit METRO M0 Express - designed for CircuitPython](https://www.adafruit.com/product/3505)
Metro is our series of microcontroller boards for use with the Arduino IDE. This new **Metro M0 Express** board looks a whole lot like our&nbsp;[original Metro 328](https://www.adafruit.com/product/2488), but with a huge upgrade. Instead of the ATmega328, this Metro...

In Stock
[Buy Now](https://www.adafruit.com/product/3505)
[Related Guides to the Product](https://learn.adafruit.com/products/3505/guides)

## Related Guides

- [Adafruit Feather HUZZAH ESP8266](https://learn.adafruit.com/adafruit-feather-huzzah-esp8266.md)
- [Adafruit Feather M0 Express](https://learn.adafruit.com/adafruit-feather-m0-express-designed-for-circuit-python-circuitpython.md)
- [Adafruit Metro M0 Express](https://learn.adafruit.com/adafruit-metro-m0-express.md)
- [Adafruit Trinket M0](https://learn.adafruit.com/adafruit-trinket-m0-circuitpython-arduino.md)
- [Adafruit Circuit Playground Express](https://learn.adafruit.com/adafruit-circuit-playground-express.md)
- [Introducing ItsyBitsy M0 Express](https://learn.adafruit.com/introducing-itsy-bitsy-m0.md)
- [LEGO Head Lamp with Audio](https://learn.adafruit.com/lego-head-lamp-with-audio.md)
- [Using Servos With CircuitPython and Arduino](https://learn.adafruit.com/using-servos-with-circuitpython.md)
- [CircuitPython Essentials](https://learn.adafruit.com/circuitpython-essentials.md)
- [CircuitPython with Jupyter Notebooks](https://learn.adafruit.com/circuitpython-with-jupyter-notebooks.md)
- [Make It Pulse](https://learn.adafruit.com/make-it-pulse.md)
- [CircuitPython 101: Functions](https://learn.adafruit.com/circuitpython-101-functions.md)
- [CircuitPython I2C and SPI Under the Hood](https://learn.adafruit.com/circuitpython-basics-i2c-and-spi.md)
- [Adafruit AirLift Shield - ESP32 WiFi Co-Processor](https://learn.adafruit.com/adafruit-airlift-shield-esp32-wifi-co-processor.md)
- [CircuitPython 101: Basic Builtin Data Structures](https://learn.adafruit.com/basic-datastructures-in-circuitpython.md)
- [Make your own PCB with Eagle, OSH Park, and Adafruit!](https://learn.adafruit.com/making-pcbs-with-oshpark-and-eagle.md)
- [Simon Game Clone with Circuit Playground Express and CircuitPython](https://learn.adafruit.com/simon-game-clone-with-circuitplayground-express-and-circuitpython.md)
- [Installing CircuitPython on SAMD21 Boards](https://learn.adafruit.com/installing-circuitpython-on-samd21-boards.md)
- [Unicorn Christmas Stocking with Rainbow Lights & Sound](https://learn.adafruit.com/unicorn-christmas-stocking-with-lights-sound.md)
- [Storage humidity and temperature monitor](https://learn.adafruit.com/storage-humidity-and-temperature-monitor.md)
