Web Server with graphical UI to set LED color

I banged up this sketch tonight to set a LED using a full color presentation from a web page.

This requires a RGB color LED attached to D5,6,9 (configurable at top of script). It also requires the Ethernet board and appropriate libraries.

/*
 ===================================================
 Use a web page to set a RGB LED to the selected color
 ===================================================

 ===================================================
 Converted to analog write commands and removed BlinkM
 Also removed simple text box page and used code from 
 http://www.colorpicker.com/ to pick the LED color.

 Mike Audleman
 Jun 3, 2012
 ===================================================

 ===================================================
 Prior Header
 ===================================================
*/

// Small Arduino Webserver --- for BlinkM
// by Andreas Cahen ---** updated for Arduino 0021 - by PsycleSam and Co. 20101219 tested on arduino uno with updated ethernet shield
//
// Used libraries and examples:
//
// Arduino Ethershield, server.pde
// Blinkm Library, BlinkMfuncs.h +++**SPI Library, SPI.h
// ---** no longer used - TextString Library, WString.h




#include <SPI.h>
#include <Ethernet.h>
//#include <WString.h>
#include <Wire.h>
//#include <BlinkM_funcs.h>
#define maxLength 25
//#define blinkm_addr 0x09

// Sets circuit for LED.  
// 0 for LED tied to ground
// 1 for LED tied to v+
int LEDInvert = 1;

byte mac[] = {
  0x12, 0x12, 0x12, 0x12, 0x12, 0x12 }; //Set your own MAC
// Using DHCP
//byte ip[] = {
//  192, 168, 0, 200 };

String inString = String(maxLength);
int val;
int r = 0;
int g = 0;
int b = 0;
char colorBuff[4];

int LEDr = 5 ;//LED Red pin
int LEDg = 6 ;//LED Green pin
int LEDb = 9 ;//LED Blue pin

EthernetServer server(80);

/*
----------------------------------------------------------
Setup configuration.
---------------------------------------------------------- 
*/
void setup()
{
  Serial.begin(9600);
  Ethernet.begin(mac);
  server.begin();

  pinMode(LEDr, OUTPUT);
  pinMode(LEDg, OUTPUT);
  pinMode(LEDb, OUTPUT);

  // Init Testing of the LED
  SetAll( 0 );
  RampPin( LEDr );
  RampPin( LEDg );
  RampPin( LEDb );
  delay(500);
  SetAll( 255 );
  delay(100);
  SetAll( 0 );
}

/*
----------------------------------------------------------
Main Logic Loop
---------------------------------------------------------- 
*/
void loop()
{
  int bufLength;
  EthernetClient client = server.available();
  if (client) {
    boolean current_line_is_blank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (inString.length() < maxLength) {
          //inString.append(c);
          inString += c;
        }        
        if (c == '\n' && current_line_is_blank) {
          if (inString.indexOf("?") > -1) {

            int Pos_CC = inString.indexOf("k=")+2;
            int End_CC = inString.indexOf("&", Pos_CC);

            if(End_CC < 0){
              End_CC =  inString.length() + 1;
            }
            String ColorHex = inString.substring(Pos_CC,End_CC);
            Serial.println( "Received Hex String " + ColorHex );
            r = CheckRange( HexToDec(ColorHex.substring(0,2)) );
            g = CheckRange( HexToDec(ColorHex.substring(2,4)) );
            b = CheckRange( HexToDec(ColorHex.substring(4,6)) );

            SetLED( LEDr, r );
            SetLED( LEDg, g );
            SetLED( LEDb, b );
          }

          ShowWebPage (client);

          break;
        }
        if (c == '\n') {
          current_line_is_blank = true;
        }
        else if (c != '\r') {
          current_line_is_blank = false;
        }
      }
    }
    delay(1);
    inString = "";
    client.stop();
  }
} 

/*
----------------------------------------------------------
Simply ramps the specific pin
---------------------------------------------------------- 
*/
void RampPin( int dPin ) {
  // fade in from min to max in increments of 5 points:
  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
    SetLED( dPin, fadeValue );         
    delay(10);                            
  } 
  // fade out from max to min in increments of 5 points:
  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
    SetLED( dPin, fadeValue );         
    delay(10);                            
  } 
}

/*
----------------------------------------------------------
Sets all colors to set value (used for all on/all off)
---------------------------------------------------------- 
*/
void SetAll( int value ) {
  SetLED( LEDr, value );
  SetLED( LEDg, value );
  SetLED( LEDb, value );
}

