pumpkin/rgb.py

388 lines
8.7 KiB
Python

#!/usr/bin/env python3
import RPi.GPIO as GPIO
from time import sleep
from time import time
from random import randint
class RGB:
def __init__(self, red, green, blue):
self.r = red
self.g = green
self.b = blue
def getDutyCycles(self):
percent = RGB.rgbToPerc(self.r, self.g, self.b)
return RGB(percent[0], percent[1], percent[2])
@staticmethod
def sanitizeColor(value):
if value < 0 or value > 255:
print('Value must be between 0 and 255! Fixing color value.')
return max(0, min(value, 255))
return value
@staticmethod
def rgbToPerc(red, green, blue):
percent = 100 / 255
return (red * percent, green * percent, blue * percent)
@staticmethod
def percToRGB(red, green, blue):
percent = 255 / 100
return (red * percent, green * percent, blue * percent)
class RGB_Control:
def __init__(self, r, g, b, freq=60):
self.pins_allowed = (7, 11, 12, 13, 15, 16, 18, 19, 21, 22)
self.frequency = freq
if r not in self.pins_allowed:
print("Fehler: r wurde ungültigem Pin zugewiesen!")
exit()
if g not in self.pins_allowed:
print("Fehler: g wurde ungültigem Pin zugewiesen!")
exit()
if b not in self.pins_allowed:
print("Fehler: b wurde ungültigem Pin zugewiesen!")
exit()
try:
GPIO.setup(r, GPIO.OUT)
GPIO.setup(g, GPIO.OUT)
GPIO.setup(b, GPIO.OUT)
except:
GPIO.setmode(GPIO.BOARD)
GPIO.setup(r, GPIO.OUT)
GPIO.setup(g, GPIO.OUT)
GPIO.setup(b, GPIO.OUT)
self.r = GPIO.PWM(r, freq)
self.g = GPIO.PWM(g, freq)
self.b = GPIO.PWM(b, freq)
self.r.start(0)
self.g.start(0)
self.b.start(0)
self.r_alt = None
self.g_alt = None
self.b_alt = None
self.intensity = 1
self.current_r = 0
self.current_g = 0
self.current_b = 0
def __del__(self):
try:
GPIO.cleanup()
except:
pass
def enableSecondLED(self, gpioRed, gpioGreen, gpioBlue):
GPIO.setup(gpioRed, GPIO.OUT)
GPIO.setup(gpioGreen, GPIO.OUT)
GPIO.setup(gpioBlue, GPIO.OUT)
self.r_alt = GPIO.PWM(gpioRed, self.frequency)
self.g_alt = GPIO.PWM(gpioGreen, self.frequency)
self.b_alt = GPIO.PWM(gpioBlue, self.frequency)
self.r_alt.start(0)
self.g_alt.start(0)
self.b_alt.start(0)
def toggleSpectrum(self,fps=30,speed=1):
self.setColor(255,0,0)
self.transition((255, 255, 0), duration = speed)
self.transition((0, 255, 0), duration = speed)
self.transition((0, 255, 255), duration = speed)
self.transition((0, 0, 255), duration = speed)
self.transition((255, 0, 255), duration = speed)
self.transition((255, 0, 0), duration = speed)
def flash(self, color = (255, 255, 255)):
color_start = (self.current_r, self.current_g, self.current_b)
self.setColor(color[0], color[1], color[2])
sleep(1/30)
self.setColor(color_start[0], color_start[1], color_start[2])
def pulse(self, from_color, to_color, freq=0.5):
duration = freq * 0.5
self.transition(from_color, duration=duration)
self.transition(to_color, duration=duration)
def fire(self, wind = 0.5, r = 255, g = 55, b = 0):
wind_power = 100 - (100 * wind)
flicker = randint(int(wind_power), 100) * 0.01
color_start = (r * flicker, g * flicker, b * flicker)
duration = randint(10, int(40 - wind * 30)) * 0.01
self.transition(color_start, duration = duration)
def panic(self, times = 10, color = (255, 255, 255)):
for t in range(times):
self.flash(color = color)
sleep(1/30)
def setColor(self, r, g, b):
perc = RGB.rgbToPerc(r, g, b)
self.current_r = r
self.current_g = g
self.current_b = b
self.r.ChangeDutyCycle(perc[0] * self.intensity)
self.g.ChangeDutyCycle(perc[1] * self.intensity)
self.b.ChangeDutyCycle(perc[2] * self.intensity)
if self.r_alt != None:
self.r_alt.ChangeDutyCycle(perc[0] * self.intensity)
if self.g_alt != None:
self.g_alt.ChangeDutyCycle(perc[1] * self.intensity)
if self.b_alt != None:
self.b_alt.ChangeDutyCycle(perc[2] * self.intensity)
def transition(self, color_finish, duration = 3, fps = 30):
start_r = self.current_r
start_g = self.current_g
start_b = self.current_b
finish_r = color_finish[0]
finish_g = color_finish[1]
finish_b = color_finish[2]
delta_r = finish_r - start_r
delta_g = finish_g - start_g
delta_b = finish_b - start_b
frames = duration * fps
frame_duration = 1 / fps
# Step per frame for every color
stf_r = delta_r / frames
stf_g = delta_g / frames
stf_b = delta_b / frames
self.setColor(self.current_r, self.current_g, self.current_b)
sleep(frame_duration)
start_time = time()
while time() - start_time < duration:
self.current_r += stf_r
self.current_g += stf_g
self.current_b += stf_b
if self.current_r > 255:
self.current_r = 255
elif self.current_r < 0:
self.current_r = 0
if self.current_g > 255:
self.current_g = 255
elif self.current_g < 0:
self.current_g = 0
if self.current_b > 255:
self.current_b = 255
elif self.current_b < 0:
self.current_b = 0
self.setColor(self.current_r, self.current_g, self.current_b)
sleep(frame_duration)
class RGBMatrix(RGB):
def __init__(self, PWM_FREQUENCY = 60):
self.PWM_FREQUENCY = PWM_FREQUENCY
self.gpiosRed = []
self.gpiosGreen = []
self.gpiosBlue = []
self.currentColor = RGB(0, 0, 0)
GPIO.setmode(GPIO.BOARD)
def __del__(self):
GPIO.cleanup()
def setupLED(self, gpio):
GPIO.setup(gpio, GPIO.OUT)
led = GPIO.PWM(gpio, self.PWM_FREQUENCY)
led.start(0)
return led
def addRed(self, gpio):
led = self.setupLED(gpio)
led.ChangeDutyCycle(self.currentColor.getDutyCycles().r)
self.gpiosRed.append(led)
def addGreen(self, gpio):
led = self.setupLED(gpio)
led.ChangeDutyCycle(self.currentColor.getDutyCycles().g)
self.gpiosGreen.append(led)
def addBlue(self, gpio):
led = self.setupLED(gpio)
led.ChangeDutyCycle(self.currentColor.getDutyCycles().b)
self.gpiosBlue.append(led)
def setColor(self, red, green, blue):
rgb = RGB(red, green, blue)
colorsDutyCycle = rgb.getDutyCycles()
for red in self.gpiosRed:
red.ChangeDutyCycle(colorsDutyCycle.r)
for green in self.gpiosGreen:
green.ChangeDutyCycle(colorsDutyCycle.g)
for blue in self.gpiosBlue:
blue.ChangeDutyCycle(colorsDutyCycle.b)
self.currentColor = RGB(rgb.r, rgb.g, rgb.b)
def fadeToColor(self, red, green, blue, seconds, fps = 30):
timeStart = time()
timeEnd = timeStart + seconds
frameDuration = 1 / fps
colorStart = self.currentColor
colorTarget = RGB(red, green, blue)
deltaRed = colorTarget.r - colorStart.r
deltaGreen = colorTarget.g - colorStart.g
deltaBlue = colorTarget.b - colorStart.b
while time() < timeEnd:
frameStart = time()
progress = (time() - timeStart) / seconds
self.setColor(
colorStart.r + deltaRed * progress,
colorStart.g + deltaGreen * progress,
colorStart.b + deltaBlue * progress
)
duration = time() - frameStart
if duration < frameDuration:
sleep(frameDuration - duration)
self.setColor(red, green, blue)
def candle(self, red, green, blue, wind = 0.5):
darkenMax = 100 - wind * 100
color = RGB(red, green, blue)
intensity = randint(darkenMax, 100) / 100
seconds = randint(darkenMax, 50) / 100
targetColor = RGB(color.r * intensity, color.g * intensity, color.b * intensity)
self.fadeToColor(targetColor.r, targetColor.g, targetColor.b, seconds)
# Chance of 5% for flickering
flickering = randint(0, 100) < 5
if flickering:
intensityLight = 1
intensityDark = 0.9
times = randint(4, 10)
duration = randint(5, 30) / 100
colorLight = RGB(color.r * intensityLight, color.g * intensityLight, color.b * intensityLight)
colorDark = RGB(color.r * intensityDark, color.g * intensityDark, color.b * intensityDark)
intensity = 1
for t in range(times):
progress = (1 / times) * t
intensity = abs(0.5 - progress) * 2
colorDark = RGB(
color.r * intensityDark * intensity,
color.g * intensityDark * intensity,
color.b * intensityDark * intensity
)
self.fadeToColor(colorLight.r, colorLight.g, colorLight.b, duration)
self.fadeToColor(colorDark.r, colorDark.g, colorDark.b, duration)
def toggleSpectrum(self, seconds):
spectrum = [
RGB(255, 0, 0),
RGB(255, 255, 0),
RGB(0, 255, 0),
RGB(0, 255, 255),
RGB(0, 0, 255),
RGB(255, 0, 255)
]
fadeDuration = seconds / len(spectrum)
for color in spectrum:
self.fadeToColor(color.r, color.g, color.b, fadeDuration)
def halloween(control):
while True:
flash = randint(1, 100)
if flash >= 1 and flash <= 5:
t = randint(1, 3)
control.panic(times = t, color = (200, 255, 255))
control.fire(wind = 0.8)
def spectrum(control):
while True:
control.toggleSpectrum()
def fire(control, wind = 0.5):
while True:
control.fire(wind = wind)
if __name__ == "__main__":
try:
control = RGB_Control(11, 12, 13)
fire(control, wind = 0.9)
GPIO.cleanup()
except:
del control