WiFi RGB Lamp Web Server

Dependencies:   mbed ESP8266_WebServer

RGB WiFi Lamp

Firmware

This is the official firmware repository for the BinarySpace RGB WiFi Lamp project. This firmware is still in alpha stage, and subject to change.

Planned changes include:

  • Configure the WiFi Lamp to connect onto your SSID
  • Variety of operating modes like
    • Fixed colour operation
    • Rainbow gradient
    • Time-based colour changing
    • API-based colour changing

Connecting to the WiFi lamp

To connect to the WiFi lamp web server, scan for an open WiFi network using your cellphone, tablet or laptop that begins with the letters ESP_xxxxxx. This is the automatically created SSID of the ESP8266 WiFi module used in the lamp. Your WiFi client needs to be configured to use DHCP.

Once connected, simply point your browser at http://192.168.4.1 and you should see the rudementary web interface allowing you to switch the WiFi lamp on in the red colour or off.

A second option is to enter the following URL
http://192.168.4.1/setcolor?r=x&g=x&b=x
where x is a number between 0 and 255 for the intensity of (r)ed, (g)reen and (b)lue respectively. Any of the r,g,b parts not specified will automatically default to 0

Supported Platforms

  • ST Nucleo F103RB
  • ST Nucleo F302R8
  • ST Nucleo L152RE
  • ST Nucleo F401RE

Unsupported Platforms

  • ST Nucleo F030R8 (unsupported due to insufficient registers for PololuLed library)

How to update your firmware

One of the best things about the ST Nucleo series is that they enumerate as a USB Mass Storage device when plugged in. Updating the firmware is as simple as compiling it using mbed compiler(free registration required to use) for your selected platform, plugging in your Nucleo and copying the .bin file created by the compiler to the USB drive enumerated by the Nucleo. That's it!

Code is fully Open Source

Please feel free to fork this repository and to submit pull requests if you make any cool additions/changes.

If you are developing changes to the firmware and monitoring via serial console for debugging purposes, note than you can simply comment out the #define DEBUG_WIFI line at the top of the main.cpp file to make the output much less verbose. This effectively disables debugging of the WebServer library code and echoing of communications between the Nucleo and the ESP. It also makes the web server noticeably faster, as it doesn't have to output a lot of serial data before handling requests.

LED Strip colour inconsistency

If you are experiencing problems with the LED's not all changing colour, or perhaps flickering or incorrect colour, there could be 2 potential problems we have identified.

  • Power Supply problems - If the power supply is not providing enough power, or not clean enough power, you may experience flickering or random colour changes. Ensure that your power supply can provide enough power (1A @ 5V recommended). If this does not solve your problem, soldering a capacitor over the power supply lines(5V, GND) may help to clean out any noise from the power supply. (100uF minimum)
  • Depending on cable lengths and connectors, noise on the data line may also be a problem. Try soldering a 100Ω - 500Ω resistor in line on the Din pin of the LED strip

Firmware update for the ESP8266 Module

We suggest you upgrade the firmware on the ESP8266 module to the latest official AT firmware from Espressif. Click Here for a detailed upgrade quide.

main.cpp

Committer:
sschocke
Date:
2015-01-08
Revision:
28:ba5c68a04f56
Parent:
27:88093aa94e24

File content as of revision 28:ba5c68a04f56:

#include "mbed.h"
#include "PololuLedStrip.h"
#include "ESP8266_WebServer.h"
#include "resource.h"
#include <string>
//#define DEBUG_WIFI

PololuLedStrip ledStrip(D11);

#define LED_COUNT 8
rgb_color colors[LED_COUNT];

DigitalOut wifiCHPD(D4);
DigitalOut wifiReset(D9);

int wifiOn = 0;
int opMode = 0;
std::string stationMAC;
std::string stationIP;
std::string ssid;
std::string apMAC;
std::string apIP;

Serial wifiSerial(D8,D2);
Serial pc(USBTX,USBRX);
ESP8266_WebServer server(&wifiSerial);

char temp[200];
const char* VERSION = "0.5-alpha";

#ifdef DEBUG_WIFI
void pcrxint(void) {
    //server.debugBuffers(&pc);
    pc.putc('@');
    server.echoMode = true;
}
#endif

void rxint(void) {
    server.rxint();
}

void setColor( uint8_t r, uint8_t g, uint8_t b )
{
    for ( int c = 0; c < LED_COUNT; c++ )
    {
        colors[c].red = r;
        colors[c].green = g;
        colors[c].blue = b;
    }
    
    ledStrip.write(colors, LED_COUNT);
}