/*
----------------------------------------------------------
Sets the LED pin and accounts for positve or negative wired LED
---------------------------------------------------------- 
*/
void SetLED( int dPin, int value ) {
  if (LEDInvert){
    analogWrite(dPin, (255-CheckRange( value )));
  } 
  else {
    analogWrite(dPin, CheckRange( value ));
  }
}

/*
----------------------------------------------------------
Validates the passed value 0 > val > 255
---------------------------------------------------------- 
*/
int CheckRange( int val ) {
  int tmpVal = val;
  if ( tmpVal > 255 ){
    tmpVal=255;
  };
  if ( tmpVal < 0 ){
    tmpVal=0;
  };
  return tmpVal;
}

/*
----------------------------------------------------------
Displays the web page
---------------------------------------------------------- 
*/
void ShowWebPage (EthernetClient theClient) {
  String t = "";
  theClient.println("HTTP/1.1 200 OK");
  theClient.println("Content-Type: text/html");
  theClient.println();
  theClient.println("<html>");

  t = "<script type='text/javascript'";
  theClient.println("<head><base href='http://www.colorpicker.com/'><link rel='stylesheet' href='css/colorpicker.com.css' type='text/css'>");
  theClient.print(t);
  theClient.println(" src='js/mootools-1.2.4-core.js'></script>");
  theClient.print(t);
  theClient.println(" src='js/colorpicker.com.js'></script></head>");
  theClient.println("<body>");

  theClient.println("<div><div style='position:absolute;top:0px;left:0px;width:430px'><div id='colorDiv' style=display:none;>.</div><div id='colorBoxes'></div></div>");
  theClient.println("<center><div id='colorWidgetDiv' style='position:relative;padding-left:100px;width:450px;height:340px;margin-top:70px;'></div></center></div>");
  theClient.println("<form method=get onSubmit='SE();'>");
  theClient.println("<input type='hidden' id='k' name='k'value='0'>");
  theClient.println("<input type='submit' id='H' name='H' value='Submit'>");
  theClient.println("<input type='hidden' id='cc' name='colorcode' value='0'>");
  theClient.println("</form>");

  theClient.println("<script language='javascript'>");
  theClient.println("function SE(){var s = $('input[class^=ColorPicker_com_colorSlider_rgbCode]');var c = s.get('value');c = c.toString(c); ");
  t = "').set('value',c); ";
  theClient.print("$('k");
  theClient.println(t);
  theClient.print("$('cc");
  theClient.println(t);
  theClient.println("}");
  theClient.println("</script>");
  theClient.println("</body></html>");

}


/*
----------------------------------------------------------
Converts a single hex character to a byte
---------------------------------------------------------- 
*/
int hex2dec(byte c) {
  if (c >= '0' && c <= '9') {
    return c - '0';
  } else if (c >= 'A' && c <= 'F') {
    return c - 'A' + 10;
  }
}

/*
----------------------------------------------------------
Converts a 2 byte hex string to an int
---------------------------------------------------------- 
*/
int HexToDec(String c) {
  int Digit1 = hex2dec( c.charAt(0) ) * 16;
  int Digit2 = hex2dec( c.charAt(1) );
  return Digit1 + Digit2;
}

Enjoy,
Wolfie

Per a request, I am posting a very simple script that looks for only one text box and sets an LED on Pin 9 to the brightness. This script does NOT use BlinkM I only used that script as a starter for this one.

// Based on
// Small Arduino Webserver --- for BlinkM
// Modified for single text box for brightness
// Jun 7 2012 - Mike Audleman

#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#define maxLength 25

byte mac[] = {
  0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA };
String inString = String(maxLength);

char colorBuff[4];
int val;

EthernetServer server(80);

void setup()
{
  Serial.begin(9600);
  Ethernet.begin(mac);
  server.begin();
}
void loop()
{
  int bufLength;
  EthernetClient client = server.available();
  if (client) {
    boolean current_line_is_blank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (inString.length() < maxLength) {
          inString += c;
        }        
        if (c == '\n' && current_line_is_blank) {
          if (inString.indexOf("?") > -1) {
            int Pos_L = inString.indexOf("L");
            int End = inString.indexOf("H", Pos_L);
            if(End < 0){
              End =  inString.length() + 1;
            }
            bufLength = ((Pos_L) - (Pos_L+2));
            if(bufLength > 4){  //dont overflow the buffer
              bufLength = 4;
            }    
            inString.substring((Pos_L+2), (End-1)).toCharArray(colorBuff, bufLength);  //transfer substring to buffer
            val = atoi(colorBuff);
            Serial.print("LED = ");
            Serial.println( val );
            analogWrite(9, val);
          }
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<html><head></head><body>");
          client.println("<h1>LED - enter values 0 to 255</h1>");
          client.print("<form method=get>LED:<input type=text size=3 name=L value=");
          client.print(val);
          client.print(">&nbsp;<input name=H type=submit value=submit></form>");
          client.println("</body></html>");
          break;
        }
        if (c == '\n') {
          current_line_is_blank = true;
        }
        else if (c != '\r') {
          current_line_is_blank = false;
        }
      }
    }
    delay(1);
    inString = "";
    client.stop();
  }
}

