April 8, 2024 at 09:47
I recently upgraded my office’s ambient lighting from basic blue to RGB and WiFi-controlled. The old setup was 12v rope lights taped along the baseboards. They looked cool and were easy to set up, but I always felt like I could do something more custom and dynamic.
With WLED and ESP32 controllers, they’ve included the ability to run RGB animations, set timers, program, access remotely, and adjust brightness over our home network. Now, they change to a random color every two hours, switch to dark blue and purple at night, and turn off at bedtime, replacing the old Kasa smart plugs and a 12v potentiometer for brightness control [edit: this was replaced with the Python code below]. Plus, I prefer using open-source software over Kasa’s closed, proprietary system.
I chose BTF-Lighting LEDs with 720 LEDs per meter and a built-in diffuser. Pairing these with Muzata low-profile aluminum channels, which also have diffusers, makes the LEDs blend seamlessly.
Installation involved mounting the aluminum channels, inserting the LED strips, wiring to the ESP, and setting up WiFi. After some tweaking and a bit of ranting, it was all set. Here’s how I programmed the WLED API for random colors:
win&GP=0&FP=R&FX=0&R=r&G=r&B=r&A=128&SM=0&SV=0&SS=0&SP=0&S=0&S2=82
win
: The command for instant light setting changes.GP=0
: Controls a group of LEDs, with 0
for all LEDs.FX=0
: Chooses the effect, with 0
for a solid color.R=r
, G=r
, B=r
: Sets LEDs to random colors, where r
would usually be a number for specific colors.A=128
: Adjusts brightness to about 50%.S=0
: Sets the effect speed, with 0
as the slowest.If you want to automate it with python, you can use their API with requests. It’s as easy as making a request to the IP with the values you want. My python script is below. Here, the lights simulate the colors of the day for every hour. I’m still tweaking the values, but you’ll get the idea. Eventually I want to add holiday theming.
led.py
import requests
import time
from datetime import datetime
import logging
logging.basicConfig(filename='/home/pi/myproject/my_script.log', level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s')
addresses = [
'http://{wled_ip_address}/json/state'
]
# Define the color settings for each hour
colors = {
1: {'on': True, 'bri': 10, 'seg': [{'col': [[1, 30, 70]]}]},
2: {'on': True, 'bri': 15, 'seg': [{'col': [[0, 48, 96]]}]},
3: {'on': True, 'bri': 20, 'seg': [{'col': [[0, 46, 93]]}]},
4: {'on': True, 'bri': 25, 'seg': [{'col': [[0, 52, 89]]}]},
5: {'on': True, 'bri': 25, 'seg': [{'col': [[0, 52, 89]]}]},
6: {'on': True, 'bri': 35, 'seg': [{'col': [[0, 81, 118]]}]},
7: {'on': True, 'bri': 45, 'seg': [{'col': [[7, 92, 133]]}]},
8: {'on': True, 'bri': 80, 'seg': [{'col': [[13, 138, 168]]}]},
9: {'on': True, 'bri': 110, 'seg': [{'col': [[89, 191, 194]]}]},
10: {'on': True, 'bri': 128, 'seg': [{'col': [[197, 228, 193]]}]},
11: {'on': True, 'bri': 128, 'seg': [{'col': [[227, 224, 122]]}]},
12: {'on': True, 'bri': 128, 'seg': [{'col': [[246, 207, 100]]}]},
13: {'on': True, 'bri': 128, 'seg': [{'col': [[255, 188, 107]]}]},
14: {'on': True, 'bri': 128, 'seg': [{'col': [[252, 181, 93]]}]},
15: {'on': True, 'bri': 128, 'seg': [{'col': [[253, 175, 92]]}]},
16: {'on': True, 'bri': 100, 'seg': [{'col': [[244, 150, 78]]}]},
17: {'on': True, 'bri': 90, 'seg': [{'col': [[241, 122, 113]]}]},
18: {'on': True, 'bri': 80, 'seg': [{'col': [[213, 102, 135]]}]},
19: {'on': True, 'bri': 75, 'seg': [{'col': [[124, 59, 133]]}]},
20: {'on': True, 'bri': 60, 'seg': [{'col': [[71, 35, 124]]}]},
21: {'on': True, 'bri': 45, 'seg': [{'col': [[46, 24, 111]]}]},
22: {'on': True, 'bri': 45, 'seg': [{'col': [[33, 37, 101]]}]},
23: {'on': True, 'bri': 40, 'seg': [{'col': [[11, 21, 74]]}]},
0: {'on': True, 'bri': 10, 'seg': [{'col': [[2, 18, 69]]}]} # Hour 0 for midnight
}
# Function to set color on WLED device
def set_color(address, color):
try:
response = requests.post(address, json=color)
if response.status_code == 200:
logging.info(f'Successfully set {address} to {color}')
else:
logging.error(f'Failed to set {address} to {color}, status code: {response.status_code}')
except requests.exceptions.RequestException as e:
logging.error(f'Error setting {address} to {color}: {e}')
# Main loop to run the script and change colors based on the hour
while True:
current_hour = datetime.now().hour
color = colors.get(current_hour)
if color:
for address in addresses:
set_color(address, color)
logging.info(f'All addresses set to color for hour {current_hour}. Waiting for ten minutes...')
else:
logging.error(f'No color setting found for hour {current_hour}')
time.sleep(600) # Wait for ten minutes
This project required some soldering and planning to conceal wires, making it a bit of a challenge. But the result is a room bathed in light that adjusts its vibe (yes, I said vibe) with the color.
Getting a good photo of this project proved more challenging than the actual installation. This, and the main pic, are the lighting underneath the kitchen cabinets.