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.

Committer:
sschocke
Date:
Thu Jan 08 18:25:16 2015 +0000
Revision:
28:ba5c68a04f56
Parent:
27:88093aa94e24
Disco Mode

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sschocke 0:d21e3e1c0a4b 1 #include "mbed.h"
sschocke 1:f07afcffeb5a 2 #include "PololuLedStrip.h"
sschocke 7:f15c81074400 3 #include "ESP8266_WebServer.h"
sschocke 22:6d7a72fab8ff 4 #include "resource.h"
sschocke 0:d21e3e1c0a4b 5 #include <string>
sschocke 13:1e8f27da036a 6 //#define DEBUG_WIFI
sschocke 0:d21e3e1c0a4b 7
sschocke 8:f819de1946a7 8 PololuLedStrip ledStrip(D11);
sschocke 1:f07afcffeb5a 9
sschocke 8:f819de1946a7 10 #define LED_COUNT 8
sschocke 1:f07afcffeb5a 11 rgb_color colors[LED_COUNT];
sschocke 1:f07afcffeb5a 12
sschocke 0:d21e3e1c0a4b 13 DigitalOut wifiCHPD(D4);
sschocke 0:d21e3e1c0a4b 14 DigitalOut wifiReset(D9);
sschocke 0:d21e3e1c0a4b 15
sschocke 0:d21e3e1c0a4b 16 int wifiOn = 0;
sschocke 23:3563e1699fb9 17 int opMode = 0;
sschocke 23:3563e1699fb9 18 std::string stationMAC;
sschocke 23:3563e1699fb9 19 std::string stationIP;
sschocke 23:3563e1699fb9 20 std::string ssid;
sschocke 23:3563e1699fb9 21 std::string apMAC;
sschocke 23:3563e1699fb9 22 std::string apIP;
sschocke 0:d21e3e1c0a4b 23
sschocke 0:d21e3e1c0a4b 24 Serial wifiSerial(D8,D2);
sschocke 0:d21e3e1c0a4b 25 Serial pc(USBTX,USBRX);
sschocke 7:f15c81074400 26 ESP8266_WebServer server(&wifiSerial);
sschocke 0:d21e3e1c0a4b 27
sschocke 22:6d7a72fab8ff 28 char temp[200];
sschocke 23:3563e1699fb9 29 const char* VERSION = "0.5-alpha";
sschocke 20:f5a6527bfda6 30
sschocke 20:f5a6527bfda6 31 #ifdef DEBUG_WIFI
sschocke 20:f5a6527bfda6 32 void pcrxint(void) {
sschocke 23:3563e1699fb9 33 //server.debugBuffers(&pc);
sschocke 23:3563e1699fb9 34 pc.putc('@');
sschocke 20:f5a6527bfda6 35 server.echoMode = true;
sschocke 20:f5a6527bfda6 36 }
sschocke 20:f5a6527bfda6 37 #endif
sschocke 20:f5a6527bfda6 38
sschocke 7:f15c81074400 39 void rxint(void) {
sschocke 7:f15c81074400 40 server.rxint();
sschocke 0:d21e3e1c0a4b 41 }
sschocke 0:d21e3e1c0a4b 42
tomvdb 4:4a502f72cbe3 43 void setColor( uint8_t r, uint8_t g, uint8_t b )
tomvdb 4:4a502f72cbe3 44 {
tomvdb 4:4a502f72cbe3 45 for ( int c = 0; c < LED_COUNT; c++ )
tomvdb 4:4a502f72cbe3 46 {
tomvdb 4:4a502f72cbe3 47 colors[c].red = r;
tomvdb 4:4a502f72cbe3 48 colors[c].green = g;
tomvdb 4:4a502f72cbe3 49 colors[c].blue = b;
tomvdb 4:4a502f72cbe3 50 }
tomvdb 4:4a502f72cbe3 51
tomvdb 4:4a502f72cbe3 52 ledStrip.write(colors, LED_COUNT);
tomvdb 4:4a502f72cbe3 53 }
tomvdb 4:4a502f72cbe3 54
leet 26:ea5e0ff46492 55 void setDiscoColor( )
leet 26:ea5e0ff46492 56 {
leet 26:ea5e0ff46492 57 for ( int c = 0; c < LED_COUNT; c++ )
leet 26:ea5e0ff46492 58 {
sschocke 28:ba5c68a04f56 59 colors[c].red = rand()%100;
sschocke 28:ba5c68a04f56 60 colors[c].green = rand()%100;
sschocke 28:ba5c68a04f56 61 colors[c].blue = rand()%100;
leet 26:ea5e0ff46492 62 }
leet 26:ea5e0ff46492 63
leet 26:ea5e0ff46492 64 ledStrip.write(colors, LED_COUNT);
leet 26:ea5e0ff46492 65 }
leet 26:ea5e0ff46492 66
leet 26:ea5e0ff46492 67 Timer DiscoTimer;
leet 26:ea5e0ff46492 68 #define DiscoDelay 100
leet 26:ea5e0ff46492 69
leet 26:ea5e0ff46492 70 int lampMode = 0;
leet 26:ea5e0ff46492 71
leet 26:ea5e0ff46492 72 unsigned long heapSize()
leet 26:ea5e0ff46492 73 {
leet 26:ea5e0ff46492 74 char stackVariable;
leet 26:ea5e0ff46492 75 void *heap;
leet 26:ea5e0ff46492 76 unsigned long result;
leet 26:ea5e0ff46492 77 heap = malloc(4);
leet 26:ea5e0ff46492 78 result = (uint8_t*)&stackVariable - (uint8_t*)heap;
leet 26:ea5e0ff46492 79 free(heap);
leet 26:ea5e0ff46492 80 return result;
leet 26:ea5e0ff46492 81 }
leet 26:ea5e0ff46492 82
sschocke 23:3563e1699fb9 83 void sendConfigJSONReply(int linkID, const char* result) {
sschocke 23:3563e1699fb9 84 sprintf(temp, jsonConfigReply, opMode, stationIP.c_str(), ssid.c_str(), result);
sschocke 23:3563e1699fb9 85 server.SendReply(linkID, temp, mimeJSON, 0);
sschocke 23:3563e1699fb9 86 }
sschocke 23:3563e1699fb9 87
sschocke 0:d21e3e1c0a4b 88 int main() {
sschocke 13:1e8f27da036a 89 pc.baud(115200);
sschocke 20:f5a6527bfda6 90 #ifdef DEBUG_WIFI
sschocke 20:f5a6527bfda6 91 pc.attach(&pcrxint);
sschocke 20:f5a6527bfda6 92 #endif
leet 10:f48a9f923271 93
leet 26:ea5e0ff46492 94 pc.printf("\r\nWiFi Lamp - %s...\r\n", VERSION);
leet 10:f48a9f923271 95
sschocke 13:1e8f27da036a 96 setColor( 25, 0, 0);
tomvdb 4:4a502f72cbe3 97
sschocke 0:d21e3e1c0a4b 98 wifiCHPD = 0;
sschocke 0:d21e3e1c0a4b 99 wifiReset = 0;
sschocke 13:1e8f27da036a 100 wifiSerial.baud(115200);
sschocke 0:d21e3e1c0a4b 101 wifiSerial.attach(&rxint);
sschocke 7:f15c81074400 102 #ifdef DEBUG_WIFI
sschocke 7:f15c81074400 103 server.debugSerial = &pc;
leet 26:ea5e0ff46492 104 pc.printf("Debug WiFi Enabled!\r\n");
sschocke 7:f15c81074400 105 #endif
sschocke 0:d21e3e1c0a4b 106 wait_ms(1000);
sschocke 0:d21e3e1c0a4b 107
sschocke 0:d21e3e1c0a4b 108 pc.printf("Powering WiFi...\r\n");
sschocke 0:d21e3e1c0a4b 109 wifiCHPD = 1;
sschocke 13:1e8f27da036a 110 wifiReset = 1;
sschocke 0:d21e3e1c0a4b 111 wait_ms(250);
sschocke 0:d21e3e1c0a4b 112 pc.printf("Hardware Reset WiFi...\r\n");
sschocke 24:849265425708 113 server.ResetModule();
sschocke 0:d21e3e1c0a4b 114 wifiOn = 1;
sschocke 0:d21e3e1c0a4b 115
sschocke 23:3563e1699fb9 116 std::string fwVer = server.GetFirmwareVersion();
sschocke 23:3563e1699fb9 117 pc.printf("ESP Firmware Version: %s\r\n", fwVer.c_str());
sschocke 23:3563e1699fb9 118
sschocke 7:f15c81074400 119 pc.printf("Starting Web Server...\r\n");
sschocke 7:f15c81074400 120 server.Initialize();
sschocke 23:3563e1699fb9 121 pc.printf("Done\r\n");
sschocke 23:3563e1699fb9 122
sschocke 23:3563e1699fb9 123 opMode = server.GetOperatingMode();
sschocke 23:3563e1699fb9 124 pc.printf("Operating Mode: %s(%d)\r\n", opModes[opMode], opMode);
sschocke 23:3563e1699fb9 125 if( (opMode & OPMODE_STATION) ) {
sschocke 23:3563e1699fb9 126 pc.printf("Waiting 5 secs for join to WiFi Network...\r\n");
sschocke 23:3563e1699fb9 127 wait_ms(5000);
sschocke 23:3563e1699fb9 128 stationMAC = server.GetStationMAC();
sschocke 23:3563e1699fb9 129 stationIP = server.GetStationIP();
sschocke 23:3563e1699fb9 130 ssid = server.GetStationSSID();
sschocke 23:3563e1699fb9 131 pc.printf("Station MAC: %s, Station SSID: %s, Station IP: %s\r\n", stationMAC.c_str(), ssid.c_str(), stationIP.c_str());
sschocke 23:3563e1699fb9 132 }
sschocke 23:3563e1699fb9 133 if( (opMode & OPMODE_SOFTAP) ) {
sschocke 23:3563e1699fb9 134 apMAC = server.GetAPMAC();
sschocke 23:3563e1699fb9 135 apIP = server.GetAPIP();
sschocke 23:3563e1699fb9 136 pc.printf("SoftAP MAC: %s, SoftAP IP: %s\r\n", apMAC.c_str(), apIP.c_str());
sschocke 23:3563e1699fb9 137 }
sschocke 23:3563e1699fb9 138
sschocke 13:1e8f27da036a 139 setColor( 0, 25, 0);
tomvdb 4:4a502f72cbe3 140 wait_ms(500);
tomvdb 4:4a502f72cbe3 141 setColor( 0, 0, 0);
tomvdb 4:4a502f72cbe3 142
leet 26:ea5e0ff46492 143 pc.printf("Heap Memory %d", heapSize());
leet 26:ea5e0ff46492 144 DiscoTimer.start();
leet 26:ea5e0ff46492 145
sschocke 23:3563e1699fb9 146 std::string httpReply;
sschocke 0:d21e3e1c0a4b 147 while(true) {
sschocke 9:319aeb6e0123 148 ESP8266_WebRequest* request = server.GetRequest();
sschocke 9:319aeb6e0123 149 if( request != NULL ) {
sschocke 9:319aeb6e0123 150 pc.printf("HTTP %s %s\r\n", request->Method.c_str(), request->URI.c_str());
sschocke 9:319aeb6e0123 151 for( std::map<std::string,std::string>::iterator it = request->Parameters.begin(); it!=request->Parameters.end(); ++it ) {
sschocke 9:319aeb6e0123 152 pc.printf("HTTP Parameter %s = %s\r\n", it->first.c_str(), it->second.c_str());
sschocke 9:319aeb6e0123 153 }
leet 26:ea5e0ff46492 154 if( request->URI == "/" || request->URI == "/index.html" ) {
sschocke 23:3563e1699fb9 155 httpReply = htmlHead;
sschocke 23:3563e1699fb9 156 httpReply += "<table><tr><td align='right'><a href='config'><img src='config.gif' /></a></td></tr>";
sschocke 23:3563e1699fb9 157 httpReply += "<tr><td align='center'>";
sschocke 23:3563e1699fb9 158 httpReply += "<img style='margin-right:2px' src='colormap.gif' usemap='#colormap' />";
sschocke 23:3563e1699fb9 159 httpReply += "<map id='colormap' name='colormap'>";
sschocke 28:ba5c68a04f56 160 httpReply += "</map></td></tr>";
sschocke 28:ba5c68a04f56 161 httpReply += "<tr><td><span onClick=\"window.location='/disco'\">Disco Mode</span></td></tr>";
sschocke 28:ba5c68a04f56 162 httpReply += "<tr><td><span onClick=\"changeColor('#000000')\">Turn Off</span></td></tr>";
sschocke 28:ba5c68a04f56 163 httpReply += "</table>";
sschocke 23:3563e1699fb9 164 httpReply += htmlTail;
sschocke 23:3563e1699fb9 165 server.SendReply(request->LinkID, httpReply, mimeHTML);
sschocke 23:3563e1699fb9 166 } else if( request->URI == "/config" ) {
sschocke 23:3563e1699fb9 167 if( (opMode & OPMODE_STATION) ) {
sschocke 23:3563e1699fb9 168 stationIP = server.GetStationIP();
sschocke 23:3563e1699fb9 169 ssid = server.GetStationSSID();
sschocke 23:3563e1699fb9 170 }
sschocke 23:3563e1699fb9 171 httpReply = htmlHead;
sschocke 23:3563e1699fb9 172 httpReply += htmlConfigHTML;
sschocke 23:3563e1699fb9 173 httpReply += htmlTail;
sschocke 23:3563e1699fb9 174 httpReply = httpReply.replace(httpReply.find("%opmode1%"), 9, (opMode==1? " selected" : ""));
sschocke 23:3563e1699fb9 175 httpReply = httpReply.replace(httpReply.find("%opmode2%"), 9, (opMode==2? " selected" : ""));
sschocke 23:3563e1699fb9 176 httpReply = httpReply.replace(httpReply.find("%opmode3%"), 9, (opMode==3? " selected" : ""));
sschocke 23:3563e1699fb9 177 httpReply = httpReply.replace(httpReply.find("%stamac%"), 8, stationMAC);
sschocke 23:3563e1699fb9 178 httpReply = httpReply.replace(httpReply.find("%staip%"), 7, stationIP);
sschocke 23:3563e1699fb9 179 httpReply = httpReply.replace(httpReply.find("%apmac%"), 7, apMAC);
sschocke 23:3563e1699fb9 180 httpReply = httpReply.replace(httpReply.find("%apip%"), 6, apIP);
sschocke 23:3563e1699fb9 181 httpReply = httpReply.replace(httpReply.find("%ssid%"), 6, ssid);
sschocke 23:3563e1699fb9 182 server.SendReply(request->LinkID, httpReply, mimeHTML, 0);
sschocke 23:3563e1699fb9 183 } else if( request->URI == "/updateconfig" ) {
sschocke 23:3563e1699fb9 184 bool result = true;
sschocke 23:3563e1699fb9 185 int newOpMode = atoi(request->Parameters["opmode"].c_str());
sschocke 23:3563e1699fb9 186 std::string newSSID = request->Parameters["ssid"];
sschocke 23:3563e1699fb9 187 std::string newPassword = request->Parameters["pwd"];
sschocke 23:3563e1699fb9 188 if( newOpMode != opMode ) {
sschocke 23:3563e1699fb9 189 result = server.SetOperatingMode(newOpMode);
sschocke 23:3563e1699fb9 190 if( result == false ) {
sschocke 23:3563e1699fb9 191 sendConfigJSONReply(request->LinkID, "Error setting Operating Mode");
sschocke 23:3563e1699fb9 192 delete request;
sschocke 23:3563e1699fb9 193 continue;
sschocke 22:6d7a72fab8ff 194 }
sschocke 23:3563e1699fb9 195 opMode = newOpMode;
sschocke 23:3563e1699fb9 196 }
sschocke 23:3563e1699fb9 197 if( (opMode & OPMODE_STATION) ) {
sschocke 23:3563e1699fb9 198 if( (ssid.compare(newSSID) != 0) || (newPassword.empty() == false) ) {
sschocke 23:3563e1699fb9 199 result = server.SetStationSSID(newSSID, newPassword);
sschocke 23:3563e1699fb9 200 if( result == false ) {
sschocke 23:3563e1699fb9 201 sendConfigJSONReply(request->LinkID, "Error connecting to SSID");
sschocke 23:3563e1699fb9 202 delete request;
sschocke 23:3563e1699fb9 203 continue;
sschocke 23:3563e1699fb9 204 }
sschocke 23:3563e1699fb9 205 // Wait for SSID to connect
sschocke 23:3563e1699fb9 206 for( int retries=0; retries < 6; retries++) {
sschocke 23:3563e1699fb9 207 wait_ms(5000);
sschocke 23:3563e1699fb9 208 ssid = server.GetStationSSID();
sschocke 23:3563e1699fb9 209 if( ssid.compare(newSSID) == 0 ) {
sschocke 23:3563e1699fb9 210 break;
sschocke 23:3563e1699fb9 211 }
sschocke 23:3563e1699fb9 212 }
sschocke 23:3563e1699fb9 213 stationIP = server.GetStationIP();
sschocke 22:6d7a72fab8ff 214 }
sschocke 22:6d7a72fab8ff 215 }
sschocke 23:3563e1699fb9 216 sendConfigJSONReply(request->LinkID, "Success");
sschocke 20:f5a6527bfda6 217 } else if( request->URI == "/wifilamp.js" ) {
sschocke 20:f5a6527bfda6 218 server.SendReply(request->LinkID, javascript, strlen(javascript), mimeJavaScript);
sschocke 20:f5a6527bfda6 219 } else if( request->URI == "/wifilamp.css" ) {
sschocke 20:f5a6527bfda6 220 server.SendReply(request->LinkID, css, strlen(css), mimeCSS);
sschocke 22:6d7a72fab8ff 221 } else if( request->URI == "/colormap.gif" ) {
leet 26:ea5e0ff46492 222 server.SendReply(request->LinkID, (char*)colorMap, sizeof(colorMap), mimeGIF);
sschocke 23:3563e1699fb9 223 } else if( request->URI == "/config.gif" ) {
sschocke 23:3563e1699fb9 224 server.SendReply(request->LinkID, (char*)configIcon, sizeof(configIcon), mimeGIF);
sschocke 27:88093aa94e24 225 } else if( request->URI == "/robots.txt" ) {
leet 26:ea5e0ff46492 226 server.SendReply(request->LinkID, robotsTxt, strlen(robotsTxt), mimeText);
leet 26:ea5e0ff46492 227 } else if( request->URI == "/favicon.ico" ) {
leet 26:ea5e0ff46492 228 server.SendReply(request->LinkID, (char*)favIcon, sizeof(favIcon), "image/x-icon");
leet 26:ea5e0ff46492 229 } else if( request->URI == "/disco" ) {
leet 26:ea5e0ff46492 230 lampMode = 2; // All colours
leet 26:ea5e0ff46492 231 DiscoTimer.reset();
leet 26:ea5e0ff46492 232 server.SendReply(request->LinkID, "OK", mimeText, 0);
leet 16:f2f2da9ef9ab 233 } else if( request->URI == "/setcolour" || request->URI == "/setcolor" ) {
sschocke 7:f15c81074400 234 int r=0, g=0, b=0;
leet 26:ea5e0ff46492 235
leet 26:ea5e0ff46492 236 lampMode = 1; // All LED 1 colour
sschocke 9:319aeb6e0123 237
sschocke 9:319aeb6e0123 238 if(request->Parameters.count("r") > 0) r=atoi(request->Parameters["r"].c_str());
sschocke 9:319aeb6e0123 239 if(request->Parameters.count("g") > 0) g=atoi(request->Parameters["g"].c_str());
sschocke 9:319aeb6e0123 240 if(request->Parameters.count("b") > 0) b=atoi(request->Parameters["b"].c_str());
sschocke 7:f15c81074400 241
leet 16:f2f2da9ef9ab 242 pc.printf( "Set colour to (%i, %i, %i)\r\n", r,g,b);
sschocke 0:d21e3e1c0a4b 243
sschocke 7:f15c81074400 244 setColor( r,g,b );
sschocke 7:f15c81074400 245
sschocke 23:3563e1699fb9 246 server.SendReply(request->LinkID, "OK", mimeText, 0);
sschocke 7:f15c81074400 247 } else {
sschocke 11:3ab606a42227 248 server.Send404Error(request->LinkID);
sschocke 0:d21e3e1c0a4b 249 }
sschocke 7:f15c81074400 250 pc.printf("\r\nHTTP Reply Sent\r\n");
sschocke 9:319aeb6e0123 251 delete request;
sschocke 0:d21e3e1c0a4b 252 }
leet 26:ea5e0ff46492 253 if( lampMode == 2 && DiscoTimer.read_ms() > DiscoDelay ) {
leet 26:ea5e0ff46492 254 setDiscoColor();
leet 26:ea5e0ff46492 255 // Delay random colour change, else it just looks white
leet 26:ea5e0ff46492 256 DiscoTimer.reset();
leet 26:ea5e0ff46492 257 }
leet 26:ea5e0ff46492 258 /*
leet 26:ea5e0ff46492 259 if( lampMode == 3 ) {
leet 26:ea5e0ff46492 260 // strobe
leet 26:ea5e0ff46492 261 }
leet 26:ea5e0ff46492 262
leet 26:ea5e0ff46492 263 if( lampMode == 4 ) {
leet 26:ea5e0ff46492 264 // fade
leet 26:ea5e0ff46492 265 }
leet 26:ea5e0ff46492 266
leet 26:ea5e0ff46492 267 */
sschocke 0:d21e3e1c0a4b 268 }
sschocke 0:d21e3e1c0a4b 269 }