initial commit

- added readme
- added recharge scripts
- added dots simple test script
- added images, transitions and animations script
This commit is contained in:
KS_HTK 2025-08-20 23:15:15 +02:00
commit 666a377e32
Signed by: KS_HTK
GPG key ID: B78139943FC60E2D
7 changed files with 404 additions and 0 deletions

199
images.py Normal file
View file

@ -0,0 +1,199 @@
"""
This file contains animations, stillframes and transitions that can be imported elsewhere.
When running this file it will randomly select a transition and a frame to transition to indefinitly.
"""
# requires: python-fluepdot, python-dotenv
import os
from dotenv import load_dotenv
from src.fluepdot.fluepdot import Fluepdot, Mode
from random import choice, sample
from itertools import product
from time import sleep
from typing import List
DELAY = 5 # hold time for completed animations/frames
ANIMATION_DELAY = 0.1 # delay between frames of animations
flipdot_logo = [
" XXXXXX ",
" XX X ",
" X X ",
" X X ",
" X XX ",
"X X",
"X X X X",
"X X X X X",
"X X XXX X",
"X XXX X X X",
"X X X X X",
" X X XXX X ",
" X X ",
" X X ",
" XX XX ",
" XXXXXX ",
]
fd1 = Fluepdot(f"http://{ip1}")
#fd2 = Fluepdot(f"http://{ip2}", flipped=True)
def checkerboard(len_x: int, len_y: int, invert: bool = False) -> List[List[bool]]:
return [[(j+i+invert)%2==0 for i in range(len_x)] for j in range(len_y)]
def droplet(fd: Fluepdot):
max_x, max_y = fd.get_size()
fd.set_mode(Mode.DIFFERENTIAL)
frame = [[False for _ in range(max_x)] for _ in range(max_y)]
cx, cy = max_x//2-.5, max_y//2-.5
r = 0
while r < cx+32:
for y in range(max_y):
for x in range(int(cx-r-2), int(cx+r+3)):
if not (0 <= x < max_x and 0 <= y < max_y):
continue
frame[y][x] = False
dist = ((x-cx)**2+(y-cy)**2)**.5
for l in range(5):
if r-1-(l**1.4)*4 < dist < r+1-(l**1.4)*4:
frame[y][x] = True
break
r+=2
if r > 36:
fd_logo_width = len(flipdot_logo[0])
s = int(cx+1 - fd_logo_width//2)
e = s + fd_logo_width
for y in range(max_y):
for x in range(s, e):
frame[y][x] = flipdot_logo[y][x-s] == "X" or frame[y][x]
sleep(ANIMATION_DELAY)
fd.post_frame(frame)
def fd_logo(fd: Fluepdot) -> List[List[bool]]:
fd.post_text("flipdot e.V.", x=7, y=0, font="fixed_7x14")
original_frame = fd.get_frame()
frame = []
for lrow, frow in zip(flipdot_logo, original_frame):
new_row = frow[:-(len(lrow)+2)]+lrow+frow[-2:]
frame.append(new_row)
return [[c=="X" for c in row] for row in frame]
def kurhacken(fd: Fluepdot) -> List[List[bool]]:
fd.post_text("Kurhecken", x=14, y=-2, font="fixed_10x20")
frame = [[c=="X" for c in row] for row in fd.get_frame()]
fd.set_mode(Mode.DIFFERENTIAL)
for x, y in [(56, 4),(57, 4),(60, 4),(61, 4),(56, 3),(57, 3),(60, 3),(61, 3)]:
frame[y][x] = True
return frame
def event37c3(fd: Fluepdot) -> List[List[bool]]:
fd.post_text("37c3Unlocked", x=-1, y=-1, font="DejaVuSerif16")
frame = [[c=="X" for c in row] for row in fd.get_frame()]
return frame
def event38c3(fd: Fluepdot) -> List[List[bool]]:
fd.post_text("38C3 Illegal Instructions", font="DejaVuSerif16")
frame = [[c=="X" for c in row] for row in fd.get_frame()]
return frame
def hackumenta(fd: Fluepdot) -> List[List[bool]]:
fd.post_text("Hackumenta", x=3, y=-1, font="DejaVuSerif16")
frame = [[c=="X" for c in row] for row in fd.get_frame()]
return frame
def wipe_to(fd: Fluepdot, frame: List[List[bool]]):
fd.set_mode(Mode.DIFFERENTIAL)
current = [[c=="X" for c in row] for row in fd.get_frame()]
for i in range(0, len(current[0])):
for j in range(len(current)):
current[j][i] = frame[j][i]
if i+1 < len(current[0]):
current[j][i+1] = True
sleep(ANIMATION_DELAY)
fd.post_frame(current)
def dither_to(fd: Fluepdot, frame: List[List[bool]]):
fd.set_mode(Mode.DIFFERENTIAL)
max_x, max_y = fd.get_size()
current = [[c=="X" for c in row] for row in fd.get_frame()]
coords = [(x,y) for x, y in product(range(max_x), range(max_y)) if current[y][x] != frame[y][x]]
while coords:
sleep(ANIMATION_DELAY)
x, y = choice(coords)
coords.remove((x, y))
if frame[y][x]:
r = fd.set_pixel(x, y)
if r.status_code != 200:
print(r.text)
else:
r = fd.unset_pixel(x, y)
if r.status_code != 200:
print(r.text)
def push_to(fd: Fluepdot, frame: List[List[bool]]):
fd.set_mode(Mode.DIFFERENTIAL)
current = [[c=="X" for c in row] for row in fd.get_frame()]
while True:
sleep(max(ANIMATION_DELAY, 1))
for crow, frow in zip(current, frame):
for _ in range(3):
crow.insert(0, frow.pop(-1))
crow.pop(-1)
if frow:
continue
else:
break
else:
fd.post_frame(current)
continue
break
def roll_to(fd: Fluepdot, frame: List[List[bool]]):
fd.set_mode(Mode.DIFFERENTIAL)
current = [[c=="X" for c in row] for row in fd.get_frame()]
while frame:
sleep(max(ANIMATION_DELAY, 1.5))
current.insert(0, frame.pop())
current.pop()
fd.post_frame(current)
if __name__ == "__main__":
load_dotenv()
hostname = os.getenv("DOTS_HOST")
fd = Fluepdot(f"http://{hostname}")
fd1.clear()
animations = [
droplet,
]
transitions = [
wipe_to,
dither_to,
push_to,
roll_to,
]
stillframes = [
kurhacken(fd), # Text endpoint
checkerboard(*fd.get_size(), invert=False), # Frame endpoint
[[True]*115]*16,
[[False]*115]*16,
#event37c3(fd), # Text endpoint
event38c3(fd), # Text endpoint
hackumenta(fd),
fd_logo(fd), # Text endpoint
]
#for i, f in enumerate(stillframes):
# print(i, len(f), [len(g) for g in f])
current = stillframes[1]
while True:
sf = sample(stillframes, k=1)[0]
tr = choice(transitions)
if sf == current:
print("Skipping same frame")
continue
print(tr.__name__)
current = sf
tr(fd, sf)
sleep(DELAY)