Hi Wolfiesden,

Thanks for your demo code.

This is just what i have been looking for, well nearly!

I am very new to the Arduino and C and and trying to run before I can walk, like most newbies :slight_smile:

My ambition is to have a Web server running on the Arduino, my problem is that I want to change a graphic on the client when an input is switched on or off. e.g an LED switching from RED to Green.

To further complicate the issue i would like to have a couple of JPG or PNG pictures on web screen as well.

So far i have been able to call a web page (INDEX.HTM), with JPG and PNG graphics being called from a SD card on the Ethernet shield. This give me the rich look i want.

I have many examples of writing to the client directly from the program, as in your example, what i cant figure out is how to combine the two.

The issue I keep on hitting is the that the WEB server libraries cannot serve PNG or JPG file to the client.

I have found the TinyWebServer.H library which almost does what i want but being a newbie i find it difficult to see how to fully use it.

I am looking at using JAVA script to possible help solve the issue but this is adding to an already steep learning curve.

Any pointers on how to crack this would be greatly appreciated.

Many Thanks in advance

Ray

PS keep up the good work :slight_smile:

Put the pictures on a completely different web site -- like a photo sharing site, and then just reference them from your http code on the ArduinoULN2803A
Just like you do to embed a photo in this newsgroup...

Ray4720:
I am looking at using JAVA script to possible help solve the issue but this is adding to an already steep learning curve.

Important note: JAVA and JavaScript have nothing in common. They are completely different languages with entirely different implementations.

Hi everybody,

I was searching for something similar and just have coded a simple solution for me.
There is a little slider with 3 Images (red.gif, green.gif & blue.gif) just 1x1 pixel.

<html>
<head>
<script type="text/javascript">
function Slider(i,c)
{
//Get last resized Image
im = c + document.getElementById(c).value
d=document.all[im];
d.height=20;
//Set Textbox to value
document.getElementById(c).value = i;
//Resice actual Image to 1
im = c + i;
d=document.all[im];
d.height=1;
//Set <hr color=""> to Hexcode
document.getElementById('color').color = '#'+document.all.r.value.toString(16)+document.all.g.value.toString(16)+document.all.b.value.toString(16);
}
</script>
<title>
Arduino Colorpicker 1.0
</title>
<meta content="width=480" />
</head>
<body>
<input type="text" id="r" size="2">
<script type="text/javascript">
for (i=0;i<=255;i++) 
 document.write("<img src='red.gif' height=20 width=1 onMouseOver='Slider(" + i + ",\"r\")' id='r" + i + "'>");
</script>


<input type="text" id="g" size="2">
<script type="text/javascript">
for (i=0;i<=255;i++)
 document.write("<img src='green.gif' height=20 width=1 onMouseOver='Slider(" + i + ",\"g\")' id='g" + i + "'>"); 
</script>


<input type="text" id="b" size="2">
<script type="text/javascript">
for (i=0;i<=255;i++) 
 document.write("<img src='blue.gif' height=20 width=1 onMouseOver='Slider(" + i + ",\"b\")' id='b" + i + "'>");  
</script>


<hr color="#ffffff" size="20" width="15" id="color"></hr>
</body>
</html>

So you can put the three Input boxes into a and send them to your EthernetShield by POST or what ever :slight_smile:

I´d love to transfer it "live" to the Arduino, but there would be a POST-Action by JavaScript needed, I think :-/

Hey,

yesterday I was animated to do the Color-Picker right.
There were some changes to the Version above:

  • Color limited from 0-32
  • Replaced Images with Table Columns
  • Preview with Hex-Colors
  • Include better Touch-Functionality for mobile devices
  • Submit wouldn´t change the actual page

