Ethernet Shield: Log sensor readings to SD card and serve the logs over Ethernet

I’ve got a sensor (TMP102 I2C thermometer), Uno R3, Ethernet Shield, RTC.

I can log the sensor readings to the SD card in one sketch, and I can view the sensor readings over the ethernet in another sketch, but I can’t figure out how to do both.

I’ve gotten as far as starting the server in the sensor reading and logging sketch, it will respond to ping, but it won’t serve up my logs. I’ve been trying for weeks, about ready to give up.

http://pastebin.com/jsaba2tk

// 20121012 1337

// TMP102
#include <Wire.h>
int TMP102Address = 0x48;

// SD
#include <SD.h>
// ss, cs
SdFile file;

// Ethernet
#include <Ethernet.h>
#include <SPI.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 8 };
EthernetServer server(80);

// RTC
#include "RTClib.h"
RTC_DS1307 RTC;


void setup() {
  Serial.begin(9600);
  Serial.println("sketch: 20121012_1758 reboot");
  Wire.begin();
  RTC.begin();
  
  pinMode(10, OUTPUT);
  pinMode(4, OUTPUT);
  digitalWrite(10, HIGH);
  if (!SD.begin(4)) {
    Serial.println("Card initialization failed...");
    return;
  }
  Serial.println("Card initialized.");
  
  Ethernet.begin(mac, ip);
  digitalWrite(10, HIGH);
  server.begin();
}

// not sure i need this
#define BUFSIZ 100

void loop() {
  DateTime now = RTC.now();
  float TMP102_C = readTMP102_C();
  
  File sensorDataFile = SD.open("fuck10.csv", FILE_WRITE);
  if (sensorDataFile) {
    sensorDataFile.print(now.unixtime());
    Serial.println(now.unixtime());
    sensorDataFile.print(", ");
    sensorDataFile.print(TMP102_C);
    Serial.println(TMP102_C);
    sensorDataFile.println("");
    sensorDataFile.close();
    
  } else {
    Serial.println("Error opening data file.");
    Serial.println("");
  }
  
  
  EthernetClient client = server.available();
  char clientline[BUFSIZ];
  int index = 0;
  if (client) {
    Serial.println("new client");
    boolean currentLineIsBlank = true;
    // 
    index = 0;
    
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        
        // i think the problem lies here
        
        if (c != '\n' && c != '\r') {
          clientline[index] = c;
          index++;
          if (index >= BUFSIZ){
            index = BUFSIZ -1;
          }
            continue;
        }
        
        clientline[index] = 0;
        Serial.println();
        Serial.print("clientline: ");
        Serial.println(clientline);
        
        if (strstr(clientline, "GET /") !=0) {
          char *filename;
          
          filename = clientline + 5;
          (strstr(clientline, " HTTP"))[0] = 0;
          
          Serial.println("file opened!");
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Tpe: text/plain");
          client.println();
          
          int16_t c;
          while ((c = file.read()) > 0) {
            client.print((char)c);
          }
          file.close();
        } else {
          Serial.println("404");
        }
        break;
      }
    }
    
    delay(1);
    client.stop();
    Serial.println("Client disconnected.");
  }
            
        
        /*
        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println();
          break;
        }
        if (c == '\n') {
          currentLineIsBlank = true;
        } else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    
    delay(1);
    client.stop();
    Serial.println("Client disconnected");
  }
  */ 
  
  
  delay(2000);
}


// TMP102
float readTMP102_C() {
  Wire.requestFrom(TMP102Address, 2);
  byte MSB = Wire.read();
  byte LSB = Wire.read();
  
  // don't understand this yet
  int TemperatureSum = ((MSB << 8) | LSB) >> 4;
  float TMP102_C = TemperatureSum*0.0625;
  return TMP102_C;
}

I've gotten as far as starting the server in the sensor reading and logging sketch, it will respond to ping, but it won't serve up my logs

You can see the serial output. We can't. That is necessary to solving the problem.

One question, though. The logging always happens in one file. Why does the client need to explicitly ask for that file by name, then?

          (strstr(clientline, " HTTP"))[0] = 0;

What's the curly brace for? What happens here if " HTTP" is not part of clientline? Why is this not manipulating filename, instead?

          Serial.println("404");

Shouldn't you be telling the client this, rather than the serial port?

        /*
        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println();
          break;
        }
        if (c == '\n') {
          currentLineIsBlank = true;
        } else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    
    delay(1);
    client.stop();
    Serial.println("Client disconnected");
  }
  */

This isn't part of the problem, is it? We didn't need to see this.

have you checked if it's not a problem with the chip select pin?

Which ethernet shield are you using?

Bubulindo - My first thought is also the chip select pin. But I thought that the libraries handled turning it off and on? At least, that's what I've read. My plan today is to read through the libraries so that I understand the functions better.

PaulS -

One question, though. The logging always happens in one file. Why does the client need to explicitly ask for that file by name, then?

What approach do I take if not asking for the file by name? I'm not sure I understand the question. How would the client ask for the file if not by name?

What's the curly brace for? What happens here if " HTTP" is not part of clientline? Why is this not manipulating filename, instead?

Sorry, I've tried to parse your question, but I don't understand it. Which curly brace? I don't know what happens if HTTP isn't present. Are you asking what happens if it gets a malformed request? You're making me realize I'm in even further over my head than I thought. This project has taken up so much of my free time for weeks, I think I need to just put it down and give up until some future point at which I understand enough to finish it.

This is the offending code. When it is absent, the ethernet webserver will return a list of the files on the card and allow me to access them. When this code is present it errors at file.open() and the webserver is not accesible through the browser, although I can ping the card successfully.

//// 
char name[] = "TEST10.TXT";
  PgmPrint("Appending to: ");
  Serial.println(name);
    if (!file.open(root, name, O_CREAT | O_APPEND | O_WRITE)) error("open failed");

    file.print(now.unixtime());
    Serial.print(now.unixtime());
    file.print(", ");
    Serial.print(", ");
    file.print(TMP102_C);
    Serial.println(TMP102_C);
    file.println("");
    if (file.writeError) error("write failed");
    if (!file.close()) error("close failed");
////

When this code is present it errors at file.open()

What does “it errors at file.open” mean? What error?

What does error() do?

I think error() is some sort of communication with a built in set of responses from the SD card.

I've got the web server and data logging working now. Honestly, I don't know what was wrong. It was late, I was tired, and all of a sudden the code was working. I'll post it soon when I've got it cleaned up. Presently I am attempting to write a newline to the file in the setup(), but that is causing the SD card to fail.

  //// write newline to beginning of log
  char filename[12] = "DATA127.CSV";
  if (!file.open(root, filename, O_CREAT | O_APPEND | O_WRITE)) error("open failed");
  //file.println();
  //file.println();

returns in the serial monitor: error: open failed SD error: 19,0

That same code snippet works fine in the loop() though.