Smart LED Window

Overview

/media/uploads/TCNoodleshop/untitled.png

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=
gndgnd
Vin5V
CTSgnd
TXOp27
RXIp28

Sliders:

Pin Name=mbed Pin=
Vin3.3V
gndgnd
Sensep19, p20

Coin Cell:

Pin Name=mbed Pin=
V+Vbat
gndgnd

Schematic

/media/uploads/TCNoodleshop/schematic.png

Parts List

Part=Link
mbed LPC1768https://tinyurl.com/y9xhax5u
CR2032 Coin Cell Batteryhttps://tinyurl.com/qus9dzq
Slider P/N 1112 (x2)https://tinyurl.com/tbcz7ho
Original Xbox 360 Power Supplyhttps://tinyurl.com/v4vwgx4
Marswell CRI 90+ LED Strip (x2, daylight and warm white)https://tinyurl.com/qrnrzl8
uxcell Aluminum Heatsinkshttps://tinyurl.com/t2t8om4
Acrylic Sheethttps://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.