Ejemplo n.º 1
0
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()
Ejemplo n.º 2
0
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()
Ejemplo n.º 3
0
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()
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
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())
Ejemplo n.º 6
0
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()
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
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()
Ejemplo n.º 10
0
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)
Ejemplo n.º 11
0
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()