<html>
<head>
<script type="text/javascript">
function Slider(i,c)
{
	//Get last Image
	im = c + document.getElementById(c).value
	d=document.all[im];
	switch (c)
	{
		case "r":
		d.bgColor = "#ff0000";
		break;
		case "g":
		d.bgColor = "#00ff00";
		break;
		case "b":
		d.bgColor = "#0000ff";
		break;
	}
	//Set Textbox to value
	document.getElementById(c).value = i;
	//Hide actual Image
	im = c + i;
	d=document.all[im];
	d.bgColor = "#000000";
	//Set <hr color=""> to Hexcode
	var r,g,b;
	r = Math.round((document.all.r.value*255)/31);
	g = Math.round((document.all.g.value*255)/31);
	b = Math.round((document.all.b.value*255)/31);
	document.getElementById('color').color = '#'+r.toString(16)+g.toString(16)+b.toString(16);
	document.getElementById('action').value = 'color'+document.all.r.value+'-'+document.all.g.value+'-'+document.all.b.value;
}

function submitformColor()
{
	var oRequest = new XMLHttpRequest();
	var sURL  = '/?action='+document.getElementById('action').value;	
	oRequest.open("GET",sURL,false);
	oRequest.setRequestHeader("User-Agent",navigator.userAgent);
	oRequest.send(null)

	if (oRequest.status==200)
	  {
	   //Get Answer
	   //var txt = oRequest.responseText;     
	   //document.write(txt);
	   //Stay on actual Site
	   return false;
	  }
	else
	  document.write('Error!');
// 	  document.forms["myform"].submit();
}
</script>
<title>Arduino Webserver 1.0 - Color</title>
</head>
<body bgcolor='#444444'  text="#c0c0c0" OnLoad="ReadCookie()">
<table border='0' width='480' cellpadding='5'>
<tr><td>

<hr/>
<h2><div align='center'><font color='#2076CD'>Arduino Webserver 1.0</font></div></h2>
<hr/>

<div align='left'><font face='Verdana' color='#FFFFFF'>Colorpicker</font></div>


<table border='1' width='460' cellpadding='5'>
<tr bgColor='#222222'>
<td align='center' bgcolor='#222222'>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input type="text" id="r" size="2" value="0"></td>
<script type="text/javascript">
for (i=0;i<=31;i++)
  document.write("<td bgcolor='#ff0000' height=40 width=10 onMouseOver='Slider(" + i + ",\"r\")' id='r" + i + "'></td>"); </script>
</tr>
</table>

<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input type="text" id="g" size="2" value="0"></td>
<script type="text/javascript">
for (i=0;i<=31;i++)
  document.write("<td bgcolor='#00ff00' height=40 width=10 onMouseOver='Slider(" + i + ",\"g\")' id='g" + i + "'></td>"); 
</script>
</tr>
</table>

<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input type="text" id="b" size="2" value="0"></td>
<script type="text/javascript">
for (i=0;i<=31;i++) 
  document.write("<td bgcolor='#0000ff' height=40 width=10 onMouseOver='Slider(" + i + ",\"b\")' id='b" + i + "'></td>"); 
</script>
</tr>
</table>
</td></tr>
<tr><td  align='center' bgcolor='#222222'>
<hr color="#ffffff" size="50" width="50" id="color"></hr>
</td></tr>
<tr bgColor='#222222'>
<td align='center' bgcolor='#222222'>
<form id="myform" action="../?" onsubmit="return submitformColor();">
<input type='hidden' name='action' id="action">
<input type="submit" name="btn" value="Change">
</form>
</td>
</tr>
</table>


</td></tr>
</table>
<a href="INDEX.HTM">Back</a>
</body></html>

So I hope someone can use it for his purpose :slight_smile:

While I was answering another Post, I´ve refered to this solution. I was shocked a little, how obsolet my post was :astonished:

So here is my current solution, how to create a Color-Picker, which constantly stays on the site and workes quite fast.
The JS-File is outsourced to possibly put it on a different webspace. It also can be re-included in the main page.

HTML-File (Color.htm):

<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<script type="text/javascript" src="color.js"></script>
<title>Arduino Webserver 1.0 - Color</title>
</head>
<body bgcolor='#444444'  text="#c0c0c0">
<table border='0' width='480' cellpadding='5'>
<tr><td>

<hr/>
<h2><div align='center'><font color='#2076CD'>Arduino Webserver 1.0</font></div></h2>
<hr/>

<div align='left'><font face='Verdana' color='#FFFFFF'>Colorpicker</font></div>



<table border='1' width='460' cellpadding='5'>
<tr bgColor='#222222'>
<td align='center' bgcolor='#222222'>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input type="hidden" id="r" size="2" value="0"></td>
<script type="text/javascript">
for (i=0;i<=31;i++)
  document.write("<td bgcolor='#ff0000' height=40 width=10 onMouseOver='Slider(" + i + ",\"r\")' id='r" + i + "'></td>"); </script>
