EtherTen and Webserver

Hello all,

My apoligies for the kludged together code - it does compile, I swear...! However, in terms of the webserver, its a "one shot" - I should be able to access the sensor data time and time again. Obviously, I can access it once, if I'm lucky...!

I'm using a Freetronics EtherTen, which is a W5100 based chipset, and a standard Uno 328 processor. Kind of an "all in one board." The XML presents analog sensor data, which will be eventually hooked up to current transformers for monitoring energy. At the moment, I've decided to activate only A0, although there is scope for all six inputs to be used.

I'm using Firefox (3 I think) for the client, and when its able to access the XML data, it does complain about stylesheets - thats ok, I'm intending this data to be received by a Beagle Board, and placed into an SQL database... eventually.

As mentioned, it does compile, it does run, I've tested it statically (loop of "client disconnected"), but due to my setup, I can't test the serial output while its connected to the network - mostly cause I'm a little lazy to take my Macbook out next to my router/ Linux box. Eventually, I want to be able to go to its IP address in Firefox, access the XML, and then refresh as I please, not have a "one shot" and thats it.

Anyway, heres the code:

#include <PString.h>
#include <AikoEvents.h>
#include <Wire.h>
#include <Ethernet.h>
#include <SPI.h>

EthernetServer server(80);

// the media access control (ethernet hardware) address for the shield:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  
//the IP address for the shield:
byte ip[] = { 192, 168, 1, 4 }; 

uint8_t house[8] = {0x4,0xe,0x1f,0xa,0xa,0xa,0xe,0x0};

#define Mains_PIN 0    // pin for the analog mains power data input

#define PowerDataInterval 1    // no of seconds between each power sample
#define TempDataInterval 900    // no of seconds between each temp sample

#define SAMPLES 1 // number of power samples to take

#define VREF 1.1      // use internal 1.1v reference

using namespace Aiko;

float val1 = 0;
float val2 = 0;

int reading_cnt = 0; // counter for 1 second samples
float total_rms1 = 0;
float total_rms2 = 0;

float max_val1 = 0;
  float ave_val1 = 0;

char buffer[400];
PString tsdata(buffer,400);

int availableMemory() {
  int size = 1024;
  byte *buf;
  while ((buf = (byte *) malloc(--size)) == NULL)
    ;
  free(buf);
  return size;
}

void powerdata()
{
  
  total_rms1 = 0;
  reading_cnt = 0;
   for (int cnt=0; cnt < SAMPLES; cnt++) {
    val1 = analogRead(Mains_PIN);
    max_val1 = max(val1,max_val1);
    if (val1 > 0.0)
    {
      reading_cnt++;
    }
    ave_val1 = ave_val1 + val1;
    total_rms1 = total_rms1 + sq(val1);
  }
  
  ave_val1 = ave_val1 / reading_cnt;
  total_rms1 = sqrt(total_rms1/(SAMPLES/2));
  
  Serial.print("Client available=");

  Serial.print("Available memory=");
  Serial.println(availableMemory());
  
  ave_val1=total_rms1*2*1100/1024/30.0*240*1.17;
  if (ave_val1 < 5) {
    ave_val1 = int(random(600,3000));
  }
//  ave_val2=total_rms2*2*1100/1024/30.0*240*1.17;
//  if (ave_val2 < 5) {
//    ave_val2 = int(random(100,2600));
  
}


void setup() {
  analogReference(INTERNAL);
  randomSeed(analogRead(1));
  
  Serial.begin(38400);
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("Server is at: ");
  Serial.println(Ethernet.localIP());
  
}

