Ejemplo n.º 1
0
    def _write_colors(self, cid, mode, colors, sval, direction='forward',):
        mval, mod3, movingFlag, mincolors, maxcolors = self._COLOR_MODES[mode]

        color_count = len(colors)
        if maxcolors == 40:
            led_padding = [0x00, 0x00, 0x00]*(maxcolors - color_count)  # turn off remaining LEDs
            leds = list(itertools.chain(*colors)) + led_padding
            self._write([0x22, 0x10, cid, 0x00] + leds[0:60])  # send first 20 colors to device (3 bytes per color)
            self._write([0x22, 0x11, cid, 0x00] + leds[60:])  # send remaining colors to device
            self._write([0x22, 0xa0, cid, 0x00, mval, mod3, 0x00, 0x00, 0x00,
                         0x00, 0x64, 0x00, 0x32, 0x00, 0x00, 0x01])
        elif mode == 'wings':  # wings requires special handling
            for [g, r, b] in colors:
                self._write([0x22, 0x10, cid])  # clear out all independent LEDs
                self._write([0x22, 0x11, cid])  # clear out all independent LEDs
                color_lists = [] * 3
                color_lists[0] = [g, r, b] * 8
                color_lists[1] = [int(x // 2.5) for x in color_lists[0]]
                color_lists[2] = [int(x // 4) for x in color_lists[1]]
                for i in range(8):   # send color scheme first, before enabling wings mode
                    mod = 0x05 if i in [3, 7] else 0x01
                    msg = ([0x22, 0x20, cid, i, 0x04, 0x39, 0x00, mod,
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
                            0x05, 0x85, 0x05, 0x85, 0x05, 0x85, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00])
                    self._write(msg + color_lists[i % 4])
                self._write([0x22, 0x03, cid, 0x08])   # this actually enables wings mode
        else:
            byte7 = movingFlag  # sets 'moving' flag for moving alternating modes
            byte8 = map_direction(direction, 0, 1)  # sets 'backward' flag
            byte9 = mod3 if mval == 0x03 else color_count  # specifies 'marquee' LED size
            byte10 = mod3 if mval == 0x05 else 0x00  # specifies LED size for 'alternating' modes
            header = [0x28, 0x03, cid, 0x00, mval, sval, byte7, byte8, byte9, byte10]
            self._write(header + list(itertools.chain(*colors)))
Ejemplo n.º 2
0
    def _write_colors(self, cid, mode, colors, sval, direction='forward'):
        mval, mod3, mod4, _, _ = self._COLOR_MODES[mode]
        # generate steps from mode and colors: usually each color set by the user generates
        # one step, where it is specified to all leds and the device handles the animation;
        # but in super mode there is a single step and each color directly controls a led

        mod3 += map_direction(direction, 0, 0x10)

        if 'super' in mode:
            steps = [list(itertools.chain(*colors))]
        else:
            steps = [color * 40 for color in colors]
        for i, leds in enumerate(steps):
            seq = i << 5
            byte4 = sval | seq | mod4
            self._write([0x2, 0x4b, mval, mod3, byte4] + leds[0:57])
            self._write([0x3] + leds[57:])
Ejemplo n.º 3
0
    def set_color(self,
                  channel,
                  mode,
                  colors,
                  speed='normal',
                  direction='forward',
                  **kwargs):
        """Set the color mode for a specific channel."""

        if not self.supports_lighting:
            raise NotSupportedByDevice()

        if mode == 'super':
            _LOGGER.warning(
                'deprecated mode, move to super-fixed, super-breathing or super-wave'
            )
            mode = 'super-fixed'
        if 'backwards' in mode:
            _LOGGER.warning(
                'deprecated mode, move to direction=backward option')
            mode = mode.replace('backwards-', '')
            direction = 'backward'

        mval, mod2, mod4, mincolors, maxcolors, ringonly = _COLOR_MODES[mode]
        mod2 += map_direction(direction, 0, 0x10)

        if ringonly and channel != 'ring':
            _LOGGER.warning(
                'mode=%s unsupported with channel=%s, dropping to ring', mode,
                channel)
            channel = 'ring'

        steps = self._generate_steps(colors, mincolors, maxcolors, mode,
                                     ringonly)
        sval = _ANIMATION_SPEEDS[speed]
        byte2 = mod2 | _COLOR_CHANNELS[channel]
        for i, leds in enumerate(steps):
            seq = i << 5
            byte4 = sval | seq | mod4
            logo = [leds[0][1], leds[0][0], leds[0][2]]
            ring = list(itertools.chain(*leds[1:]))
            self._write([0x2, 0x4c, byte2, mval, byte4] + logo + ring)
Ejemplo n.º 4
0
    def set_color(self,
                  channel,
                  mode,
                  colors,
                  direction='forward',
                  speed='medium',
                  start_led=1,
                  maximum_leds=1,
                  **kwargs):
        """Set the color of each LED.

        The table bellow summarizes the available channels, modes, and their
        associated maximum number of colors for each device family.

        | Channel  | Mode        | Num colors |
        | -------- | ----------- | ---------- |
        | led      | off         |          0 |
        | led      | fixed       |          1 |
        | led      | color_shift |          2 |
        | led      | color_pulse |          2 |
        | led      | color_wave  |          2 |
        | led      | visor       |          2 |
        | led      | blink       |          2 |
        | led      | marquee     |          1 |
        | led      | sequential  |          1 |
        | led      | rainbow     |          0 |
        | led      | rainbow2    |          0 |
        """

        # a special mode to clear the current led settings.
        # this is usefull if the the user wants to use a led mode for multiple devices
        if mode == 'clear':
            self._data.store('saved_effects', None)
            return

        colors = list(colors)
        expanded = colors[:3]
        c = itertools.chain(*((r, g, b) for r, g, b in expanded))
        colors = list(c)

        direction = map_direction(direction, _LED_DIRECTION_FORWARD,
                                  _LED_DIRECTION_BACKWARD)
        speed = _LED_SPEED_SLOW if speed == 'slow' else _LED_SPEED_FAST if speed == 'fast' else _LED_SPEED_MEDIUM
        start_led = clamp(start_led, 1, 204) - 1
        num_leds = clamp(maximum_leds, 1, 204 - start_led - 1)
        random_colors = 0x00 if mode == 'off' or len(colors) != 0 else 0x01
        mode_val = _MODES.get(mode, -1)

        if mode_val == -1:
            raise ValueError(f'mode "{mode}" is not valid')

        # FIXME clears on 'off', while the docs only mention this behavior for 'clear'
        saved_effects = [] if mode == 'off' else self._data.load(
            'saved_effects', default=[])

        for led_channel in self._get_hw_led_channels(channel):

            lighting_effect = {
                'channel': led_channel,
                'start_led': start_led,
                'num_leds': num_leds,
                'mode': mode_val,
                'speed': speed,
                'direction': direction,
                'random_colors': random_colors,
                'colors': colors
            }

            saved_effects += [lighting_effect]

            # check to make sure that too many LED effects are not being sent.
            # the max seems to be 8 as found here https://github.com/liquidctl/liquidctl/issues/154#issuecomment-762372583
            if len(saved_effects) > 8:
                _LOGGER.warning(
                    f'too many lighting effects. Run `liquidctl set {channel} color clear` to reset the effect'
                )
                return

            # start sending the led commands
            self._send_command(_CMD_RESET_LED_CHANNEL, [led_channel])
            self._send_command(_CMD_BEGIN_LED_EFFECT, [led_channel])
            self._send_command(_CMD_SET_LED_CHANNEL_STATE, [led_channel, 0x01])

        # FIXME clears on 'off', while the docs only mention this behavior for 'clear'
        self._data.store('saved_effects',
                         None if mode == 'off' else saved_effects)

        for effect in saved_effects:
            config = [
                effect.get('channel'),
                effect.get('start_led'),
                effect.get('num_leds'),
                effect.get('mode'),
                effect.get('speed'),
                effect.get('direction'),
                effect.get('random_colors'), 0xff
            ] + effect.get('colors')
            self._send_command(_CMD_LED_EFFECT, config)

        self._send_command(_CMD_LED_COMMIT, [0xff])
Ejemplo n.º 5
0
    def _write_colors(self, cid, mode, colors, sval, direction):
        mval, size_variant, speed_scale, mincolors, maxcolors = _COLOR_MODES[mode]
        color_count = len(colors)

        if 'super-fixed' == mode or 'super-breathing' == mode:
            color = list(itertools.chain(*colors)) + [0x00, 0x00, 0x00] * (maxcolors - color_count)
            speed_value = _SPEED_VALUE[speed_scale][sval]
            self._write([0x22, 0x10, cid, 0x00] + color)
            self._write([0x22, 0x11, cid, 0x00])
            self._write([0x22, 0xa0, cid, 0x00, mval] + speed_value +
                        [0x08, 0x00, 0x00, 0x80, 0x00, 0x32, 0x00, 0x00, 0x01])

        elif mode == 'wings':  # wings requires special handling
            self._write([0x22, 0x10, cid])  # clear out all independent LEDs
            self._write([0x22, 0x11, cid])  # clear out all independent LEDs
            color_lists = {}
            color_lists[0] = colors[0] * 2
            color_lists[1] = [int(x // 2.5) for x in color_lists[0]]
            color_lists[2] = [int(x // 4) for x in color_lists[1]]
            color_lists[3] = [0x00] * 8
            speed_value = _SPEED_VALUE[speed_scale][sval]
            for i in range(8):  # send color scheme first, before enabling wings mode
                mod = 0x05 if i in [3, 7] else 0x01
                alt = [0x04, 0x84] if i // 4 == 0 else [0x84, 0x04]
                msg = ([0x22, 0x20, cid, i, 0x04] + speed_value + [mod] + [0x00] * 7 + [0x02] +
                       alt + [0x00] * 10)
                self._write(msg + color_lists[i % 4])
            self._write([0x22, 0x03, cid, 0x08])   # this actually enables wings mode

        else:
            opcode = [0x2a, 0x04]
            address = [cid, cid]
            speed_value = _SPEED_VALUE[speed_scale][sval]
            header = opcode + address + [mval] + speed_value
            color = list(itertools.chain(*colors)) + [0, 0, 0] * (16 - color_count)

            if 'marquee' in mode:
                backward_byte = 0x04
            elif mode == 'starry-night' or 'moving-alternating' in mode:
                backward_byte = 0x01
            else:
                backward_byte = 0x00

            backward_byte += map_direction(direction, 0, 0x02)

            if mode == 'fading' or mode == 'pulse' or mode == 'breathing':
                mode_related = 0x08
            elif mode == 'tai-chi':
                mode_related = 0x05
            elif mode == 'water-cooler':
                mode_related = 0x05
                color_count = 0x01
            elif mode == 'loading':
                mode_related = 0x04
            else:
                mode_related = 0x00

            static_byte = _STATIC_VALUE[cid]
            led_size = size_variant if mval == 0x03 or mval == 0x05 else 0x03
            footer = [backward_byte, color_count, mode_related, static_byte, led_size]
            self._write(header + color + footer)