Compare commits
No commits in common. 'master' and 'master' have entirely different histories.
16 changed files with 72 additions and 453 deletions
@ -1,17 +0,0 @@ |
|||||||
ENVIRONMENT=prod |
|
||||||
USE_EMULATOR=false |
|
||||||
BIND_ADDR=127.0.0.1 |
|
||||||
BIND_PORT=8080 |
|
||||||
|
|
||||||
# Strip configuration |
|
||||||
STRIP_PIXELS=290 |
|
||||||
STRIP_GPIO_PIN=18 |
|
||||||
STRIP_HZ=800000 |
|
||||||
STRIP_DMA=10 |
|
||||||
STRIP_INVERT=false |
|
||||||
STRIP_BRIGHTNESS=255 |
|
||||||
STRIP_CHANNEL=0 |
|
||||||
STRIP_TYPE=4104 |
|
||||||
|
|
||||||
REGIONS=46,96,191,241 |
|
||||||
BPM_DEFAULT=60 |
|
||||||
@ -1,2 +0,0 @@ |
|||||||
ENVIRONMENT=dev |
|
||||||
USE_EMULATOR=true |
|
||||||
@ -1,2 +1 @@ |
|||||||
.env |
|
||||||
litsimaja.log |
litsimaja.log |
||||||
|
|||||||
@ -1,38 +0,0 @@ |
|||||||
from dotenv import dotenv_values |
|
||||||
import pathlib |
|
||||||
|
|
||||||
|
|
||||||
def populate_values(load: {}): |
|
||||||
conf = load |
|
||||||
conf['IS_DEV']: bool = str.lower(load['ENVIRONMENT']) == 'dev' |
|
||||||
conf['USE_EMULATOR']: bool = str.lower(load['USE_EMULATOR']) == 'true' |
|
||||||
conf['BIND_PORT']: int = int(load['BIND_PORT']) |
|
||||||
|
|
||||||
conf['STRIP_PIXELS']: int = int(load['STRIP_PIXELS']) |
|
||||||
conf['STRIP_GPIO_PIN']: int = int(load['STRIP_GPIO_PIN']) |
|
||||||
conf['STRIP_HZ']: int = int(load['STRIP_HZ']) |
|
||||||
conf['STRIP_DMA']: int = int(load['STRIP_DMA']) |
|
||||||
conf['STRIP_INVERT']: bool = str.lower(load['STRIP_INVERT']) == 'true' |
|
||||||
conf['STRIP_BRIGHTNESS']: int = int(load['STRIP_BRIGHTNESS']) |
|
||||||
conf['STRIP_CHANNEL']: int = int(load['STRIP_CHANNEL']) |
|
||||||
conf['STRIP_TYPE']: int = int(load['STRIP_TYPE']) |
|
||||||
|
|
||||||
conf['REGIONS']: [] = [int(x) for x in load['REGIONS'].split(',')] |
|
||||||
conf['BPM_DEFAULT']: int = int(load['BPM_DEFAULT']) |
|
||||||
|
|
||||||
return conf |
|
||||||
|
|
||||||
|
|
||||||
class Config(object): |
|
||||||
_config: {} = {} |
|
||||||
|
|
||||||
def __init__(self): |
|
||||||
rp = str(pathlib.Path(__file__).parent.parent.absolute()) |
|
||||||
load_conf = { |
|
||||||
**dotenv_values(rp + "/.env.defaults"), |
|
||||||
**dotenv_values(rp + "/.env"), |
|
||||||
} |
|
||||||
self._config = populate_values(load_conf) |
|
||||||
|
|
||||||
def get(self, key: str): |
|
||||||
return self._config[key] |
|
||||||
@ -1,38 +0,0 @@ |
|||||||
class Regions(object): |
|
||||||
_pixelsEnabled: [] = [] |
|
||||||
_regions: [] = [] |
|
||||||
|
|
||||||
def __init__(self, strip_length: int, splitters: []): |
|
||||||
self._length: int = strip_length |
|
||||||
start_pixel = 0 |
|
||||||
for i in splitters: |
|
||||||
if i > self._length: |
|
||||||
raise ValueError('splitter out of bounds, you idiot') |
|
||||||
self._regions.append([start_pixel, i + 1, True]) |
|
||||||
start_pixel = i + 1 |
|
||||||
|
|
||||||
self._regions.append([start_pixel, self._length, True]) |
|
||||||
for i in range(self._length): |
|
||||||
self._pixelsEnabled.append(True) |
|
||||||
|
|
||||||
def region_switch(self, region_id: int, enabled: bool): |
|
||||||
pixel_region = self._regions[region_id] |
|
||||||
for i in range(pixel_region[0], pixel_region[1]): |
|
||||||
self._pixelsEnabled[i] = enabled |
|
||||||
self._regions[region_id][2] = enabled |
|
||||||
|
|
||||||
def is_pixel_enabled(self, pixel_id: int) -> bool: |
|
||||||
return self._pixelsEnabled[pixel_id] |
|
||||||
|
|
||||||
def is_region_enabled(self, region_id: int) -> bool: |
|
||||||
return self._regions[region_id][2] |
|
||||||
|
|
||||||
def switch_region(self, region_id: int): |
|
||||||
status: bool = self._regions[region_id][2] |
|
||||||
self.region_switch(region_id, not status) |
|
||||||
|
|
||||||
def list_region_ids(self): |
|
||||||
result = [] |
|
||||||
for i in range(len(self._regions)): |
|
||||||
result.append(i) |
|
||||||
return result |
|
||||||
@ -1,45 +0,0 @@ |
|||||||
import time |
|
||||||
from typing import Optional |
|
||||||
|
|
||||||
|
|
||||||
class Tempo(object): |
|
||||||
_last_beat: float |
|
||||||
_override_beat: Optional[float] = None |
|
||||||
|
|
||||||
def __init__(self, bpm: float = 60): |
|
||||||
self._bpm: float = bpm |
|
||||||
self.update_last_beat() |
|
||||||
|
|
||||||
def set_bpm(self, bpm: float) -> None: |
|
||||||
self._bpm = bpm |
|
||||||
|
|
||||||
def get_bpm(self) -> float: |
|
||||||
return self._bpm |
|
||||||
|
|
||||||
def update_last_beat(self) -> None: |
|
||||||
self._last_beat = time.time() |
|
||||||
|
|
||||||
def get_beat_time(self) -> float: |
|
||||||
return 1000 / (self._bpm / 60) |
|
||||||
|
|
||||||
def get_beat_delay(self) -> Optional[float]: |
|
||||||
tick = self._override_beat |
|
||||||
if tick is None: |
|
||||||
return None |
|
||||||
self._override_beat = None |
|
||||||
return tick - self._last_beat |
|
||||||
|
|
||||||
def sync_beat(self): |
|
||||||
self._override_beat = time.time() |
|
||||||
|
|
||||||
def wait(self, beat_divider: int = 1): |
|
||||||
now = time.time() |
|
||||||
next_beat = self._last_beat + (self.get_beat_time() / beat_divider / 1000) |
|
||||||
wait_time = next_beat - now |
|
||||||
beat_delay = self.get_beat_delay() |
|
||||||
if beat_delay is not None: |
|
||||||
wait_time += beat_delay |
|
||||||
if wait_time > 0: |
|
||||||
time.sleep(wait_time) |
|
||||||
self.update_last_beat() |
|
||||||
return True |
|
||||||
@ -1,38 +0,0 @@ |
|||||||
from lib.Program import Program |
|
||||||
from rpi_ws281x import Color |
|
||||||
import time |
|
||||||
|
|
||||||
def name(): |
|
||||||
return 'Christmas Lights' |
|
||||||
|
|
||||||
class ChristmasLights(Program): |
|
||||||
def run(self, args: [] = None): |
|
||||||
# Configuration |
|
||||||
wait_ms = 0 # Speed of the animation |
|
||||||
|
|
||||||
# Define classic festive colors |
|
||||||
RED = Color(255, 0, 0) |
|
||||||
GREEN = Color(0, 255, 0) |
|
||||||
WARM_WHITE = Color(200, 180, 60) # A golden-ish warm white |
|
||||||
|
|
||||||
colors = [RED, GREEN, WARM_WHITE] |
|
||||||
|
|
||||||
# This determines how many pixels of the same color are next to each other |
|
||||||
group_size = 2 |
|
||||||
|
|
||||||
offset = 0 |
|
||||||
while self.get_loop().status(): |
|
||||||
num_pixels = self._lm.count_pixels() |
|
||||||
|
|
||||||
for i in range(num_pixels): |
|
||||||
# Calculate which color index to use based on pixel position and current offset |
|
||||||
# This creates the "moving" effect |
|
||||||
color_index = ((i + offset) // group_size) % len(colors) |
|
||||||
self._lm.set_pixel_color(i, colors[color_index]) |
|
||||||
|
|
||||||
self._lm.show() |
|
||||||
|
|
||||||
# Increment offset to move the lights |
|
||||||
offset = (offset + 1) % (len(colors) * group_size) |
|
||||||
self._lm.get_tempo().wait() |
|
||||||
time.sleep(wait_ms / 1000.0) |
|
||||||
@ -1,35 +0,0 @@ |
|||||||
from lib.Program import Program |
|
||||||
from rpi_ws281x import Color |
|
||||||
import time |
|
||||||
|
|
||||||
|
|
||||||
def name(): |
|
||||||
return 'RGBT Gaynbow' |
|
||||||
|
|
||||||
|
|
||||||
def wheel(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) |
|
||||||
|
|
||||||
|
|
||||||
class Gaynbow(Program): |
|
||||||
def run(self, args: [] = None): |
|
||||||
wait_ms = 20 |
|
||||||
iterations = 5 |
|
||||||
while self.get_loop().status(): |
|
||||||
"""Draw rainbow that uniformly distributes itself across all pixels.""" |
|
||||||
for j in range(256 * iterations): |
|
||||||
if not self.get_loop().status(): |
|
||||||
break |
|
||||||
for i in range(self._lm.count_pixels()): |
|
||||||
self._lm.set_pixel_color(i, wheel( |
|
||||||
(int(i * 256 / self._lm.count_pixels()) + j) & 255)) |
|
||||||
self._lm.show() |
|
||||||
time.sleep(wait_ms / 1000.0) |
|
||||||
@ -1,22 +0,0 @@ |
|||||||
from lib.Program import Program |
|
||||||
import time |
|
||||||
|
|
||||||
|
|
||||||
def name(): |
|
||||||
return '1Hz tick' |
|
||||||
|
|
||||||
|
|
||||||
# Tick seconds like analog clock |
|
||||||
class HzTick(Program): |
|
||||||
def run(self, args: [] = None) -> None: |
|
||||||
tempo = self._lm.get_tempo() |
|
||||||
|
|
||||||
while self.get_loop().status(): |
|
||||||
second = time.localtime().tm_sec |
|
||||||
second_pixel = int(self._lm.count_pixels() / 60 * second) |
|
||||||
color_arr = args['color'] |
|
||||||
for i in range(self._lm.count_pixels()): |
|
||||||
self._lm.set_pixel_color(i, (color_arr[0] << 16) | (color_arr[1] << 8) | color_arr[2]) |
|
||||||
self._lm.set_pixel_color(second_pixel, 255) |
|
||||||
self._lm.show() |
|
||||||
tempo.wait() |
|
||||||
Loading…
Reference in new issue