388 lines
8.7 KiB
Python
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
|