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!