Creating a controller board for RGBW LEDs that connects via WiFi, and can integrate with any home automation system and can control any constant voltage LED.

The goal was this: create a circuit that could interface with any system and could control any LED (well, constant voltage LED…).

This was accomplished using an ESP-12 Wifi module in a custom circuit board, manufactured by LCSC electronics and assembled at home on the bench.

The controller can connect to any system capable of communicating over a network, tested with Lutron, Openhab, Crestron.

The first time the board is powered up, it will create a WiFi hotspot. Once connected to the hotspot, you can configure the device to your own wifi network, and then send commands to it to change the lighting.

Bench Test

Original Protoype

Original Prototype Reverse Side

Help yourself to the firmware, GPL
/*
* ESP8266 RGBW LED Controller version 1.2
*
* by Tom Porter: tgb.porter@googlemail.com
*
* Many thanks to tzapu for the Wifi Config Software: https://github.com/tzapu/WiFiManager
*
* Many thanks to the ESP8266 and Arduino Community http://www.esp8266.com
*
* How this program works:
* Upon first boot of the board, the ESP broadcasts a config SSID.
* Connecting to this SSID then produces a "captive portal" and takes you to the config page.
* i.e. If you try to go to any web address (with the exception of google.com from Chrome and android), you will be shown the config page.
*
* Through here you can scan for a Wifi Network and connect using your SSID and Password.
* If you wish to use the controller without a Wifi Router, then wait for 180 seconds and then refresh the config page.
*
* This will then allow you to see the Web Interface without a router.
*
* You can alos by navigate to http://192.168.4.1 (a standard for the ESP8266)
*
* To then try again to connect to the WiFi Network, just reboot the board.
*
* If you go the router way (recommended), the SSID and Password will be saved to the ESP and it will reconnect every time you reboot.
*
* If you are connected to a Wifi Network, you need to find the IP address and this can be done a number of ways:
* 1. Through the serial port if you are hard wired to the board (advanced)
* 2. Through your router's interface (you can ask me how to do this)(intermediate)
* 3. A smartphone app called "Fing Network Tools". (Connect to Network, Scan SSID, look for "ESPXXXX") (easy)
*
* You can then put the IP address in the title bar of any browser connected to the same network to bring up the web interface.
*
* However, I recommend using third party apps such as "Tasker" that can send HTTP POST commands to the ESP to control the strip.
*
* I find this to be the most convenient as I can have the icons on the home screen of my android phone and it is much more customisable. (my apologies iOS, don't blame me, blame Steve)
*
* Also this product is compatible with smarthome control systems such as Lutron, Crestron and Control4 (All Tested). And I am sure it will be trivial to set up with Domoticz, or other Open Source alternatives to these.
*
* Please email me if you need assistance setting anything up.
*
* Hope you enjoy,
*
* Thank you,
*
* Tom Porter
*
*/

#include //https://github.com/esp8266/Arduino
#include
#include
#include //https://github.com/tzapu/WiFiManager

#define redPin 16 //This is how the pins are wired, labels are on the underside of the board
#define greenPin 14
#define bluePin 12
#define whitePin 13
#define configTimeout 180

DNSServer dnsServer; //A leftover from ver1.0, but I am leaving it here for now just in case
const byte DNS_PORT = 53;

ESP8266WebServer server(80);

String webPage = ""; //Hold this here Please

