text: # Techno-Tiki RGB LED Torch with IR Remote Control
  # Created by Tony DiCola for Arduino
  # Ported to CircuitPython by Mikey Sklar
  #
  # See guide at: https://learn.adafruit.com/techno-tiki-rgb-led-torch
  #
  # Released under a MIT license: http://opensource.org/licenses/MIT
  
  import time
  import board
  import neopixel
  import adafruit_irremote
  import pulseio
  # pylint: disable=global-statement
  
  pixel_pin = board.D1    # Pin where NeoPixels are connected
  
  pixel_count = 10        # Number of NeoPixels
  
  speed = .1              # Animation speed (in seconds).
                          # This is how long to spend in a single animation frame.
                          # Higher values are slower.
                          # Good values to try are 400, 200, 100, 50, 25, etc.
  
  animation = 1           # Type of animation, can be one of these values:
                          # 0 - Solid color pulse
                          # 1 - Moving color pulse
  
  
  brightness = 1.0        # 0-1, higher number is brighter
  
  ir_code_min = 60
  ir_code_max = 70
  pulsein = pulseio.PulseIn(board.D2, maxlen=100, idle_state=True)
  decoder = adafruit_irremote.GenericDecode()
  
  # Adafruit IR Remote Codes:
  # Button       Code               Button  Code
  # -----------  ------             ------  -----
  # VOL-:        255   0xff         0/10+:    207  0xcf
  # Play/Pause:  127   0x7f         1:        247  0xf7
  # VOL+:        191   0xbf         2:        119  0x77
  # SETUP:       223   0xdf         3:        183  0x87
  # STOP/MODE:   159   0x9f         4:        215  0xd7
  # UP:          95    0x5f         5:        87   0x57
  # DOWN:        79    0x4f         6:        151  0x97
  # LEFT:        239   0xef         7:        231  0xe7
  # RIGHT:       175   0xaf         8:        103  0x67
  # ENTER/SAVE:  111   0x6f         9:        167  0xa7
  # Back:        143   0x8f
  
  color_change = 175        # Button that cycles through color animations.
  animation_change = 239    # Button that cycles through animation types (only two supported).
  speed_change = 95        # Button that cycles through speed choices.
  power_off = 255            # Button that turns off the pixels.
  power_on = 191            # Button that turns on the pixels.  Must be pressed twice to register!
  
  # Build lookup table/palette for the color animations so they aren't computed at runtime.
  # The colorPalette two-dimensional array below has a row for each color animation and a column
  # for each step within the animation.  Each value is a 24-bit RGB color.  By looping through
  # the columns of a row the colors of pixels will animate.
  color_steps = 8         # Number of steps in the animation.
  color_count = 23        # number of columns/steps
  
  color_palette = [
      # Complimentary colors
      ([255, 0, 0], [218, 36, 36], [182, 72, 72], [145, 109, 109],
       [109, 145, 145], [72, 182, 182], [36, 218, 218], [0, 255, 255]),       # red cyan
      ([255, 255, 0], [218, 218, 36], [182, 182, 72], [145, 145, 109],
       [109, 109, 145], [72, 72, 182], [36, 36, 218], [0, 0, 255]),           # yellow blue
      ([0, 255, 0], [36, 218, 36], [72, 182, 72], [109, 145, 109],
       [145, 109, 145], [182, 72, 182], [218, 36, 218], [255, 0, 255]),       # green magenta
  
      # Adjacent colors (on color wheel).
      ([255, 255, 0], [218, 255, 0], [182, 255, 0], [145, 255, 0],
       [109, 255, 0], [72, 255, 0], [36, 255, 0], [0, 255, 0]),               # yello green
      ([0, 255, 0], [0, 255, 36], [0, 255, 72], [0, 255, 109],
       [0, 255, 145], [0, 255, 182], [0, 255, 218], [0, 255, 255]),           # green cyan
      ([0, 255, 255], [0, 218, 255], [0, 182, 255], [0, 145, 255],
       [0, 109, 255], [0, 72, 255], [0, 36, 255], [0, 0, 255]),               # cyan blue
      ([0, 0, 255], [36, 0, 255], [72, 0, 255], [109, 0, 255],
       [145, 0, 255], [182, 0, 255], [218, 0, 255], [255, 0, 255]),           # blue magenta
      ([255, 0, 255], [255, 0, 218], [255, 0, 182], [255, 0, 145],
       [255, 0, 109], [255, 0, 72], [255, 0, 36], [255, 0, 0]),               # magenta red
  
      # Other combos
      ([255, 0, 0], [218, 36, 0], [182, 72, 0], [145, 109, 0],
       [109, 145, 0], [72, 182, 0], [36, 218, 0], [0, 255, 0]),               # red green
      ([255, 255, 0], [218, 255, 36], [182, 255, 72], [145, 255, 109],
       [109, 255, 145], [72, 255, 182], [36, 255, 218], [0, 255, 255]),       # yellow cyan
      ([0, 255, 0], [0, 218, 36], [0, 182, 72], [0, 145, 109],
       [0, 109, 145], [0, 72, 182], [0, 36, 218], [0, 0, 255]),               # green blue
      ([0, 255, 255], [36, 218, 255], [72, 182, 255], [109, 145, 255],
       [145, 109, 255], [182, 72, 255], [218, 36, 255], [255, 0, 255]),       # cyan magenta
      ([0, 0, 255], [36, 0, 218], [72, 0, 182], [109, 0, 145],
       [145, 0, 109], [182, 0, 72], [218, 0, 36], [255, 0, 0]),               # blue red
      ([255, 0, 255], [255, 36, 218], [255, 72, 182], [255, 109, 145],
       [255, 145, 109], [255, 182, 72], [255, 218, 36], [255, 255, 0]),       # magenta yellow
  
      # Solid colors fading to dark.
      ([255, 0, 0], [223, 0, 0], [191, 0, 0], [159, 0, 0],
       [127, 0, 0], [95, 0, 0], [63, 0, 0], [31, 0, 0]),                      # red
      ([255, 153, 0], [223, 133, 0], [191, 114, 0], [159, 95, 0],
       [127, 76, 0], [95, 57, 0], [63, 38, 0], [31, 19, 0]),                  # orange
      ([255, 255, 0], [223, 223, 0], [191, 191, 0], [159, 159, 0],
       [127, 127, 0], [95, 95, 0], [63, 63, 0], [31, 31, 0]),                 # yellow
      ([0, 255, 0], [0, 223, 0], [0, 191, 0], [0, 159, 0],
       [0, 127, 0], [0, 95, 0], [0, 63, 0], [0, 31, 0]),                      # green
      ([0, 0, 255], [0, 0, 223], [0, 0, 191], [0, 0, 159],
       [0, 0, 127], [0, 0, 95], [0, 0, 63], [0, 0, 31]),                      # blue
      ([75, 0, 130], [65, 0, 113], [56, 0, 97], [46, 0, 81],
       [37, 0, 65], [28, 0, 48], [18, 0, 32], [9, 0, 16]),                    # indigo
      ([139, 0, 255], [121, 0, 223], [104, 0, 191], [86, 0, 159],
       [69, 0, 127], [52, 0, 95], [34, 0, 63], [17, 0, 31]),                  # violet
      ([255, 255, 255], [223, 223, 223], [191, 191, 191], [159, 159, 159],
       [127, 127, 127], [95, 95, 95], [63, 63, 63], [31, 31, 31]),            # white
      ([255, 0, 0], [255, 153, 0], [255, 255, 0], [0, 255, 0],
       [0, 0, 255], [75, 0, 130], [139, 0, 255], [255, 255, 255])             # rainbow colors
  ]
  
  # List of animations speeds (in seconds).  This is how long an animation spends before
  # changing to the next step.  Higher values are slower.
  speeds = [.4, .2, .1, .05, .025]
  
  # Global state used by the sketch
  strip = neopixel.NeoPixel(pixel_pin, pixel_count, brightness=brightness, auto_write=False)
  color_index = 0
  animation_index = 0
  speed_index = 2
  
  def read_NEC():
  # Check if a NEC IR remote command is the correct length.
  # Save the third decoded value as our unique identifier.
      pulses = decoder.read_pulses(pulsein, max_pulse=5000)
      command = None
  
      try:
          if len(pulses) >= ir_code_min and len(pulses) <= ir_code_max:
              code = decoder.decode_bits(pulses)
              if len(code) > 3:
                  command = code[2]
      except adafruit_irremote.IRNECRepeatException:  # Catches the repeat signal
          pass
      except adafruit_irremote.IRDecodeException:  # Failed to decode
          pass
  
      return command
  
  def handle_remote():
      global color_index, animation_index, speed_index
  
      ir_code = read_NEC()
  
      if ir_code is None:
          time.sleep(.1)
          return
  
      if ir_code == color_change:
          color_index = (color_index + 1) % color_count
      elif ir_code == animation_change:
          animation_index = (animation_index + 1) % 2
      elif ir_code == speed_change:
          speed_index = (speed_index + 1) % 5
      elif ir_code == power_off:
          strip.fill([0, 0, 0])
          strip.show()
  
  while True:  # Loop forever...
  
      # Main loop will update all the pixels based on the animation.
      for i in range(pixel_count):
  
          # Animation 0, solid color pulse of all pixels.
          if animation_index == 0:
              current_step = (time.monotonic() / speeds[speed_index]) % (color_steps * 2 - 2)
              if current_step >= color_steps:
                  current_step = color_steps - (current_step - (color_steps - 2))
  
          # Animation 1, moving color pulse.  Use position to change brightness.
          elif animation == 1:
              current_step = (time.monotonic() / speeds[speed_index] + i) % (color_steps * 2 - 2)
              if current_step >= color_steps:
                  current_step = color_steps - (current_step - (color_steps - 2))
  
          strip[i] = color_palette[int(color_index)][int(current_step)]
  
      # Next check for any IR remote commands.
      handle_remote()
  
      # Show the updated pixels.
      strip.show()
  
      # Next check for any IR remote commands.
      handle_remote()
  