Home lighting system with ESP8266 powered by Blynk

It’s been a long time since I wrote my last blog entry. This is mainly because I didn’t have time due to my extensive travels (world trip) and moving into a new flat. But now I’m back and try to update the site a bit more frequently.

There are quite a few commercially available home lighting systems that are controllable over the internet and have various features. Obviously I could have bought one of those but the affordable ones didn’t fit my needs and others were too expensive. (I wanted to build at least 10 lamps) In the end my build is quite a bit cheaper excluding the time i spent building it. At the time of writing this article I already have 10 lamps running and two were still under construction. In general I am satisfied with the system but there is one major flaw that I didn’t think of before building the system. I’m gonna write more about that later.

Most importantly I wanted to have a decent light quality. That’s why I decided to use the Citizen CLU028-1204C4-303H7K4 with a CRI of 97 and 1300lm output @ test current. It is available from DigiKey @ around 10USD per piece. Is is driven by a TPS92513HV which doesn’t even cost a dollar per piece. In addition I added 30 WS2812B on each board that I had lying around from the Wordclock project. The 30 WS2812B are not only there for ambient lighting but also to change the perceived color temperature of the main LED. I wanted to fit the main LED and the WS2812B into a PAR30 can that is often used in stage lighting. Unfortunately there aren’t any short versions available unlike for it’s bigger brother the PAR56.

So I made a PCB with two connectors. One for the power supply and the other one for the ESP8266 because I wasn’t sure whether the WIFI module would work if it’s placed inside the PAR30 can. Here’s the schematic, it’s quite straight forward. The 74AHCT acts as a level shifter for the WS2812B. I added the pot to set the current level for each board.

I assembled one board and it was working perfectly fine. I wrote the test software, did some testing… the WS2812B were working fine, as well as the main LED. The current via the potentiometer was also settable to a minimum level without shutting the LED completely off, exactly as written in the datasheet. But the idiot I am I didn’t test the PWM function until after I assembled 12 boards. When I tried to use it for the first time there was a very audible hum coming from the board. Apparently the TPS92513 switches off the gate driver and the output FET, basically acting as an enable switch and it only allows a PWM frequency up to 1kHz. That wouldn’t be a problem in a high noise environment like a street lamp or a car. But for home lighting the noise is absolutely not tolerable. I tried different coils, adding hot glue etc. but it was still too annoying.

Assembled board without modification. Heat sink is from Aliexpress (2.6USD)

The solution: I desoldered the potentiometer and cut the trace to the PDIM input. Then I soldered a resistor from pin 2 of the JST connector to the wiper pad of the FET. The RC time constant of the resistor (1M) and C5 is one second (Increased C5 to 1uF) , which is a lot lower than the PWM frequency. So it acts a kinda like a DAC and now I can still dim the LED but only to a certain level. The LEDs never turn off entirely. That’s why I added a P-Mosfet switch to the 48V supply line that is controlled with another ESP8266.

Then I drilled some holes in the ceiling and installed a rig to mount the lamps. Several days later I installed the lamps and the PSU. It was working fine but I still wasn’t too satisfied. The light spot were expectedly quite small due to the long nose of the PAR cans. I decided to shorten the cans a bit and voilà.. spots bigger, nicer light. Just like I wanted to have it.

So if anyone wants to build something similar, here’s the source code and the eagle files. I didn’t make any adjustments in the schematic, so the flaw with the noisy components still exist.

ParLedGerber ParLed

#include "FastLED.h"
#include 
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN 14

Adafruit_NeoPixel strip = Adafruit_NeoPixel(30, PIN, NEO_GRB + NEO_KHZ800);
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

//char auth[] = "********************************";  //Lampe1
//char auth[] = "********************************";  //Lampe2
//char auth[] = "********************************";  //Lampe3
//char auth[] = "********************************";  //Lampe4
//char auth[] = "********************************";  //Lampe5
//char auth[] = "********************************";  //Lampe6
//char auth[] = "********************************";  //Lampe7
//char auth[] = "********************************";  //Lampe8
char auth[] = "********************************";  //Lampe9
//char auth[] = "********************************";  //Lampe10
//char auth[] = "********************************";  //Lampe11
//char auth[] = "********************************";  //Lampe12

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "**********";
char pass[] = "**********";

