Die Steuerung von adressierbaren LED-Streifen mit einem benutzerdefinierten Controller wie einem Puck-Gerät bietet eine spannende Möglichkeit, individuelle Lichtsetzungen zu realisieren. In diesem Leitfaden wird erläutert, wie Sie mit einem ESP32 und Python (MicroPython) eine präzise und flexible Steuerung implementieren können. Der Fokus liegt auf der Verwendung eines Puck-Geräts mit einem drehbaren Außenring und einem zentralen Button, um LEDs einzeln zu steuern und die Breite des Lichtpunkts dynamisch anzupassen.
Der Aufbau der Hardware erfordert eine präzise Verbindung der einzelnen Komponenten. Folgen Sie diesen Schritten, um eine stabile und funktionale Schaltung zu erstellen:
Komponente | Verbindung |
---|---|
ESP32 GPIO5 | Datenpin des WS2812B LED-Streifens (über 330Ω Widerstand) |
ESP32 GPIO18 | CLK-Pin des Rotary Encoders |
ESP32 GPIO19 | DT-Pin des Rotary Encoders |
ESP32 GPIO23 | Button |
5V | LED-Streifen und ESP32 Vcc |
GND | Alle Komponenten |
MicroPython ist eine schlanke Implementierung von Python 3, die speziell für Mikrocontroller wie den ESP32 entwickelt wurde. Es ermöglicht eine einfache und effiziente Programmierung zur Steuerung der Hardware-Komponenten.
esptool.py --chip esp32 --port COM3 erase_flash
esptool.py --chip esp32 --port COM3 write_flash -z 0x1000 esp32-xxxxxx.bin
Für die Steuerung der LEDs und die Verarbeitung der Eingaben vom Rotary Encoder und dem Button sind spezifische Bibliotheken erforderlich:
Der folgende Code zeigt eine grundlegende Implementierung zur Steuerung des LED-Streifens mit dem Puck-Gerät:
from machine import Pin
import neopixel
import time
from rotary_irq_esp import RotaryIRQ
# Pin-Definitionen
LED_PIN = 5
NUM_LEDS = 60
ENCODER_CLK = 18
ENCODER_DT = 19
BUTTON_PIN = 23
# Initialisierung der LEDs
strip = neopixel.NeoPixel(Pin(LED_PIN), NUM_LEDS)
# Initialisierung des Rotary Encoders
rotary = RotaryIRQ(pin_num_clk=ENCODER_CLK, pin_num_dt=ENCODER_DT, min_val=0, max_val=NUM_LEDS-1, reverse=False, range_mode=RotaryIRQ.RANGE_WRAP)
# Initialisierung des Buttons
button = Pin(BUTTON_PIN, Pin.IN, Pin.PULL_UP)
# Zustandsvariable
mode = 'single' # 'single' oder 'width'
current_pos = 0
light_width = 1
def clear_strip():
for i in range(NUM_LEDS):
strip[i] = (0, 0, 0)
strip.write()
def update_strip(position, width):
clear_strip()
start = max(0, position - (width // 2))
end = min(NUM_LEDS, position + (width // 2) + 1)
for i in range(start, end):
strip[i] = (255, 255, 255) # Weiß
strip.write()
def handle_button(pin):
global mode, light_width
if not pin.value():
time.sleep_ms(20) # Entprellen
if not pin.value():
# Doppelklick-Logik oder Moduswechsel
if mode == 'single':
mode = 'width'
elif mode == 'width':
mode = 'single'
update_strip(current_pos, light_width)
def handle_rotation():
global current_pos, light_width
delta = rotary.value()
if delta != current_pos:
current_pos = delta
if mode == 'single':
light_width = 1
elif mode == 'width':
light_width = min(NUM_LEDS, max(1, light_width))
update_strip(current_pos, light_width)
# Interrupt für den Button
button.irq(trigger=Pin.IRQ_FALLING, handler=handle_button)
# Hauptschleife
while True:
handle_rotation()
time.sleep_ms(10)
Um die Funktionalität für Doppelklicks und die dynamische Anpassung der Lichtbreite zu erweitern, kann der Code wie folgt angepasst werden:
from machine import Pin
import neopixel
import time
from rotary_irq_esp import RotaryIRQ
# Pin-Definitionen
LED_PIN = 5
NUM_LEDS = 60
ENCODER_CLK = 18
ENCODER_DT = 19
BUTTON_PIN = 23
# Initialisierung der LEDs
strip = neopixel.NeoPixel(Pin(LED_PIN), NUM_LEDS)
# Initialisierung des Rotary Encoders
rotary = RotaryIRQ(pin_num_clk=ENCODER_CLK, pin_num_dt=ENCODER_DT, min_val=0, max_val=NUM_LEDS-1, reverse=False, range_mode=RotaryIRQ.RANGE_WRAP)
# Initialisierung des Buttons
button = Pin(BUTTON_PIN, Pin.IN, Pin.PULL_UP)
# Zustandsvariablen
mode = 'single' # 'single' oder 'width'
current_pos = 0
light_width = 1
last_click_time = 0
click_count = 0
def clear_strip():
for i in range(NUM_LEDS):
strip[i] = (0, 0, 0)
strip.write()
def update_strip(position, width):
clear_strip()
start = max(0, position - (width // 2))
end = min(NUM_LEDS, position + (width // 2) + 1)
for i in range(start, end):
strip[i] = (255, 255, 255) # Weiß
strip.write()
def handle_button(pin):
global mode, light_width, last_click_time, click_count
if not pin.value():
current_time = time.ticks_ms()
if time.ticks_diff(current_time, last_click_time) < 300:
click_count += 1
else:
click_count = 1
last_click_time = current_time
time.sleep_ms(20) # Entprellen
if click_count == 1:
# Einzelklick: Einschalten/Ausschalten
if mode == 'off':
mode = 'single'
update_strip(current_pos, light_width)
else:
mode = 'off'
clear_strip()
elif click_count == 2:
# Doppelklick: Moduswechsel zu Breitensteuerung
if mode == 'single':
mode = 'width'
elif mode == 'width':
mode = 'single'
update_strip(current_pos, light_width)
def handle_rotation():
global current_pos, light_width
delta = rotary.value()
if delta != current_pos:
current_pos = delta
if mode == 'single':
light_width = 1
elif mode == 'width':
light_width = min(NUM_LEDS, max(1, light_width))
update_strip(current_pos, light_width)
# Interrupt für den Button
button.irq(trigger=Pin.IRQ_FALLING, handler=handle_button)
# Hauptschleife
while True:
handle_rotation()
time.sleep_ms(10)
Zusätzlich zur Steuerung der Position und Breite der LEDs können Farben dynamisch angepasst werden. Dies erhöht die visuelle Attraktivität und Flexibilität des Systems.
def update_strip(position, width, color=(255, 255, 255)):
clear_strip()
start = max(0, position - (width // 2))
end = min(NUM_LEDS, position + (width // 2) + 1)
for i in range(start, end):
strip[i] = color
strip.write()
Implementieren Sie sanfte Übergänge und Animationen, um die Bewegungen der LEDs flüssiger und ansprechender zu gestalten.
def smooth_update(position, width, color=(255, 255, 255)):
for i in range(NUM_LEDS):
current_color = strip[i]
target_color = color if (i >= position - (width // 2) and i <= position + (width // 2)) else (0, 0, 0)
new_color = tuple(min(255, current_color[j] + (target_color[j] - current_color[j]) // 10) for j in range(3))
strip[i] = new_color
strip.write()
Um benutzerdefinierte Einstellungen wie aktuelle Position, Breite und Farbe zu speichern, können diese Werte im Flash-Speicher des ESP32 abgelegt werden. Dies ermöglicht eine Wiederherstellung der letzten Konfiguration nach einem Neustart.
import json
import ujson
def save_settings(position, width, mode):
settings = {
'position': position,
'width': width,
'mode': mode
}
with open('settings.json', 'w') as f:
f.write(ujson.dumps(settings))
def load_settings():
try:
with open('settings.json', 'r') as f:
settings = ujson.loads(f.read())
return settings['position'], settings['width'], settings['mode']
except:
return 0, 1, 'single'
# Beim Start
current_pos, light_width, mode = load_settings()
update_strip(current_pos, light_width)
# Beim Ändern
def handle_button(pin):
global mode, light_width, last_click_time, click_count, current_pos
if not pin.value():
current_time = time.ticks_ms()
if time.ticks_diff(current_time, last_click_time) < 300:
click_count += 1
else:
click_count = 1
last_click_time = current_time
time.sleep_ms(20) # Entprellen
if click_count == 1:
if mode == 'off':
mode = 'single'
update_strip(current_pos, light_width)
else:
mode = 'off'
clear_strip()
elif click_count == 2:
if mode == 'single':
mode = 'width'
elif mode == 'width':
mode = 'single'
update_strip(current_pos, light_width)
save_settings(current_pos, light_width, mode)
Nach der Implementierung der Hardware und Software ist es entscheidend, das System gründlich zu testen und anzupassen, um eine reibungslose Funktionalität zu gewährleisten.
Basierend auf den Testergebnissen passen Sie den Code und die Hardware-Verbindungen an, um eine optimale Leistung zu erzielen:
Stellen Sie sicher, dass das System stabil im Langzeitbetrieb funktioniert:
Die Steuerung eines adressierbaren LED-Streifens mit einem ESP32 und einem Puck-Gerät bietet eine flexible und leistungsstarke Lösung für individuelle Lichtprojekte. Durch die sorgfältige Auswahl und Verbindung der Hardware-Komponenten sowie eine durchdachte Software-Implementierung mit MicroPython können Benutzer eine intuitive und anpassbare Steuerung realisieren. Die Möglichkeit, LED-Position und -Breite dynamisch zu steuern, eröffnet vielfältige kreative Möglichkeiten für Lichtdesigns.