Previously I talked about a LED box. I explained how to
operate a ws2812 led strip. Thoses strips can be connected together in
serial.
After a first try one year ago, I built this clock from scratch with
360 leds, divided in 3 parts.
My first try was not a success. I bought some 1cm wide bars. Those aluminium bars can be easily bent in circles. However it is impossible to have a perfect circle. If the circle is wide the shape seems good. With smaller circles (diameter < 50cm) it looks bad.
Back to the basis : wood circles ! With a jigsaw (thanks @bluxte) and a simple wire it is the best way for perfect circles. I learned that at the age of 6 :-). I made 3 concentric circles : one with 60 leds, a second with 120 and the last have 180 leds.
There is 60 leds per meter on this strip. I need a 31,8cm diameter circle (100 / 3,14). I glued the strip on the edge.
Behind I removed some wood where the wires reach. On the final result, no wires are visible.
Wood circles are glued together after wiring. Remember for next time : painting will be far easier before gluing leds...
ws2812 need a 5 volts power supply, with 20mA consumption per LED. 360x0.02 = 7.2 A so 36W ! It may be very bright ! I found a 50w power supply on Amazon.
I have 3 separated strips. Each strip is powered by 2 points
on each end.
On my first mount, I soldered 2 wires (+5v and GND) at the begining of
the strip. A strip with a length greater than 2 meters need a redundant
power.
The wide circle have LEDs from 1 to 180, the mid 181 to 300 and the smallest 301 to 360.
Signal wire is plugged on a PWM output on a raspberry pi.
Get the library and install it : https://github.com/jgarff/rpi_ws281x
Example files written in python are great for testing. Put the right configuration :
# LED strip configuration:
LED_COUNT = 360 # Number of LED pixels.
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 0
LED_STRIP = ws.SK6812_STRIP_RGBW
Mounted on the wall :
def simple_clock(hours, minutes, seconds):
global strip
global q
global brightness
if not q.empty():
brightness = q.get()
strip.setBrightness( brightness )
# show seconds :
for i in range(0, 59):
offset = i + 29
# show in hours color elapsed
if offset >= 60:
offset = offset - 60
if i == seconds:
strip.setPixelColor((offset*3)-1, Color(0,255,0))
strip.setPixelColor((offset*3), Color(0,255,0))
strip.setPixelColor((offset*3)+1, Color(0,255,0))
else:
strip.setPixelColor((offset)*3-1, Color(0,0,0))
strip.setPixelColor((offset*3), Color(0,0,0))
strip.setPixelColor((offset*3)+1, Color(0,0,0))
Do the same with minutes, with leds from 181 to 300 :
# same for minutes, with an offset
for i in range(0,60):
offset = i + 30
# show in green color elapsed
if offset >= 60:
offset = offset - 60
if i == minutes :
strip.setPixelColor((offset*2)+180, Color(255,0,0))
strip.setPixelColor((offset*2+1)+180, Color(255,0,0))
else :
strip.setPixelColor((offset*2)+180, Color(0,0,0))
strip.setPixelColor((offset*2+1)+180, Color(0,0,0))
Then the hours, from leds 301 to 360.
# hours
for i in range(0,60):
if hours > 12:
hours = hours - 12
if hours == 0:
hours = 12
offset = i + 30
if offset >= 60:
offset = offset - 60
#show in blue
index = hours *5 -1
if (i == index) :
strip.setPixelColor(offset + 300 , Color(0,0,255))
else:
strip.setPixelColor(offset + 300 , Color(0,0,0))
Define an infinite loop for a mode, with a queue for input events such as brightness adjustment.
def loop_simple_clock(queue):
global brightness
global q
q = queue
brightness = q.get()
# LED strip configuration:
LED_COUNT = 360 # Number of LED pixels.
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 5 # DMA channel to use for generating signal (try 5)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
# True to invert the signal (when using NPN transistor level shift)
LED_INVERT = False
global strip
strip = Adafruit_NeoPixel(
LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS)
# Intialize the library (must be called once before other functions).
strip.begin()
# Shutdown all leds
for i in range(0, strip.numPixels(), 1):
strip.setPixelColor(i, Color(0, 0, 0))
strip.show()
while 1 :
localtime = time.localtime()
simple_clock(localtime.tm_hour, localtime.tm_min, localtime.tm_sec)
time.sleep(0.5)
And 2 REST API endpoints :
@app.route('/simple', methods=['POST'])
def simple():
global p
global q
q.put(lastBrightness)
if p is not None:
p.terminate()
p = Process(target=loop_simple_clock, args=(q,))
p.start()
return "ok"
@app.route('/bright', methods=['POST'])
def bright():
global q
q.put( int(request.args.get("brightness")))
lastBrightness = int(request.args.get("brightness"))
return "ok"
if (i <= index) :
strip.setPixelColor(offset + 300 , Color(0,0,255))
else:
strip.setPixelColor(offset + 300 , Color(0,0,0))
For minutes, hours and seconds.
With this mode, I can show every color I want on the 300 other leds ! Hours tooks 3 blue leds, minutes 2 green leds and seconds only one red.
# show seconds :
for i in range(0, 60):
if hours > 12:
hours = hours - 12
if hours == 0:
hours = 12
red = 0
blue = 0
green = 0
offset = i + 29
# show in hours color elapsed
if offset >= 60:
offset = offset - 60
if i == seconds:
red=255
if (i == minutes) or (i == minutes-1):
green=255
if (i == hours*5) or (i == (hours*5-1)) or (i == (hours*5+1)) :
blue=255
strip.setPixelColorRGB((offset)+300, red, green, blue)
In the loop, I intialize the strip (from 1 to 300) with a fixed color.
def loop_fixed_color(red, green, blue, queue, strip):
usleep = lambda x: time.sleep(x/1000000.0)
global q
global brightness
q = queue
brightness = q.get()
print strip
if not queue.empty():
brightness = q.get()
strip.setBrightness( brightness )
for i in range(0, 300, 5):
for j in range( 0, 5):
strip.setPixelColor(i+j, Color(red, green, blue ))
strip.show()
usleep(2)
strip.show()
while 1 :
localtime = time.localtime()
minimal_clock(localtime.tm_hour, localtime.tm_min, localtime.tm_sec, strip)
if not queue.empty():
brightness = q.get()
strip.setBrightness( brightness )
time.sleep(0.5)
# show a simple clock POST /simple # switch to continuous mode POST /continuous # switch to minimal mode POST /minimal # set bightness GET /bright
Slider are not included in bootstrap.