""" 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)