void loop() {
  Events.loop();
  EthernetClient client = server.available();
  boolean currentLine = true;
  while (client.connected()) {
  if (client.available()) {
    char c = client.read();
    Serial.write(c);
    if (c == '\n' && currentLine) {
      // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/xml");
      //    client.println("Connnection: close");
      //    client.println();
      //    client.println("<!DOCTYPE XML>");
    tsdata.begin();
  tsdata.println("<sensor1>");
  tsdata.println("<maxamps>");
  tsdata.println(max_val1);
  tsdata.println("</maxamps>");
  tsdata.println("<averageamps>");
  tsdata.println(ave_val1);
  tsdata.println("</averageamps>");
  tsdata.println("<rmsamps>");
  tsdata.println(total_rms1);
  tsdata.println("</rmsamps>");
  tsdata.println("<ppamps>");
  tsdata.println(total_rms1*2/sqrt(2));
  tsdata.println("</ppamps>");
  tsdata.println("<rmspow>");
  tsdata.println(total_rms1*240);
  tsdata.println("</rmspow>");
  tsdata.println("<peakpow>");
  tsdata.println(total_rms1*2*240/sqrt(2));
  tsdata.println("</peakpow>");
  tsdata.println("</sensor1>");
  //tsdata.print(ave_val2); //second sensor here?
  //tsdata += "";
  Serial.println("Sending multi-value put data now..");
  Serial.println(tsdata);
 // Serial.print(",Length=");
 // Serial.println(tsdata.length());
  
  if (!client.connected()) {

//    client.connect("192,168.1.56", 80);
  } 
  client.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  //client.println();
  client.println("<sensors>");
  
  client.println(tsdata);

  client.println("</sensors>");        
  }
  if (c == '\n') {
          // you're starting a new line
          currentLine = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLine = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1000);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }

Theres a few things commented - please ignore them...! They're either to do with a second sensor (not used in this example) or to do with the XML code itself (so theres no blank lines after the header - Firefox gets a little funky, and I imagine it isn't good XML to do that).

I imagine the guts of the issue is in the loop(), but I've posted the complete program in case theres any clues from elsewhere in the program for why its "one shot."

Thanks in advance for any help you may be able to give.

Boris.

So take a look at the following shortened code from loop()

void loop() {
  Events.loop();
  EthernetClient client = server.available();
//  boolean currentLine = true;
  while (client.connected()) {
    if (client.available()) {
      char c = client.read();
      Serial.write(c);
      if (c == '\n' /* && currentLine */) {
        // send data
      }
/*      if (c == '\n') {
        // you're starting a new line
        currentLine = true;
      } 
      else if (c != '\r') {
        // you've gotten a character on the current line
        currentLine = false;
      } */
    }
  }
  // give the web browser time to receive the data
  delay(1000);
  // close the connection:
  client.stop();
  Serial.println("client disconnected");
}

I have no idea about the purpose of currentLine, but the behaviour you described fits the code. Just modify your code by commenting out all functionality of currentLine and see if it works like you want. At the moment data is send whenever a '\n' is received ignoring all other received data.

In the end you still have to write some code to evaluate received commands.

Hello Marek, and others,

Unusually, I didn't receive an email to indicate you had replied. My bad.

The source of the error that produced the "one shot" was actually pretty simple - I had done what you suggested Marek, and commented out those lines, only to lose webserver functionality completely. By the way, "currentLine" should be "currentLineIsBlank" - someone is lazy ^.^

By putting a "break;" after the file, so to speak, ends in the code, I was able to restore "multiple shot" functionality. What I hadn't noticed (and which clued me on) was the web browser would just sit there, loading, and loading, and getting nowhere after the file had been transmitted.

Of course, I did try "Connection: close" in the HTTP header, this might be a part 2 to the whole thing, this alone didn't restore functionality, but putting the "break;" in worked wonders.

Ok, my new problem is as such - I've changed the file type to "text/plain" due to a change in the server software I'm using. So no more XML constructs...! But now, the browser is not displaying anything, just a blank white page. I've tried Chrome, Firefox and Safari on the Mac. Now I know the webserver is working, the "GET" requests come in. Something I've noticed though, is each browser asks for "favicon.ico" - could this be a problem? I might download and try Amaya, the W3C test browser, I've used it in the past for compliance - surely its not dumb enough to ask for a favicon?

Obviously, I don't want to put in unnecessary code to handle a stupid function on modern web browsers when at the end of the day, the program that will be asking for this data isn't a web browser at all, but a service on another computer.

Anyway, I'll post my updated code, in the hopes that it might provide a clue - header error possibly? When the file "breaks;" I should put in a "client.println();" beforehand? Don't know, of course, thats why I'm asking...! =)

#include <PString.h>
#include <AikoEvents.h>
#include <Wire.h>
#include <Ethernet.h>
#include <SPI.h>

EthernetServer server(80);

// the media access control (ethernet hardware) address for the shield:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  
//the IP address for the shield:
byte ip[] = { 192, 168, 1, 4 }; 

uint8_t house[8] = {0x4,0xe,0x1f,0xa,0xa,0xa,0xe,0x0};

#define Mains_PIN 0    // pin for the analog mains power data input

#define PowerDataInterval 1    // no of seconds between each power sample
#define TempDataInterval 900    // no of seconds between each temp sample

#define SAMPLES 1 // number of power samples to take

#define VREF 1.1      // use internal 1.1v reference

using namespace Aiko;

float val1 = 0;
float val2 = 0;

int reading_cnt = 0; // counter for 1 second samples
float total_rms1 = 0;
float total_rms2 = 0;

float max_val1 = 0;
  float ave_val1 = 0;

char buffer[400];
PString tsdata(buffer,400);

int availableMemory() {
  int size = 1024;
  byte *buf;
  while ((buf = (byte *) malloc(--size)) == NULL)
    ;
  free(buf);
  return size;
}

void powerdata()
{
  
  total_rms1 = 0;
  reading_cnt = 0;
   for (int cnt=0; cnt < SAMPLES; cnt++) {
    val1 = analogRead(Mains_PIN);
    max_val1 = max(val1,max_val1);
    if (val1 > 0.0)
    {
      reading_cnt++;
    }
    ave_val1 = ave_val1 + val1;
    total_rms1 = total_rms1 + sq(val1);
  }
  
  ave_val1 = ave_val1 / reading_cnt;
  total_rms1 = sqrt(total_rms1/(SAMPLES/2));
  
  Serial.print("Client available=");

  Serial.print("Available memory=");
  Serial.println(availableMemory());
  
  ave_val1=total_rms1*2*1100/1024/30.0*240*1.17;
  if (ave_val1 < 5) {
    ave_val1 = int(random(600,3000));
  }
//  ave_val2=total_rms2*2*1100/1024/30.0*240*1.17;
//  if (ave_val2 < 5) {
//    ave_val2 = int(random(100,2600));
  
}


void setup() {
  analogReference(INTERNAL);
  randomSeed(analogRead(1));
  
  Serial.begin(38400);
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("Server is at: ");
  Serial.println(Ethernet.localIP());
  
}

void loop() {
  Events.loop();
  EthernetClient client = server.available();
  boolean currentLine = true;
  while (client.connected()) {
  if (client.available()) {
    char c = client.read();
    Serial.write(c);
    if (c == '\n' && currentLine) {
      // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/plain");
          client.println("Connnection: close");
      //    client.println();
      //    client.println("<!DOCTYPE XML>");
    tsdata.begin();
//  tsdata.println("<sensor1>");
//  tsdata.println("<maxamps>");
  tsdata.println(max_val1);
//  tsdata.println("</maxamps>");
//  tsdata.println("<averageamps>");
  tsdata.println(ave_val1);
//  tsdata.println("</averageamps>");
//  tsdata.println("<rmsamps>");
  tsdata.println(total_rms1);
//  tsdata.println("</rmsamps>");
//  tsdata.println("<ppamps>");
  tsdata.println(total_rms1*2/sqrt(2));
//  tsdata.println("</ppamps>");
//  tsdata.println("<rmspow>");
  tsdata.println(total_rms1*240);
//  tsdata.println("</rmspow>");
//  tsdata.println("<peakpow>");
  tsdata.println(total_rms1*2*240/sqrt(2));
//  tsdata.println("</peakpow>");
//  tsdata.println("</sensor1>");
  //tsdata.print(ave_val2); //second sensor here?
  //tsdata += "";
  Serial.println("Sending multi-value put data now..");
  Serial.println(tsdata);
 // Serial.print(",Length=");
 // Serial.println(tsdata.length());
  
  if (!client.connected()) {

//    client.connect("192,168.1.56", 80);
  } 
//  client.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  //client.println();
//  client.println("<sensors>");
  
  client.println(tsdata);

//  client.println("</sensors>");
  break;  
  }
  
  if (c == '\n') {
          // you're starting a new line
          currentLine = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLine = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    //Serial.println("client disconnected");
}

Unusually, I didn't receive an email to indicate you had replied. My bad.

Totally

you need to hit the the spam inbox (if you have one) half the time the messages get sent there if you use gmail, so chances are other online and maybe some virus scanners may block mail from this address?... some get through some don't, probably due to the large userbase this site has and the people using it falsely getting flagged as spam...

write a little Arduino server to show a Postbox light up when you get mail, might be easier to get mobile phone to relay that info via bluetooth to cut costs....

Could you provide the debug output? After sending the header a blank line should be sent, doesn't it? And I think it would be good to look at the request and reply with an "HTTP/1.1 404 Not Found" to all but the right get. This way the favicon and other requests would work.