class Light(Thread): def __init__(self, light_state:LightState): super().__init__() self.state = light_state self.periodic = None self.refresh_period_or_duty_cycle() self.strip = PixelStrip(self.state.get_num_pixels(), 18) async def loop(self): while True: await self.periodic.wait_for_period_boundary() self.set_first_half_of_period() await self.periodic.wait_for_semi_period_boundary() self.set_second_half_of_period() def set_first_half_of_period(self): if not self.state.get_power(): self.set_off() else: self.set_on() def set_second_half_of_period(self): if not self.state.get_power() or self.state.get_blink(): self.set_off() else: self.set_on() def set_on(self): self.strip.setBrightness(self.state.get_brightness()) for pixel in range(self.state.get_num_pixels()): self.strip.setPixelColorRGB(pixel, self.state.get_red(), self.state.get_green(), self.state.get_blue()) self.strip.show() def set_off(self): for pixel in range(self.state.get_num_pixels()): self.strip.setPixelColorRGB(pixel, 0, 0, 0) self.strip.show() def refresh_period_or_duty_cycle(self): self.periodic = Periodic( period_sec=self.state.get_period(), semi_period_percent=self.state.get_duty_cycle() ) def run(self): self.strip.begin() asyncio.run(self.loop())
def run(): prev_animation = None prev_brightness = None strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP) strip.begin() threading.Thread(target=app.run).start() print('Press Ctrl-C to quit.') len_animations = None try: while True: if len(curr_animations) != len_animations: len_animations = len(curr_animations) clear(strip) generators = [] for animation in curr_animations: generators.append(animation(VStrip(strip))) if curr_brightness != prev_brightness: strip.setBrightness(curr_brightness) prev_brightness = curr_brightness vstrips = [] for gen in generators: vstrips.append(next(gen)) # vstrip.reverse() for pos in range(strip.numPixels()): col = np.array([0., 0., 0.]) transparency = 1 for v in vstrips: cur_col = np.array(v.getPixelColor(pos)) col += cur_col[:3] * transparency transparency *= cur_col[3] col = np.maximum( np.minimum(np.array(np.floor(col), dtype=np.int), 255), 0) strip.setPixelColor(pos, Color(*col.tolist())) strip.show() except KeyboardInterrupt: clear(strip)
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 LedManager: """ Class that controlles the led matrix Also parses incomming data Uses the config file """ matrix = [] top_row = [] # Coloumns and Frets ##################################################### LED_STRIP = None STRING_CNT = 6 FRET_CNT = 4 CONFIG = {} logger = None has_logger = False FILE_CONFIG = "ledconfig.json" BROKEN_PCB = True def __init__(self, logger=None): self.logger = logger if self.logger is not None: self.has_logger = True self.reloadconfig() self.preparematrix() self.preparetop() self.dosetup() # LED CONTROL def colorwipe(self, color=Color(0, 0, 0)): """ Sets one color for the hole strip """ wait_time = self.CONFIG["WAIT_MS"] for i in range(self.LED_STRIP.numPixels()): if (self.BROKEN_PCB and i == 24): continue self.LED_STRIP.setPixelColor(i, color) self.LED_STRIP.show() time.sleep(wait_time / 1000) def colorwipeTop(self, color=Color(0, 0, 0)): """ If top installed, clear it """ wait_time = self.CONFIG["WAIT_MS"] if (self.CONFIG["TOP_INSTALLED"]): for i in range(6): self.LED_STRIP.setPixelColor(i, color) self.LED_STRIP.show() time.sleep(wait_time / 1000) def applydata(self): self.applymatrix() self.applytop() def applymatrix(self): """ State matrix applied on the strip """ cur_mat = self.matrix offset = 0 ## DEBUG: for line in cur_mat: print(str(list(line))) if (self.CONFIG["TOP_INSTALLED"]): offset = 6 for y in range(len(cur_mat)): for x in range(len(cur_mat[y])): tmp_index = offset + (y * 6 + x) if (tmp_index >= 24 and self.BROKEN_PCB): tmp_index += 1 self.LED_STRIP.setPixelColor(tmp_index, cur_mat[y][x]) self.LED_STRIP.show() time.sleep(self.CONFIG["WAIT_MS"] / 1000) def applytop(self): """ TopRow-State applied to the strip """ wait_time = self.CONFIG["WAIT_MS"] for x in range(len(self.top_row)): self.LED_STRIP.setPixelColor(x, self.top_row[x]) self.LED_STRIP.show() time.sleep(wait_time / 1000) def dosetup(self): """ Init. of a default rgb strip Note: The config file need to be loaded before calling this method """ fix = 0 if self.BROKEN_PCB: fix = 1 LED_COUNT = ( (self.FRET_CNT + self.CONFIG["TOP_INSTALLED"]) * self.STRING_CNT + fix) LED_PIN = 18 LED_FREQ = 800000 LED_DMA = 10 LED_BRIGHTNESS = self.CONFIG["BRIGHTNESS"] self.LED_STRIP = PixelStrip(\ LED_COUNT,\ LED_PIN,\ LED_FREQ,\ LED_DMA,\ False,\ LED_BRIGHTNESS) self.LED_STRIP.begin() def clean_up(self): """ Calls spooky cleanup on strip Maybe neccessary """ self.LED_STRIP._cleanup() # DATA MANAGMENT def preparematrix(self): """ Init. dark matrix """ ROW = [Color(0, 0, 0)] * self.STRING_CNT mat = [[]] * self.FRET_CNT for idx in range(len(mat)): # Copy the list to create the complete matrix mat[idx] = ROW.copy() self.matrix = mat self.ilog(__name__ + " Matrix Prep Done", 10) def preparetop(self): self.top_row = [Color(0, 0, 0)] * self.STRING_CNT def reloadconfig(self): """ Reloads LED Config File """ self.ilog(__name__ + " Starting config reload...", 10) curconfig = {} if (os.path.isfile(self.FILE_CONFIG)): with open(self.FILE_CONFIG, "r", encoding="utf-8") as f: curconfig = json.load(f) self.CONFIG = curconfig self.ilog(__name__ + " Config reload done!", 20) else: self.ilog(__name__ + " No config file found. Creating default", 10) default_colors = { "-2": Color(255, 0, 0), "-1": Color(52, 255, 13), "0": Color(255, 255, 255), "1": Color(255, 0, 0), "2": Color(0, 255, 0), "3": Color(0, 0, 255), "4": Color(255, 255, 0) } default_config = { "TOP_INSTALLED": False, "WAIT_MS": 10, "BRIGHTNESS": 20, "finger_color": default_colors } with open(self.FILE_CONFIG, "w", encoding="utf-8") as f: json.dump(default_config, f, ensure_ascii=False, indent=4) self.ilog(__name__ + " Default config created!", 20) self.reloadconfig() def store_config(self): """ Stores current config to file """ self.ilog(__name__ + " Start saving config to file", 10) with open("ledconfig.json", "w", encoding="utf-8") as f: json.dump(self.CONFIG, f, ensure_ascii=False, indent=4) self.ilog(__name__ + " Currenct config successfully saved!", 20) def set_strings_to_hit(self, strings): """ For each one in a binary six digit string the corresponding string will be activated """ for charIDx in range(len(strings)): if (strings[charIDx] == "1"): self.top_row[charIDx] = self.CONFIG["finger_color"]["0"] else: self.top_row[charIDx] = Color(0, 0, 0) def set_single_in_matrix(self, pos, string, finger): """ Adds given data to internal matrix Note: Use applymatrix to activate the changes """ cur_mat = self.matrix tmpColor = self.get_finger_color(finger) cur_mat[pos][string] = tmpColor def set_array_in_matrix(self, data_array): """ Adding a collection through set_single_in_matrix Needs fret, string, finger per element Note: Use applymatrix to activate the changes """ for values in data_array: self.set_single_in_matrix(values[0], values[1], values[2]) # MODIFIER def setbrightness(self, brightness=20): """ Sets brightness value Also applies the brightness to the LED strip """ self.CONFIG["BRIGHTNESS"] = brightness self.LED_STRIP.setBrightness(self.CONFIG["BRIGHTNESS"]) self.ilog( __name__ + " Applied new brightness: {} (~{}%)".format( brightness, (brightness / 255) * 100), 10) def setinstalled(self, intalled=True): """ (De)activates first row skip """ self.CONFIG["TOP_INSTALLED"] = installed self.ilog(__name__ + "Top installed...", 10) def setwaittime(self, time=10): """ Sets wait time for the LEDs Note: Wait time between every led change """ self.CONFIG["WAIT_MS"] = time self.ilog(__name__ + "{} ms wait time applied".format(time), 10) # Threadfunctions def thread_load_indicator(self, sharedVariable): """ Thread task, use utils.sharedVariable to indicate finish """ if (self.CONFIG["TOP_INSTALLED"]): accentColor = Color(136, 176, 75) # 2017 Greenery mainColor = Color(255, 0, 0) secondColor = Color(140, 0, 0) thirdColor = Color(60, 0, 0) baseValue = sharedVariable.get_storage() + 1 lowerBound = baseValue current_position = lowerBound upwards = True upperBound = 5 while (not sharedVariable.get_task_done()): if (sharedVariable.has_changed()): self.ilog(__name__ + " thread, new value!") baseValue = sharedVariable.get_storage() + 1 lowerBound = baseValue current_position = lowerBound for idx in range(self.STRING_CNT): if (idx < baseValue): self.top_row[idx] = accentColor else: self.top_row[idx] = Color(0, 0, 0) if (upwards): delta = current_position - baseValue if (delta > 0): self.top_row[current_position - 1] = secondColor if (delta > 1): self.top_row[current_position - 2] = thirdColor else: delta = upperBound - current_position if (delta > 0): self.top_row[current_position + 1] = secondColor if (delta > 1): self.top_row[current_position + 2] = thirdColor self.top_row[current_position] = mainColor self.applytop() if (upwards): #Todo inc or dec counter if (current_position == upperBound): upwards = False else: current_position = current_position + 1 else: if (current_position == lowerBound): upwards = True else: current_position = current_position - 1 else: self.colorwipeTop() #END thread_load_indicator def thread_idle_indicator(self, sharedVariable): """ Thread task, use utils.sharedVariable to indicate finish """ if (not self.CONFIG["TOP_INSTALLED"]): return mainColor = Color(0, 140, 0) position = 0 while (not sharedVariable.get_task_done()): self.colorwipeTop() if (position > 5): position = 0 self.top_row[position] = mainColor self.applytop() position = position + 1 self.colorwipe() # Tools def ilog(self, msg, level=30): """ If logger given, logs on given level """ if self.has_logger: self.logger.log(level, msg) else: #print(msg) pass def get_finger_color(self, finger): """ Returns the correct color for a finger index """ return self.CONFIG["finger_color"][str(finger)] def cleanup(self): """ Reset the tempory internal state and clears LED Strip """ self.preparematrix() self.preparetop() self.colorwipe()
class Ledstrip: def __init__(self): self.onGoingTask = None self.cancelTask = False self.brightness = constants.LED_BRIGHTNESS self.pixels = PixelStrip(constants.LED_COUNT, constants.LED_PIN, constants.LED_FREQ_HZ, constants.LED_DMA, constants.LED_INVERT, constants.LED_BRIGHTNESS, constants.LED_CHANNEL, constants.LED_STRIP) self.pixels.begin() LedUtil.clear(self.pixels) self.pixels.setPixelColor(0, Color(255, 255, 255, 255)) self.pixels.show() print("Controlling ledstrip on pin ", constants.LED_PIN) def pixel_rainbow_colors(self, args): wait, isFloat = Util.floatTryParse(args["wait"]) loop_forever, isBool = Util.boolTryParse(args["loop_forever"]) if (isFloat and isBool): self.__execute_task( LedUtil.rainbow_colors, (self.pixels, lambda: self.cancelTask, wait, loop_forever)) def pixel_rainbow_cycle(self, args): loop_forever, isBool = Util.boolTryParse(args["loop_forever"]) wait, isFloat = Util.floatTryParse(args["wait"]) loop, isInt = Util.intTryParse(args["loop"]) if (isBool and isFloat and isInt): self.__execute_task(LedUtil.rainbow_cycle, (self.pixels, lambda: self.cancelTask, wait, loop, loop_forever)) def pixel_rainbow_cycle_successive(self, args): wait, isFloat = Util.floatTryParse(args["wait"]) if (isFloat): self.__execute_task(LedUtil.rainbow_cycle_successive, (self.pixels, lambda: self.cancelTask, wait)) def pixel_brightness_decrease(self, args): wait, isFloat = Util.floatTryParse(args["wait"]) step, isInt = Util.intTryParse(args["step"]) if (isFloat and isInt): self.__execute_task( LedUtil.brightness_decrease, (self.pixels, lambda: self.cancelTask, wait, step)) def pixel_blink_color(self, args): color, isColor = Util.colorTryParse(args["color"]) wait, isFloat = Util.floatTryParse(args["wait"]) blink_time, isInt = Util.intTryParse(args["blink_time"]) if (isColor and isFloat and isInt): self.__execute_task(LedUtil.blink_color, (self.pixels, lambda: self.cancelTask, blink_time, wait, color)) def pixel_appear_from_back(self, args): color, isColor = Util.colorTryParse(args["color"]) wait, isFloat = Util.floatTryParse(args["wait"]) size, isInt = Util.intTryParse(args["size"]) if (isColor and isFloat and isInt): self.__execute_task( LedUtil.appear_from_back, (self.pixels, lambda: self.cancelTask, color, wait, size)) def pixel_color_wipe(self, args): color, isColor = Util.colorTryParse(args["color"]) wait, isFloat = Util.floatTryParse(args["wait"]) should_clear, isBool = Util.boolTryParse(args["should_clear"]) if (isColor and isFloat and isBool): self.__execute_task(LedUtil.color_wipe, (self.pixels, lambda: self.cancelTask, wait, color, should_clear)) def pixel_color_wipe_cycle(self, args): color, isColor = Util.colorTryParse(args["color"]) wait, isFloat = Util.floatTryParse(args["wait"]) fade_step, isInt = Util.intTryParse(args["fade_step"]) loop_forever, isBool = Util.boolTryParse(args["loop_forever"]) if (isColor and isFloat and isInt and isBool): self.__execute_task(LedUtil.color_wipe_cycle, (self.pixels, lambda: self.cancelTask, wait, color, fade_step, loop_forever)) def pixel_theater_chase(self, args): color, isColor = Util.colorTryParse(args["color"]) wait, isFloat = Util.floatTryParse(args["wait"]) is_rainbow, isBool = Util.boolTryParse(args["is_rainbow"]) if (isColor and isFloat and isBool): self.__execute_task(LedUtil.theaterChase, (self.pixels, lambda: self.cancelTask, color, wait, is_rainbow)) def pixel_color_wipe_rainbow(self, args): wait, isFloat = Util.floatTryParse(args["wait"]) fade_step, isInt = Util.intTryParse(args["fade_step"]) color_step, isInt2 = Util.intTryParse(args["color_step"]) if (isFloat and isInt and isInt2): self.__execute_task(LedUtil.color_wipe_rainbow, (self.pixels, lambda: self.cancelTask, wait, fade_step, color_step)) def pixel_breathing(self, args): color, isColor = Util.colorTryParse(args["color"]) move_factor, isFloat = Util.floatTryParse(args["move_factor"]) if (isFloat and isColor): self.__execute_task( LedUtil.breathing, (self.pixels, lambda: self.cancelTask, color, move_factor)) def pixel_breathing_lerp(self, args): color_to, isColor1 = Util.colorTryParse(args["color_to"]) color_from, isColor2 = Util.colorTryParse(args["color_from"]) move_factor, isFloat = Util.floatTryParse(args["move_factor"]) if (isColor1 and isColor2 and isFloat): self.__execute_task(LedUtil.breathing_lerp, (self.pixels, lambda: self.cancelTask, color_from, color_to, move_factor)) def pixel_breathing_rainbow(self, args): move_factor, isFloat = Util.floatTryParse(args["move_factor"]) color_step, isInt = Util.intTryParse(args["color_step"]) if (isInt and isFloat): self.__execute_task(LedUtil.breathing_rainbow, (self.pixels, lambda: self.cancelTask, color_step, move_factor)) def pixel_fireworks(self, args): size, isInt = Util.intTryParse(args["size"]) color, isColor = Util.colorTryParse(args["color"]) is_rainbow, isBool = Util.boolTryParse(args["is_rainbow"]) number_of_fireworks, isInt1 = Util.intTryParse( args["number_of_fireworks"]) chance_of_explosion, isInt2 = Util.intTryParse( args["chance_of_explosion"]) fade_step, isInt3 = Util.intTryParse(args["fade_step"]) firework_fade, isInt4 = Util.intTryParse(args["firework_fade"]) if (isColor and isBool and isInt and isInt1 and isInt2 and isInt3 and isInt4): self.__execute_task( LedUtil.fireworks, (self.pixels, lambda: self.cancelTask, size, color, is_rainbow, number_of_fireworks, chance_of_explosion, fade_step, firework_fade)) def pixel_labyrinth(self, args): wait, isFloat = Util.floatTryParse(args["wait"]) color, isColor = Util.colorTryParse(args["color"]) contact_color, isColor2 = Util.colorTryParse(args["contact_color"]) count, isInt = Util.intTryParse(args["count"]) turn_chance, isInt2 = Util.intTryParse(args["turn_chance"]) if (isColor and isColor2 and isFloat and isInt and isInt2): self.__execute_task(LedUtil.labyrinth, (self.pixels, lambda: self.cancelTask, wait, count, turn_chance, color, contact_color)) def pixel_color_pair(self, args): wait, isFloat = Util.floatTryParse(args["wait"]) color1, isColor1 = Util.colorTryParse(args["color1"]) color2, isColor2 = Util.colorTryParse(args["color2"]) size1, isInt1 = Util.intTryParse(args["size1"]) size2, isInt2 = Util.intTryParse(args["size2"]) with_animation, isBool = Util.boolTryParse(args["with_animation"]) fade_step, isInt = Util.intTryParse(args["fade_step"]) if (isColor1 and isColor2 and isFloat and isInt1 and isInt2 and isInt and isBool): self.__execute_task( LedUtil.color_pair, (self.pixels, lambda: self.cancelTask, wait, color1, color2, size1, size2, with_animation, fade_step)) def set_brightness(self, args): brightness, isInt = Util.intTryParse(args["brightness"]) if (isInt): self.brightness = brightness self.pixels.setBrightness(brightness) self.pixels.show() def set_settings(self, args): self.__cancel_task() led_pixel_count, isInt = Util.intTryParse(args["led_pixel_count"]) if (isInt): self.led_count = led_pixel_count self.led_type = args["led_type"] ledType = constants.LED_STRIP if (self.led_type == constants.LED_STRIP_SK6812): ledType = ws.SK6812W_STRIP elif (self.led_type == constants.LED_STRIP_WS2811): ledType = ws.WS2811_STRIP_RGB elif (self.led_type == constants.LED_STRIP_WS2812B): ledType = ws.WS2811_STRIP_RGB self.pixels = PixelStrip(self.led_count, constants.LED_PIN, constants.LED_FREQ_HZ, constants.LED_DMA, constants.LED_INVERT, self.brightness, constants.LED_CHANNEL, ledType) self.pixels.begin() def pixel_off(self, args): self.__cancel_task() LedUtil.clear(self.pixels) self.pixels.show() def __execute_task(self, task, args): self.__cancel_task() self.onGoingTask = threading.Thread(target=task, args=args) self.onGoingTask.start() def __cancel_task(self): if (self.onGoingTask != None): self.cancelTask = True self.onGoingTask.join() self.cancelTask = False
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
'--clear', action='store_true', help='clear the display on exit') args = parser.parse_args() # Create NeoPixel object with appropriate configuration. strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL) # Intialize the library (must be called once before other functions). strip.begin() print('Press Ctrl-C to quit.') if not args.clear: print('Use "-c" argument to clear LEDs on exit') try: #while True: for countdown in range(LED_BRIGHTNESS, 0, -1): print countdown strip.setBrightness(countdown) sleepyTimeCycle(strip) print 'Going to sleep' time.sleep(10) print 'waking up' colorWipe(strip, Color(0, 0, 0)) except KeyboardInterrupt: if args.clear: colorWipe(strip, Color(0, 0, 0), 10)
class LedRingAnimations: """ Object which implements control method for the Led ring """ def __init__(self): # - Parameters self.__is_simulation = rospy.get_param("~simulation_mode") # LED self.strip configuration: self.LED_COUNT = rospy.get_param('~led_count') # Number of LED pixels. self.LED_PIN = rospy.get_param( '~led_pin') # GPIO pin connected to the pixels (must support PWM!) self.LED_FREQ_HZ = rospy.get_param( '~led_freq_hs') # LED signal frequency in hertz (usually 800khz) self.LED_DMA = rospy.get_param( '~led_dma') # DMA channel to use for generating signal (try 10) self.LED_BRIGHTNESS = rospy.get_param( '~led_brightness') # Set to 0 for darkest and 255 for brightest self.LED_INVERT = rospy.get_param( '~led_invert' ) # True to invert the signal (when using NPN transistor level shift) self.LED_CHANNEL = rospy.get_param('~led_channel') self.__led_offset = rospy.get_param("~led_offset") if not self.__is_simulation: self.LED_STRIP = ws.WS2811_STRIP_GRB # default param for led ring control methods self.default_flashing_period = rospy.get_param( '~default_flashing_period') self.default_alternate_period = rospy.get_param( '~default_alternate_period') self.default_chase_period = rospy.get_param('~default_chase_period') self.default_colorwipe_period = rospy.get_param( '~default_colorwipe_period') self.default_rainbow_period = rospy.get_param( '~default_rainbow_period') self.default_rainbowcycle_period = rospy.get_param( '~default_rainbowcycle_period') self.default_rainbowchase_period = rospy.get_param( '~default_rainbowchase_period') self.default_goup_period = rospy.get_param('~default_goup_period') self.default_goupanddown_period = rospy.get_param( '~default_goupanddown_period') self.default_breath_period = rospy.get_param('~default_breath_period') self.default_snake_period = rospy.get_param('~default_snake_period') self.__stop_func = False self.__animation_lock = Lock() self._observers = [] self.current_animation_color = BLACK self.current_animation = LedRingAnimation.NONE self.set_current_anim_and_color( self.current_animation, self.current_animation_color, ) if not self.__is_simulation: self.strip = PixelStrip(self.LED_COUNT, self.LED_PIN, self.LED_FREQ_HZ, self.LED_DMA, self.LED_INVERT, self.LED_BRIGHTNESS, self.LED_CHANNEL, self.LED_STRIP) self.strip.begin() if self.__is_simulation: self.led_count = self.LED_COUNT else: self.led_count = self.strip.numPixels() self.off_color = GREY if self.__is_simulation else BLACK # for real mode # list used to store the current state of the real led ring, as a list of ColorRGBA objects self.current_real_led_ring_state = [] self.led_ring_makers = LedRingSimulation(self.led_count) self.blackout() def __del__(self): self.set_and_show_leds(self.off_color) if not self.__is_simulation: del self.strip def stop_animation(self): """ Stop iteration (and endless iteration) for functions that perform continous action like alternate_color, and wait until the previous function is finished. Used when launched in robot status display mode. Indeed, when used by the user, the previous function is stopped before, in the start thread function """ if self.is_animation_running(): self.__stop_func = True with self.__animation_lock: # wait the end of the running animation self.blackout() def init_animation(self): self.__stop_func = False def is_animation_running(self): return self.__animation_lock.locked() def was_function_interrupted(self): return self.__stop_func # if true, function was interrupted def __play_cycle_animation(self, color_cycle, period, iterations, animation_function): # start playing animation : loop_period = period * 1.0 / len(color_cycle) next_loop_time = rospy.Time.now() count = 1 if not iterations else iterations while count > 0: for cycle_index in range(len(color_cycle)): if self.__stop_func: break animation_function(color_cycle, cycle_index) next_loop_time += rospy.Duration(loop_period) self.__sleep_animation(next_loop_time) if self.__stop_func: break if iterations: count -= 1 self.blackout() def none(self): """ Turn off leds, in simu and in real, with the "solid" method """ self.solid(self.off_color) def solid(self, color_rgba): """ Sets all Leds to a color at once """ self.init_animation() with self.__animation_lock: self.set_and_show_leds(color_rgba) mode = LedRingAnimation.NONE if color_rgba == self.off_color else LedRingAnimation.SOLID self.set_current_anim_and_color(mode, color_rgba) def custom(self, color_rgba): """ Sets all Leds to a color at once """ self.init_animation() with self.__animation_lock: colors = color_rgba[:self.led_count] if len( color_rgba) > self.led_count else color_rgba + ( len(color_rgba) - self.led_count) * [BLACK] for led_id, led_color in enumerate(colors): # set color led by led self.set_led(led_id, led_color) self.show_leds() # display all leds self.set_current_anim_and_color(LedRingAnimation.CUSTOM) def set_led_color(self, led_id, color_rgba): self.init_animation() with self.__animation_lock: self.set_led(led_id, color_rgba) self.show_leds() self.set_current_anim_and_color(LedRingAnimation.CUSTOM) def flashing(self, color_rgba, period=None, iterations=0): """ Flash a color according to a frequency """ def animation_function(anim_color_cycle, anim_cycle_index): self.set_and_show_leds(anim_color_cycle[anim_cycle_index]) self.init_animation() # set default frequency if not period: period = self.default_flashing_period # configure the animation color_cycle = [color_rgba, self.off_color] # start the animation with self.__animation_lock: self.set_current_anim_and_color(LedRingAnimation.FLASHING, color_rgba) self.__play_cycle_animation(color_cycle, period, iterations, animation_function) def alternate(self, color_list_rgba, period=None, iterations=0): """ The different colors are alternated one after the other. If iterations is 0, do it indefinitely """ def animation_function(anim_color_cycle, anim_cycle_index): self.set_current_anim_and_color(LedRingAnimation.ALTERNATE, anim_color_cycle[anim_cycle_index]) self.set_and_show_leds(anim_color_cycle[anim_cycle_index]) self.init_animation() # configure the animation if not period: period = self.default_alternate_period color_cycle = color_list_rgba[:] # start the animation with self.__animation_lock: self.__play_cycle_animation(color_cycle, period, iterations, animation_function) def chase(self, color_rgba, period=None, iterations=0): """ Movie theater light style chaser animation. If iterations is 0, do it indefinitely """ def animation_function(anim_color_cycle, anim_cycle_index): for led_id in range(self.led_count): # set color led by led self.set_led( led_id, anim_color_cycle[led_id % len(anim_color_cycle) - anim_cycle_index]) self.show_leds() # display all leds self.init_animation() # configure the animation if not period: period = self.default_chase_period color_cycle = [self.off_color, self.off_color, color_rgba] # start the animation with self.__animation_lock: self.set_and_show_leds(self.off_color) self.set_current_anim_and_color(LedRingAnimation.CHASE, color_rgba) self.__play_cycle_animation(color_cycle, period, iterations, animation_function) def color_wipe(self, color_rgba, duration=None): """ Wipe color across, light a Led at a time. Similar to goUp, but Leds are not turned off at the end. """ self.init_animation() if not duration: duration = self.default_colorwipe_period with self.__animation_lock: self.set_current_anim_and_color(LedRingAnimation.COLOR_WIPE, color_rgba) self.__wipe_animation(color_rgba, duration) if self.__stop_func: self.blackout() # turn off leds def __wipe_animation(self, color_rgba, duration): next_loop = rospy.Time.now() period = rospy.Duration(duration * 1.0 / self.led_count) for led_id in range(self.led_count): if self.__stop_func: break self.set_led((led_id + self.__led_offset) % self.led_count, color_rgba) self.show_leds() next_loop += period self.__sleep_animation(next_loop) def breath_animation(self, color_rgba, duration): next_loop = rospy.Time.now() gamma = 0.2 # affects the width of peak (more or less darkness) beta = 0.5 # shifts the gaussian to be symmetric nb_steps = 255 anim_period = rospy.Duration(duration * 1.0 / nb_steps) self.current_animation_color = color_rgba for counter in range(nb_steps): if self.__stop_func: break # value = 255 * math.sin(2 * math.pi * (counter * 1.0 / smoothness_pts)) factor = math.exp(-(pow( ((counter * 1.0 / nb_steps) - beta) / gamma, 2.0)) / 2.0) # self.set_brightness(value) self.set_and_show_leds( ColorRGBA(self.current_animation_color.r * factor, self.current_animation_color.g * factor, self.current_animation_color.b * factor, 0)) next_loop += anim_period rospy.sleep(next_loop - rospy.Time.now()) def breath(self, color_rgba, period=None, iterations=0): """ Leds turn on like a loading circle, and are all turned off at the same time If iterations is 0, do it indefinitely """ self.init_animation() if period == 0 or period is None: period = self.default_breath_period # start playing animation : with self.__animation_lock: self.set_current_anim_and_color(LedRingAnimation.BREATH, color_rgba) if not iterations: while not self.__stop_func: self.breath_animation(color_rgba, period) else: for _i in range(iterations): if self.__stop_func: break self.breath_animation(color_rgba, period) self.blackout() def snake(self, color_rgba, period=None, iterations=0): def animation_function(anim_color_cycle, anim_cycle_index): for led_id in range(self.led_count): # set color led by led self.set_led( led_id, anim_color_cycle[(led_id + anim_cycle_index) % len(anim_color_cycle)]) self.show_leds() # display all leds self.init_animation() # configure the animation if not period: period = self.default_snake_period attenuated_color = ColorRGBA(color_rgba.r * 0.5, color_rgba.g * 0.5, color_rgba.b * 0.5, 0) snake_length = 10 snake_pattern = [ attenuated_color ] + (snake_length - 2) * [color_rgba] + [ attenuated_color ] + (self.LED_COUNT - snake_length) * [self.off_color] # start the animation with self.__animation_lock: self.set_and_show_leds(self.off_color) self.set_current_anim_and_color(LedRingAnimation.SNAKE, color_rgba) self.__play_cycle_animation(snake_pattern, period, iterations, animation_function) def go_up(self, color_rgba, period=None, iterations=0): """ Leds turn on like a loading circle, and are all turned off at the same time If iterations is 0, do it indefinitely """ def animation(duration): end_time = rospy.Time.now() + rospy.Duration(duration) self.__wipe_animation( color_rgba, duration * self.led_count / (self.led_count + 1)) self.set_and_show_leds(self.off_color) rospy.sleep(end_time - rospy.Time.now()) self.init_animation() if period == 0 or period is None: period = self.default_goup_period # start playing animation : with self.__animation_lock: self.set_current_anim_and_color(LedRingAnimation.GO_UP, color_rgba) if not iterations: while not self.__stop_func: animation(period) else: for _ in range(iterations): if self.__stop_func: break animation(period) self.blackout() def go_up_and_down(self, color_rgba, period=None, iterations=0): """ Leds turn on like a loading circle, and turn off the same way If iterations is 0, do it indefinitely """ def animation(duration): self.__wipe_animation(color_rgba, duration / 2.0) self.__wipe_animation(self.off_color, duration / 2.0) self.init_animation() if period == 0 or period is None: period = self.default_goupanddown_period with self.__animation_lock: self.set_current_anim_and_color(LedRingAnimation.GO_UP_AND_DOWN, color_rgba) # start playing animation : if not iterations: while not self.__stop_func: animation(period) else: for _ in range(iterations): if self.__stop_func: break animation(period) self.blackout() def __rainbow_animation(self, duration, animation_function): next_loop = rospy.Time.now() anim_period = rospy.Duration(duration / 256.0) for color_counter in range(256): if self.__stop_func: break animation_function(color_counter) next_loop += anim_period rospy.sleep(next_loop - rospy.Time.now()) def rainbow(self, period=None, iterations=0): """ Draw rainbow that fades across all Leds at once If iterations is 0, do it indefinitely """ def animation(color_counter): # for led_id in range(self.led_count): # self.set_led(led_id, wheel_rgba((led_id + color_counter) & 255)) # self.show_leds() self.set_and_show_leds(wheel_rgba(color_counter & 255)) self.init_animation() # configure the animation if not period: period = self.default_rainbow_period with self.__animation_lock: # no color info in led_ring_status topic, so we just notify that the animation changed self.set_current_anim_and_color(LedRingAnimation.RAINBOW) # start playing animation : if not iterations: while not self.__stop_func: self.__rainbow_animation(period, animation) else: for _ in range(iterations): if self.__stop_func: break self.__rainbow_animation(period, animation) self.blackout() # turn off leds after all iterations def rainbow_cycle(self, period=None, iterations=0): """ Draw rainbow that uniformly distributes itself across all Leds If iterations is 0, do it indefinitely """ def animation(color_counter): for led_id in range(self.led_count): self.set_led( led_id, wheel_rgba( int((led_id * 256.0 // self.led_count + color_counter)) & 255)) self.show_leds() self.init_animation() if not period: period = self.default_rainbowcycle_period with self.__animation_lock: self.set_current_anim_and_color(LedRingAnimation.RAINBOW_CYLE) # start playing animation : if not iterations: while not self.__stop_func: self.__rainbow_animation(period, animation) else: for _ in range(iterations): if self.__stop_func: break self.__rainbow_animation(period, animation) self.blackout() # turn off leds after all iterations def rainbow_chase(self, period=None, iterations=0): """ Rainbow chase animation If iterations is 0, do it indefinitely """ def animation(color_counter): for led_id in range(self.led_count): offset = color_counter % 3 if (led_id + offset) % 3 == 0: self.set_led(led_id, wheel_rgba((led_id + color_counter) & 255)) else: self.set_led(led_id, self.off_color) # don't show self.show_leds() self.init_animation() if not period: period = self.default_rainbowchase_period with self.__animation_lock: self.set_current_anim_and_color(LedRingAnimation.RAINBOW_CHASE) self.set_and_show_leds(self.off_color) # start playing animation : if not iterations: while not self.__stop_func: self.__rainbow_animation(period, animation) else: for _ in range(iterations): if self.__stop_func: break self.__rainbow_animation(period, animation) self.blackout() # turn off leds after all iterations def blackout(self): """ Black out every led, without stopping previous function """ self.set_and_show_leds(self.off_color) self.set_current_anim_and_color(LedRingAnimation.NONE, BLACK) def fade(self, color_rgba, duration=3.5, steps=100): current_color = self.current_animation_color step_r = (color_rgba.r - current_color.r) / float(steps) step_g = (color_rgba.g - current_color.g) / float(steps) step_b = (color_rgba.b - current_color.b) / float(steps) sleep_duration = duration / float(steps) for _ in range(steps): self.current_animation_color = ColorRGBA( self.current_animation_color.r + step_r, self.current_animation_color.g + step_g, self.current_animation_color.b + step_b, 0) rospy.sleep(sleep_duration) # - Real Led ring related method def get_state_list_from_pixel_strip(self): """ Return a list of size self.led_count, containing the current rgb color [r, g, b] of each Led in the real led ring """ real_leds_state = [] if not self.__is_simulation: for i in range(self.led_count): # read back the state from the library memory buffer # (can't read directly Led state, they are Write-only) color_i = self.strip.getPixelColorRGB(i) real_leds_state.append([color_i.r, color_i.g, color_i.b]) return real_leds_state # - Generic methods usable for simulation and real robot def set_led(self, index, color_rgba): """ Set the color of a pixel, in simu or in real """ if not self.__is_simulation: color = get_24bits_color_from_msg(color_rgba) self.strip.setPixelColor(index, color) self.led_ring_makers.set_one_led_marker(index, color_rgba) def show_leds(self): """ Display all Led's values previously set, in simu or in real """ if not self.__is_simulation: self.strip.show() # update value of current led state current_rgb_array_led_state = self.get_state_list_from_pixel_strip( ) current_color_rgba_led_state = [] # transform a list like [[r, g, b], [r, g, b], ...] to a list like [ColorRGBA, ColorRGBA, ...] for elem in current_rgb_array_led_state: current_color_rgba_led_state.append( get_rgba_color_from_list(elem)) self.set_current_real_leds_state(current_color_rgba_led_state) self.led_ring_makers.show_led_ring_markers() def set_and_show_leds(self, color, range_=None, index_delta=0): """ Iterate over all leds, set them to the chosen color and show them all at once. "range_" must be filled only if we want to iterate over a part of the led ring. "index_delta" is used by "chase" methods only. """ if range_ is None: range_ = self.led_count for i in range(range_): self.set_led(i + index_delta, color) self.show_leds() elif isinstance(range_, list) and len(range_) == 3: for i in range(range_[0], range_[1], range_[2]): self.set_led(i + index_delta, color) self.show_leds() def set_brightness(self, brightness): if not self.__is_simulation: self.strip.setBrightness(brightness) def __sleep_animation(self, until_time): while (until_time - rospy.Time.now()).to_sec() > 0.1: rospy.sleep(0.1) if self.__stop_func: break else: rospy.sleep(until_time - rospy.Time.now()) # Observable related methods def set_current_anim_and_color(self, animation, color=None): self.current_animation_color = color if color is not None else BLACK self.current_animation = animation self.notify_observers() def set_current_real_leds_state(self, rgb_list): self.current_real_led_ring_state = rgb_list def notify_observers(self): """ trigger a function in the observer (led ring node) class """ for obs in self._observers: obs.notify_current_anim_and_color(self) def register_observer(self, observer): """ Used to add the led ring node as an observer of this class """ self._observers.append(observer)
class lbhtest(): def __init__(self, rows, columns, serial_type=1, led_pin=18): ## # serial_type 信号线连接方式, 1表示弓字形连线,2表示Z字形连线 ## self.rows = rows self.columns = columns self.led_numbers = rows * columns self._mod = 1 self.leds = [] for i in range(self.led_numbers): self.leds.append(LED(i)) self.led_index = [[0 for i in range(self.columns)] for i in range(self.rows)] if (serial_type == 1): for i in range(0, rows, 2): for j in range(0, self.columns): self.led_index[i][j] = i * self.columns + j for i in range(1, rows, 2): for j in range(0, self.columns): self.led_index[i][j] = (i + 1) * self.columns - (j + 1) elif (serial_type == 2): for i in range(0, rows): for j in range(0, columns): self.led_index[i][j] = i * self.columns + j self.strip = PixelStrip(self.led_numbers, led_pin) self.strip.begin() self.strip.setBrightness(255) def del_cmd(self, paras): self._mod = paras["mod"] if (paras["mod"] == 1): # 全体显示 if (paras["function"] == 0): self._symbolLeftToRight(wan, Color(100, 100, 0), 500) elif (paras["function"] == 1): self._symbolRightToLeft(wan, Color(100, 100, 0), 500) elif (paras["function"] == 2): self._leftToRight(Color(100, 100, 0), 50) elif (paras["function"] == 3): self._symbolLeftToRight(zhong, Color(100, 100, 0), 500) elif (paras["function"] == 4): self._leftToRight(Color(100, 100, 0), 50) elif (paras["function"] == 5): self._rightToLeft(Color(100, 100, 0), 50) elif (paras["function"] == 6): self._bottomToTop(Color(100, 100, 0), 50) elif (paras["function"] == 7): self._topToBottom(Color(100, 100, 0), 50) elif (paras["mod"] == 0): #单个显示 row = paras["led_row"] - 1 col = paras["led_column"] - 1 led_index = self.led_index[row][col] self.leds[led_index]._set_color(0) self.leds[led_index]._set_cycle(paras["cycle"]) self.leds[led_index]._set_delay(paras["delay"]) def light(self): if (self._mod == 0): # 单个显示 for i in range(self.led_numbers): if (self.leds[i]._recycle > 0): color = self.leds[i].get_cur_color() if (not color is None): self.strip.setPixelColor(i, color) print("第i个灯", i, color) self.strip.show() def _showGivenSymbolAt(self, symbol, x, y, color, bgcolor=Color(0, 0, 0)): m = len(symbol) n = len(symbol[0]) for i in range(m): for j in range(n): if (symbol[i][j] == 1): self.strip.setPixelColor(self.led_index[i + x][j + y], color) else: self.strip.setPixelColor(self.led_index[i + x][j + y], bgcolor) self.strip.show() def _colorWipe(self, color): """Wipe color across display a pixel at a time.""" for i in range(self.led_numbers): self.strip.setPixelColor(i, color) self.strip.show() def _theaterChase(self, color, wait_ms=50, iterations=10): """Movie theater light style chaser animation.""" for j in range(iterations): for q in range(3): for i in range(0, self.led_numbers, 3): self.strip.setPixelColor(i + q, color) self.strip.show() time.sleep(wait_ms / 1000.0) for i in range(0, self.led_numbers, 3): self.strip.setPixelColor(i + q, 0) def _wheel(self, pos): """Generate rainbow colors across 0-255 positions.""" 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(self, wait_ms=20, iterations=1): """Draw rainbow that fades across all pixels at once.""" for j in range(256 * iterations): for i in range(self.led_numbers): self.strip.setPixelColor(i, self._wheel((i + j))) self.strip.show() time.sleep(wait_ms / 1000.0) def _rainbowCycle(self, wait_ms=20, iterations=5): """Draw rainbow that uniformly distributes itself across all pixels.""" for j in range(256 * iterations): for i in range(self.led_numbers): self.strip.setPixelColor( i, self._wheel((int(i * 256 / self.strip.numPixels()) + j) & 255)) self.strip.show() time.sleep(wait_ms / 1000.0) def _theaterChaseRainbow(self, wait_ms=50): """Rainbow movie theater light style chaser animation.""" for j in range(256): for q in range(3): for i in range(0, self.led_numbers, 3): self.strip.setPixelColor(i + q, self._wheel((i + j))) self.strip.show() time.sleep(wait_ms / 1000.0) for i in range(0, self.led_numbers, 3): self.strip.setPixelColor(i + q, Color(0, 0, 0)) self.strip.show() def _leftToRight(self, color, wait_ms=50): for j in range(self.columns): for i in range(self.rows): self.strip.setPixelColor(self.led_index[i][j], color) self.strip.show() time.sleep(wait_ms / 1000.0) def _rightToLeft(self, color, wait_ms=50): for j in reversed(range(self.columns)): for i in range(self.rows): self.strip.setPixelColor(self.led_index[i][j], color) self.strip.show() time.sleep(wait_ms / 1000.0) def _topToBottom(self, color, wait_ms=50): for i in range(self.rows): for j in range(self.columns): self.strip.setPixelColor(self.led_index[i][j], color) self.strip.show() time.sleep(wait_ms / 1000.0) def _bottomToTop(self, color, wait_ms=50): for i in reversed(range(self.rows)): for j in range(self.columns): self.strip.setPixelColor(self.led_index[i][j], color) self.strip.show() time.sleep(wait_ms / 1000.0) def _symbolLeftToRight(self, symbol, color, wait_ms): for j in range(self.columns - len(symbol[0])): self._showGivenSymbolAt(symbol, 0, j, color) time.sleep(wait_ms / 1000.0) self._colorWipe(Color(0, 0, 0)) def _symbolRightToLeft(self, symbol, color, wait_ms): for j in reversed(range(self.columns - len(symbol[0]))): self._showGivenSymbolAt(symbol, 0, j, color) time.sleep(wait_ms / 1000.0) self._colorWipe(Color(0, 0, 0))
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
class LEDPanel: """Listens to new data on the needed universes start_universe: The universe in which the panel starts start_channel: Inside the start_universe, the first channel used by the panel. Internally numbered starting from 0. """ def __init__(self, universe, channel, size=17): self.address_lock = threading.Lock() self.start_universe = universe self.start_channel = channel - 1 self._rows = size self._columns = self._rows # We assume it's a square self._old_universes = {} self.updateUniversesChannels() self._strip = PixelStrip(num=self._led_count, pin=12) # uses PWM0 self._strip.begin() self._wrapper = ClientWrapper() self._client = self._wrapper.Client() self.subscribeToUniverses() @property def columns(self): return self._columns @property def rows(self): return self._rows def getCallbackForUniverse(self, universe): if universe == self.start_universe: first_channel = self.start_channel last_channel = self._last_channel_used_in_first_universe + 1 first_pixel_index = 0 elif universe == self._last_universe: first_channel = 0 last_channel = self._last_channel + 1 first_pixel_index = self._led_count - ( self._rows_in_last_universe * self._columns) elif universe > self.start_universe and universe < self._last_universe: first_channel = 0 last_channel = self._last_channel + 1 internal_universe_index = universe - self.start_universe pixels_in_first = self._rows_in_first_universe * self._columns pixels_in_full = self._rows_per_full_universe * self._columns first_pixel_index = pixels_in_first + ( (internal_universe_index - 1) * pixels_in_full) else: raise ValueError('universe must be one of the listened universes') strip = self._strip old_universes = self._old_universes def callback(data): data = list(data)[first_channel:last_channel] if universe not in old_universes or data != old_universes[universe]: old_universes[universe] = data GPIO.output(STATUS_LED, GPIO.HIGH) for i in range(0, last_channel - first_channel, 3): try: r = data[i] except IndexError: r = 0 try: g = data[i+1] except IndexError: g = 0 try: b = data[i+2] except IndexError: b = 0 strip.setPixelColorRGB(int(i/3)+first_pixel_index, r, g, b) strip.show() print(universe) GPIO.output(STATUS_LED, GPIO.LOW) return callback def updateUniversesChannels(self): self._led_count = self._rows * self._columns self._channel_count_per_row = self._columns * 3 self._rows_per_full_universe = DMX_UNIVERSE_SIZE // self._channel_count_per_row channels_in_first_universe = DMX_UNIVERSE_SIZE - self.start_channel self._rows_in_first_universe = channels_in_first_universe \ // self._channel_count_per_row self._last_channel_used_in_first_universe = self.start_channel + \ self._rows_in_first_universe * self._channel_count_per_row - 1 self._universe_count = 1 rows_left = self._rows - self._rows_in_first_universe while rows_left >= self._rows_per_full_universe: self._universe_count += 1 rows_left -= self._rows_per_full_universe if rows_left != 0: self._universe_count += 1 self._last_channel = rows_left * self._channel_count_per_row - 1 self._rows_in_last_universe = rows_left else: self._last_channel = DMX_UNIVERSE_SIZE self._last_universe = self.start_universe + self._universe_count - 1 def subscribeToUniverses(self): self._old_universes.clear() for uni in range(self.start_universe, self._last_universe + 1): self._client.RegisterUniverse(uni, self._client.REGISTER, self.getCallbackForUniverse(uni)) def unsubscribeFromUniverses(self): for uni in range(self.start_universe, self._last_universe + 1): self._client.RegisterUniverse(uni, self._client.UNREGISTER, data_callback=None) def run(self): print("Launched LEDPanel") self._wrapper.Run() def setOnOff(self, activate=True): self._strip.setBrightness(activate * 255) self._strip.show() def threadSafeSchedule(self, time_in_ms, callback): def f(): self._wrapper.AddEvent(time_in_ms, callback) self._wrapper.Execute(f) def setAddress(self, universe=None, channel=None): """Sets the panel's address This method is threadsafe """ with self.address_lock: universe = universe if universe is not None else self.start_universe channel = channel - 1 if channel is not None else self.start_channel self.unsubscribeFromUniverses() self.start_universe = universe self.start_channel = channel self.updateUniversesChannels() self.subscribeToUniverses() def showFrame(self, frame): for i, pixel in enumerate(frame): self._strip.setPixelColorRGB(i, *pixel) self._strip.show()