</tr>
</table>

<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input type="hidden" id="g" size="2" value="0"></td>
<script type="text/javascript">
for (i=0;i<=31;i++)
  document.write("<td bgcolor='#00ff00' height=40 width=10 onMouseOver='Slider(" + i + ",\"g\")' id='g" + i + "'></td>"); 
</script>
</tr>
</table>

<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input type="hidden" id="b" size="2" value="0"></td>
<script type="text/javascript">
for (i=0;i<=31;i++) 
  document.write("<td bgcolor='#0000ff' height=40 width=10 onMouseOver='Slider(" + i + ",\"b\")' id='b" + i + "'></td>"); 
</script>
</tr>
</table>
</td></tr>
<tr><td  align='center' bgcolor='#222222'>
<hr color="#ffffff" size="50" width="50" id="color"></hr>
</td></tr>
<tr bgColor='#222222'>
<td align='center' bgcolor='#222222'>
<form id="myform" action="../?" onsubmit="return submitformColor();">
<input type='hidden' name='action' id="action">
Password: <input type="password" name="pw" id="pw">


<input type="submit" name="btn" value="Change">
</form>
</td>
</tr>
</table>



</td></tr>
</table>
<a href="INDEX.HTM">back</a>
</body></html>

JavaScript-File (color.js):

function Slider(i,c)
{
	//Get last resized Image
	im = c + document.getElementById(c).value
	d=document.all[im];
	switch (c)
	{
		case "r":
		d.bgColor = "#ff0000";
		break;
		case "g":
		d.bgColor = "#00ff00";
		break;
		case "b":
		d.bgColor = "#0000ff";
		break;
	}
	//Set Textbox to value
	document.getElementById(c).value = i;
	//Resice actual Image to 1
	im = c + i;
	d=document.all[im];
	d.bgColor = "#000000";
	//Set <hr color=""> to Hexcode
	var r,g,b;
	r = Math.round((document.all.r.value*255)/31);
	g = Math.round((document.all.g.value*255)/31);
	b = Math.round((document.all.b.value*255)/31);
	document.getElementById('color').color = '#'+r.toString(16)+g.toString(16)+b.toString(16);
	document.getElementById('action').value = 'color'+document.all.r.value+'-'+document.all.g.value+'-'+document.all.b.value;
}

function submitformColor()
{
	var oRequest = new XMLHttpRequest();
	var sURL  = '/?action='+document.getElementById('action').value;
	sURL += '&pw='+document.getElementById('pw').value;
	sURL += '&btn=Change';
	oRequest.open("GET",sURL,false);
	oRequest.setRequestHeader("User-Agent",navigator.userAgent);
	oRequest.send(null)

	if (oRequest.status==200)
	  {
	   //var txt = oRequest.responseText;     
	   //document.write(txt);
	   return false;
	  }
	else
	  document.write('Error while sending!');
}

Arduino Code:
(A working Ethernet Shield is mandatory & some knowlodge where to paste the code required)

 char pw[21] = "&pw=MySecurepassword&btn=Change"; 
  if(strstr(filename,"?action=") !=0)
  {
    filename = filename + 8; // look behind "?action=" (8 chars) 
    if(strstr(filename,pw) !=0)
    {
      //Delete Password stuff
      (strstr(filename, pw))[0] = 0;

      if(strstr(filename, "color") != 0)
        { 
          All(LP.color(0,0,0));
          client.println("Color:
");
          filename = filename + 5; //Remove "color"
          client.println(filename);
                
          String str = filename;
          char theName[3];
          str = str.substring(0,str.indexOf('-'));
          str.toCharArray(theName, 3);
          Serial.println(theName);
          r = atoi(theName);          
    
          str = filename;
          str = str.substring(str.indexOf('-')+1,str.lastIndexOf('-'));
          str.toCharArray(theName, 3);
          Serial.println(theName);
          g = atoi(theName);
          
          str = filename;
          str = str.substring(str.lastIndexOf('-')+1);
          str.toCharArray(theName, 3);
          Serial.println(theName);
          b = atoi(theName);
          All(LP.color(r,g,b));
        }
   }
}

This string conversations are quite ugly and should be redesigned...
The Password-Thing is just a little unsecure solution, but there werent high confidential data on my arduino. So it is just to avoid people to turn my livingroom into a disco :slight_smile:

And this is how it looks like: