/ PyBadge_Conference_Badge / code.py
code.py
1 # SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries 2 # 3 # SPDX-License-Identifier: MIT 4 5 """ 6 This is a Conference Badge type Name Tag that is intended to be displayed on 7 the PyBadge. Feel free to customize it to your heart's content. 8 """ 9 10 from math import sqrt, cos, sin, radians 11 import board 12 from micropython import const 13 import displayio 14 import neopixel 15 from keypad import ShiftRegisterKeys, Event 16 from adafruit_display_shapes.rect import Rect 17 from adafruit_display_text.label import Label 18 from adafruit_bitmap_font import bitmap_font 19 20 # Button Constants 21 BUTTON_LEFT = const(7) 22 BUTTON_UP = const(6) 23 BUTTON_DOWN = const(5) 24 BUTTON_RIGHT = const(4) 25 BUTTON_SEL = const(3) 26 BUTTON_START = const(2) 27 BUTTON_A = const(1) 28 BUTTON_B = const(0) 29 30 # Customizations 31 HELLO_STRING = "HELLO" 32 MY_NAME_STRING = "MY NAME IS" 33 NAME_STRING = "Blinka" 34 NAME_FONTNAME = "/fonts/Noto-18.bdf" 35 NEOPIXEL_COUNT = 5 36 BACKGROUND_COLOR = 0xFF0000 37 FOREGROUND_COLOR = 0xFFFFFF 38 BACKGROUND_TEXT_COLOR = 0xFFFFFF 39 FOREGROUND_TEXT_COLOR = 0x000000 40 41 settings = {"brightness": 0.2, "direction": 1, "speed": 1} 42 43 # Define the NeoPixel 44 neopixels = neopixel.NeoPixel( 45 board.NEOPIXEL, 46 NEOPIXEL_COUNT, 47 brightness=settings["brightness"], 48 auto_write=False, 49 pixel_order=neopixel.GRB, 50 ) 51 52 # Define Events and Shift Register 53 latest_event = Event() 54 last_event = Event() 55 56 pad = ShiftRegisterKeys( 57 clock=board.BUTTON_CLOCK, 58 data=board.BUTTON_OUT, 59 latch=board.BUTTON_LATCH, 60 key_count=8, 61 value_when_pressed=True, 62 interval=0.1, 63 max_events=1, 64 ) 65 66 # Make the Display Background 67 splash = displayio.Group() 68 board.DISPLAY.show(splash) 69 70 color_bitmap = displayio.Bitmap(160, 128, 1) 71 color_palette = displayio.Palette(1) 72 color_palette[0] = BACKGROUND_COLOR 73 74 bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 75 splash.append(bg_sprite) 76 77 # Draw a Foreground Rectangle where the name goes 78 rect = Rect(0, 50, 160, 70, fill=FOREGROUND_COLOR) 79 splash.append(rect) 80 81 # Load the Hello font 82 large_font_name = "/fonts/Verdana-Bold-18.bdf" 83 large_font = bitmap_font.load_font(large_font_name) 84 large_font.load_glyphs(HELLO_STRING.encode("utf-8")) 85 86 # Load the "My Name Is" font 87 small_font_name = "/fonts/Arial-12.bdf" 88 small_font = bitmap_font.load_font(small_font_name) 89 small_font.load_glyphs(MY_NAME_STRING.encode("utf-8")) 90 91 # Load the Name font 92 name_font_name = NAME_FONTNAME 93 name_font = bitmap_font.load_font(name_font_name) 94 name_font.load_glyphs(NAME_STRING.encode("utf-8")) 95 96 # Setup and Center the Hello Label 97 splash.append( 98 Label( 99 large_font, 100 anchor_point=(0.5, 0.5), 101 anchored_position=(board.DISPLAY.width // 2, 15), 102 text=HELLO_STRING, 103 color=BACKGROUND_TEXT_COLOR, 104 ) 105 ) 106 107 # Setup and Center the "My Name Is" Label 108 splash.append( 109 Label( 110 small_font, 111 anchor_point=(0.5, 0.5), 112 anchored_position=(board.DISPLAY.width // 2, 35), 113 text=MY_NAME_STRING, 114 color=BACKGROUND_TEXT_COLOR, 115 ) 116 ) 117 118 # Setup and Center the Name Label 119 splash.append( 120 Label( 121 name_font, 122 anchor_point=(0.5, 0.5), 123 anchored_position=(board.DISPLAY.width // 2, 85), 124 text=NAME_STRING, 125 color=FOREGROUND_TEXT_COLOR, 126 ) 127 ) 128 129 # Remap the calculated rotation to 0 - 255 130 def remap(vector): 131 return int(((255 * vector + 85) * 0.75) + 0.5) 132 133 134 # Calculate the Hue rotation starting with Red as 0 degrees 135 def rotate(degrees): 136 cosA = cos(radians(degrees)) 137 sinA = sin(radians(degrees)) 138 red = cosA + (1.0 - cosA) / 3.0 139 green = 1.0 / 3.0 * (1.0 - cosA) + sqrt(1.0 / 3.0) * sinA 140 blue = 1.0 / 3.0 * (1.0 - cosA) - sqrt(1.0 / 3.0) * sinA 141 return (remap(red), remap(green), remap(blue)) 142 143 144 palette = [] 145 pixels = [] 146 147 # Generate a rainbow palette 148 for degree in range(0, 360): 149 color = rotate(degree) 150 palette.append(color[0] << 16 | color[1] << 8 | color[2]) 151 152 # Create the Pattern 153 for x in range(0, NEOPIXEL_COUNT): 154 pixels.append(x * 360 // NEOPIXEL_COUNT) 155 156 157 def check_buttons(event): 158 if event.key_number == BUTTON_RIGHT: 159 settings["direction"] = -1 160 elif event.key_number == BUTTON_LEFT: 161 settings["direction"] = 1 162 elif (event.key_number == BUTTON_UP) and settings["speed"] < 10: 163 settings["speed"] += 1 164 elif (event.key_number == BUTTON_DOWN) and settings["speed"] > 1: 165 settings["speed"] -= 1 166 elif (event.key_number == BUTTON_A) and settings["brightness"] < 0.5: 167 settings["brightness"] += 0.025 168 elif (event.key_number == BUTTON_B) and settings["brightness"] > 0.025: 169 settings["brightness"] -= 0.025 170 171 172 # Main Loop 173 last_read = 0 174 while True: 175 for color in range(0, 360, settings["speed"]): 176 for index in range(0, NEOPIXEL_COUNT): 177 palette_index = pixels[index] + color * settings["direction"] 178 if palette_index >= 360: 179 palette_index -= 360 180 elif palette_index < 0: 181 palette_index += 360 182 neopixels[index] = palette[palette_index] 183 neopixels.show() 184 neopixels.brightness = settings["brightness"] 185 pad.events.get_into(latest_event) 186 if latest_event.pressed and latest_event.key_number != last_event.key_number: 187 check_buttons(latest_event) 188 last_event = latest_event 189 latest_event = Event( 190 key_number=8 191 ) # An imaginary key number that doesn't exist!