593 lines
20 KiB
Python
593 lines
20 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
PTI LEDY - Raspberry Pi 4 port
|
|
Requires: sudo pip3 install rpi_ws281x flask
|
|
Run with: sudo python3 main.py
|
|
"""
|
|
|
|
import time
|
|
import random
|
|
import socket
|
|
import sys
|
|
|
|
from rpi_ws281x import PixelStrip, ws
|
|
|
|
import config
|
|
import low_level
|
|
import server
|
|
from fonts import FONT_7X5
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Strip init
|
|
# ---------------------------------------------------------------------------
|
|
strip = PixelStrip(
|
|
config.NUMPIXELS,
|
|
config.PIN,
|
|
freq_hz=800000,
|
|
dma=10,
|
|
invert=False,
|
|
brightness=255,
|
|
channel=0,
|
|
strip_type=ws.WS2811_STRIP_GRB,
|
|
)
|
|
strip.begin()
|
|
low_level.strip = strip
|
|
|
|
_udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
_udp_addr = ('127.0.0.1', 4210)
|
|
|
|
|
|
def _send_frame():
|
|
buf = bytearray(48 * 16 * 3)
|
|
off = 0
|
|
for y in range(16):
|
|
for x in range(48):
|
|
r, g, b = low_level.get_pixel_color(x, y)
|
|
buf[off] = r
|
|
buf[off + 1] = g
|
|
buf[off + 2] = b
|
|
off += 3
|
|
_udp_sock.sendto(buf, _udp_addr)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Global state
|
|
# ---------------------------------------------------------------------------
|
|
global_node_id = 0
|
|
|
|
text_nodes = [None] * config.MAX_TEXT_NODES_COUNT
|
|
multi_color_text_nodes = [None] * config.MAX_TEXT_NODES_COUNT
|
|
|
|
for i in range(config.MAX_TEXT_NODES_COUNT):
|
|
text_nodes[i] = {
|
|
'global_id': 0, 'content': '', 'color': (0, 0, 0),
|
|
'char_height': config.MEDIUM_TEXT_HEIGHT, 'char_width': config.MEDIUM_TEXT_WIDTH,
|
|
'pos_x': 0, 'pos_y': 0, 'character_count': 0,
|
|
'scroll_slowness': 0, 'scroll_progress': 0,
|
|
'disappear_time': 0, 'is_scrolling': True, 'is_repeating': False,
|
|
}
|
|
multi_color_text_nodes[i] = {
|
|
'global_id': 0, 'content': '', 'colors': [], # list of (r,g,b,start_index)
|
|
'char_height': config.MEDIUM_TEXT_HEIGHT, 'char_width': config.MEDIUM_TEXT_WIDTH,
|
|
'pos_x': 0, 'pos_y': 0, 'character_count': 0, 'color_count': 0,
|
|
'scroll_slowness': 0, 'scroll_progress': 0,
|
|
'disappear_time': 0, 'is_scrolling': True, 'is_repeating': False,
|
|
}
|
|
|
|
main_animation_started = False
|
|
bottom_text_state = 0
|
|
scroll_node_global_id = 0
|
|
scroll_node_active = False
|
|
|
|
top_text_node_global_id = 0
|
|
top_text_cycle_count = 0
|
|
|
|
program2_active = False
|
|
bottom_text_iteration_count = 0
|
|
program2_vehicles_spawned = 0
|
|
program2_drain_counter = 0
|
|
program2_done = False
|
|
program2_scroll_progress = 0
|
|
program2_spacing_counter = 0
|
|
program2_draw_col = 0
|
|
program2_current_vehicle = None
|
|
|
|
dvd_pending = False
|
|
dvd_active = False
|
|
dvd_x = 0
|
|
dvd_y = 0
|
|
dvd_dx = 1
|
|
dvd_dy = 1
|
|
dvd_iteration = 0
|
|
dvd_move_counter = 0
|
|
|
|
DVD_TEXT = "PTI"
|
|
DVD_TEXT_W = 17 # 3 chars * 5px + 2 gaps
|
|
DVD_TEXT_H = 7
|
|
DVD_MAX_X = config.DISPLAY_MAX_X - DVD_TEXT_W + 1 # 31
|
|
DVD_MAX_Y = config.DISPLAY_MAX_Y - DVD_TEXT_H + 1 # 9
|
|
DVD_COLOR = (0, 0, 50)
|
|
|
|
VEHICLES = [
|
|
[[0,0,0,0,0,0,0,0],[0,0,1,1,1,1,1,0],[1,1,1,1,1,1,1,1],[0,1,0,0,0,0,1,0]],
|
|
[[0,0,1,1,0,0,0,0],[0,1,1,1,0,0,0,0],[1,1,1,1,1,1,1,1],[0,1,0,0,0,0,1,0]],
|
|
[[0,0,1,1,0,1,1,1],[0,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1],[0,1,0,0,0,0,1,0]],
|
|
[[0,0,0,0,1,1,0,0],[0,0,1,1,1,1,1,0],[0,1,1,1,1,1,1,1],[0,0,1,0,0,0,1,0]],
|
|
[[0,0,0,0,0,0,0,0],[0,0,0,1,1,1,1,1],[0,0,1,1,1,1,1,1],[0,0,0,1,0,0,1,0]],
|
|
[[1,1,1,1,1,1,1,1],[0,1,0,1,0,1,0,1],[0,1,1,1,1,1,1,1],[0,0,1,0,0,0,1,0]],
|
|
[[0,0,0,0,0,0,0,0],[0,0,1,1,0,0,0,0],[1,1,1,1,1,1,1,1],[0,1,0,0,0,0,1,0]],
|
|
[[1,1,0,1,1,1,1,1],[1,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1],[0,1,0,0,0,0,1,0]],
|
|
[[0,0,0,1,1,1,1,1],[0,0,1,1,1,1,1,1],[1,1,1,1,1,1,1,1],[0,1,0,0,0,0,1,0]],
|
|
[[0,0,0,0,0,0,0,0],[0,1,1,1,0,0,0,1],[1,1,1,1,1,1,1,0],[0,1,0,0,0,1,0,0]],
|
|
[[0,1,0,1,1,1,1,1],[1,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1],[0,0,1,0,0,0,1,0]],
|
|
[[0,0,0,0,0,0,0,0],[0,0,0,0,0,1,1,0],[0,0,0,1,1,1,1,1],[0,0,0,0,1,0,1,0]],
|
|
]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def _get_text_node_x2(node):
|
|
if node['character_count'] == 0:
|
|
return node['pos_x']
|
|
return node['pos_x'] + (node['char_width'] * node['character_count']) + (node['character_count'] - 1) - 1
|
|
|
|
def _get_text_node_y2(node):
|
|
return node['pos_y'] + node['char_height'] - 1
|
|
|
|
def _color_for_char(r, g, b):
|
|
return (r, g, b)
|
|
|
|
def _add_text_node(content, color, pos_x, pos_y, scroll_slowness, is_scrolling, is_small, disappear_time, is_repeating):
|
|
global global_node_id
|
|
if not content:
|
|
return None
|
|
h = config.SMALL_TEXT_HEIGHT if is_small else config.MEDIUM_TEXT_HEIGHT
|
|
w = config.SMALL_TEXT_WIDTH if is_small else config.MEDIUM_TEXT_WIDTH
|
|
for node in text_nodes:
|
|
if node['disappear_time'] == 0:
|
|
node['content'] = content
|
|
node['color'] = color
|
|
node['pos_x'] = pos_x
|
|
node['pos_y'] = pos_y
|
|
node['char_height'] = h
|
|
node['char_width'] = w
|
|
node['character_count'] = len(content)
|
|
node['scroll_slowness'] = scroll_slowness
|
|
node['scroll_progress'] = 0
|
|
node['is_scrolling'] = is_scrolling
|
|
node['is_repeating'] = is_repeating
|
|
node['disappear_time'] = disappear_time
|
|
node['global_id'] = global_node_id
|
|
global_node_id += 1
|
|
return node
|
|
return None
|
|
|
|
def _add_multi_color_node(content, colors, pos_x, pos_y, scroll_slowness, is_scrolling, is_small, disappear_time, is_repeating):
|
|
global global_node_id
|
|
if not content:
|
|
return None
|
|
h = config.SMALL_TEXT_HEIGHT if is_small else config.MEDIUM_TEXT_HEIGHT
|
|
w = config.SMALL_TEXT_WIDTH if is_small else config.MEDIUM_TEXT_WIDTH
|
|
for node in multi_color_text_nodes:
|
|
if node['disappear_time'] == 0:
|
|
node['content'] = content
|
|
node['colors'] = list(colors)
|
|
node['color_count'] = len(colors)
|
|
node['pos_x'] = pos_x
|
|
node['pos_y'] = pos_y
|
|
node['char_height'] = h
|
|
node['char_width'] = w
|
|
node['character_count'] = len(content)
|
|
node['scroll_slowness'] = scroll_slowness
|
|
node['scroll_progress'] = 0
|
|
node['is_scrolling'] = is_scrolling
|
|
node['is_repeating'] = is_repeating
|
|
node['disappear_time'] = disappear_time
|
|
node['global_id'] = global_node_id
|
|
global_node_id += 1
|
|
return node
|
|
return None
|
|
|
|
def _is_node_existing(gid):
|
|
for node in text_nodes:
|
|
if node['global_id'] == gid and node['disappear_time'] != 0:
|
|
return True
|
|
for node in multi_color_text_nodes:
|
|
if node['global_id'] == gid and node['disappear_time'] != 0:
|
|
return True
|
|
return False
|
|
|
|
def _reset_global_id():
|
|
global global_node_id
|
|
global_node_id = 2
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Drawing
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def _draw_char(ch, height, width, r, g, b, cursor):
|
|
if ord(ch) < ord('!') or ord(ch) > ord('~'):
|
|
ch = ' '
|
|
glyph = FONT_7X5[ord(ch) - ord(' ')]
|
|
low_level.draw_character(glyph, height, width, r, g, b, cursor)
|
|
|
|
def scroll_all_texts(split_scroll_mode=False):
|
|
for node in text_nodes:
|
|
if node['disappear_time'] == 0:
|
|
continue
|
|
if node['is_scrolling']:
|
|
if node['scroll_slowness'] > node['scroll_progress']:
|
|
node['scroll_progress'] += 1
|
|
else:
|
|
node['scroll_progress'] = 0
|
|
x2 = _get_text_node_x2(node)
|
|
if split_scroll_mode or node['pos_y'] >= 7:
|
|
if x2 < 0:
|
|
if node['is_repeating']:
|
|
node['pos_x'] = config.DISPLAY_MAX_X
|
|
else:
|
|
node['disappear_time'] = 1
|
|
continue
|
|
node['pos_x'] -= 1
|
|
else:
|
|
if node['pos_x'] > config.DISPLAY_MAX_X:
|
|
if node['is_repeating']:
|
|
node['pos_x'] = -x2 + node['pos_x']
|
|
else:
|
|
node['disappear_time'] = 1
|
|
continue
|
|
node['pos_x'] += 1
|
|
|
|
cursor = {'x': node['pos_x'], 'y': node['pos_y']}
|
|
r, g, b = node['color']
|
|
for ch in node['content']:
|
|
_draw_char(ch, node['char_height'], node['char_width'], r, g, b, cursor)
|
|
|
|
def scroll_all_multi_color_texts(split_scroll_mode=False):
|
|
for node in multi_color_text_nodes:
|
|
if node['disappear_time'] == 0:
|
|
continue
|
|
if node['is_scrolling']:
|
|
if node['scroll_slowness'] > node['scroll_progress']:
|
|
node['scroll_progress'] += 1
|
|
else:
|
|
node['scroll_progress'] = 0
|
|
x1 = node['pos_x']
|
|
x2 = x1 + (node['char_width'] * node['character_count']) + (node['character_count'] - 1) - 1
|
|
if split_scroll_mode or node['pos_y'] >= 7:
|
|
if x2 < 0:
|
|
if node['is_repeating']:
|
|
node['pos_x'] = config.DISPLAY_MAX_X
|
|
else:
|
|
node['disappear_time'] = 1
|
|
continue
|
|
node['pos_x'] -= 1
|
|
else:
|
|
if x1 > config.DISPLAY_MAX_X:
|
|
if node['is_repeating']:
|
|
node['pos_x'] = -x2 + x1
|
|
else:
|
|
node['disappear_time'] = 1
|
|
continue
|
|
node['pos_x'] += 1
|
|
|
|
cursor = {'x': node['pos_x'], 'y': node['pos_y']}
|
|
color_index = 0
|
|
r, g, b, _ = node['colors'][0]
|
|
for j, ch in enumerate(node['content']):
|
|
if color_index < node['color_count'] - 1 and node['colors'][color_index + 1][3] == j:
|
|
color_index += 1
|
|
r, g, b, _ = node['colors'][color_index]
|
|
_draw_char(ch, node['char_height'], node['char_width'], r, g, b, cursor)
|
|
|
|
def handle_disappear_timers():
|
|
for node in text_nodes:
|
|
if node['disappear_time'] > 0:
|
|
node['disappear_time'] -= 1
|
|
if node['disappear_time'] == 0:
|
|
low_level.fill_pixels(
|
|
node['pos_x'], node['pos_y'],
|
|
_get_text_node_x2(node), _get_text_node_y2(node),
|
|
0, 0, 0
|
|
)
|
|
|
|
def handle_multi_color_disappear_timers():
|
|
for node in multi_color_text_nodes:
|
|
if node['disappear_time'] > 0:
|
|
node['disappear_time'] -= 1
|
|
if node['disappear_time'] == 0:
|
|
x2 = node['pos_x'] + (node['char_width'] * node['character_count']) + (node['character_count'] - 1) - 1
|
|
low_level.fill_pixels(
|
|
node['pos_x'], node['pos_y'],
|
|
x2, node['pos_y'] + node['char_height'] - 1,
|
|
0, 0, 0
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Programs
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def handle_program1():
|
|
global main_animation_started, scroll_node_active, scroll_node_global_id
|
|
global bottom_text_state, bottom_text_iteration_count, program2_active
|
|
global top_text_node_global_id, top_text_cycle_count
|
|
global dvd_pending, dvd_active
|
|
|
|
s = server.state
|
|
|
|
# --- DVD active: handled entirely in loop() ---
|
|
if dvd_active:
|
|
return
|
|
|
|
# --- DVD pending: wait for bottom area to clear ---
|
|
if dvd_pending:
|
|
if scroll_node_active and not _is_node_existing(scroll_node_global_id):
|
|
scroll_node_active = False
|
|
if not scroll_node_active and not program2_active:
|
|
dvd_pending = False
|
|
dvd_active = True
|
|
reset_dvd()
|
|
low_level.fill_pixels(0, 0, config.DISPLAY_MAX_X, config.DISPLAY_MAX_Y, 0, 0, 0)
|
|
return
|
|
|
|
# --- Top text management ---
|
|
if not s['program_top_text_enabled']:
|
|
for node in multi_color_text_nodes:
|
|
if node['disappear_time'] != 0:
|
|
node['disappear_time'] = 1
|
|
main_animation_started = False
|
|
elif not main_animation_started:
|
|
if not _is_node_existing(0) and not _is_node_existing(1):
|
|
main_animation_started = True
|
|
node = _add_multi_color_node(
|
|
"Witamy w PTI",
|
|
[(40, 40, 40, 0), (0, 0, 50, 9)],
|
|
0, 0, 3, True, True, -1, False
|
|
)
|
|
if node:
|
|
top_text_node_global_id = node['global_id']
|
|
elif not _is_node_existing(top_text_node_global_id):
|
|
# Top text cycle ended
|
|
top_text_cycle_count += 1
|
|
|
|
force_dvd = s.get('force_dvd', False)
|
|
if force_dvd:
|
|
with server._lock:
|
|
server.state['force_dvd'] = False
|
|
|
|
if force_dvd or (top_text_cycle_count >= config.DVD_TOP_TEXT_CYCLES
|
|
and random.randint(0, 99) < config.DVD_TRIGGER_CHANCE):
|
|
top_text_cycle_count = 0
|
|
dvd_pending = True
|
|
main_animation_started = False
|
|
return
|
|
|
|
# Re-add top text from right edge
|
|
node = _add_multi_color_node(
|
|
"Witamy w PTI",
|
|
[(40, 40, 40, 0), (0, 0, 50, 9)],
|
|
config.DISPLAY_MAX_X, 0, 3, True, True, -1, False
|
|
)
|
|
if node:
|
|
top_text_node_global_id = node['global_id']
|
|
|
|
# --- Bottom text management ---
|
|
if not s['program_bottom_text_enabled']:
|
|
if scroll_node_active:
|
|
for node in text_nodes:
|
|
if node['disappear_time'] != 0:
|
|
node['disappear_time'] = 1
|
|
scroll_node_active = False
|
|
if program2_active:
|
|
program2_active = False
|
|
return
|
|
|
|
if program2_active:
|
|
return
|
|
|
|
if (main_animation_started or not s['program_top_text_enabled']) and \
|
|
(not scroll_node_active or not _is_node_existing(scroll_node_global_id)):
|
|
|
|
if scroll_node_active:
|
|
bottom_text_iteration_count += 1
|
|
scroll_node_active = False
|
|
force = s.get('force_vehicles', False)
|
|
if s['program_vehicles_enabled'] and (force or bottom_text_iteration_count >= config.PROGRAM2_TEXT_ITERATIONS):
|
|
if force or random.randint(0, 99) < config.PROGRAM2_TRIGGER_CHANCE:
|
|
if force:
|
|
with server._lock:
|
|
server.state['force_vehicles'] = False
|
|
bottom_text_iteration_count = 0
|
|
program2_active = True
|
|
reset_program2()
|
|
low_level.fill_pixels(0, 9, config.DISPLAY_MAX_X, config.DISPLAY_MAX_Y, 0, 0, 0)
|
|
return
|
|
|
|
texts = [
|
|
("Technik informatyk + ai, robotyka", (0, 0, 50)),
|
|
("Technik programista", (50, 40, 0)),
|
|
("Technik poligrafii i grafiki komputerowej", (0, 45, 0)),
|
|
("Technik reklamy", (60, 20, 0)),
|
|
]
|
|
text, color = texts[bottom_text_state]
|
|
node = _add_text_node(text, color, config.DISPLAY_MAX_X, 9, 1, True, True, -1, False)
|
|
if node is not None:
|
|
scroll_node_global_id = node['global_id']
|
|
scroll_node_active = True
|
|
bottom_text_state = (bottom_text_state + 1) % 4
|
|
|
|
|
|
def reset_dvd():
|
|
global dvd_x, dvd_y, dvd_dx, dvd_dy, dvd_iteration, dvd_move_counter
|
|
dvd_x = random.randint(0, DVD_MAX_X)
|
|
dvd_y = random.randint(0, DVD_MAX_Y)
|
|
dvd_dx = random.choice([-1, 1])
|
|
dvd_dy = random.choice([-1, 1])
|
|
dvd_iteration = 0
|
|
dvd_move_counter = 0
|
|
|
|
|
|
def handle_dvd():
|
|
global dvd_x, dvd_y, dvd_dx, dvd_dy, dvd_iteration, dvd_move_counter
|
|
global dvd_active, main_animation_started
|
|
|
|
if dvd_iteration >= config.DVD_ITERATIONS:
|
|
dvd_active = False
|
|
main_animation_started = False
|
|
return
|
|
|
|
dvd_iteration += 1
|
|
|
|
dvd_move_counter += 1
|
|
if dvd_move_counter >= 2:
|
|
dvd_move_counter = 0
|
|
|
|
new_x = dvd_x + dvd_dx
|
|
new_y = dvd_y + dvd_dy
|
|
|
|
if new_x < 0 or new_x > DVD_MAX_X:
|
|
dvd_dx = -dvd_dx
|
|
new_x = dvd_x + dvd_dx
|
|
if new_y < 0 or new_y > DVD_MAX_Y:
|
|
dvd_dy = -dvd_dy
|
|
new_y = dvd_y + dvd_dy
|
|
|
|
dvd_x = new_x
|
|
dvd_y = new_y
|
|
|
|
cursor = {'x': dvd_x, 'y': dvd_y}
|
|
for ch in DVD_TEXT:
|
|
_draw_char(ch, config.SMALL_TEXT_HEIGHT, config.SMALL_TEXT_WIDTH, *DVD_COLOR, cursor)
|
|
|
|
|
|
def draw_vehicle(index, pos_x, pos_y):
|
|
vr, vg, vb = config.VEHICLE_COLOR
|
|
for row in range(4):
|
|
for col in range(8):
|
|
if VEHICLES[index][row][col]:
|
|
low_level.set_pixel(pos_x + col, pos_y + row, vr, vg, vb)
|
|
|
|
|
|
def reset_program2():
|
|
global program2_scroll_progress, program2_spacing_counter
|
|
global program2_vehicles_spawned, program2_drain_counter, program2_done
|
|
global program2_draw_col, program2_current_vehicle
|
|
program2_scroll_progress = 0
|
|
program2_spacing_counter = 0
|
|
program2_vehicles_spawned = 0
|
|
program2_drain_counter = 0
|
|
program2_done = False
|
|
program2_draw_col = 0
|
|
program2_current_vehicle = None
|
|
|
|
|
|
def handle_program2(spacing=4, scroll_slowness=1, y=0, max_vehicles=0):
|
|
global program2_scroll_progress, program2_spacing_counter
|
|
global program2_vehicles_spawned, program2_drain_counter, program2_done
|
|
global program2_draw_col, program2_current_vehicle
|
|
|
|
if scroll_slowness > program2_scroll_progress:
|
|
program2_scroll_progress += 1
|
|
return
|
|
program2_scroll_progress = 0
|
|
|
|
low_level.shift_rectangle_left(0, y, config.DISPLAY_MAX_X, y + 3, 1)
|
|
|
|
if max_vehicles > 0 and program2_vehicles_spawned >= max_vehicles:
|
|
program2_drain_counter += 1
|
|
if program2_drain_counter >= config.DISPLAY_MAX_X + 1:
|
|
program2_done = True
|
|
return
|
|
|
|
if program2_spacing_counter > 0:
|
|
program2_spacing_counter -= 1
|
|
return
|
|
|
|
veh = VEHICLES[random.randint(0, 11)] if program2_draw_col == 0 else program2_current_vehicle
|
|
if program2_draw_col == 0:
|
|
program2_current_vehicle = veh
|
|
|
|
vr, vg, vb = config.VEHICLE_COLOR
|
|
for row in range(4):
|
|
if veh[row][program2_draw_col]:
|
|
low_level.set_pixel(config.DISPLAY_MAX_X, y + row, vr, vg, vb)
|
|
|
|
program2_draw_col += 1
|
|
if program2_draw_col >= 8:
|
|
program2_draw_col = 0
|
|
program2_spacing_counter = spacing
|
|
if max_vehicles > 0:
|
|
program2_vehicles_spawned += 1
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Main loop
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def setup():
|
|
strip.setBrightness(255)
|
|
for i in range(config.NUMPIXELS):
|
|
strip.setPixelColor(i, 0)
|
|
strip.show()
|
|
server.start_server(port=80)
|
|
print("Server started. Running display loop.")
|
|
|
|
|
|
def loop():
|
|
global program2_active
|
|
|
|
s = server.state
|
|
|
|
if dvd_active:
|
|
low_level.fill_pixels(0, 0, config.DISPLAY_MAX_X, config.DISPLAY_MAX_Y, 0, 0, 0)
|
|
handle_dvd()
|
|
strip.show()
|
|
_send_frame()
|
|
return
|
|
|
|
low_level.fill_pixels(0, 0, config.DISPLAY_MAX_X, 7, 0, 0, 0)
|
|
handle_program1()
|
|
|
|
if dvd_active:
|
|
strip.show()
|
|
_send_frame()
|
|
return
|
|
|
|
if s['program_top_text_enabled']:
|
|
scroll_all_multi_color_texts(split_scroll_mode=True)
|
|
handle_multi_color_disappear_timers()
|
|
|
|
if not s['program_bottom_text_enabled']:
|
|
if program2_active:
|
|
program2_active = False
|
|
low_level.fill_pixels(0, 9, config.DISPLAY_MAX_X, config.DISPLAY_MAX_Y, 0, 0, 0)
|
|
elif program2_active and not s['program_vehicles_enabled']:
|
|
program2_active = False
|
|
low_level.fill_pixels(0, 9, config.DISPLAY_MAX_X, config.DISPLAY_MAX_Y, 0, 0, 0)
|
|
elif program2_active:
|
|
handle_program2(spacing=4, scroll_slowness=1, y=12, max_vehicles=config.PROGRAM2_VEHICLE_COUNT)
|
|
if program2_done:
|
|
program2_active = False
|
|
low_level.fill_pixels(0, 9, config.DISPLAY_MAX_X, config.DISPLAY_MAX_Y, 0, 0, 0)
|
|
else:
|
|
low_level.fill_pixels(0, 9, config.DISPLAY_MAX_X, config.DISPLAY_MAX_Y, 0, 0, 0)
|
|
scroll_all_texts(split_scroll_mode=True)
|
|
handle_disappear_timers()
|
|
|
|
strip.show()
|
|
_send_frame()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
setup()
|
|
try:
|
|
while True:
|
|
loop()
|
|
time.sleep(0.02) # ~50 fps
|
|
except KeyboardInterrupt:
|
|
for i in range(config.NUMPIXELS):
|
|
strip.setPixelColor(i, 0)
|
|
strip.show()
|
|
print("\nStopped.")
|
|
sys.exit(0)
|