class LEDController(Component): def __init__(self, config: dict): super().__init__("leds") self.controller = None self.leds = {} led_config = config['leds'] if led_config['type'] == "pixelstrip": self._process_pixelstrip(led_config) def _process_pixelstrip(self, config): self.controller = PixelStrip(config['count'], config['pin'], config['frequency'], config['dma'], config['invert'], config['brightness'], config['channel']) self.controller.begin() for index, name in config['names'].items(): self.leds[name] = PixelStripLED(self.controller, index) def process_control(self, message): updated = False for name, led in self.leds.items(): if name in message: state = message[name] led.set_color(state.get('red', 0), state.get('green', 0), state.get('blue', 0)) updated = True if "brightness" in message: self.controller.setBrightness(message["brightness"]) updated = True if updated: self.controller.show() self.update_state() @property def state(self): return { "brightness": self.controller.getBrightness(), "leds": {name: led.state for name, led in self.leds.items()}}
class RGBLight(): "Simple wrapper for a RGB light device " def __init__(self, pin: int, nb_led: int = 5): self.pixels = PixelStrip(nb_led, pin) self.pixels.begin() self._state: bool = False self.delay: float = 0.01 self._mode: int = MODE_RGB self.off() @property def state(self) -> bool: return self._state @state.setter def state(self, state: bool) -> None: self._state = state @property def mode(self) -> int: return self._mode @mode.setter def mode(self, mode) -> None: self._mode = mode def on(self) -> None: self.state = True for i in range(self.pixels.numPixels()): print(i) self.pixels.setPixelColorRGB(i, 50, 50, 50) self.pixels.show() sleep(0.01) def off(self) -> None: self.state = False for i in range(self.pixels.numPixels()): self.pixels.setPixelColorRGB(i, 0, 0, 0) self.pixels.show() sleep(self.delay) def toggle(self) -> None: if self.state is True: self.off() else: self.on() @property def color(self) -> Tuple[int, int, int]: if self.mode != MODE_RGB: raise Exception("Light is not in RGB mode") color_raw = self.pixels.getPixelColorRGB(0) color = (color_raw.r, color_raw.g, color_raw.b) return color @color.setter def color(self, color: Tuple[int, int, int]) -> None: self.state = True self.mode = MODE_RGB for i in range(self.pixels.numPixels()): self.pixels.setPixelColorRGB(i, *color) self.pixels.show() sleep(self.delay) @property def brightness(self) -> int: bri = self.pixels.getBrightness() return bri @brightness.setter def brightness(self, value: int) -> None: self.pixels.setBrightness(value) @property def temperature(self) -> int: if self.mode != MODE_TEMPERATURE: raise Exception("Light is not in temperature mode") color_raw = self.pixels.getPixelColorRGB(0) rgb = (color_raw.r, color_raw.g, color_raw.b) print(rgb) for temp in kelvin_table.keys(): if kelvin_table[temp] == rgb: return temp return 0 @temperature.setter def temperature(self, temp: int) -> None: self.mode = MODE_TEMPERATURE safe_temp = temp - (temp % 100) rgb: Tuple[int, int, int] = kelvin_table[safe_temp] for i in range(self.pixels.numPixels()): self.pixels.setPixelColorRGB(i, *rgb) self.pixels.show() sleep(self.delay)
class Led(Thread): # LED strip configuration: LED_COUNT = 95 # Number of LED pixels. LED_PIN = 18 # GPIO pin connected to the pixels (18 uses PWM!). # LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0). LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz) LED_DMA = 10 # DMA channel to use for generating signal (try 10) LED_BRIGHTNESS = 170 # Set to 0 for darkest and 255 for brightest LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53 FRAMERATE = 50 def __init__(self): # Create NeoPixel object with appropriate configuration. self.strip = PixelStrip(self.LED_COUNT, \ self.LED_PIN, \ self.LED_FREQ_HZ, \ self.LED_DMA, \ self.LED_INVERT, \ self.LED_BRIGHTNESS//2, \ self.LED_CHANNEL) # Intialize the library (must be called once before other functions). self.strip.begin() # Variables that store what the LEDs will do self.loop = False # whether the current sequence of frames should be # repeated after completion self.colorSeqs = {} # a dictionary storing color sequences # KEY: the key is arbitrary, to distinguish different color sequences # - It is up to the implementation to determine the key # VAL: a list of colors, stored as integers, that form the sequence # - All values in colorSeqs must have the same length self.seqLen = 0 # the length of color sequences in colorSeqs self.mapping = [] # a list containing integers # these integers correspond to indices in colorSeqs # length of mapping = number of LEDs in the LightBox self.currInd = 0 # an integer marking where in the color sequences the LEDs are self.targetBrightness = self.strip.getBrightness( ) # value storing brightness to be attained # during gradual fade towards it # Initialize these variables for the first time (LEDs off) self.loop = False self.colorSeqs[0] = [0x000000] self.seqLen = 1 self.mapping = [0] * self.strip.numPixels() self.currInd = 0 # These settings will cause the LED's to switch to #000000 (off) once # Start thread that will handle LED changes in the background Thread.__init__(self) self.daemon = True print("Led Strip Initialized") # Continuous loop that handles LED changes registered in mapping and colorSeqs def run(self): while True: refreshStrip = True time.sleep(1.0 / self.FRAMERATE) if self.currInd == self.seqLen: #reached end of sequence if self.loop: self.currInd = 0 #loop to beginning of sequence else: refreshStrip = False if refreshStrip: try: for i in range(self.strip.numPixels()): self.strip.setPixelColor( i, self.colorSeqs[self.mapping[i]][self.currInd]) except KeyError: print("Error: invalid key %d" % self.mapping[i]) continue self.currInd += 1 if self.strip.getBrightness() != self.targetBrightness: self.strip.setBrightness( max( min( self.strip.getBrightness() + (self.FRAMERATE//25) * \ (1 if self.targetBrightness > self.strip.getBrightness() else -1) \ , 255), 0) \ ) if (abs(self.targetBrightness - self.strip.getBrightness())) < (self.FRAMERATE // 25): self.strip.setBrightness(self.targetBrightness) refreshStrip = True if refreshStrip: self.strip.show() # Color Manipulation functions... def solidColor(self, color): ''' Changes LightBox to a solid color, defined by color ''' colorSeqs = {} mapping = [0] * self.strip.numPixels() # Iterate through each led in the strip for currLed in range(self.strip.numPixels()): # Add entry to mapping for the color sequence mapping[currLed] = self.strip.getPixelColor(currLed) # Add sequence to colorSeqs if it doesn't exist already if mapping[currLed] not in colorSeqs: colorSeqs[mapping[currLed]] = \ colorUtil.linear_gradient(mapping[currLed], \ color, \ self.FRAMERATE//4) self.loop = False self.seqLen = self.FRAMERATE // 4 self.currInd = 0 self.mapping = mapping self.colorSeqs = colorSeqs def clear(self): '''clears all leds''' self.solidColor(0) def changeBrightness(self, newBrightnessValue): '''sets brightness of LEDs (0-100)''' self.targetBrightness = int(self.LED_BRIGHTNESS * newBrightnessValue**1.5 / 1000) #1000=100^1.5 def rainbow(self): '''creates a rainbow sequence that loops''' #generates list of colors that cycle in hue numFrames = self.FRAMERATE * 10 # the number is how many seconds per rainbow cycle rainbowColors = [ colorUtil.HSV_to_hex(k / numFrames * 360, 1, 1) for k in range(0, numFrames, 1) ] colorSeqs = {} seqLen = len(rainbowColors) mapping = [0] * self.strip.numPixels() for led in range(self.strip.numPixels()): mapping[led] = led #unique mapping for each led colorSeqs[led] = [0] * seqLen for colorPos in range(seqLen): for led in range(self.strip.numPixels()): colorSeqs[led][colorPos] = rainbowColors[(colorPos + led) % seqLen] self.loop = True self.seqLen = seqLen self.currInd = 0 self.colorSeqs = colorSeqs self.mapping = mapping def sparkle(self, seqLenSeconds=30): '''creates a sparkle sequence that loops''' numFrames = self.FRAMERATE * 1 # the number is how many seconds for average flash deviation = self.FRAMERATE // 2 # random deviation of the flash lengths satChoice = ([0.0]) + ([0.5] * 5) + ( [1] * 50) # weighted probability for saturation # prevents too many 'white' LEDs valChoice = ([0.2]) + ([0.5] * 5) + ( [1] * 10) # weighted probability for value # prevents too many dim LED's colorSeqs = {} seqLen = numFrames * seqLenSeconds mapping = [0] * self.strip.numPixels() for led in range(self.strip.numPixels()): mapping[led] = led # unique mapping for each led colorSeqs[led] = [0] * seqLen for colorPos in range(seqLen): for i in range(random.randrange( 0, 4)): # repeat a random number of times # to create variety led = random.randrange(0, self.strip.numPixels()) if colorSeqs[led][colorPos] != 0: # already a flash at that led continue # don't overwrite it duration = random.randint(numFrames - deviation, numFrames + deviation) hue = random.uniform(0, 360) sat = random.choice(satChoice) val = random.choice(valChoice) for k in range(duration): # fill in colorSeqs for the flash, given by the piecewise function # at https://www.desmos.com/calculator/lmsoc2uoif colorSeqs[led][(colorPos+k)%seqLen] = colorUtil.HSV_to_hex(hue, sat, \ val * ( (3/duration)*k if k < duration/3 \ else (-3/(2*duration))*(k-duration) ) \ ) self.loop = True self.seqLen = seqLen self.currInd = 0 self.colorSeqs = colorSeqs self.mapping = mapping
class Moodlights(): def __init__(self, led_count, led_pin, led_freq_hz, led_dma, led_invert, led_brightness, led_channel): self.strip = PixelStrip(led_count, led_pin, led_freq_hz, led_dma, led_invert, led_brightness, led_channel) self.strip.begin() self.led_count = led_count self.pixels = [Pixel(self.strip, x) for x in range(led_count)] signal.signal(signal.SIGINT, self.signal_handler) def in_range(self, led_num): return led_num >= 0 and led_num < self.led_count def shutdown(self): self.all_pixels_off() sys.exit() def signal_handler(self, sig, frame): print("You pressed Ctrl-C! Exiting...") self.shutdown() def all_pixels_off(self): for pixel in self.pixels: pixel.switch_off() self.strip.show() def color_wipe(self, colors, iterations=0, wait_ms=0): """ params: colors: sequence of colors to display wait_ms: wait time between each pixel (0 for instant) """ is_infinite = iterations == 0 i = 0 while is_infinite or i < iterations: self.all_pixels_off() for j in range(self.led_count): pixel = self.pixels[j] pixel.set_color(colors[j % len(colors)]) self.strip.show() time.sleep(wait_ms / 1000.0) i += 1 def pulse(self, iterations=0, wait_ms=2): """ params: iteration: number of pulses (0 means infinite) wait_ms: wait time before changing brightness by 1/255 of max brightness """ is_increasing = self.strip.getBrightness() < 255 is_infinite = iterations == 0 i = 0 while is_infinite or i < iterations * 256 * 2: if is_increasing: next_brightness = self.strip.getBrightness() + 1 is_increasing = next_brightness != 255 else: next_brightness = self.strip.getBrightness() - 1 is_increasing = next_brightness == 0 self.strip.setBrightness(next_brightness) time.sleep(wait_ms / 1000.0) self.strip.show() i += 1 def wave(self, colors, iterations, intensity, wait_ms=50, spread=0, is_reverse=False): """ params: colors: sequence of colors to display intensity: brightness of the crest (from 0 to 255) wait_ms: wait time before the crest of the wave shifts spread: how many pixels away from the crest will be lighted up """ intensity_interval = float(intensity / (spread + 1)) led_iteration = list( range(-1 - spread, self.strip.numPixels() + spread + 1)) if is_reverse: led_iteration.reverse() is_infinite = iterations == 0 k = 0 while is_infinite or k < iterations: for i in led_iteration: if self.in_range(i): self.pixels[i].set_color(colors[i % len(colors)]) self.pixels[i].set_brightness(intensity) for j in range(1, spread + 1): brightness = int(abs(intensity - intensity_interval * j)) if self.in_range(i - j): self.pixels[i - j].set_color(colors[(i - j) % len(colors)]) self.pixels[i - j].set_brightness(brightness) if self.in_range(i + j): self.pixels[i + j].set_color(colors[(i + j) % len(colors)]) self.pixels[i + j].set_brightness(brightness) if self.in_range(i - spread - 1): self.pixels[i - spread - 1].switch_off() if self.in_range(i + spread + 1): self.pixels[i + spread + 1].switch_off() self.strip.show() time.sleep(wait_ms / 1000.0) k += 1 def wheel(self, pos): if pos < 85: return Color(pos * 3, 255 - pos * 3, 0) elif pos < 170: pos -= 85 return Color(255 - pos * 3, 0, pos * 3) else: pos -= 170 return Color(0, pos * 3, 255 - pos * 3) def rainbow_cycle(self, iterations=0, wait_ms=160): is_infinite = iterations == 0 j = 0 while is_infinite or j < iterations * 256: for i in range(self.strip.numPixels()): self.strip.setPixelColor(i, self.wheel((i + j) & 255)) self.strip.show() j += 1 time.sleep(wait_ms / 1000.0) def rainbow_chase(self, iterations=0, wait_ms=100): is_infinite = iterations == 0 j = 0 while is_infinite or j < iterations * 256: for q in range(3): for i in range(0, self.strip.numPixels(), 3): self.strip.setPixelColor(i + q, self.wheel((i + j) % 255)) self.strip.show() time.sleep(wait_ms / 1000.0) for i in range(0, self.strip.numPixels(), 3): self.strip.setPixelColor(i + q, 0) j += 1