Installing the Project Code

Download a zip of the project by clicking 'Download: Project Zip' in the preview of code.py below.

After unzipping the file, copy its contents to the CIRCUITPY drive which appears when the MagTag is connected to your computer via a USB cable and turned on via a small on/off switch onboard.

After you've copied everything over, this is what the CIRCUITPY drive should look like.

import time
import terminalio
from adafruit_magtag.magtag import MagTag

magtag = MagTag()
magtag.peripherals.neopixel_disable = False

magtag.add_text(
    text_font=terminalio.FONT,
    text_position=(140, 55),
    text_scale=7,
    text_anchor_point=(0.5, 0.5),
)

magtag.set_text("00:00")

# Function that makes the neopixels display the seconds left
def update_neopixels(seconds):
    n = seconds // 15
    for j in range(n):
        magtag.peripherals.neopixels[3 - j] = (128, 0, 0)
    magtag.peripherals.neopixels[3 - n] = (int(((seconds / 15) % 1) * 128), 0, 0)


alarm_set = False
while True:
    if not alarm_set:
        # Set the timer to 1 minute
        if magtag.peripherals.button_a_pressed:
            alarm_time = 60
            alarm_set = True
            start = time.time()
            magtag.set_text("01:00")
            last_set = 60
            magtag.peripherals.neopixels.fill((128, 0, 0))

        # Set the timer to 5 minutes
        elif magtag.peripherals.button_b_pressed:
            alarm_time = 300
            alarm_set = True
            start = time.time()
            magtag.set_text("05:00")
            last_set = 300
            magtag.peripherals.neopixels.fill((128, 0, 0))

        # Set the timer to 20 minutes
        elif magtag.peripherals.button_c_pressed:
            alarm_time = 1200
            alarm_set = True
            start = time.time()
            magtag.set_text("20:00")
            last_set = 1200
            magtag.peripherals.neopixels.fill((128, 0, 0))

    else:
        time.sleep(1)
        remaining = alarm_time - (time.time() - start)
        if (remaining < 0):
            remaining = 0
        print(remaining)
        if remaining == 0:
            magtag.peripherals.neopixels.fill((255, 0, 0))
            # Play alarm and flash neopixels to indicate the timer is done
            for i in range(2):
                magtag.peripherals.neopixels.fill((255, 0, 0))
                magtag.peripherals.play_tone(3000, 0.5)
                magtag.peripherals.neopixels.fill((0, 0, 0))
                time.sleep(0.1)
                magtag.peripherals.neopixels.fill((255, 0, 0))
                magtag.peripherals.play_tone(3000, 0.5)
                magtag.peripherals.neopixels.fill((0, 0, 0))
                time.sleep(0.5)
            alarm_set = False
            magtag.set_text("00:00")
            last_set = 0
            continue

        update_neopixels(remaining % 60)
        if remaining % 60 == 0 and remaining != last_set:
            magtag.set_text("{:02d}:00".format(remaining // 60))
            last_set = remaining

    # Reset the timer
    if magtag.peripherals.button_d_pressed:
        time.sleep(0.1)
        magtag.peripherals.neopixels.fill((0, 0, 0))
        time.sleep(0.1)
        magtag.peripherals.neopixels.fill((255, 0, 0))
        time.sleep(0.1)
        magtag.peripherals.neopixels.fill((0, 0, 0))
        time.sleep(0.1)

        alarm_set = False
        magtag.set_text("00:00")
Be sure you have the libraries and secrets.py file complete and loaded onto the CIRCUITPY drive also or the code will not run properly.

Code Behavior

I'll quickly explain how to use this because I recognize it may not be too obvious at first. To set an alarm, press one of the first three buttons. The first button sets a 1-minute alarm, the second one sets a 5-minute alarm, and the third one sets a 20-minute alarm, but you can change these values by making a few small edits in the code that I'll explain in the 'Code Run Through' section. The fourth button stops the current alarm, allowing the user to set a new one.

When the code is running, the number of minutes left will be displayed on the display. However, this only updates once a minute so the built-in NeoPixels are also used as indicators for the seconds. Each NeoPixel represents 15 seconds, so if there are 3 NeoPixels lit and the display says "05:00", there is between 5:30 and 5:45 left on the timer. The NeoPixel furthest to the right that is still illuminated will slowly dim so that at the end of the 15 seconds that it is indicating it will turn off.

Code Run Through

First, the code imports the required libraries.

import time
import terminalio
from adafruit_magtag.magtag import MagTag

Then, the code initializes the MagTag object and makes sure built-in NeoPixels are enabled.

magtag = MagTag()
magtag.peripherals.neopixel_disable = False

After that, the text object is added to the center of the display and it is set to "00:00."

magtag.add_text(
    text_font=terminalio.FONT,
    text_position=(140, 55),
    text_scale=7,
    text_anchor_point=(0.5, 0.5),
)

magtag.set_text("00:00")

Now, the code defines a function, update_neopixels. This function takes the amount of seconds left in the current minute (so if there were 5 minutes and 33 seconds left in the timer, the function would be given 33) and dims one NeoPixel at a time. At 59 seconds, all 4 NeoPixels are fully illuminated. At 46 seconds, the NeoPixel furthest to the right is almost completely out but the other three are still fully illuminated, and when this function is given 45 seconds, it will turn the fourth NeoPixel off and start dimming the third one. 

def update_neopixels(seconds):
    n = seconds // 15
    for j in range(n):
        magtag.peripherals.neopixels[3 - j] = (128, 0, 0)
    magtag.peripherals.neopixels[3 - n] = (int(((seconds / 15) % 1) * 128), 0, 0)

At this point, the main loop starts. It first checks to see if an alarm is currently active. If there isn't an active alarm, it starts scanning to see if a button is pressed. If button a, b, or c (first three buttons, going left to right) is pressed, it then activates an alarm and sets a few variables that make keeping track of the alarm easier. 

If you want to change the time an alarm lasts, change alarm_time, the string in magtag.set_text, and last_set.

alarm_set = False
while True:
    if not alarm_set:
        # Set the timer to 1 minute
        if magtag.peripherals.button_a_pressed:
            alarm_time = 60
            alarm_set = True
            start = time.time()
            magtag.set_text("01:00")
            last_set = 60
            magtag.peripherals.neopixels.fill((128, 0, 0))

        # Set the timer to 5 minutes
        elif magtag.peripherals.button_b_pressed:
            alarm_time = 300
            alarm_set = True
            start = time.time()
            magtag.set_text("05:00")
            last_set = 300
            magtag.peripherals.neopixels.fill((128, 0, 0))

        # Set the timer to 20 minutes
        elif magtag.peripherals.button_c_pressed:
            alarm_time = 1200
            alarm_set = True
            start = time.time()
            magtag.set_text("20:00")
            last_set = 1200
            magtag.peripherals.neopixels.fill((128, 0, 0))

This next part of the loop only gets executed when alarm_set is True, that is to say when an alarm is active. It starts by printing out the time left in the alarm (in seconds) to the serial console. Then, if the time remaining has reached zero, it plays an alarm through the speaker and flashes the NeoPixels on and off a few times to indicate that the alarm is done. Next, it sets the necessary variables to indicate that an alarm isn't set.

else:
  	time.sleep(1)
    remaining = alarm_time - (time.time() - start)
    if (remaining < 0):
    	remaining = 0
    print(remaining)
    if remaining == 0:
        magtag.peripherals.neopixels.fill((255, 0, 0))
        # Play alarm and flash neopixels to indicate the timer is done
        for i in range(2):
            magtag.peripherals.neopixels.fill((255, 0, 0))
            magtag.peripherals.play_tone(3000, 0.5)
            magtag.peripherals.neopixels.fill((0, 0, 0))
            time.sleep(0.1)
            magtag.peripherals.neopixels.fill((255, 0, 0))
            magtag.peripherals.play_tone(3000, 0.5)
            magtag.peripherals.neopixels.fill((0, 0, 0))
            time.sleep(0.5)
        alarm_set = False
        magtag.set_text("00:00")
        last_set = 0
        continue

If there is still time left in the alarm, update_neopixels is called. The code then checks to see if there is a whole number of minutes left and if there is, updates the display to reflect that.

update_neopixels(remaining % 60)
if remaining % 60 == 0 and remaining != last_set:
    magtag.set_text("{:02d}:00".format(remaining // 60))
    last_set = remaining

Finally, the code checks to see if button D (furthest to the right) is being pressed. If it is, it flashes the NeoPixels a few times and resets the alarm.

# Reset the timer
if magtag.peripherals.button_d_pressed:
    time.sleep(0.1)
    magtag.peripherals.neopixels.fill((0, 0, 0))
    time.sleep(0.1)
    magtag.peripherals.neopixels.fill((255, 0, 0))
    time.sleep(0.1)
    magtag.peripherals.neopixels.fill((0, 0, 0))
    time.sleep(0.1)

    alarm_set = False
    magtag.set_text("00:00")

This guide was first published on Dec 23, 2020. It was last updated on Dec 23, 2020.

This page (Code the Kitchen Timer) was last updated on Apr 22, 2021.

Text editor powered by tinymce.