Smart LED Window
Overview
This project is a Smart LED panel designed to imitate sunlight through a window. The panel consists of alternating strips of warm white and cool white LEDs that can be controlled in several modes. By adjusting the brightness of the cool/warm LEDs, the brightness and hue of the panel can be adjusted.
There are 3 modes of operation, that can be switched between using the Bluefruit LE Connect companion app: bluetooth control, slider control, and real-time clock control
Bluetooth Control
This can be selected by pressing the '1' button on the app. Pressing the '4' button toggles between control of the warm or cool LEDs. Pressing the up or down button will increase or decrease the specified LEDs.
Slider Control
This can be selected by pressing the '2' button on the app. The two sliders on the side of the panel correspond to the brightness of the warm and cool LEDs, so the color and brightness can be adjusted manually
Real-Time Clock Control
This can be selected by pressing the '3' button on the app. This scales the brightness of the panel depending on the time of day using the built-in real-time clock on the mbed. The panel turns off in between sunset and sunrise (7 AM and 6 PM respectively).
Hardware
Each color of LEDs is controlled by a power MOSFET, which received a PWM signal from the mbed. The panel has two sliders on the side, which each control the brightness of either the warm or cool LEDs. Connected to the mbed is a bluetooth module, which allows communication with a smartphone, as well as a coin cell battery that provides power to the mbed's real-time clock when the system is not plugged into wall power. The power supply is a repurposed Xbox 360 power supply, which provides a 12 V line for LED power and a 5V line for mbed power. The frame is a wood rectangle with an aluminum sheet as the backpane. The LED strips are attached to the backplane with double-sided thermal tape. The elctronics are secured to the back of the frame with hot glue. The Xbox power supply needs to have the Xbox-side connector removed and the insulation stripped to expose the 12V, 5V, and gnd wires.
Breakout Board Hookup
Bluetooth Module:
Pin Name= | mbed Pin= |
---|---|
gnd | gnd |
Vin | 5V |
CTS | gnd |
TXO | p27 |
RXI | p28 |
Sliders:
Pin Name= | mbed Pin= |
---|---|
Vin | 3.3V |
gnd | gnd |
Sense | p19, p20 |
Coin Cell:
Pin Name= | mbed Pin= |
---|---|
V+ | Vbat |
gnd | gnd |
Schematic
Parts List
Part= | Link |
---|---|
mbed LPC1768 | https://tinyurl.com/y9xhax5u |
CR2032 Coin Cell Battery | https://tinyurl.com/qus9dzq |
Slider P/N 1112 (x2) | https://tinyurl.com/tbcz7ho |
Original Xbox 360 Power Supply | https://tinyurl.com/v4vwgx4 |
Marswell CRI 90+ LED Strip (x2, daylight and warm white) | https://tinyurl.com/qrnrzl8 |
uxcell Aluminum Heatsinks | https://tinyurl.com/t2t8om4 |
Acrylic Sheet | https://tinyurl.com/t3vkssb |
Aluminum Sheet | |
Wood and Screws |
Code
Import programSmartLEDWindow
Smart LED window to mimic the sun
main.cpp
#include "mbed.h" #include <PwmOut.h> // **I/O INITIALIZATION** Serial pc(USBTX, USBRX); // tx, rx for Serial Port (Debugging) Serial Blue(p28,p27); // Bluetooh Initialization PwmOut bLED(p21); // Blue LEDS PWM pin assignment PwmOut rLED(p23); // Red LEDS PWM pin assignment AnalogIn bSliderIn(p20); // Slider in for blue AnalogIn rSliderIn(p19); // Slider in for red // **GLOBAL VARIABLES** int mode = 0; //Mode 0 = bluetooth; Mode 1 = slider; Mode 2 = RTC // These percentages are based off 0-100, // They do not correleate linearly with direct PwmOut. int bPercent=0; int rPercent=0; // **BLUETOOTH** // Variables volatile bool button_ready = 0; volatile int bnum = 0; volatile int bhit =0; // State used to remember previous characters read in a button message enum statetype {start = 0, got_exclm, got_B, got_num, got_hit}; statetype state = start; // Interrupt routine to parse message with one new character per serial RX interrupt void parse_message() { switch (state) { case start: if (Blue.getc()=='!') state = got_exclm; else state = start; break; case got_exclm: if (Blue.getc() == 'B') state = got_B; else state = start; break; case got_B: bnum = Blue.getc(); state = got_num; break; case got_num: bhit = Blue.getc(); state = got_hit; break; case got_hit: if (Blue.getc() == char(~('!' + ' B' + bnum + bhit))) button_ready = 1; state = start; break; default: Blue.getc(); state = start; } } // **FUNCTIONS** // setLight: Sets a specified color strip to an input (0-100) // then saves that input to the variables rPercent or bPercent. // // Input values are not linearly correlated with the PWM duty cycle, // instead they are translated with a cubic function, so the lights // *appear* to be acting linearly void setLight(int input, PwmOut *LED){ if (input >100){ //Correct input to 100 if input is somehow too high input = 100; } else if (input <0){ //Correct input to 0 if input is somehow too low input = 0; } if (LED == &bLED){ //If input is the blue LEDs if (input >= bPercent){ // If input is HIGHER than current brightness for (int i = bPercent; i < input; i++){ //Loop to gradually increase brightness until reaches desired value float temp = i; *LED = (((temp*temp*temp)/1000000)); wait(.01); } } else { // If input is LOWER than current brightness for (int i = bPercent; i > input; i--){ //Loop until reaches desired value float temp = i; *LED = (((temp*temp*temp)/1000000)); wait(.01); } } bPercent = (input); //Record input to current bPercent } else { //If input is the red LEDs if (input >= rPercent){ for (int i = rPercent; i < input; i++){ float temp = i; *LED = (((temp*temp*temp)/1000000)); wait(.01); } } else { //if input < bPercent for (int i = rPercent; i > input; i--){ float temp = i; *LED = (((temp*temp*temp)/1000000)); wait(.01); } } rPercent = (input); } } // sliderSet: Nearly the same as setLight() but with built-in noise reduction // (Doesn't allow any changes greater than 2 at a time) void sliderSet(int input, PwmOut *LED){ float temp = input; if (input >100){ //Set LED to 1 if input is somehow >= 100 *LED = 1; return; } else if (input <0){ //Set LED to 0 if input is somehow <= 100 *LED = 0; return; } else { //Cubic Function with noise reduction int bDif = abs( bPercent - input); int rDif = abs( rPercent - input); if (LED == &bLED){ //IF BLUE LED if (bDif <2 && bDif > -2){ *LED = (((temp*temp*temp)/1000000)); bPercent = (input); } } else { // IF RED LED if (rDif <2 && rDif > -2){ *LED = (((temp*temp*temp)/1000000)); rPercent = (input); } } } } // Returns the user percentage assigned to that LED. int getPercent(PwmOut *LED){ if (LED == &bLED){ return bPercent; } else return rPercent; } // **MAIN** int main() { //attach interrupt function for each new Bluetooth serial character Blue.attach(&parse_message,Serial::RxIrq); bLED.period_ms (1); //Set LED freq to 1Khz rLED.period_ms (1); PwmOut *LEDToControl = &bLED; //bLED is default LEDToControl set_time(1574588800); //7:00am while(1) { if (mode == 1){ sliderSet(bSliderIn*100,&bLED); sliderSet(rSliderIn*100,&rLED); } else if (mode == 2){ time_t now = time(0); tm *ltm = localtime(&now); int cHour = ltm->tm_hour; int cMin = ltm->tm_min; if (cHour > 18 || cHour <7){ //If between 6pm and 7am, turn all lights off setLight(0, &bLED); setLight(0, &rLED); } else if (cHour >= 7 && cHour < 8) { //From 7-8, fade as sunrise int lightset = cHour*100+(cMin)/.6; setLight((lightset-710)*8,&bLED); //Blue LED fade in at 7:06 setLight((lightset-700)*8,&rLED); //Red LED fade in at 7-7:08 pc.printf("Lightset: %i \n", lightset); } else if (cHour >= 17 && cHour < 18) { //From 5-6, fade as sunset int lightset = cHour*100+(cMin)/.6; setLight(100-((lightset-1725)*8),&rLED); //Red LED fade out at 5:15-5:30 setLight(100-((lightset-1700)*8),&bLED); //Blue LED fade out at 5-5:15 } else { setLight(100, &bLED); setLight(100, &rLED); } } //check for a new button message ready if(button_ready) { // button changed if(bnum=='1' && bhit == '1'){ mode = 0; pc.printf("mode 0!\n"); } else if (bnum=='2' && bhit == '1'){ mode = 1; setLight(bSliderIn*100,&bLED); setLight(rSliderIn*100,&rLED); pc.printf("mode 1!\n"); } else if (bnum=='3' && bhit == '1'){ mode = 2; pc.printf("mode 2!\n"); }else if (bnum=='4' && bhit == '1'){ if (mode == 0){ if (LEDToControl == &bLED){ LEDToControl = &rLED; } else { LEDToControl = &bLED; } } pc.printf("color!\n"); }else if (bnum=='5' && bhit == '1'){ if (mode == 0){ if (getPercent(LEDToControl) <= 95){ setLight((getPercent(LEDToControl)+10),LEDToControl); } } pc.printf("inc!\n"); }else if (bnum=='6' && bhit == '1'){ if (mode == 0){ if (getPercent(LEDToControl)>=5){ setLight((getPercent(LEDToControl)-10),LEDToControl); } //time_t seconds = time(0); //pc.printf("Time as a basic string = %s", ctime(&seconds)); } } button_ready = 0; //reset flag after reading button message } } }
Please log in to post comments.