int r=0; //values for zeRGBa
int g=0;
int b=0;

int r_colorFade=0; //values for colorfade
int g_colorFade=0;
int b_colorFade=0;

long random_r=0;  
long random_g=0;
long random_b=0;

int mainled = 0;

boolean colorFade = false;
boolean randomColorFade = false;

BLYNK_WRITE(V1) // zeRGBa assigned to V1 
{
    // get a RED channel value
     r = param[0].asInt();
    // get a GREEN channel value
     g = param[1].asInt();
    // get a BLUE channel value
     b = param[2].asInt();
     colorWipe(strip.Color(r, g, b),0);
}
BLYNK_WRITE(V2) // 
{
    mainled = param.asInt();
    analogWrite(4,mainled);
}
BLYNK_WRITE(V3){
if(param.asInt()){
  colorFade = true;
  //randomColorFade=false;  //hack, ändern auf blynk.virtualWrite(Vx,LOW); oder ähnlich. ebense in den 2 Funktionen unten

  Blynk.virtualWrite(V4, LOW);
  }
  else{
  colorFade=false;
  }
}

BLYNK_WRITE(V4){
if(param.asInt()){
  randomColorFade = true;
  //colorFade=false;
  Blynk.virtualWrite(V3, LOW);
  }
  else{
  randomColorFade=false;
  }
}

BLYNK_WRITE(V5){

  cinemaMode();
 // colorFade=false;
 // randomColorFade=false;
    Blynk.virtualWrite(V3, LOW);
    Blynk.virtualWrite(V4, LOW);
}
void setup() {

  random_r=random(100000);
  random_g=random(100000);
  random_b=random(100000);

  Serial.begin(115200);

  pinMode(4,OUTPUT);
  analogWriteFreq(100);
  analogWrite(4,25);
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  colorWipe(strip.Color(50, 50, 50), 30); // White
  colorWipe(strip.Color(0, 0, 0), 8); // 
  Blynk.begin(auth, ssid, pass);



if(Blynk.connected()){
  colorWipe(strip.Color(255, 0, 0), 30); // Red
  colorWipe(strip.Color(0, 0, 0), 8); // Red
   Blynk.syncAll();
  }
  
}

void loop() {

Blynk.run();

if(colorFade){                                                            //alle lampen synchron
  float redVal = (exp(sin(millis()/7000.0*PI)) - 0.36787944)*108.0;
  float grnVal = (exp(cos(millis()/11000.0*PI)) - 0.36787944)*108.0;
  float bluVal = (exp(sin(millis()/13000.0*PI)) - 0.36787944)*108.0;
  r_colorFade = (int) redVal;
  g_colorFade = (int) grnVal;
  b_colorFade = (int) bluVal;
  colorWipe(strip.Color(r_colorFade, g_colorFade, b_colorFade), 1); // Red
  }
else if(randomColorFade){
  
  long red=millis()+random_r;                                           //lampen asynchron
  long green=millis()+random_g;
  long blue=millis()+random_b;
  
  float redVal = (exp(sin(red/7000.0*PI)) - 0.36787944)*108.0;
  float grnVal = (exp(cos(green/11000.0*PI)) - 0.36787944)*108.0;
  float bluVal = (exp(sin(blue/13000.0*PI)) - 0.36787944)*108.0;
  r_colorFade = (int) redVal;
  g_colorFade = (int) grnVal;
  b_colorFade = (int) bluVal;
  colorWipe(strip.Color(r_colorFade, g_colorFade, b_colorFade), 1); // Red
  }

 else{
  colorWipe(strip.Color(r, g, b),0);
  }

}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    
    delay(wait);
    strip.show();
  }
}

void cinemaMode(){
    analogWrite(4,mainled);
    colorWipe(strip.Color(255, 40, 0), 100); // Red
}
}