void setup() {
Serial.begin(115200);

//###############################################################WIFI MANAGER THANKS AGAIN TZAPU#######################################################################################
WiFiManager wifiManager; //WiFiManager's business
// wifiManager.resetSettings();
wifiManager.setTimeout(configTimeout);

if(!wifiManager.autoConnect("RGBW LED Controller")) { //fetches SSID and PW and tries to connect
Serial.println("Booting to Standalone Mode"); //if it does not connect it starts an access point with the specified name
delay(3000); //user can boot to standalone by forcing a timeout (i.e. put an incorrect SSID or PW) if 180 seconds is too long to wait.
}

Serial.print("my IP address is : "); // print the IP address in the case that user is connected via serial
Serial.println(WiFi.localIP());

//##############################################################WIFI MANAGER IS DONE#################################################################################################

pinMode(redPin, OUTPUT); //initialise LED Pins
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
pinMode(whitePin, OUTPUT);

analogWrite(redPin, 0); //keep them off after boot, it is on my to do list to bring on the last colour from when it was switched off.
analogWrite(greenPin, 0);
analogWrite(bluePin, 0);
analogWrite(whitePin, 0);

//####################################################START HTML########################################################################################################################
//I am always looking for suggestions on how to improve the web interface.

webPage +="



<h1 style="0font-size: 300%\;">RGBW LED Controller</h1>




"
"<a href="\"><button style="0font-size: 300%; background-color: red; height: 10%; width: 100%;">RED</button></a>
"
"<a href="\"><button style="0font-size: 300%; background-color: yellow; height: 10%; width: 100%;">YELLOW</button></a>
"
"<a href="\"><button style="0font-size: 300%; background-color: green; height: 10%; width: 100%;">GREEN</button></a>
"
"<a href="\"><button style="0font-size: 300%; background-color: cyan; height: 10%; width: 100%;">CYAN</button></a>
"
"<a href="\"><button style="0font-size: 300%; background-color: blue; height: 10%; width: 100%;">BLUE</button></a>
"
"<a href="\"><button style="0font-size: 300%; background-color: magenta; height: 10%; width: 100%;">MAGENTA</button></a>
"
"<a href="\"><button style="0font-size: 300%; background-color: white; height: 10%; width: 100%;">WHITE</button></a>
"
"<a href="\"><button style="0font-size: 300%; height: 10%; width: 100%;">OFF</button></a>
"

"



<h1 style="0font-size: 200%\;">Individual RGBW Values
for more control
Any value between 0 and 1023</h1>




"
"<b style="0font-size: 100%\;">This is primarily used for other apps to send colour data to the strip via HTTP POST</b>"
"



<form action="/submit" method="POST">"
"Red: <input style="0font-size: 300%\;" name="\" type="\" />
"
"Green: <input style="0font-size: 300%\;" name="\" type="\" />
"
"Blue: <input style="0font-size: 300%\;" name="\" type="\" />
"
"White: <input style="0font-size: 300%\;" name="\" type="\" />
"
"<input style="0font-size: 300%\;" type="\" value="\" />"
"</form>




";
//####################################################END HTML###########################################################################################################################

delay (100); //and breathe, please don't judge me on my html.

server.on("/", [](){server.send(200, "text/html", webPage);}); //manage all of the HTTP requests and posts
server.on("/red", red);
server.on("/green", green);
server.on("/blue", blue);
server.on("/magenta", magenta);
server.on("/yellow", yellow);
server.on("/cyan", cyan);
server.on("/white", white);
server.on("/off", off);
server.on("/submit", handleSubmit);

server.begin();
Serial.println("HTTP server started"); //essential line right there
}

void loop() {
dnsServer.processNextRequest(); //relic
server.handleClient();
}

//###############################################################################BEGIN ANCILLIARY FUNCTION DEFINITION####################################################################

int colourWrite(int red, int green, int blue, int white) { //this makes the following much easier
analogWrite(redPin, red);
analogWrite(greenPin, green);
analogWrite(bluePin, blue);
analogWrite(whitePin, white);
}

void red(){
server.send(200, "text/html", webPage);
colourWrite(1023,0,0,0);
delay(500);
}

void yellow(){
server.send(200, "text/html", webPage);
colourWrite(1023,1023,0,0);
delay(500);
}

void green(){
server.send(200, "text/html", webPage);
colourWrite(0,1023,0,0);
delay(500);
}

void cyan(){
server.send(200, "text/html", webPage);
colourWrite(0,1023,1023,0);
delay(500);
}

void blue(){
server.send(200, "text/html", webPage);
colourWrite(0,0,1023,0);
delay(500);
}

void magenta(){
server.send(200, "text/html", webPage);
colourWrite(1023,0,1023,0);
delay(500);
}

void white(){
server.send(200, "text/html", webPage);
colourWrite(0,0,0,1023);
delay(500);
}

void off(){
server.send(200, "text/html", webPage);
colourWrite(0,0,0,0);
delay(500);
}

void handleSubmit(){

server.send(200, "text/html", webPage);

if (server.args() > 0 ) {
for ( uint8_t i = 0; i < server.args(); i++ ) {
if (server.argName(i) == "redIn") {
analogWrite(redPin, server.arg(i).toInt());
}
else if (server.argName(i) == "greenIn") {
analogWrite(greenPin, server.arg(i).toInt());
}
else if (server.argName(i) == "blueIn") {
analogWrite(bluePin, server.arg(i).toInt());
}
else if (server.argName(i) == "whiteIn") {
analogWrite(whitePin, server.arg(i).toInt());
}
}
}
}
//###############################################################################END ANCILLIARY FUNCTION DEFINITION####################################################################