Hi,
This is my fourth post on my series of blogs related to element14's TI Connected Launchpad roadtest. You can find my previous blogs in the following link
- [TI Connected Launchpad] 0. The packet arrives!!!
- [TI Connected Launchpad] 1. Turn On, Tune In, Boot Up -- CLP+Energia+Ubuntu!!!
- [TI Connected Launchpad] 2. Installing CCSv6 in Ubuntu 14.04
In this post, I'll be introducing you to a small application of controlling the LEDs on connected launchpad over internet. This application is inspired by one of the examples I found in the energia. But that example somethings....a visual indication on whether the command worked or not, design, reliability. But that was a really good starting point. I tinkered around it for a while. And finally I fixed what ate all the things I want
- Beautiful UI
- Some kind of feedback on whether the LED is on or not.
- Report current status of the board - ie., which leds are ON and OFF upon loading the page for first time.
Based on the above requirements, I found out the following ways to implement my system
- For beautiful UI, use CSS
- For realtime feedback, use javascript and AJAX
- For reporting current status upon loading, use javascript again.
Looking at the list of javascript,CSS, ajax etc., I was pretty scared. I was not a web designer,. All the web design I knew is some old school HTML tags. But it pretty excited me. It took me days to figure out how to solve these problems. But the result was beautiful....and I'm very excited to share it with you.
First I will show you a video on how it works:
In the video, you will be able to see that when click on the buttons for LEDs, they toggle on the board and in my webpage the button changes color. This color changing of button is not a blind change. What actually happens in the background is when you click the button, an AJAX request is framed and send to the connected launchpad. Once the launchpad receives this request, it will toggle the LED and sends back and AJAX response. The button in webpage then changes the color.
And the good thing is it even works with your smartphones. Check this video :
How to use?
Step 1 : Connect your launchpad to a network. I am using my home router to connect it. You can also connect it directly to your PC, but make sure you have modified the code to use a static IP before doing that.
Step 2 : Open your serial monitor in Energia IDE. In it set 115200N1 configuration.
Step 3 : Once launchpad acquires IP, it will report in the terminal.
Step 4 : Go to your browser( I have support for firefox only ) and type in the IP
Step 5 : In your serial monitor, you can type 'i' to get your IP information and 'h' for displaying help menu.
And Here is the code
// Launchpad control panel
#include "Ethernet.h"
// Prototypes
void printConfig();
void printEthernetData();
void printIndex();
void printHelp();
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0x00, 0x1A, 0xB6, 0x02, 0xAE, 0xA0 };
EthernetServer server( 80 );
EthernetClient client;
int statusConfig = 0;
int led1Status = HIGH;
int led2Status = HIGH;
int led3Status = HIGH;
int led4Status = HIGH;
int errFlag = false;
int serveHome = false;
void setup() {
pinMode( D1_LED, OUTPUT );
pinMode( D2_LED, OUTPUT );
pinMode( D3_LED, OUTPUT );
pinMode( D4_LED, OUTPUT );
pinMode( PUSH1, INPUT_PULLUP ); // released = HIGH, pressed = LOW
pinMode( PUSH2, INPUT_PULLUP );
digitalWrite( D1_LED, led1Status );
digitalWrite( D2_LED, led2Status );
digitalWrite( D3_LED, led3Status );
digitalWrite( D4_LED, led4Status );
// start the serial library:
Serial.begin( 115200 );
Serial.print("Accquiring IP address...........");
// start the Ethernet connection:
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
// no point in carrying on, so do nothing forevermore:
led1Status = LOW;
led2Status = HIGH;
led3Status = LOW;
led4Status = HIGH;
for(;;) {
digitalWrite( D1_LED, led1Status );
digitalWrite( D2_LED, led2Status );
digitalWrite( D3_LED, led3Status );
digitalWrite( D4_LED, led4Status );
led1Status = ~led1Status;
led2Status = ~led2Status;
led3Status = ~led3Status;
led4Status = ~led4Status;
delay( 1000 );
}
}
Serial.println( "[OK]" );
printEthernetData();
led1Status = LOW;
led2Status = LOW;
led3Status = LOW;
led4Status = LOW;
digitalWrite( D1_LED, led1Status );
digitalWrite( D2_LED, led2Status );
digitalWrite( D3_LED, led3Status );
digitalWrite( D4_LED, led4Status );
server.begin();
}
void loop() {
client = server.available();
if (client) { // if you get a client,
Serial.print("new client on port "); // print a message out the serial port
Serial.println(client.port());
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
// This lockup is because the recv function is blocking.
// Serial.print(c);
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
break;
}
else { // if you got a newline, then clear currentLine:
currentLine = "";
}
}
else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
errFlag = false;
serveHome = false;
if (currentLine.endsWith("GET / ")) {
statusConfig = 0;
serveHome = true;
page_home();
}
// Check the AJAX request
else if (currentLine.endsWith("GET /led_0_ON.php")) {
led1Status = HIGH;
}
else if (currentLine.endsWith("GET /led_1_ON.php")) {
led2Status = HIGH;
}
else if (currentLine.endsWith("GET /led_2_ON.php")) {
led3Status = HIGH;
}
else if (currentLine.endsWith("GET /led_3_ON.php")) {
led4Status = HIGH;
}
else if (currentLine.endsWith("GET /led_0_OFF.php")) {
led1Status = LOW;
}
else if (currentLine.endsWith("GET /led_1_OFF.php")) {
led2Status = LOW;
}
else if (currentLine.endsWith("GET /led_2_OFF.php")) {
led3Status = LOW;
}
else if (currentLine.endsWith("GET /led_3_OFF.php")) {
led4Status = LOW;
}
else if (currentLine.endsWith("GET /getDeviceStatus.php")) {
//Setting errFlag and serveHome to false will automatically trigger an AJAX response
errFlag = false;
serveHome = false;
}
else {
errFlag = true;
}
if( !errFlag && !serveHome ) {
Serial.print( "Sending AJAX response..." );
digitalWrite( D1_LED, led1Status );
digitalWrite( D2_LED, led2Status );
digitalWrite( D3_LED, led3Status );
digitalWrite( D4_LED, led4Status );
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println();
if( led1Status == HIGH ) { client.print( "1" ); } else { client.print( "0" ); } client.print( "," );
if( led2Status == HIGH ) { client.print( "1" ); } else { client.print( "0" ); } client.print( "," );
if( led3Status == HIGH ) { client.print( "1" ); } else { client.print( "0" ); } client.print( "," );
if( led4Status == HIGH ) { client.print( "1" ); } else { client.print( "0" ); } client.print( "," );
client.println( "" );
Serial.println( "[OK]" );
}
}
}
// close the connection:
client.stop();
//Serial.println("client disonnected");
}
}
void page_home( void ) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println();
client.println( "<html> <head><title>TI Connected Launchpad Roadtest</title>" );
client.println( "<script> var ledStatus = [ false, false, false, false ]; var xmlhttp; xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if( (xmlhttp.readyState == 4) && (xmlhttp.status == 200) ) { buffer = xmlhttp.responseText.split(\",\"); ledStatus[0] = (buffer[0]==\"1\")?true:false; ledStatus[1] = (buffer[1]==\"1\")?true:false; ledStatus[2] = (buffer[2]==\"1\")?true:false; ledStatus[3] = (buffer[3]==\"1\")?true:false; if( ledStatus[0] == true ) { document.getElementById( \"led_0\" ).className = \"ledStatusOn\"; } else { document.getElementById( \"led_0\" ).className = \"ledStatusOff\"; } if( ledStatus[1] == true ) { document.getElementById( \"led_1\" ).className = \"ledStatusOn\"; } else { document.getElementById( \"led_1\" ).className = \"ledStatusOff\"; } if( ledStatus[2] == true ) { document.getElementById( \"led_2\" ).className = \"ledStatusOn\"; } else { document.getElementById( \"led_2\" ).className = \"ledStatusOff\"; } if( ledStatus[3] == true ) { document.getElementById( \"led_3\" ).className = \"ledStatusOn\"; } else { document.getElementById( \"led_3\" ).className = \"ledStatusOff\"; } } }" );
client.println( "function getDeviceStatus() { xmlhttp.open( \"GET\", \"getDeviceStatus.php\", true );xmlhttp.send();}function triggerInput( ledButton ) { if( ledStatus[ledButton.name] == false ) { ledStatus[ledButton.name] = true; xmlhttp.open( \"GET\", ledButton.id+\"_ON.php\", true ); xmlhttp.send(); } else { ledStatus[ledButton.name] = false; xmlhttp.open( \"GET\", ledButton.id+\"_OFF.php\", true ); xmlhttp.send(); } }" );
client.println( " </script>" );
client.println( "<style> input.ledStatusOff{ border-radius:10px 10px 10px 10px;height:40px;width:120px;text-align:center;background-color:#F0F0F0;border:1px solid rgba(0, 0, 0, 0.1); } input.ledStatusOn{ border-radius:10px 10px 10px 10px;height:40px;width:120px;text-align:center;background-color:#7FFF7F;border:1px solid rgba(0, 0, 0, 0.1);}</style></head>" );
client.println( "<body style='background: #D0D0D0;' onload=\"getDeviceStatus()\"> <table id=\"mainFrame\" style=\"position:relative;margin-left:auto;margin-right:auto;padding-left:10px;padding-right:10px;padding-top:10px;background:#FFFFFF;border-radius: 20px 20px 20px 20px;height:180px;\" > <tr><td align='center'><h1 align=center><font color=\"blue\">e14 Roadtest</font></h1></td></tr> <tr><td align='center'><input type=\"button\" class=\"ledStatusOff\" id=\"led_0\" name=\"0\" value=\"LED1\" onClick=\"triggerInput( this )\"></input></td></tr> <tr><td align='center'><input type=\"button\" class=\"ledStatusOff\" id=\"led_1\" name=\"1\" value=\"LED2\" onClick=\"triggerInput( this )\"></input></td></tr> <tr><td align='center'><input type=\"button\" class=\"ledStatusOff\" id=\"led_2\" name=\"2\" value=\"LED3\" onClick=\"triggerInput( this )\"></input></td></tr> <tr><td align='center'><input type=\"button\" class=\"ledStatusOff\" id=\"led_3\" name=\"3\" value=\"LED4\" onClick=\"triggerInput( this )\"></input></td></tr> </table></body></html>" );
client.println( "" );
}
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
switch(inChar) {
case 'h':
printHelp();
break;
case 'i':
printEthernetData();
break;
default:
Serial.println();
Serial.println("Invalid menu option");
}
}
}
void printHelp() {
Serial.println();
Serial.println("+++++++++++++++++++++++++++++++++++++");
Serial.println("Help menu:");
Serial.println("\th: This help menu");
Serial.println("\ti: IP address information");
Serial.println("+++++++++++++++++++++++++++++++++++++");
}
void printEthernetData() {
// print your IP address:
Serial.println();
Serial.println("IP Address Information:");
IPAddress ip = Ethernet.localIP();
Serial.print("IP Address:\t");
Serial.println(ip);
// print your MAC address:
IPAddress subnet = Ethernet.subnetMask();
Serial.print("NetMask:\t");
Serial.println(subnet);
// print your gateway address:
IPAddress gateway = Ethernet.gatewayIP();
Serial.print("Gateway:\t");
Serial.println(gateway);
// print your gateway address:
IPAddress dns = Ethernet.dnsServerIP();
Serial.print("DNS:\t\t");
Serial.println(dns);
}
Happy coding,
vish