| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- #!/usr/bin/env python3
- """
- WLED Segment class for Raspberry Pi
- Manages LED strip segments and their effects
- """
- import time
- from typing import List, Callable, Optional
- from .utils.colors import *
- from .utils.palettes import color_from_palette, get_palette
- class Segment:
- """LED segment with effect support"""
- def __init__(self, pixels, start: int, stop: int):
- """
- Initialize a segment
- pixels: neopixel.NeoPixel object
- start: starting LED index
- stop: ending LED index (exclusive)
- """
- self.pixels = pixels
- self.start = start
- self.stop = stop
- self.length = stop - start
- # Colors (up to 3 colors like WLED)
- self.colors = [0x00FF0000, 0x000000FF, 0x0000FF00] # Red, Blue, Green defaults
- # Effect parameters
- self.speed = 128 # 0-255
- self.intensity = 128 # 0-255
- self.palette_id = 0 # Palette ID
- self.custom1 = 0 # Custom parameter 1
- self.custom2 = 0 # Custom parameter 2
- self.custom3 = 0 # Custom parameter 3
- # Runtime state (like SEGENV in WLED)
- self.call = 0 # Number of times effect has been called
- self.step = 0 # Effect step counter
- self.aux0 = 0 # Auxiliary variable 0
- self.aux1 = 0 # Auxiliary variable 1
- self.next_time = 0 # Next time to run effect (ms)
- self.data = [] # Effect data storage
- # Timing
- self._start_time = time.time() * 1000 # Convert to milliseconds
- def get_pixel_color(self, i: int) -> int:
- """Get color of pixel at index i (segment-relative)"""
- if i < 0 or i >= self.length:
- return 0
- actual_idx = self.start + i
- color = self.pixels[actual_idx]
- # Convert from neopixel (R,G,B) or (G,R,B) to 32-bit
- if isinstance(color, tuple):
- if len(color) == 3:
- return (color[0] << 16) | (color[1] << 8) | color[2]
- elif len(color) == 4:
- return (color[3] << 24) | (color[0] << 16) | (color[1] << 8) | color[2]
- return 0
- def set_pixel_color(self, i: int, color: int):
- """Set color of pixel at index i (segment-relative)"""
- if i < 0 or i >= self.length:
- return
- actual_idx = self.start + i
- r = get_r(color)
- g = get_g(color)
- b = get_b(color)
- self.pixels[actual_idx] = (r, g, b)
- def fill(self, color: int):
- """Fill entire segment with color"""
- for i in range(self.length):
- self.set_pixel_color(i, color)
- def fade_out(self, amount: int):
- """Fade all pixels in segment toward black"""
- for i in range(self.length):
- current = self.get_pixel_color(i)
- faded = color_fade(current, amount)
- self.set_pixel_color(i, faded)
- def blur(self, amount: int):
- """Blur/blend pixels with neighbors"""
- if amount == 0 or self.length < 3:
- return
- # Simple blur: blend each pixel with neighbors
- temp = [self.get_pixel_color(i) for i in range(self.length)]
- for i in range(self.length):
- if i == 0:
- # First pixel: blend with next
- blended = color_blend(temp[i], temp[i + 1], amount)
- elif i == self.length - 1:
- # Last pixel: blend with previous
- blended = color_blend(temp[i], temp[i - 1], amount)
- else:
- # Middle pixels: blend with both neighbors
- left = color_blend(temp[i], temp[i - 1], amount // 2)
- blended = color_blend(left, temp[i + 1], amount // 2)
- self.set_pixel_color(i, blended)
- def now(self) -> int:
- """Get current time in milliseconds since segment start"""
- return int((time.time() * 1000) - self._start_time)
- def color_from_palette(self, index: int, use_index: bool = True,
- brightness: int = 255) -> int:
- """
- Get color from current palette
- index: LED index or palette position
- use_index: if True, scale index across palette
- brightness: 0-255
- """
- palette = get_palette(self.palette_id)
- if use_index and self.length > 1:
- # Map LED position to palette position
- palette_pos = (index * 255) // (self.length - 1)
- else:
- palette_pos = index & 0xFF
- return color_from_palette(palette, palette_pos, brightness)
- def get_color(self, index: int) -> int:
- """Get segment color by index (0-2)"""
- if 0 <= index < len(self.colors):
- return self.colors[index]
- return 0
- def reset(self):
- """Reset segment state"""
- self.call = 0
- self.step = 0
- self.aux0 = 0
- self.aux1 = 0
- self.next_time = 0
- self.data = []
|