#!/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