This project is coded using CircuitPython which makes it super simple to edit. There are a couple of customisations you can update to make this project fit your needs. If you also want to change the style and type of LED animations, there is a guide on using the CircuitPython LED Animation library that covers all the features. This guide does not go into customising the animations.
This page will show you how to customise a couple of things in the code. However, before the code will run, you need to load the LED Animation library onto your CIRCUITPY drive.
Install Code and Libraries
CIRCUITPYcode.py with the example script.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, open the directory MagTag_Cheerlights_LED_Animations/ and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your CIRCUITPY drive.
CIRCUITPY
# SPDX-FileCopyrightText: 2020 Kattni Rembor, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense import time import board import neopixel from adafruit_magtag.magtag import MagTag from adafruit_led_animation.animation.comet import Comet from adafruit_led_animation.animation.sparkle import Sparkle from adafruit_led_animation.animation.chase import Chase from adafruit_led_animation.animation.blink import Blink from adafruit_led_animation.animation.pulse import Pulse from adafruit_led_animation.sequence import AnimationSequence from adafruit_led_animation.group import AnimationGroup from adafruit_led_animation.color import RED, GREEN, BLUE, CYAN, WHITE,\ OLD_LACE, PURPLE, MAGENTA, YELLOW, ORANGE, PINK # =============== CUSTOMISATIONS ================ # The strip LED brightness, where 0.0 is 0% (off) and 1.0 is 100% brightness, e.g. 0.3 is 30% strip_pixel_brightness = 1 # The MagTag LED brightness, where 0.0 is 0% (off) and 1.0 is 100% brightness, e.g. 0.3 is 30%. magtag_pixel_brightness = 0.5 # The rate interval in seconds at which the Cheerlights data is fetched. # Defaults to one minute (60 seconds). refresh_rate = 60 # =============================================== # Set up where we'll be fetching data from DATA_SOURCE = "http://api.thingspeak.com/channels/1417/field/1/last.json" COLOR_LOCATION = ['field1'] DATE_LOCATION = ['created_at'] magtag = MagTag( url=DATA_SOURCE, json_path=(COLOR_LOCATION, DATE_LOCATION), ) magtag.network.connect() strip_pixels = neopixel.NeoPixel(board.D10, 30, brightness=strip_pixel_brightness) magtag_pixels = magtag.peripherals.neopixels magtag_pixels.brightness = magtag_pixel_brightness # Cheerlights color magtag.add_text( text_scale=2, text_position=(10, 15), text_transform=lambda x: "New Color: {}".format(x), # pylint: disable=unnecessary-lambda ) # datestamp magtag.add_text( text_scale=2, text_position=(10, 65), text_transform=lambda x: "Updated on:\n{}".format(x), # pylint: disable=unnecessary-lambda ) timestamp = None while True: if not timestamp or ((time.monotonic() - timestamp) > refresh_rate): # Refresh rate in seconds try: # Turn on the MagTag NeoPixels. magtag.peripherals.neopixel_disable = False # Fetch the color and datetime, and print it to the serial console. cheerlights_update_info = magtag.fetch() print("Response is", cheerlights_update_info) # Get the color from the fetched info for use below. cheerlights_color = cheerlights_update_info[0] # If red, blue or pink, do a comet animation in the specified color. if cheerlights_color in ('red', 'blue', 'pink'): if cheerlights_color == 'red': comet_color = RED elif cheerlights_color == 'blue': comet_color = BLUE elif cheerlights_color == 'pink': comet_color = PINK animations = AnimationSequence( AnimationGroup( Comet(magtag_pixels, 0.3, color=comet_color, tail_length=3), Comet(strip_pixels, 0.05, color=comet_color, tail_length=15), ) ) # If green or orange, do a pulse animation in the specified color. if cheerlights_color in ('green', 'orange'): if cheerlights_color == 'green': pulse_color = GREEN elif cheerlights_color == 'orange': pulse_color = ORANGE animations = AnimationSequence( AnimationGroup( Pulse(magtag_pixels, speed=0.1, color=pulse_color, period=3), Pulse(strip_pixels, speed=0.1, color=pulse_color, period=3), ) ) # If oldlace, warmmwhite or magenta, do a sparkle animation in the specified color. if cheerlights_color in ('oldlace', 'warmwhite', 'magenta'): if cheerlights_color in ('oldlace', 'warmwhite'): sparkle_color = OLD_LACE elif cheerlights_color == 'magenta': sparkle_color = MAGENTA animations = AnimationSequence( AnimationGroup( Sparkle(magtag_pixels, speed=0.1, color=sparkle_color, num_sparkles=1), Sparkle(strip_pixels, speed=0.01, color=sparkle_color, num_sparkles=15), ) ) # If cyan or purple, do a blink animation in the specified color. if cheerlights_color in ('cyan', 'purple'): if cheerlights_color == 'cyan': blink_color = CYAN elif cheerlights_color == 'purple': blink_color = PURPLE animations = AnimationSequence( AnimationGroup( Blink(magtag_pixels, speed=0.5, color=blink_color), Blink(strip_pixels, speed=0.5, color=blink_color), ) ) # If white or yellow, do a chase animation in the specified color. if cheerlights_color in ('white', 'yellow'): if cheerlights_color == 'white': chase_color = WHITE elif cheerlights_color == 'yellow': chase_color = YELLOW animations = AnimationSequence( AnimationGroup( Chase(magtag_pixels, speed=0.1, size=2, spacing=1, color=chase_color), Chase(strip_pixels, speed=0.1, size=3, spacing=2, color=chase_color), ) ) timestamp = time.monotonic() except (ValueError, RuntimeError, ConnectionError, OSError) as e: # Catch any random errors so the code will continue running. print("Some error occured, retrying! -", e) try: # This runs the animations. animations.animate() except NameError: # If Cheerlights adds a color not included above, the code would fail. This allows it to # continue to retry until a valid color comes up. print("There may be a Cheerlights color not included above.")
Each time the MagTag fetches the current Cheerlights color, the current animation will pause. Once the information is fetched, the new animation will begin and the display will refresh. This is expected behavior. The following shows a transition from orange to white.
Customisations
There are a couple of things you can easily change in this code.
LED Brightness
You can set the brightness of both the MagTag LEDs and the strip separately. Depending on how you mounted the strip, you may want to decrease the brightness.
strip_pixel_brightness = 1 magtag_pixel_brightness = 0.5
NeoPixels can get really bright. The code defaults to 0.5
, or 50% brightness, for the MagTag LEDs, and 1
, or 100% brightness, for the strip. The strip cannot get any brighter than 100%, however you can increase the MagTag LED brightness number to make them brighter. You can decrease either of the numbers to make them dimmer, however, be aware that some of the colors look different when the LEDs are very dim.
Refresh Rate
You can also set the rate in seconds at which the MagTag fetches the Cheerlights data. Bear in mind that the animations pause during the data retrieval, so if you set the rate too low, your animations won't run for long between fetches. As well, it is not good for the display to refresh too frequently.
refresh_rate = 60
The refresh_rate
defaults to 60 seconds, or one minute. You can increase or decrease this to fit your needs.
Let's take a look at the code.
First, we set up where we'll be fetching the data from.
Cheerlights has three feeds available - one that provides the hex value of the latest color and the update time, one that provides the name of the latest color and the update time, and one that contains the entire feed of hex and color names and update times. This project uses the feed that provides the name of the latest color and update time because it does not require you to know hex colors, and makes the code easier to read.
DATA_SOURCE = "http://api.thingspeak.com/channels/1417/field/1/last.json" COLOR_LOCATION = ['field1'] DATE_LOCATION = ['created_at']
Then we initialise the MagTag library, including the information needed to fetch the Cheerlights data, and we tell the board to connect to the network.
magtag = MagTag( url=DATA_SOURCE, json_path=(COLOR_LOCATION, DATE_LOCATION), ) magtag.network.connect()
Next, we set up the external NeoPixel strip, and set the brightness specified at the beginning of the code on both the strip NeoPixels and the MagTag NeoPixels.
strip_pixels = neopixel.NeoPixel(board.D10, 30, brightness=strip_pixel_brightness) magtag_pixels = magtag.peripherals.neopixels magtag_pixels.brightness = magtag_pixel_brightness
Then we set up the text that will be display on the screen. By using the text_transform
option, we can set up the display text in the beginning, and update it each time we fetch new data in the loop.
magtag.add_text( text_scale=2, text_position=(10, 15), text_transform=lambda x: "New Color: {}".format(x), ) magtag.add_text( text_scale=2, text_position=(10, 65), text_transform=lambda x: "Updated on:\n{}".format(x), )
The first thing inside the loop is checking whether it's the first time the loop has started or if the refresh_rate
seconds (set in the beginning of the code - defaults to 60 seconds) has passed.
if not timestamp or ((time.monotonic() - timestamp) > refresh_rate):
The next block of code is wrapped in a try
/except
to avoid the code stopping if it experiences any errors with regards to fetching the data.
[...] try: [...] # Main block of code is here. except (ValueError, RuntimeError) as e: print("Some error occured, retrying! -", e)
Inside, we first enable the NeoPixels by turning off magtag.neopixel_disable
.
magtag.peripherals.neopixel_disable = False
Then we fetch the Cheerlights data, which returns a two-member list that includes the latest color, and the current date and time. For example, it appears as something like the following:
['white', '2020-12-02T22:52:45Z']
.
We assign it to the cheerlights_update_info
variable, and print that information to the serial console.
cheerlights_update_info = magtag.fetch() print("Response is", cheerlights_update_info)
For the animations, we need only the color from the data we fetch. So, to make it easy to use the color, we assign the first member of the list (using [0]
) to a variable called cheerlights_color
.
cheerlights_color = cheerlights_update_info[0]
Then we begin using the colors to display animations. There are eleven colors available for Cheerlights, and five basic animations, so each animation applies to multiple colors. Each animation checks the cheerlights_color
variable to see what the latest color is, and displays the matching animation. The same general format is used for every animation - therefore this will only cover the first animation.
This section of the code could be more succinct if the hex value feed was used. However, not everyone is familiar with hex colors, so this section is slightly longer-form to enhance simplicity and ease of understanding.
First, the code checks if the latest color is one that applies to that particular animation, in this case, is it red, blue or pink.
Then, it verifies the specific Cheerlights color, and sets the animation color to the appropriate color. In this case, for example, if the Cheerlights color is red, it sets comet_color = RED
.
Last, it creates the animation, in this case the comet animation, along with any necessary animation settings. For more details on the animations or their settings, take a look at the CircuitPython LED Animation guide.
if cheerlights_color in ('red', 'blue', 'pink'): if cheerlights_color == 'red': comet_color = RED elif cheerlights_color == 'blue': comet_color = BLUE elif cheerlights_color == 'pink': comet_color = PINK animations = AnimationSequence( AnimationGroup( Comet(magtag_pixels, 0.3, color=comet_color, tail_length=3), Comet(strip_pixels, 0.05, color=comet_color, tail_length=15), ) )
Finally, the code runs the animations. This code is also wrapped in a try
/except
. In the event that Cheerlights adds a new color, the code would fail - this ensures your code will continue and display the next time one of the current colors is fetched.
try: animations.animate() except NameError: print("There may be a Cheerlights color not included above.")
That's all there is to displaying LED animations based on Cheerlights data!
Text editor powered by tinymce.