forked from pvx/litsimaja
Compare commits
16 Commits
Author | SHA1 | Date |
---|---|---|
|
33109455c9 | 4 years ago |
|
103e04a1b4 | 4 years ago |
|
86dd419080 | 4 years ago |
|
0a5e1a3a5d | 4 years ago |
|
74b6cbe7e3 | 4 years ago |
|
e6fb8ea528 | 4 years ago |
|
0d59414104 | 4 years ago |
|
3fa0bc376f | 4 years ago |
|
b3240631f6 | 4 years ago |
|
76759f986b | 4 years ago |
|
57559ea70a | 4 years ago |
|
1b3b23bc99 | 4 years ago |
|
d135c8c24f | 4 years ago |
|
bdcfdb9a9f | 4 years ago |
|
810fefe323 | 4 years ago |
|
4be70b9c31 | 4 years ago |
15 changed files with 415 additions and 72 deletions
@ -0,0 +1,17 @@ |
||||
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 |
@ -0,0 +1,2 @@ |
||||
ENVIRONMENT=dev |
||||
USE_EMULATOR=true |
@ -1 +1,2 @@ |
||||
.env |
||||
litsimaja.log |
||||
|
@ -0,0 +1,38 @@ |
||||
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] |
@ -0,0 +1,38 @@ |
||||
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 |
@ -0,0 +1,45 @@ |
||||
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 |
@ -0,0 +1,35 @@ |
||||
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) |
@ -0,0 +1,22 @@ |
||||
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