class WS2812(Driver): """ Legacy driver. Passes through calls to some other driver. """ def __init__(self, width, height, serpentine=False, name=None): self.serpentine = serpentine super().__init__(np.zeros((height, width, 3), dtype=np.uint8), 8, name=name) self.pixelstrip = PixelStrip(self.height * self.width, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_GAMMA) def __enter__(self): self.pixelstrip.begin() return super().__enter__() def show(self): if self.serpentine: # TODO: handle serpentine, but i don't have hardware to test :( outbuf = self.rawbuf else: outbuf = self.rawbuf outbuf = outbuf.reshape(self.width * self.height, 3) for i in range(outbuf.shape[0]): self.pixelstrip.setPixelColorRGB(i, *outbuf[i].tolist()) # ugh self.pixelstrip.show() super().show()
class PlasmaWS281X(Plasma): """Class for Plasma light devices in the WS281X/SK6812 family.""" name = "WS281X" options = { 'pixel_count': int, "gpio_pin": int, "strip_type": str, "channel": int, "brightness": int, "freq_hz": int, "dma": int, "invert": bool } option_order = ("gpio_pin", "strip_type", "channel", "brightness", "freq_hz", "dma", "invert") def __init__(self, pixel_count=1, gpio_pin=13, strip_type='WS2812', channel=None, brightness=255, freq_hz=800000, dma=10, invert=False): """Initialise WS281X device. :param pixel_count: Number of individual RGB LEDs :param gpio_pin: BCM GPIO pin for output signal :param strip_type: Strip type: one of WS2812 or SK6812 :param channel: LED channel (0 or 1, or None for automatic) :param brightness: Global WS281X LED brightness scale :param freq_hz: WS281X output signal frequency (usually 800khz) :param dma: DMA channel :param invert: Invert signals for NPN-transistor based level shifters """ from rpi_ws281x import PixelStrip, ws strip_types = {} for t in ws.__dict__: if '_STRIP' in t: k = t.replace('_STRIP', '') v = getattr(ws, t) strip_types[k] = v strip_type = strip_types[strip_type] if channel is None: if gpio_pin in [13]: channel = 1 elif gpio_pin in [12, 18]: channel = 0 self._strip = PixelStrip(pixel_count, gpio_pin, freq_hz, dma, invert, brightness, channel, strip_type) self._strip.begin() Plasma.__init__(self, pixel_count) def show(self): """Output the buffer.""" for i in range(self._strip.numPixels()): r, g, b, brightness = self._pixels[i] self._strip.setPixelColorRGB(i, r, g, b) self._strip.show()
class WS2812(Driver): """ Legacy driver. Passes through calls to some other driver. """ def __init__(self, width, height, led_pin=18, map=None, name=None): self.map = map if self.map is None: n_leds = self.height * self.width else: n_leds = len(self.map) super().__init__(np.zeros((height, width, 3), dtype=np.uint8), 8, name=name) self.pixelstrip = PixelStrip(n_leds, led_pin, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_GAMMA) def __enter__(self): self.pixelstrip.begin() return super().__enter__() def show(self): if self.map is not None: outbuf = self.rawbuf[self.map] else: outbuf = self.rawbuf outbuf = outbuf.reshape(-1, 3) for i in range(outbuf.shape[0]): self.pixelstrip.setPixelColorRGB(i, *outbuf[i].tolist()) # ugh self.pixelstrip.show() super().show()
class PlasmaWS281X(Plasma): def __init__(self, light_count, gpio_pin=13, strip_type='WS2812', channel=1, brightness=255, freq_hz=800000, dma=10, invert=False): from rpi_ws281x import PixelStrip, ws strip_types = {} for t in ws.__dict__: if '_STRIP' in t: k = t.replace('_STRIP', '') v = getattr(ws, t) strip_types[k] = v strip_type = strip_types[strip_type] self._strip = PixelStrip(light_count, gpio_pin, freq_hz, dma, invert, brightness, channel, strip_type) self._strip.begin() Plasma.__init__(self, light_count) def show(self): """Output the buffer.""" for i in range(self._strip.numPixels()): r, g, b, brightness = self._pixels[i] self._strip.setPixelColorRGB(i, r, g, b) self._strip.show()
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())
class RpiWs281xLedstrip(AbstractLight): def __init__(self) -> None: super().__init__(led_count=LED_COUNT) self.pixel_strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL) self.pixel_strip.begin() def write(self): assert self.pixel_strip.numPixels() == len(self.leds) # Update the value for each of the pixels in the strip for i in range(startLED, self.pixel_strip.numPixels()): [red, green, blue, brightness] = self.leds[i] colors = (int(c * brightness * 255) for c in (red, green, blue)) self.pixel_strip.setPixelColorRGB(i, *colors, 255) # Flush the new values to the strip self.pixel_strip.show()
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)
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz) LED_DMA = 10 # DMA channel to use for generating signal LED_BRIGHTNESS = 128 # Set to 0 for darkest and 255 for brightest LED_CHANNEL = 0 # PWM channel LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) LED_GAMMA = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40, 40, 41, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 98, 99, 100, 102, 103, 104, 106, 107, 109, 110, 111, 113, 114, 116, 117, 119, 120, 121, 123, 124, 126, 128, 129, 131, 132, 134, 135, 137, 138, 140, 142, 143, 145, 146, 148, 150, 151, 153, 155, 157, 158, 160, 162, 163, 165, 167, 169, 170, 172, 174, 176, 178, 179, 181, 183, 185, 187, 189, 191, 193, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 227, 229, 231, 233, 235, 237, 239, 241, 244, 246, 248, 250, 252, 255 ] ws2812 = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_GAMMA) ws2812.begin() ws2812.setPixelColorRGB(1, 255, 255, 0) ws2812.setPixelColorRGB(1, 255, 0, 255) ws2812.setPixelColorRGB(1, 0, 255, 255)
class Strip: """ Creates an led Strip with the provided configuration. :type terminal: int :param terminal: Which terminal the terminal is attached to (1-4). :type size: int or tuple :param size: The size of the LED string or matrix. Either the number of LEDs for a string, or (width, height) for a matrix. :type shape: str, optional :param shape: The 'shape' of the LEDs attached: * :data:`straight` - A LED string (default) * :data:`reverse` - A LED string which starts at the opposite end. * :data:`zmatrix` - A matrix where the LEDs in the first row go left to right, the next one right to left. i.e: | 1 2 3 4 | 8 7 6 5 | 9 . . . * :data:`matrix` - a normal matrix where the led order goes left to right. i.e: | 1 2 3 4 | 5 6 7 8 | 9 . . . :type ledtype: str :param ledtype: One of the supported LED types: ``WS2812`` *(default)*, ``SK6812``, ``SK6812W``, ``SK6812_RGBW``, ``SK6812_RBGW``, ``SK6812_GRBW``, ``SK6812_GBRW``, ``SK6812_BRGW``, ``SK6812_BGRW``, ``WS2811_RGB``, ``WS2811_RBG``, ``WS2811_GRB``, ``WS2811_GBR``, ``WS2811_BRG``, ``WS2811_BGR`` :type brightness: int :param brightness: The default brightness for all LEDs (0-255). """ ledtypeslist = [ "WS2812", "SK6812", "SK6812W", "SK6812_RGBW", "SK6812_RBGW", "SK6812_GRBW", "SK6812_GBRW", "SK6812_BRGW", "SK6812_BGRW", "WS2811_RGB", "WS2811_RBG", "WS2811_GRB", "WS2811_GBR", "WS2811_BRG", "WS2811_BGR" ] matrixshapelist = ["zmatrix", "matrix"] stringshapelist = ["straight", "reverse"] allshapeslist = matrixshapelist + stringshapelist rotatelist = ["LEFT", "RIGHT", "UP", "DOWN"] mirrorlist = ["HORIZONTAL", "VERTICAL"] def __init__(self, terminal, size, shape='straight', ledtype='WS2812', brightness=255): # --------------------------------------------- # Which terminal connection is being used (1 to 4) # --------------------------------------------- if terminal == 1: self.__controlpin = 10 self.__channel = 0 self.__onoffpin = 27 elif terminal == 2: self.__controlpin = 12 self.__channel = 0 self.__onoffpin = 4 elif terminal == 3: self.__controlpin = 21 self.__channel = 0 self.__onoffpin = 17 elif terminal == 4: self.__controlpin = 13 self.__channel = 1 self.__onoffpin = 22 else: raise ValueError('The terminal number must be between 1 and 4.') self.__stripnum = terminal # -------------- # The terminal type # -------------- if ledtype not in self.ledtypeslist: raise ValueError('This terminal type is not supported.') self.__striptype = ledtype supportedstriptypes = {} for t in ws.__dict__: if '_STRIP' in t: k = t.replace('_STRIP', '') v = getattr(ws, t) supportedstriptypes[k] = v self.__internalstriptype = supportedstriptypes[ledtype] # --------------- # The terminal shape # --------------- if shape not in self.allshapeslist: raise ValueError('The terminal shape is not supported.') elif shape in self.matrixshapelist and type(size) is not tuple: raise ValueError( 'A matrix shape has been defined, but the size is not a tuple (i.e. (x, y)).' ) elif shape not in self.matrixshapelist and type(size) is tuple: raise ValueError( 'A non-matrix shape has been defined, but the size is a tuple.' ) self.__stripshape = shape # ----------------------------------------- # The size of the terminal # striplength is the total number of shift # ----------------------------------------- if type(size) is tuple: if len(size) != 2: raise ValueError( 'The matrix shape must be defined in width and length size (x, y) only.' ) width, height = size striplength = height * width self.__width = width self.__height = height else: striplength = size self.__width = 1 self.__height = striplength if striplength <= 0: raise ValueError('The terminal length needs to be 1 or more.') self.__striplength = striplength # ----------------------------------- # The default brightness at the start # ----------------------------------- self.__brightness = self.__checkBrightness(brightness) # ----------------------------------------------- # A list to hold the led colours and brightness # ----------------------------------------------- self.__pixels = [[0, 0, 0, self.__brightness]] * self.__striplength # ---------------------------- # Set up the rpi_ws281x callingclass # ---------------------------- self.__strip = PixelStrip(self.__striplength, self.__controlpin, 800000, 10, False, self.__brightness, self.__channel, self.__internalstriptype) # --------------------- # Start the terminal logic # --------------------- self.__strip.begin() # ------------------------------------------------------------------- # Set up the pin which defines whether the terminal is written to or not # ------------------------------------------------------------------- self.__statuspin = OutputDevice(self.__onoffpin, active_high=False, initial_value=False) self.updateStatus = True # --------------- # Clear the terminal # --------------- self.clearLEDs() def __del__(self): """Disposes of the rpi_ws281x callingclass""" del self.__strip @staticmethod def __version(): return __version__ @property def getLength(self): """Returns how many LEDs are in the strip/matrix.""" return self.__striplength @property def getWidth(self): """Returns the width of the matrix (1 if an LED string).""" return self.__width @property def getHeight(self): """Returns the height of the matrix (or length of an LED string).""" return self.__height @property def getStripType(self): """Returns the set LED type.""" return self.__striptype @property def getStripNumber(self): """Returns the terminal the LEDs are attached to.""" return self.__stripnum @property def updateStatus(self): """ Returns or sets whether output is currently enabled for the LEDs. When set to ``False``, the current LED pattern will remain unchanged even if the pattern is changed and :class:`showLEDs()` is called. :getter: Returns the status. :setter: Sets the status. :type: bool """ return self.__statuspin.value == 1 @updateStatus.setter def updateStatus(self, status=True): """ The setter for updateStatus property. """ if status: self.__statuspin.on() else: self.__statuspin.off() def __checkBrightness(self, brightness): """ Checks whether the brightness value given is within range (0-255) :type brightness: int or None :param brightness: A value between 0 (off) and 255 (full brightness) """ if brightness is None: brightness = self.__brightness else: if 0 < brightness > 255: raise ValueError('Brightness must be between 0 and 255') return brightness @staticmethod def __checkRGB(rgb): """Checks whether the rgb value passed in is valid.""" if type(rgb) is not tuple: raise ValueError( 'The rgb value must be a tuple of the form (r, g, b).') elif len(rgb) != 3: raise ValueError( 'The rgb tuple must have three elements (r, g, b).') red, green, blue = [int(c) & 0xff for c in rgb] return red, green, blue @staticmethod def __checkPattern(pattern): """ Checks whether the pattern passed in is valid :param pattern: A list of the RGB and brightness values of each led in the terminal """ if len(pattern) == 0: raise ValueError("The pattern must have elements") if len(pattern[0]) != 4: raise ValueError( "Each index of the pattern must have four elements (red, green, blue, brightness)" ) return pattern def __setBrightness(self, brightness, led=None): """ Sets the brightness of one or more LEDs. :type brightness: int or None :param brightness: The brightness :type led: int or None :param led: If defined, only set that led, otherwise set all """ brightness = self.__checkBrightness(brightness) if led is None: for led in range(self.__striplength): self.__pixels[led][3] = brightness else: pixelnumber = self.__translate(led) if 0 <= pixelnumber < self.__striplength: raise ValueError('The led index is out of range.') self.__pixels[led][3] = brightness def __setImage(self, image, position=None): """ Plots an RGB image to the matrix or string of LEDs. :type image: RGB Format image :param image: An image in RGB format (see PILLOW library) :type position: int, tuple or None :param position: The location on the matrix """ if image.mode != 'RGB': raise ValueError("The image must be in RGB format.") imagewidth, imageheight = image.size if self.__stripshape in self.matrixshapelist: if position is None: position = (0, 0) elif type(position) is not tuple: raise ValueError( "A matrix shape has been defined, but the size is not a tuple (i.e. (x, y))." ) elif len(position) != 2: raise ValueError( 'A matrix shape has been defined, but the start position does not have two elements (i.e. (x, y)).' ) px, py = position width = min(imagewidth, self.__width) height = min(imageheight, self.__height) else: if position is None: position = 0 if type(position) is tuple: raise ValueError( 'A non-matrix shape has been defined, but the size is a tuple.' ) px, py = position, 0 width = 1 height = min(imageheight, self.__height) imagecolours = list(image.getdata()) for y in range(height): for x in range(width): r, g, b = imagecolours[x + y * 8] self.setLEDs(led=(px + x, py + y), rgb=(r, g, b)) def __setPattern(self, pattern): """ Sets the RGB and brightness of the LEDs using the pattern passed in :param pattern: """ pattern = self.__checkPattern(pattern) for pixelnumber in range(min(self.__striplength, len(pattern))): self.__pixels[pixelnumber] = pattern[pixelnumber] def __translate(self, pixel): """Translates co-ordinates for various different shapes""" realpixel = -1 if self.__stripshape == "straight" or type(pixel) is not tuple: if 0 <= pixel < self.__striplength: realpixel = pixel elif self.__stripshape == "reverse": if 0 <= pixel < self.__striplength: realpixel = self.__striplength - pixel elif self.__stripshape == "zmatrix": x, y = pixel if 0 <= x < self.__width and 0 <= y <= self.__height: if y % 2 == 0: realpixel = (y * self.__width) + x else: realpixel = ((y + 1) * self.__width) - (x + 1) elif self.__stripshape == "matrix": x, y = pixel if 0 <= x < self.__width and 0 <= y <= self.__height: realpixel = y * self.__width + x return realpixel def getLEDs(self, led=None): """ If ``led`` is supplied, returns the RGB and brightness values of a specific LED. If led is not supplied or set to ``None`` a list of red, green, blue and brightness values for each LED is returned in a list. :type led: int, tuple or None :param led: The led location, either the LED count from the start, or the x,y matrix location, or if None, a list of all LEDs will be returned :return: (red, green, blue, brightness) or a list of (red, green, blue, brightness) """ if led is None: return self.__pixels else: pixelnumber = self.__translate(led) if 0 <= pixelnumber < self.__striplength: r, g, b, brightness = self.__pixels[pixelnumber] else: r, g, b, brightness = [0, 0, 0, 0] return r, g, b, brightness def setLEDs(self, led=None, rgb=None, brightness=None, image=None, pattern=None): """ Sets the RGB value, and optionally brightness, of one or more LEDs. If ``led`` is not supplied or set to ``None``, all LEDs will be set to the defined colour and brightness. If a matrix is being used, ``led`` can either be the LED count from the first LED, or the (x, y) location. If a brightness value is not supplied, or set to ``None``, the current LED brightness will be kept. If an image is supplied, then it must be in RGB format (see `Pillow image file formats <https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html>`_) If a pattern is supplied, it must be a list consisting of a tuple with four elements, ``(red, green, blue, brightness)``. :type led: int, tuple or None :param led: The LED location or None to set all LEDs to the desired colour. :type rgb: tuple or None :param rgb: A tuple consisting of 3 elements, (red, green, blue), with each value being between 0 and 255. :type brightness: int or None :param brightness: A value between 0 (dim) to 255 (very bright) or None to take the default. :type image: image or None :param image: An image callingclass (see PIL or Pillow libraries) containing an RGB formatted image. :type pattern: list or None :param pattern: A list of the RGB and brightness values for each LED, in numerical order from the start of the strip/matrix. """ if image is not None: self.__setImage(image, position=led) elif pattern is not None: self.__setPattern(pattern) elif led is None and rgb is None and brightness is None: self.clearLEDs() else: if rgb is None: self.__setBrightness(brightness, led) else: red, green, blue = self.__checkRGB(rgb) if led is None: brightness = self.__checkBrightness(brightness) self.__pixels = [[red, green, blue, brightness] ] * self.__striplength else: pixelnumber = self.__translate(led) if 0 <= pixelnumber < self.__striplength: if brightness is None: brightness = self.__pixels[pixelnumber][3] self.__pixels[pixelnumber] = [ red, green, blue, brightness ] def clearLEDs(self): """ Clears the LEDs (sets them to black), leaving the brightness as it is. """ for pixel in range(self.__striplength): self.__pixels[pixel][0:3] = [0, 0, 0] def shift(self, direction="UP", shift=1): """ Shifts the LEDs on the matrix or string by :data:`shift` LEDs in the direction specified. :type direction: str :param direction: The direction the LEDs should shift (LEFT, RIGHT, UP, DOWN) :type shift: int :param shift: The number of LEDs the matrix/string should be moved in the specified direction. """ direction = direction.upper() if direction not in self.rotatelist: raise ValueError( 'The rotation direction must be one of LEFT, RIGHT, UP or DOWN.' ) if self.__stripshape in self.stringshapelist: if self.__striplength < shift or shift <= 0: raise ValueError( 'The shift value must be positive and shorter than the string length.' ) if direction == "LEFT" or direction == "UP": for _ in range(shift): self.__pixels.insert(0, self.__pixels[self.__striplength - 1]) self.__pixels.pop(self.__striplength) else: for _ in range(shift): self.__pixels.append(self.__pixels[0]) self.__pixels.pop(0) else: if direction == "UP" or direction == "DOWN": if shift >= self.__height: raise ValueError( 'The shift must be smaller than the height of the matrix.' ) if direction == "DOWN": shift = -shift tempstrip = self.__pixels.copy() for y in range(self.__height): newy = (y + shift) % self.__height for x in range(self.__width): self.__pixels[self.__translate( (x, newy))] = tempstrip[self.__translate((x, y))] else: if shift >= self.__width: raise ValueError( 'The shift must be smaller than the width of the matrix.' ) if direction == "LEFT": shift = -shift tempstrip = self.__pixels.copy() for x in range(self.__width): newx = (x + shift) % self.__width for y in range(self.__height): self.__pixels[self.__translate( (newx, y))] = tempstrip[self.__translate((x, y))] def mirror(self, mirror="VERTICAL"): """ Mirrors the matrix LEDs either in the :data:`VERTICAL` or :data:`HORIZONTAL` plane. Reverses the LED colours on an LED string. The ``mirror`` parameter is not required for strings. :type mirror: str :param mirror: :data:`VERTICAL` *(default)* or :data:`HORIZONTAL` """ if self.__stripshape in self.matrixshapelist: mirror = mirror.upper() if mirror not in self.mirrorlist: raise ValueError( 'The mirror value must be either VERTICAL or HORIZONTAL.') tempstrip = self.__pixels.copy() if mirror == "VERTICAL": for y in range(int(self.__height / 2)): for x in range(self.__width): self.__pixels[self.__translate( (x, y))] = tempstrip[self.__translate( (x, self.__height - 1 - y))] self.__pixels[self.__translate( (x, self.__height - 1 - y))] = tempstrip[self.__translate((x, y))] else: for x in range(int(self.__width / 2)): for y in range(self.__height): self.__pixels[self.__translate( (x, y))] = tempstrip[self.__translate( (self.__width - 1 - x, y))] self.__pixels[self.__translate( (self.__width - 1 - x, y))] = tempstrip[self.__translate((x, y))] else: self.__pixels.reverse() def showLEDs(self): """ Once you have set the colours of the string/matrix LEDs, use :class:`showLEDs` to update the LEDs. """ for pixel in range(self.__strip.numPixels()): r, g, b, brightness = self.__pixels[pixel] self.__strip.setPixelColorRGB(pixel, r, g, b) self.__strip.show()
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 # 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() bereit = 0 anruf = 1 zugang = 2 verweigert = 3 warte = 4 strip.setPixelColorRGB(bereit, 255, 100, 0) strip.show() GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) ## todo: set usb adapter to fixed enumeration try: ser = serial.Serial('/dev/ttyAMA0', 19200) except: print "wrong USB port" #----------------------------------------------------------------------------------------------------------------- # pygame related stuff BLACK = (0, 0, 0) WHITE = (255, 255, 255)
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()