/ LED_Candles / code.py
code.py
1 # SPDX-FileCopyrightText: 2017 Mikey Sklar for Adafruit Industries 2 # 3 # SPDX-License-Identifier: MIT 4 5 import time 6 7 import board 8 import neopixel 9 from analogio import AnalogIn 10 11 try: 12 import urandom as random 13 except ImportError: 14 import random 15 16 wick_pin = board.D0 # The data-in pin of the NeoPixel 17 unconnected_pin = board.A0 # Any unconnected pin, to generate random seed 18 19 # The LED can be in only one of these states at any given time 20 bright = 0 21 up = 1 22 down = 2 23 dim = 3 24 bright_hold = 4 25 dim_hold = 5 26 27 # Percent chance the LED will suddenly fall to minimum brightness 28 index_bottom_percent = 10 29 # Absolute minimum red value (green value is a function of red's value) 30 index_bottom = 128 31 # Minimum red value during "normal" flickering (not a dramatic change) 32 index_min = 192 33 index_max = 255 # Maximum red value 34 35 # Decreasing brightness will take place over a number of milliseconds 36 down_min_msecs = 20 37 down_max_msecs = 250 38 39 # Increasing brightness will take place over a number of milliseconds 40 up_min_msecs = 20 41 up_max_msecs = 250 42 43 # Percent chance the color will hold unchanged after brightening 44 bright_hold_percent = 20 45 46 # When holding after brightening, hold for a number of milliseconds 47 bright_hold_min_msecs = 0 48 bright_hold_max_msecs = 100 49 50 # Percent chance the color will hold unchanged after dimming 51 dim_hold_percent = 5 52 53 # When holding after dimming, hold for a number of milliseconds 54 dim_hold_min_msecs = 0 55 dim_hold_max_msecs = 50 56 57 numpix = 1 # Number of NeoPixels 58 pixpin = board.D0 # Pin where NeoPixels are connected 59 strip = neopixel.NeoPixel(pixpin, numpix, brightness=1, 60 auto_write=True) # initialize strip 61 62 # Random number generator is seeded from an unused 'floating' 63 # analog input - this helps ensure the random color choices 64 # aren't always the same order. 65 pin = AnalogIn(unconnected_pin) 66 random.seed(pin.value) 67 pin.deinit() 68 69 index_start = 255 70 index_start = 255 71 index_end = 255 72 state = bright 73 74 75 def set_color(index): 76 index = max(min(index, index_max), index_bottom) 77 if index >= index_min: 78 strip[0] = [index, int((index * 3) / 8), 0] 79 elif index < index_min: 80 strip[0] = [index, int((index * 3.25) / 8), 0] 81 82 83 set_color(255) 84 85 while True: 86 87 current_time = time.monotonic() 88 89 # BRIGHT 90 if state == bright: 91 flicker_msecs = random.randint( 92 0, down_max_msecs - down_min_msecs) + down_min_msecs 93 flicker_start = current_time 94 index_start = index_end 95 96 is_index_in_range = index_start > index_bottom 97 is_random_in_range = random.randint(0, 100) < index_bottom_percent 98 if is_index_in_range and is_random_in_range: 99 index_end = random.randint( 100 0, index_start - index_bottom) + index_bottom 101 else: 102 index_end = random.randint(0, index_start - index_min) + index_min 103 104 state = down 105 106 # DIM 107 elif state == dim: 108 flicker_msecs = random.randint( 109 0, up_max_msecs - up_min_msecs) + up_min_msecs 110 flicker_start = current_time 111 index_start = index_end 112 index_end = random.randint(0, (index_max - index_start)) + index_min 113 state = down 114 115 # DIM_HOLD 116 elif state == dim_hold: 117 # dividing flicker_msecs by 1000 to convert to milliseconds 118 if current_time >= (flicker_start + (flicker_msecs / 1000)): 119 if state == bright_hold: 120 state = bright 121 else: 122 state = dim 123 124 # DOWN 125 elif state == down: 126 # dividing flicker_msecs by 1000 to convert to milliseconds 127 if current_time < (flicker_start + (flicker_msecs / 1000)): 128 index_range = index_end - index_start 129 time_range = (current_time - flicker_start) * 1.0 130 131 set_color(index_start + int( 132 (index_range * (time_range / flicker_msecs)))) 133 else: 134 set_color(index_end) 135 136 if state == down: 137 if random.randint(0, 100) < dim_hold_percent: 138 flicker_start = current_time 139 140 dim_max = dim_hold_max_msecs - dim_hold_min_msecs 141 flicker_msecs = random.randint( 142 0, dim_max 143 ) + dim_hold_min_msecs 144 state = dim_hold 145 else: 146 state = dim 147 else: 148 if random.randint(0, 100) < bright_hold_percent: 149 flicker_start = current_time 150 151 max_flicker = bright_hold_max_msecs - bright_hold_min_msecs 152 flicker_msecs = random.randint( 153 0, max_flicker) + bright_hold_min_msecs 154 state = bright_hold 155 else: 156 state = bright