void setDiscoColor( )
{
    for ( int c = 0; c < LED_COUNT; c++ )
    {
        colors[c].red = rand()%100;
        colors[c].green = rand()%100;
        colors[c].blue = rand()%100;
    }
    
    ledStrip.write(colors, LED_COUNT);
}

Timer DiscoTimer;
#define DiscoDelay 100

int lampMode = 0;

unsigned long heapSize()
{
    char   stackVariable;
    void   *heap;
    unsigned long result;
    heap  = malloc(4);
    result  = (uint8_t*)&stackVariable - (uint8_t*)heap;
    free(heap);
    return result;
}

void sendConfigJSONReply(int linkID, const char* result) {
    sprintf(temp, jsonConfigReply, opMode, stationIP.c_str(), ssid.c_str(), result);
    server.SendReply(linkID, temp, mimeJSON, 0);
}

int main() {
    pc.baud(115200);
#ifdef DEBUG_WIFI
    pc.attach(&pcrxint);
#endif
    
    pc.printf("\r\nWiFi Lamp - %s...\r\n", VERSION);    
    
    setColor( 25, 0, 0);
    
    wifiCHPD = 0;
    wifiReset = 0;
    wifiSerial.baud(115200);
    wifiSerial.attach(&rxint);
#ifdef DEBUG_WIFI
    server.debugSerial = &pc;
    pc.printf("Debug WiFi Enabled!\r\n");
#endif
    wait_ms(1000);
    
    pc.printf("Powering WiFi...\r\n");    
    wifiCHPD = 1;
    wifiReset = 1;
    wait_ms(250);
    pc.printf("Hardware Reset WiFi...\r\n");    
    server.ResetModule();
    wifiOn = 1;
    
    std::string fwVer = server.GetFirmwareVersion();
    pc.printf("ESP Firmware Version: %s\r\n", fwVer.c_str());
    
    pc.printf("Starting Web Server...\r\n");
    server.Initialize();
    pc.printf("Done\r\n");
    
    opMode = server.GetOperatingMode();
    pc.printf("Operating Mode: %s(%d)\r\n", opModes[opMode], opMode);
    if( (opMode & OPMODE_STATION) ) {
        pc.printf("Waiting 5 secs for join to WiFi Network...\r\n");
        wait_ms(5000);
        stationMAC = server.GetStationMAC();
        stationIP = server.GetStationIP();
        ssid = server.GetStationSSID();
        pc.printf("Station MAC: %s, Station SSID: %s, Station IP: %s\r\n", stationMAC.c_str(), ssid.c_str(), stationIP.c_str());
    }
    if( (opMode & OPMODE_SOFTAP) ) {
        apMAC = server.GetAPMAC();
        apIP = server.GetAPIP();
        pc.printf("SoftAP MAC: %s, SoftAP IP: %s\r\n", apMAC.c_str(), apIP.c_str());
    }
    
    setColor( 0, 25, 0);
    wait_ms(500);
    setColor( 0, 0, 0);
    
    pc.printf("Heap Memory %d", heapSize());
    DiscoTimer.start();
                    
    std::string httpReply;
    while(true) {
        ESP8266_WebRequest* request = server.GetRequest();
        if( request != NULL ) {
            pc.printf("HTTP %s %s\r\n", request->Method.c_str(), request->URI.c_str());
            for( std::map<std::string,std::string>::iterator it = request->Parameters.begin(); it!=request->Parameters.end(); ++it ) {
                pc.printf("HTTP Parameter %s = %s\r\n", it->first.c_str(), it->second.c_str());
            }
            if( request->URI == "/" || request->URI == "/index.html" ) {
                httpReply = htmlHead;
                httpReply += "<table><tr><td align='right'><a href='config'><img src='config.gif' /></a></td></tr>";
                httpReply += "<tr><td align='center'>";
                httpReply += "<img style='margin-right:2px' src='colormap.gif' usemap='#colormap' />";
                httpReply += "<map id='colormap' name='colormap'>";
                httpReply += "</map></td></tr>";
                httpReply += "<tr><td><span onClick=\"window.location='/disco'\">Disco Mode</span></td></tr>";
                httpReply += "<tr><td><span onClick=\"changeColor('#000000')\">Turn Off</span></td></tr>";
                httpReply += "</table>";
                httpReply += htmlTail;
                server.SendReply(request->LinkID, httpReply, mimeHTML);
            } else if( request->URI == "/config" ) {
                if( (opMode & OPMODE_STATION) ) {
                    stationIP = server.GetStationIP();
                    ssid = server.GetStationSSID();
                }
                httpReply = htmlHead;
                httpReply += htmlConfigHTML;
                httpReply += htmlTail;
                httpReply = httpReply.replace(httpReply.find("%opmode1%"), 9, (opMode==1? " selected" : ""));
                httpReply = httpReply.replace(httpReply.find("%opmode2%"), 9, (opMode==2? " selected" : ""));
                httpReply = httpReply.replace(httpReply.find("%opmode3%"), 9, (opMode==3? " selected" : ""));
                httpReply = httpReply.replace(httpReply.find("%stamac%"), 8, stationMAC);
                httpReply = httpReply.replace(httpReply.find("%staip%"), 7, stationIP);
                httpReply = httpReply.replace(httpReply.find("%apmac%"), 7, apMAC);
                httpReply = httpReply.replace(httpReply.find("%apip%"), 6, apIP);
                httpReply = httpReply.replace(httpReply.find("%ssid%"), 6, ssid);
                server.SendReply(request->LinkID, httpReply, mimeHTML, 0);
            } else if( request->URI == "/updateconfig" ) {
                bool result = true;
                int newOpMode = atoi(request->Parameters["opmode"].c_str());
                std::string newSSID = request->Parameters["ssid"];
                std::string newPassword = request->Parameters["pwd"];
                if( newOpMode != opMode ) {
                    result = server.SetOperatingMode(newOpMode);
                    if( result == false ) {
                        sendConfigJSONReply(request->LinkID, "Error setting Operating Mode");
                        delete request;
                        continue;
                    }
                    opMode = newOpMode;
                }
                if( (opMode & OPMODE_STATION) ) {
                    if( (ssid.compare(newSSID) != 0) || (newPassword.empty() == false) ) {
                        result = server.SetStationSSID(newSSID, newPassword);
                        if( result == false ) {
                            sendConfigJSONReply(request->LinkID, "Error connecting to SSID");
                            delete request;
                            continue;
                        }
                        // Wait for SSID to connect
                        for( int retries=0; retries < 6; retries++) {
                            wait_ms(5000);
                            ssid = server.GetStationSSID();
                            if( ssid.compare(newSSID) == 0 ) {
                                break;
                            }
                        }
                        stationIP = server.GetStationIP();
                    }
                }
                sendConfigJSONReply(request->LinkID, "Success");
            } else if( request->URI == "/wifilamp.js" ) {
                server.SendReply(request->LinkID, javascript, strlen(javascript), mimeJavaScript);
            } else if( request->URI == "/wifilamp.css" ) {
                server.SendReply(request->LinkID, css, strlen(css), mimeCSS);
            } else if( request->URI == "/colormap.gif" ) {
                server.SendReply(request->LinkID, (char*)colorMap, sizeof(colorMap), mimeGIF);
            } else if( request->URI == "/config.gif" ) {
                server.SendReply(request->LinkID, (char*)configIcon, sizeof(configIcon), mimeGIF);
           } else if( request->URI == "/robots.txt" ) {
                server.SendReply(request->LinkID, robotsTxt, strlen(robotsTxt), mimeText);
            } else if( request->URI == "/favicon.ico" ) {
                server.SendReply(request->LinkID, (char*)favIcon, sizeof(favIcon), "image/x-icon");
            } else if( request->URI == "/disco" ) {
                lampMode = 2; // All colours
                DiscoTimer.reset();
                server.SendReply(request->LinkID, "OK", mimeText, 0);
            } else if( request->URI == "/setcolour" || request->URI == "/setcolor" ) {
                int r=0, g=0, b=0;

                lampMode = 1; // All LED 1 colour                
                
                if(request->Parameters.count("r") > 0) r=atoi(request->Parameters["r"].c_str());
                if(request->Parameters.count("g") > 0) g=atoi(request->Parameters["g"].c_str());
                if(request->Parameters.count("b") > 0) b=atoi(request->Parameters["b"].c_str());
                
                pc.printf( "Set colour to (%i, %i, %i)\r\n", r,g,b);
                
                setColor( r,g,b );
                
                server.SendReply(request->LinkID, "OK", mimeText, 0);
            } else {
                server.Send404Error(request->LinkID);
            }
            pc.printf("\r\nHTTP Reply Sent\r\n");
            delete request;
        }
        if( lampMode == 2 && DiscoTimer.read_ms() > DiscoDelay ) {
            setDiscoColor();
            // Delay random colour change, else it just looks white
            DiscoTimer.reset();
        }
/*
        if( lampMode == 3 ) {
            // strobe
        }

        if( lampMode == 4 ) {
            // fade
        }

*/
    }
}