Hello and welcome to my entry for MAKE’s Raspberry Pi Design Contest! I’ve spent the past week working hard on building a ceiling lamp with a ring of LED’s below it.
I call it the Cloud Lamp, and here’s how it all went down:
The Goal
After getting my home somewhat automated with a z-wave network and a few other custom devices, I thought I’d like to have a simple way to see the status of my home, the weather, surf report, etc, easily visible from my bed. My initial thought was that I’d buy a conventional ceiling lamp and put four rgb LEDs around the perimeter of the lamp as status indicators. Well, two weeks ago I came upon Make’s contest and even though I was already behind I thought it’d be really fun to try building something. So I took my original idea and made the following changes: I went from 4 to 60 rgb LEDs after being inspired by this beautiful clock. Well, that and I love circular LED displays! :) I probably wouldn’t use the analogue-like clock functionality but I thought it was a beautiful design and I thought I could add something to it. And of course I changed out the Arduino for a Rasberry Pi, which made the project amazingly versatile!
The Build Process
The building process broke down into three major parts, the electronics, the physical lamp and the software.
Lamp Hardware
To start, I bought a cheap, commercial ceiling lamp from Home Depot for about 30 (Girlfriend reminded me that we got one on sale) 10 bucks along with a bunch of flat pieces of steel, wires and assorted nuts and bolts. I shaped the pieces of steel into a simple bracket that could attach to the lamp base and welded the assembly together. This would also be the platform for the power supply, power switch tail (for switching the light bulbs off and on), the Pi and electronics board.
To make the lamp shade, I used the thick steel wire and built a template on plywood. I drew a circle using a pencil and twine connected to a wood screw in the center of the circle. (A trick that I used many times during this build) More wood-screws held the wire in
place while I soldered it together. This worked really well with a few caveats. Because the wire was under tension after welding it to keep it’s circular shape, welding cross-braces was problematic because the hot steel was ply-able enough to bend. Also, it’s just plain hard to make a nice, round circle even without the welding problems.
Lastly, the LED holder was done using a thin but durable board. I drew the initial circles using three strings, one had the outer diameter, another was the inner diameter and the final one was where the LED’s would be situated. I used the angle markings on a cheap protractor/square to get the rotational position of each LED; 60 LED’s, so I put one LED at every 6th degree. (360 degrees / 60 LEDs). Then, I cut out four holes from the center of the disk to allow light from the bulbs through, but left a wide column to keep the disc sturdy for the LEDs.
Electronics Hardware
For the electronics portion I breadboard-ed out a ws2801 LED string using the schematic on Cody Ledbetter’s blog. Hooking them up is really simple. There’s four wires coming from the LED string, the Yellow wire (DI, on the LED string I used, the four wires are labled on the small PCB embedded in the plastic below the LED) should connect to the Raspberry Pi’s MOSI pin. And the Green wire should connect to the SCLK pin. The red and black should be +5 Volts to the red and Gnd for the black. Note that you’ll probably need a beefy power supply if you plan to control many lights and definitely more than the small usb power supplies used for Raspberry Pi’s.
The two light bulbs in the fixture are wired to the Power Switch Tail 2, which made it safe and easy to control them from the Pi. I simply connected a GPIO pin to screw terminal 1 (+in) and ground to 2 (-in).
I also soldered up a prototyping board next to the Raspberry Pi for future expansions. There’s an H-bridge motor driver IC connected to two GPIOs and the PWM pin so that I can add a motor and another GPIO pin broken out so that I can connect other LED’s.
Software
The software was really exciting for this project. I’ve built lots of things with Arduino and it can be a lot of fun but it can also be limiting. To get this up and running quickly enough for the contest I’ve written a simple bit of code that will act as a web server, accepting commands over http that can control all the functions of the lamp. It works likes this:
To turn the bulbs off and on, send this command:
- http://[ ip of Pi ]:8080/?light=[ off or on ]
To change the ‘mode’ that the string lights are in
- http://[ ip of Pi ]:8080/?mode=[ Integer of mode you want to select ]
The ‘Modes’ allow you to switch the functionality of string LEDs. Mode 0 is LEDs off, Mode 1 is the color swirl pattern that came with Lady Ada’s ws2801 example; and mode 2 is an analogue clock. However, I plan to create new and more useful modes. Like one that will tell me the weather and surfing forcast, along with whether the house is secure or not. I also thought about a music visualizer, a rain simulator and many more! The fact that I can ssh into a full development environment to code new functionality without taking anything apart is amazing and really shows the power of embedding a Pi into something.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
#!/usr/bin/env python # title: lamp daemon # author: falldeaf # date: April 11th 10:16pm Eastern # details: This code acts as a web server to accept commands over http # as request variables to control all the functions of the cloud lamp # # This code is modified from the: # Test code for Adafruit LED Pixels, uses hardware SPI import RPi.GPIO as GPIO, time, os, datetime from twisted.web import server, resource from twisted.internet import reactor #Setup variables MODE = 2 #initial mode DEBUG = 1 #debug flag GPIO.setmode(GPIO.BCM) #gpio mode power_pin = 17 #powerswitch tail pin GPIO.setup(power_pin, GPIO.OUT) #This class defines the web server object class Simple(resource.Resource): isLeaf = True def render_GET(self, request): global MODE print request #If light command is sent, turn bulbs off or on if 'light' in request.args: if request.args['light'][0] == "off": GPIO.output(power_pin, False) return " light off " if request.args['light'][0] == "on": GPIO.output(power_pin, True) return " light on " #Set the 'mode' for the RGB LED circle if 'mode' in request.args: if request.args['mode'][0] == "0": colorwipe(ledpixels, Color(0, 0, 0), 0) MODE = 0 return " mode set to 0 " if request.args['mode'][0] == "1": MODE = 1 return " mode set to 1 " if request.args['mode'][0] == "2": MODE = 2 return " mode set to 2 " return "invalid command" def slowspiwrite(clockpin, datapin, byteout): GPIO.setup(clockpin, GPIO.OUT) GPIO.setup(datapin, GPIO.OUT) for i in range(8): if (byteout & 0x80): GPIO.output(datapin, True) else: GPIO.output(clockpin, False) byteout < <= 1 GPIO.output(clockpin, True) GPIO.output(clockpin, False) SPICLK = 18 SPIDO = 17 ledpixels = [0] * 60 def writestrip(pixels): spidev = file("/dev/spidev0.0", "w") for i in range(len(pixels)): spidev.write(chr((pixels[i]>>16) & 0xFF)) spidev.write(chr((pixels[i]>>8) & 0xFF)) spidev.write(chr(pixels[i] & 0xFF)) spidev.close() time.sleep(0.002) def Color(r, g, b): return ((r & 0xFF) < < 16) | ((g & 0xFF) << 8) | (b & 0xFF) def setpixelcolor(pixels, n, r, g, b): if (n >= len(pixels)): return pixels[n] = Color(r,g,b) def setpixelcolor(pixels, n, c): if (n >= len(pixels)): return pixels[n] = c def colorwipe(pixels, c, delay): for i in range(len(pixels)): setpixelcolor(pixels, i, c) writestrip(pixels) time.sleep(delay) def Wheel(WheelPos): if (WheelPos < 85): return Color(WheelPos * 3, 255 - WheelPos * 3, 0) elif (WheelPos < 170): WheelPos -= 85; return Color(255 - WheelPos * 3, 0, WheelPos * 3) else: WheelPos -= 170; return Color(0, WheelPos * 3, 255 - WheelPos * 3) def rainbowCycle(pixels, wait): for j in range(256): # one cycle of all 256 colors in the wheel for i in range(len(pixels)): # tricky math! we use each pixel as a fraction of the full 96-color wheel # (thats the i / strip.numPixels() part) # Then add in j which makes the colors go around per pixel # the % 96 is to make the wheel cycle around setpixelcolor(pixels, i, Wheel( ((i * 256 / len(pixels)) + j) % 256) ) writestrip(pixels) time.sleep(wait) #This function displays a real-time analogue clock def clockdraw(pixels): hour = 60 / int(time.strftime('%l')) minute = int(time.strftime('%M')) second = int(time.strftime('%S')) one = 1 quarter = 15 half = 30 threequarter = 46 for i in range(len(pixels)): c = Color(0,50,100) #This is the background color if i == one or i == quarter or i == half or i == threequarter: c = Color(0,0,20) #This is the four cardinal directions color if i == hour: c = Color(20,0,0) #Color of the hour hand if i == minute: c = Color(20,0,20) #Color of the minute hand if i == second: c = Color(20,20,20) #Color of the second hand setpixelcolor(pixels, i, c) writestrip(pixels) time.sleep(1) #print(time.strftime('%l:%M%S')) #start the web server on port 8080 site = server.Site(Simple()) reactor.listenTCP(8080, site) reactor.startRunning(False) #main loop - check the web connection and draw to the leds once for each loop while True: reactor.iterate() if MODE == 1: rainbowCycle(ledpixels, 0.00) if MODE == 2: clockdraw(ledpixels) #if MODE == 3: #TODO: displaydata(ledpixels) #if MODE == 4: #TODO: rainsimulation(ledpixels) |
Conclusion
This is the first personal project I’ve ever done that wasn’t only for the fun of it. It was stressful in some ways but also really rewarding and challenging. For instance, given more time, I probably would have used a service like Ponoko to CNC cut the LED holder. But with the time crunch it was cool figuring out how-to create and cut the shape and solve the LED spacing problem. ( I got some help on this ;) Thanks Corey! ) I hope that if anyone wants to recreate this or some variation thereof that I was explicit enough in my directions and code commenting. If not, please feel free to email me at falldeaf@gmail.com or leave a comment in the comment section below!
I plan on adding some more features in both hardware and software, so if you get a chance, check back here!
Oh, and here’s the injury tally for anyone keeping score:
Injuries sustained:
- Minor lacerations (Steel is sharp after you cut it)
- Sub-dermal irritatants (The lamp was chock full of insulation)
- Welding Tan (New to welding… didn’t know this was a thing. Wear sunscreen!)
- Severe Burns (Metal is very, very hot after you weld it, there’s probably room for a Captain Obvious Meme here…)
Ok, that’s all, Thanks for reading! :)
π