diff --git a/Color.py b/Color.py new file mode 100644 index 0000000000000000000000000000000000000000..ac2c96ea49143005ce9d3f293112e46983687075 --- /dev/null +++ b/Color.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- + +# -*- coding: utf-8 -*- + +import colorsys +import numpy + +class Color(object): + @staticmethod + def hex_to_rgb(hex): + """Turns a hex value #123456 into rgb (18, 52, 86)""" + return tuple(int(hex[i:i+2], 16) for i in (0, 2 ,4)) + + red = 0 + green = 0 + blue = 0 + + hue = 0 + saturation = 0 + value = 0 + + def __init__(self, rgb=None, hsv=None, hex=None): + + rgb_passed = type(rgb) is tuple + hsv_passed = type(hsv) is tuple + hex_passed = type(hex) is str + + if rgb_passed and hsv_passed and hex_passed: + raise ValueError("Color can't be initialized with RGB, HSV and Hex at the same time.") + elif hsv_passed: + hue, saturation, value = hsv + + if not hue: + hue = 0.0 + if not saturation: + saturation = 0.0 + if not value: + value = 0.0 + + self.hue = hue + self.saturation = saturation + self.value = value + elif rgb_passed: + red, green, blue = rgb + + if not red: + red = 0 + if not green: + green = 0 + if not blue: + blue = 0 + + self.red = red + self.green = green + self.blue = blue + elif hex_passed: + red, green, blue = Color.hex_to_rgb(hex) + + self.red = red + self.green = green + self.blue = blue + else: + raise ValueError("No format was specified (RGB, HSV, Hex)") + + def _update_hsv(self): + hue, saturation, value = colorsys.rgb_to_hsv(self.red/255.0, self.green/255.0, self.blue/255.0) + super(Color, self).__setattr__('hue', hue * 360.0) + super(Color, self).__setattr__('saturation', saturation) + super(Color, self).__setattr__('value', value) + + def _update_rgb(self): + red, green, blue = colorsys.hsv_to_rgb(self.hue / 360.0, self.saturation, self.value) + super(Color, self).__setattr__('red', red * 255.0) + super(Color, self).__setattr__('green', green * 255.0) + super(Color, self).__setattr__('blue', blue * 255.0) + + def __setattr__(self, key, value): + if key in ('red', 'green', 'blue'): + if value > 255.0: + value = value % 255.0 + super(Color, self).__setattr__(key, value) + self._update_hsv() + + elif key in ('hue', 'saturation', 'value'): + if key == 'hue' and (value >= 360.0 or value < 0): + value = value % 360.0 + elif key != 'hue' and value > 1.0: + value = 1.0 + super(Color, self).__setattr__(key, value) + self._update_rgb() + else: + super(Color, self).__setattr__(key, value) + + def __repr__(self): + return '<%s: red %f, green %f, blue %f, hue %f, saturation %f, value %f>' % ( + self.__class__.__name__, + self.red, + self.green, + self.blue, + self.hue, + self.saturation, + self.value, + ) + + def __str__(self): + return "%d %d %d" % ( + int(self.red), + int(self.green), + int(self.blue), + ) + + def copy(self): + return Color(self.red, self.green, self.blue) + + def hex(self): + return "%.2X%.2X%.2X" % (self.red, self.green, self.blue) + + def rgb_tuple(self, p_int=False): + if p_int: + return (int(self.red), int(self.green), int(self.blue)) + else: + return (self.red, self.green, self.blue) diff --git a/animation.py b/animation.py new file mode 100644 index 0000000000000000000000000000000000000000..a783fe1a21089194fe1d0e8638c2bae072ef5fcd --- /dev/null +++ b/animation.py @@ -0,0 +1,76 @@ +import time +from threading import Thread +from blinkenfoo import DMX, WARP_SIGN, SPHERES, PANEL, CUBES + +class Animation(Thread): + """ + An animation describes transition of pixels on various blinkenfoos. The + blinkenfoo can not be changed after the animation has been initialized. It + is possible to start an animation with a different blinkenroom everytime. + """ + + required_args = {} + + def __init__(self): + Thread.__init__(self) + self.name = None + self.args = None + self.blinkenroom = None + self._frame = None + self._fps = 0 + self._time_should = 0 + self._currently_adjusted_for = None + self._running = False + self._paused = False + self._last_cycle = time.time() + + self.set_fps(30) + + def set_args(self, p_args): + self.args = p_args + + def calc_devices_adjusted_fps(self, p_fps): + for device in self.blinkenroom.device_list: + device.calc_fps(p_fps) + + def adjust_fps_for_device(self, p_device): + adjusted_fps = p_device.current_fps + if not self._currently_adjusted_for == p_device: + self.set_fps(adjusted_fps) + self._currently_adjusted_for = p_device + + def adjust_fps_for_index(self, p_index): + device = self.blinkenroom.get_device_by_index(p_index) + self.adjust_fps_for_device(device) + + def cycle(self): + pass + + def set_fps(self, p_fps): + self._fps = p_fps + self._time_should = 1 / float(self._fps) + + def run(self): + """ + Code stolen from olel + """ + self._running = True + while self._running: + if self._paused: + continue + self.cycle() + if self._fps: + time_spend = time.time() - self._last_cycle + sleep_time = self._time_should - time_spend + if sleep_time > 0: + time.sleep(sleep_time) + self._last_cycle = time.time() + + def stop(self): + self._running = False + + def pause(self): + self._paused = True + + def resume(self): + self._paused = False diff --git a/animation_handler.py b/animation_handler.py new file mode 100644 index 0000000000000000000000000000000000000000..1ab1f55837509991420887fe96daca095a9def8f --- /dev/null +++ b/animation_handler.py @@ -0,0 +1,108 @@ +from animation import Animation +from blinkenroom import Blinkenroom +import blinkenroom +import animation +import time +from darken import darken + +class AnimationHandler(object): + + ERROR_ANIMATION_RUNNING = 100 + ERROR_ANIMATION_NOT_FOUND = 101 + ERROR_OVERLAPPING = 102 + + def __init__(self): + self.running_animations = {} + self.known_animations = {} + self.last_frame = None + + ####################### + ###Animation control### + ###################### + + def stop_animation(self, p_name): + if p_name in self.running_animations: + animation = self.running_animations[p_name] + print("Stopping %s" % p_name) + animation.stop() + del self.running_animations[p_name] + + def stop_all_animations(self, p_args=None): + for running in self.running_animations.values(): + running.stop() + self.running_animations = {} + self.last_frame = blinkenroom.BLINKENROOM_LOUNGE.get_last_frame() + + def pause_animation(self, p_animation_name): + if p_animation_name in self.running_animations: + animation = self.running_animations[p_animation_name] + animation.pause() + + def pause_all_animations(self): + for animation in self.running_animations.values(): + animation.pause() + + def resume_animation(self, p_animation_name): + if p_animation_name in self.running_animations: + animation = self.running_animations[p_animation_name] + animation.resume() + + def resume_all_animations(self): + for animation in self.running_animations.values(): + animation.resume() + + def start_animation(self, p_name, p_animation_args): + #def start_animation(self, p_name): + p_name = p_name.lower() + + #if p_name in self.running_animations: + # print("Animation already running") + # return self.ERROR_ANIMATION_RUNNING + + animation_class = None + try: + exec("from %s import %s" % (p_name, p_name)) + animation_class = eval(p_name) + except ImportError: + print("Animation not found '%s'" % p_name) + return self.ERROR_ANIMATION_NOT_FOUND + + animation = animation_class() + required_args = animation.required_args + for arg in required_args: + required = required_args[arg] + if arg not in p_animation_args: + p_animation_args[arg] = required[1] + else: + casting_method = required[0] + current_arg = p_animation_args[arg] + p_animation_args[arg] = casting_method(current_arg) + + animation.set_args(p_animation_args) + animation.init_animation() + to_stop = [] + for running in self.running_animations.values(): + if animation.blinkenroom.is_overlapping(running.blinkenroom): + to_stop.append(running.name) + + for running in to_stop: + self.stop_animation(running) + + self.running_animations[p_name] = animation + animation.start() + + ################# + ###Light-Level### + ################# + + def darken(self, p_args): + self.stop_all_animations() + darken_dicts = { + "frame": self.last_frame, + "rate": 30, + "steps": 100 + } + animation = darken() + animation.set_args(darken_dicts) + animation.init_animation() + animation.start() diff --git a/blinkenfoo.py b/blinkenfoo.py new file mode 100644 index 0000000000000000000000000000000000000000..a73b209af6c2b78ac76ce76bfba41ddc675d8669 --- /dev/null +++ b/blinkenfoo.py @@ -0,0 +1,145 @@ +import socket +from Color import Color + +STANDARD_WIDTH = 3.5 + +COLOR_BLACK = Color((0, 0, 0)) + +class Blinkenfoo(object): + """This class represents a blinkenfoo instance. + A blinkenfoo can display information send via upd and can listen to mqtt to play + preconfigured animations. It als knows how many pixels it has: + A pixel is one blinken-unit which can be controlled separately from the other + units. A pixel can be a single LED on a i.E. ws2812 or a whole stripe. + If the blinkenfoo is a led matrix then the pixel count is a*b. + The physical width describes the width in cm of one blinkenunit/pixel. This is + to make animations run the same speed on different blinkenfoo devices""" + + def __init__(self, p_name, p_udp_host, p_length, p_physikal_width = STANDARD_WIDTH, p_udp_port = 2390, p_brightness = 100): + self.name = p_name + self.udp_host = p_udp_host + self.udp_port = p_udp_port + + self.length = p_length + self.physikal_width = p_physikal_width + self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.buffer = None + self._reset_buffer() + + self.current_fps = None + if p_brightness < 100: + self.brightness_factor = (100.0 / p_brightness) + else: + self.brightness_factor = 1 + + def _split_to_byte(self, p_number): + """ + Splits an integer into an array of two bytes. the lower bytes are in [1] + """ + return [(p_number >> 8) & 0xFF, p_number & 0xFF] + #return [0, p_number] + + def _generate_package(self, startpixel, endpixel, rgb): + """ Generates a udp package the blinkenfoo understands""" + pack = bytearray() + pack.extend(self._split_to_byte(startpixel)) + pack.extend(self._split_to_byte(endpixel)) + for color in rgb: + r, g, b = color + pack.extend([r, g, b]) + return pack + + + def _send_package(self, p_package): + """Sends the given udp_package to this's host:port""" + try: + self.udp_socket.sendto(p_package, (self.udp_host, self.udp_port)) + except socket.error: + pass + + def _reset_buffer(self): + """ + Sets the content of the buffer to black. + """ + self.buffer = [COLOR_BLACK for _ in range(self.length)] + + #################### + ###Public methods### + #################### + + def is_reachable(self): + """ + Checks wether a blinkenfoo is reachable or not. sends a dummy package. + """ + rgb_frame = [(0, 0, 0) for _ in range(self.length)] + package = self._generate_package(0, 1, [(0, 0, 0)]) + try: + self.udp_socket.sendto(package, (self.udp_host, self.udp_port)) + return True + except socket.error: + return False + + def calc_fps(self, p_fps): + """ + Calculates fps according to this blinkenfoo width in order for an + animation to run the same "speed" on every device. + """ + return STANDARD_WIDTH * p_fps / self.physikal_width + + def send_frame(self, p_frame): + """ + Sends an frame to the blinkenfoo. A frame is a list of color objects. + Other types may cause erros later in the programm. The length of the + frame must match the pixel count of this blinkenfoo. + """ + length = len(p_frame) + if length == self.length: + rgb_frame = [] + self.buffer = p_frame + for i in range(len(p_frame)): + r, g, b = p_frame[i].rgb_tuple(True) + r = int(r / self.brightness_factor) + g = int(g / self.brightness_factor) + b = int(b / self.brightness_factor) + rgb_frame.append((r, g, b)) + package = self._generate_package(0, length-1, rgb_frame) + else: + raise ValueError("Given list length does not match pixel count!: Given %d, expected %d" % (length, self.length)) + self._send_package(package) + + def set_full_color(self, p_color): + """Displays the given color on every pixel of the blinkenfoo""" + rgb_list = [p_color for _ in range(self.length)] + self.send_frame(rgb_list) + + def set_pixel(self, p_index, p_color): + """Sets an specific color at the given index. The change is visible after + flush is called""" + if p_index > self.length: + raise ValueError("Out of range: given %d, length %d" % (p_index, self.length)) + self.buffer[p_index] = p_color + + def flush(self, p_reset=False): + """ + Sends the content of the buffer to the blinkenfoo. If p_reset = True + then the buffer is resetet (see _reset_buffer()) + """ + self.send_frame(self.buffer) + if p_reset: + self._reset_buffer() + +################## +###End of class### +################## + + +SPHERES = Blinkenfoo("Spheres", "ESP_35D447.warpzone", 9, 20) +PANEL = Blinkenfoo("Panel", "ESP_35d9E4.warpzone", 8, 12) +WARP_SIGN = Blinkenfoo("Warp-Sign", "ESP_133C4C.warpzone", 1, 25) +DMX = Blinkenfoo("DMX", "10.0.3.27", 5, 10, p_brightness = 50) +CUBES = Blinkenfoo("Cubes", "cubes.warpzone", 8, 5) +TISCH = Blinkenfoo("Tisch", "tisch.warpzone", 700) + +DEVICE_LIST_LOUNGE = [DMX, WARP_SIGN, SPHERES, PANEL, CUBES, TISCH] +#DEVICE_LIST_LOUNGE = [PANEL] +#DEVICE_LIST_LOUNGE = [TISCH] diff --git a/blinkenroom.py b/blinkenroom.py new file mode 100644 index 0000000000000000000000000000000000000000..1a8d64bdc1e5f8ad2e159cd2e9f7bd5723ff304a --- /dev/null +++ b/blinkenroom.py @@ -0,0 +1,121 @@ +import blinkenfoo +from Color import Color + +class Blinkenroom: + + def __init__(self, p_device_list, p_fps = 42): + self.fps = p_fps + self.device_list = p_device_list + self._calc_total_length() + self._generate_index_map() + self.previous_device = None + self._remove_unreachable_devices() + + ##################### + ###private methods### + ##################### + + def _remove_unreachable_devices(self): + """ + Removes devices that are not reachable from the devices list + """ + for device in self.device_list: + if not device.is_reachable(): + print(device.name + " is not available") + del self.device_list[self.device_list.index(device)] + + def _calc_total_length(self): + self.total_length = 0 + for device in self.device_list: + self.total_length += device.length + return self.total_length + + def _generate_index_map(self): + self.global_map = [0 for _ in range(self.total_length)] + + current_index = 0 + for device in self.device_list: + for i in range(device.length): + self.global_map[current_index + i] = device + current_index += device.length + + #################### + ###public methods### + #################### + + def send_frame(self, p_frame, p_offset = 0): + """ + Sends an whole frame to all blinkenfoo devices. The frames length has to + match all blinkenfoos length combined. + """ + frame_length = len(p_frame) + + #TODO Make this more efficient -> use blinkenfoo's send_frame, dont send + #a frame pixel wise, as every single pixel has to be mapped to a + #blinkenfoo + if not frame_length == self.total_length: + raise ValueError("Frame length does not match total length: Given %d, expected %d" % (frame_length, self.total_length)) + for i in range(frame_length): + current_index = (i + p_offset) % frame_length + pixel = p_frame[current_index] + self.set_pixel(i, pixel) + self.flush() + + def set_full_color(self, p_color): + """ + Sets all blinkenfoo to the given color. + """ + for device in self.device_list: + device.set_full_color(p_color) + + def set_pixel(self, p_index, p_color): + """ + Sets a single pixel. The index is mapped to a blinkenfoo in the + blinkenroom. + """ + device = self.global_map[p_index] + if device == None: + raise ValueError("Index is not mapped to any device (out of range)") + + # Mapping index to device + # (Substracting foregone device length) + for i in range(len(self.device_list)): + current_device = self.device_list[i] + if current_device == device: + break + p_index -= current_device.length + device.set_pixel(p_index, p_color) + + def flush(self, p_reset=False): + """ + Flushes the changes made in the buffer (blinkefoo buffers, a + blinkenroom has no buffer). + """ + for device in self.device_list: + device.flush(p_reset) + + def get_device_by_index(self, p_index): + """ + Returns the blinkenfoo that the given index is mapped on + """ + if p_index > self.total_length: + raise ValueError("Index out of range:%d > %d" % (p_index, self.total_length)) + return self.global_map[p_index] + + def is_overlapping(self, p_blinkeroom): + """ + Checks wether a blinkenroom's devices overlap with this's devices + """ + return len(set(self.device_list).intersection(p_blinkeroom.device_list)) is not 0 + + def get_last_frame(self): + """ + Returns the buffer of all blinkenfoos concatenated. Does not work if + flush(True) is invoked, since this will clear the buffer after sending. + """ + frame = [] + for device in self.device_list: + frame += device.buffer + return frame + +BLINKENROOM_LOUNGE = Blinkenroom(blinkenfoo.DEVICE_LIST_LOUNGE) diff --git a/darken.py b/darken.py new file mode 100644 index 0000000000000000000000000000000000000000..3dce18bb0cc9eb03620a880c26580bcbe0b619b0 --- /dev/null +++ b/darken.py @@ -0,0 +1,40 @@ +import animation +import blinkenfoo +from animation import Animation +from blinkenroom import Blinkenroom + +class darken(Animation): + def init_animation(self): + self.frame = self.args["frame"] + self.rate = float(self.args["rate"]) + self.steps = float(self.args["steps"]) + self.blinkenroom = Blinkenroom(blinkenfoo.DEVICE_LIST_LOUNGE) + self.name = "darken" + self._calc_pixel_delta() + + def cycle(self): + is_dark = True + for i in range(len(self.frame)): + delta = self.delta_list[i] + pixel = self.frame[i] + value = pixel.value + if value <= 0: + continue + else: + is_dark = False + pixel.__setattr__("value", value - delta) + self.frame[i] = pixel + self.blinkenroom.send_frame(self.frame) + if is_dark: + self.stop() + + def _calc_pixel_delta(self): + delta_list = [] + self.factor = 100.0 / self.rate + for i in range(len(self.frame)): + pixel = self.frame[i] + value = pixel.value + new_value = value / self.factor + delta_per_step = (value - new_value) / self.steps + delta_list.append(delta_per_step) + self.delta_list = delta_list diff --git a/flash.py b/flash.py new file mode 100644 index 0000000000000000000000000000000000000000..ce9542dfb50387ad1e010aa5ac38a88d397df154 --- /dev/null +++ b/flash.py @@ -0,0 +1,32 @@ +from animation import Animation +from blinkenroom import BLINKENROOM_LOUNGE +import random +from Color import Color +import time + +class flash(Animation): + + required_args = { + "wait_range": [int, 100], + "stay": [float, 0.1] + } + + def init_animation(self): + self.name = "flash" + self.wait_range = int(self.args["wait_range"]) + self.stay = float(self.args["stay"]) + self.wait = random.randrange(self.wait_range) + self.blinkenroom = BLINKENROOM_LOUNGE + self.white = Color((255, 255, 255)) + + def cycle(self): + if self.wait > 0: + self.wait -= 1 + else: + index = random.randrange(self.blinkenroom.total_length) + self.blinkenroom.set_pixel(index, self.white) + #flushing and setting every pixel to black + self.blinkenroom.flush(True) + time.sleep(self.stay) + self.blinkenroom.flush() + self.wait = random.randrange(self.wait_range) diff --git a/mqtt.py b/mqtt.py new file mode 100644 index 0000000000000000000000000000000000000000..224a0656ce826663ba91e57afc39013670de5352 --- /dev/null +++ b/mqtt.py @@ -0,0 +1,64 @@ +import paho.mqtt.client as mqtt +from animation_handler import AnimationHandler + +handler = AnimationHandler() + +command_handler_dict = {} + +client = mqtt.Client() + +def on_connect(c, u, f, rc): + print("connected") + client.subscribe("light/blinkenfoo") + +def on_message(client, userdata, p_message): + p_message = p_message.payload.decode("UTF-8") + print("Received message:", p_message) + args = p_message.split(" ") + if args[0] in command_handler_dict: + command_handler = command_handler_dict[args[0]] + command_handler(args[1:]) + +client.on_connect = on_connect +client.on_message = on_message + +def handler_start_animation(p_args): + if len(p_args) > 1 and len(p_args) % 2 == 0: + print("Animation args count invalid") + return + + animation_name = p_args[0] + animation_args_dict = {} + for i in range(1, len(p_args), 2): + key = str(p_args[i]) + value = p_args[i+1] + animation_args_dict[key] = value + + handler.start_animation(animation_name, animation_args_dict) + +def handler_pause(p_args): + length = len(p_args) + if length is 0: + handler.pause_all_animations() + else: + args = p_args[1:] + for name in args: + handler.pause_animation(name) + +def handler_resume(p_args): + length = len(p_args) + if length is 0: + handler.resume_all_animations() + else: + args = p_args[1:] + for name in args: + handler.resume_animation(name) + +command_handler_dict["play"] = handler_start_animation +command_handler_dict["exit"] = handler.stop_all_animations +command_handler_dict["resume"] = handler_resume +command_handler_dict["pause"] = handler_pause +command_handler_dict["darken"] = handler.darken + +client.connect("warpsrvint.warpzone", 1883, 60) +client.loop_forever() diff --git a/random_color.py b/random_color.py new file mode 100644 index 0000000000000000000000000000000000000000..0aff63cdb464ca9761317d8c3f0030cb2eb8e4b9 --- /dev/null +++ b/random_color.py @@ -0,0 +1,52 @@ +from animation import Animation +import blinkenfoo +from blinkenroom import Blinkenroom +from Color import Color +import random + +class Blink(object): + + def __init__(self, p_index): + self.index = p_index + hue = random.randrange(360) + self.color = Color(hsv=(hue,1,0)) + self.step_per_cycle = 1.0/ random.randrange(5, 25) + self.rising = 1 + self.dest_value = 1 + + def step(self): + current_value = self.color.value + if current_value >= self.dest_value: + self.rising = -1 + next_value = current_value + self.step_per_cycle * self.rising + if next_value < 0: + next_value = 0 + self.color.__setattr__("value", next_value) + if next_value <= 0: + return True + return False + +class random_color(Animation): + + def init_animation(self): + self.blinkenroom = Blinkenroom(blinkenfoo.DEVICE_LIST_LOUNGE) + self.set_fps(20) + self.blink_dict = {} + self.name = "random_color" + + def cycle(self): + for _ in range(3): + index = random.randrange(self.blinkenroom.total_length) + if index not in self.blink_dict: + blink = Blink(index) + self.blink_dict[index] = blink + to_pop =[] + for blink in self.blink_dict.values(): + result = blink.step() + index = blink.index + if result: + to_pop.append(index) + self.blinkenroom.set_pixel(index, blink.color) + for index in to_pop: + self.blink_dict.pop(index, None) + self.blinkenroom.flush() diff --git a/sirene.py b/sirene.py new file mode 100644 index 0000000000000000000000000000000000000000..b5fa38309dbf07f86689af47e5d2b5d68515a010 --- /dev/null +++ b/sirene.py @@ -0,0 +1,47 @@ +from animation import Animation +from Color import Color +from blinkenroom import Blinkenroom +import blinkenfoo +import time + +class sirene(Animation): + + def init_animation(self): + red = Color((255, 0, 0)) + blue = Color((0, 0, 255)) + white = Color((255, 255, 255)) + black = Color((0, 0, 0)) + grey = Color((32, 32, 32)) + self.flash_left = [ + [red, blue, red, grey, grey, black, black, black], + [white, white, white, grey, grey, black, black, black], + [blue, red, blue, grey, grey, black, black, black], + [white, white, white, grey, grey, black, black, black], + [red, blue, red, grey, grey, black, black, black], + [white, white, white, grey, grey, black, black, black] + + ] + self.flash_right = [ + [black, black, black, grey, grey, red, blue, red], + [black, black, black, grey, grey, white, white, white], + [black, black, black, grey, grey, blue, red, blue], + [black, black, black, grey, grey, white, white, white], + [black, black, black, grey, grey, red, blue, red], + [black, black, black, grey, grey, white, white, white] + ] + self.states = [ + self.flash_right, + self.flash_left + ] + self.counter = 0 + self.name = "sirene" + self.blinkenroom = Blinkenroom([blinkenfoo.CUBES]) + self.set_fps(5) + + def cycle(self): + i = self.counter % 2 + state = self.states[i] + for line in state: + self.blinkenroom.send_frame(line) + time.sleep(0.06) + self.counter += 1 diff --git a/test.py b/test.py index f6f678195197609f9b1e16c97475889d5d34d644..7cd99b3b15c1e362df0764e091b8c53da499bf75 100644 --- a/test.py +++ b/test.py @@ -1,7 +1,24 @@ from blinkenfoo import Blinkenfoo -from blinkenfoo import spheres, warp_sign, panel, cubes +from blinkenfoo import DMX, WARP_SIGN, SPHERES, PANEL, CUBES from blinkenroom import Blinkenroom +from Color import Color +from animation import Animation +import animation -device_list = [spheres, panel, cubes, warp_sign] -blinkenroom = Blinkenroom(device_list) -blinkenroom.set_full_color("ff0000") +device_list = [DMX, WARP_SIGN, SPHERES, PANEL, CUBES] +blinkenroom = Blinkenroom(animation.DEVICE_LIST_LOUNGE) +#blinkenroom.set_full_color("ff0000") + +class test(Animation): + + def init_animation(self): + self.counter = 0 + self.color = Color(hsv=(0, 1, 1)) + self.blinkenroom = blinkenroom + self.name = "test" + self.set_fps(self.args["fps"]) + + def cycle(self): + self.color.__setattr__("hue", self.counter % 360) + self.blinkenroom.set_full_color(self.color) + self.counter += 1