Ethernet+SD

Hello everyone,

I have a couple quick question regarding the ethernet shield and a sd card.

  • 1.Would it be easier on the arduino with live data to load a pre-made .htm file from the sd card (i.e tables and lables) or would it be easier to load the html in client.println?

    1. In the case of client.println vs PROGMEM. What would you say are the benefits and the negatives of each?

Notes I already have most of my html code written in client.println and it shows live data. I was just wondering if it would be quicker to load all the formatting and tables on a .htm file, then load in the live data.

Can you post your code?

Depending on the amount of html involved and the fraction that is dynamic content, the answer could change. If you have a simple page and most of it is dynamic data, not using sd card is easiest. What do you mean by println vs. PROGMEM? Can you not use the F() helper in print or copy from PROGMEM to a buffer and print buffer?

I have another technique but it is only worthy doing if your web page is long.

Here is my code (I put it in html form so it would look better):

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Reef Controller</title>
    
    <style type="text/css">
    <!--
    body {
      color:#FFFFFF;
      background-color:#000000;
      background-image:url('Background[1].jpg');

    }
    a  { color:#0000FF; }
    a:visited { color:#800080; }
    a:hover { color:#008000; }
    a:active { color:#FF0000; }
    -->
    </style>
    <!--[if IE]>
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
  </head>
  <body>
  

  

  

  

  

  

  

  

  

  

  

  
<table border="1"  width="100%">
  <tr><!-- Row 1 -->
     <td></td><!-- Col 1 -->
     <td>Daily High</td><!-- Col 2 -->
     <td>Daily Low</td><!-- Col 3 -->
     <td>Current</td><!-- Col 4 -->
  </tr>
  <tr><!-- Row 2 -->
     <td>Internal Temperature</td><!-- Col 1 -->
     <td>*This would be logged data*</td><!-- Col 2 -->
     <td>*This would be logged data*</td><!-- Col 3 -->
     <td>*Live Data*</td><!-- Col 4 -->
  </tr>
  <tr><!-- Row 3 -->
     <td>External Temperature</td><!-- Col 1 -->
     <td>*This would be logged data*</td><!-- Col 2 -->
     <td>*This would be logged data*</td><!-- Col 3 -->
     <td>*Live Data*</td><!-- Col 4 -->
  </tr>
  <tr><!-- Row 4 -->
     <td>pH</td><!-- Col 1 -->
     <td>*This would be logged data*</td><!-- Col 2 -->
     <td>*This would be logged data*</td><!-- Col 3 -->
     <td>*Live Data*</td><!-- Col 4 -->
  </tr>
</table>




<table border="1"  width="100%">
  <tr><!-- Row 1 -->
     <td>Return Pump</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 2 -->
     <td>Skimmer</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 3 -->
     <td>Actinics</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 4 -->
     <td>Halides</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 5 -->
     <td>Pump 1</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 6 -->
     <td>Pump 2</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
</table>

  </body>
</html>

Also, how would I make the background stretch to the window, rather than repeat. When I do no-repeat it just displays the image in the top left corner, not stretched.

OK, I just rendered your web page on my browser. There seems to be just a few spots for data but rest is static. I would recommend using some PROGMEM to save fragments of the page and insert dynamic contents between these fragments. If you are doing this with println using string constants, using PROGMEM will save a lot of sram.

You can do:

char buffer[128];
...
strcpy_P(buffer,PROGMEM_message_00);
client.print(buffer);
client.print(int_temp);
...

Check out strcpy_P in avr library manual. Your Arduino IDE should carry a pdf copy.

P.S. I have some more convoluted way to do the above but it is convoluted. If you are good with javascript, you are welcome to try.
Here is What I would do:

  1. save this to a file on an SD card
  2. add containers. Say you have a cell for current internal temperature. You go in there and add something like Loading…, right where your data should display.
  3. add some javascript to the end of your web page before your like:
  1. create a js1.js with the following command in it:

document.getElementById(“int_temp”).innerHTML=25;

What this does is:
The web page will be loaded to the browser, then js1.js will be requested and executed so your web page reads 25 on internal temperature. If you save the page on your pc and load to your browser, you will barely see the “loading…” as the script overwrites it with 25.

Why is this useful?!
Now your entire web page is static! There is nothing that need to be dynamically inserted. You can save it in sd card, eeprom, flash etc. and serve it as is. The entire dynamic feature is in that js1.js

So when your client asks for js1.js, you don’t just send it to the client, you generate one yourself, replacing the 25 with actual readings like:

sprintf(buffer,"document.getElementById(\"int_temp\").innerHTML=%d;",int_temp);

This way the only burden is to create this js file, not to insert numbers into a large file, practically fragmenting it into many many many ungraceful pieces :slight_smile:

Modified web page:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Reef Controller</title>
    
    <style type="text/css">
    <!--
    body {
      color:#FFFFFF;
      background-color:#000000;
      background-image:url('Background[1].jpg');

    }
    a  { color:#0000FF; }
    a:visited { color:#800080; }
    a:hover { color:#008000; }
    a:active { color:#FF0000; }
    -->
    </style>
    <!--[if IE]>
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
  </head>
  <body>
  

  

  

  

  

  

  

  

  

  

  

  
<table border="1"  width="100%">
  <tr><!-- Row 1 -->
     <td></td><!-- Col 1 -->
     <td>Daily High</td><!-- Col 2 -->
     <td>Daily Low</td><!-- Col 3 -->
     <td>Current</td><!-- Col 4 -->
  </tr>
  <tr><!-- Row 2 -->
     <td>Internal Temperature</td><!-- Col 1 -->
     <td>*This would be logged data*</td><!-- Col 2 -->
     <td>*This would be logged data*</td><!-- Col 3 -->
     <td><span id="int_temp">Loading...</span></td><!-- Col 4 -->
  </tr>
  <tr><!-- Row 3 -->
     <td>External Temperature</td><!-- Col 1 -->
     <td>*This would be logged data*</td><!-- Col 2 -->
     <td>*This would be logged data*</td><!-- Col 3 -->
     <td>*Live Data*</td><!-- Col 4 -->
  </tr>
  <tr><!-- Row 4 -->
     <td>pH</td><!-- Col 1 -->
     <td>*This would be logged data*</td><!-- Col 2 -->
     <td>*This would be logged data*</td><!-- Col 3 -->
     <td>*Live Data*</td><!-- Col 4 -->
  </tr>
</table>




<table border="1"  width="100%">
  <tr><!-- Row 1 -->
     <td>Return Pump</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 2 -->
     <td>Skimmer</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 3 -->
     <td>Actinics</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 4 -->
     <td>Halides</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 5 -->
     <td>Pump 1</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 6 -->
     <td>Pump 2</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
</table>
<script type="text/javascript" src="js1.js"></script>
  </body>
</html>

js1.js

document.getElementById("int_temp").innerHTML=25;

milesmiles902: - 2. In the case of client.println vs PROGMEM. What would you say are the benefits and the negatives of each?

If your HTML code is less than PROGMEM (32k or 128k, depending on the processor) and would never change, it would be much easier to hard code it.

[quote author=James C4S link=topic=180638.msg1340288#msg1340288 date=1375485951]

milesmiles902: - 2. In the case of client.println vs PROGMEM. What would you say are the benefits and the negatives of each?

If your HTML code is less than PROGMEM (32k or 128k, depending on the processor) and would never change, it would be much easier to hard code it. [/quote]

It's 3KB of size but has a few dynamic numbers. We don't see the OP's code but just the web page so I'm still not sure if OP has used PROGMEM or F() etc. Since a lot of these HTML features are repetitive, using PROGMEM and a buffer may save some space by reusing messages. F() doesn't optimize so if you do two F() with identical messages you double FLASH usage.

[quote author=James C4S link=topic=180638.msg1340288#msg1340288 date=1375485951]

milesmiles902: - 2. In the case of client.println vs PROGMEM. What would you say are the benefits and the negatives of each?

If your HTML code is less than PROGMEM (32k or 128k, depending on the processor) and would never change, it would be much easier to hard code it. [/quote]

Thanks. That clears things up a little. I wasn't quite sure what I should be using.

liudr: [quote author=James C4S link=topic=180638.msg1340288#msg1340288 date=1375485951]

milesmiles902: - 2. In the case of client.println vs PROGMEM. What would you say are the benefits and the negatives of each?

If your HTML code is less than PROGMEM (32k or 128k, depending on the processor) and would never change, it would be much easier to hard code it.

It's 3KB of size but has a few dynamic numbers. We don't see the OP's code but just the web page so I'm still not sure if OP has used PROGMEM or F() etc. Since a lot of these HTML features are repetitive, using PROGMEM and a buffer may save some space by reusing messages. F() doesn't optimize so if you do two F() with identical messages you double FLASH usage. [/quote]

Originally I used this tutorial on PROGMEM: http://playground.arduino.cc/Code/WebServer

It seemed to work just fine. Although I wanted to use client.println because I didn't know how to add "cool" looking things to the website correctly. So I switched over to client.println. I think that for someone who is relatively new to programming (me) client.println simplified many things. After reading both of your posts I am going to convert back to PROGMEM. It sounds like there are more benefits to this.

All in all I want this to run as efficiently as possible. My arduino is slowly becoming a reef controller and it has many things it is doing at once. I just don't want to overload it with too many functions.

I am always willing to learn and just jump into something. So I am going to attempt to use your "convoluted" way of processing the data. I will probably have a few more questions as I go.

That being said. I couldn't figure out a good way to graph data on the webpage with solely the arduino and have it be posted to the webpage. Many tutorials used third-party applications that were only able to be accessed on the computer, but not online. So I am having the arduino send data to Pachube.com to plot the data (who doesn't love a good graph). Then when I used the link from pachube to reference the graphs on my arduino webpage it would never load. Got any ideas (I think it was on the arduino end, because the graphs worked fine elsewhere)?

liudr:
OK, I just rendered your web page on my browser. There seems to be just a few spots for data but rest is static. I would recommend using some PROGMEM to save fragments of the page and insert dynamic contents between these fragments. If you are doing this with println using string constants, using PROGMEM will save a lot of sram.

You can do:

char buffer[128];


strcpy_P(buffer,PROGMEM_message_00);
client.print(buffer);
client.print(int_temp);



Check out strcpy_P in avr library manual. Your Arduino IDE should carry a pdf copy.

P.S. I have some more convoluted way to do the above but it is convoluted. If you are good with javascript, you are welcome to try.
Here is What I would do:
1) save this to a file on an SD card
2) add containers. Say you have a cell for current internal temperature. You go in there and add something like <span id="int_temp">Loading...</span>, right where your data should display.
3) add some javascript to the end of your web page before your </body>like:

<script type="text/javascript" src="js1.js"></script>

4) create a js1.js with the following command in it:

document.getElementById("int_temp").innerHTML=25;

What this does is:
The web page will be loaded to the browser, then js1.js will be requested and executed so your web page reads 25 on internal temperature. If you save the page on your pc and load to your browser, you will barely see the "loading..." as the script overwrites it with 25.

Why is this useful?!
Now your entire web page is static! There is nothing that need to be dynamically inserted. You can save it in sd card, eeprom, flash etc. and serve it as is. The entire dynamic feature is in that js1.js

So when your client asks for js1.js, you don't just send it to the client, you generate one yourself, replacing the 25 with actual readings like:



sprintf(buffer,“document.getElementById(“int_temp”).innerHTML=%d;”,int_temp);




This way the only burden is to create this js file, not to insert numbers into a large file, practically fragmenting it into many many many ungraceful pieces :)

Modified web page:


     Reef Controller            
 
 

                                                                               
Daily High Daily Low Current
Internal Temperature *This would be logged data* *This would be logged data* Loading...
External Temperature *This would be logged data* *This would be logged data* *Live Data*
pH *This would be logged data* *This would be logged data* *Live Data*
                                                                                               
Return Pump
Skimmer
Actinics
Halides
Pump 1
Pump 2
  > ``` > > > > js1.js > > > ``` > document.getElementById("int_temp").innerHTML=25; > ```

Actually…after re-reading this post. I am not sure which method I should use. On one hand with PROGMEM you save a lot of sram, while on the other hand the convoluted way has a static webpage and many many ungraceful pieces. Static webpages are nice and saving ram is almost equally as useful.

Can you combine both to create code that has ungraceful things and is super quick (i.e tie fighters)?

The convoluted way does not require large memory footprint. The memory requirement is small enough and can be made to use PROGMEM to store javascript code as well and much more elegant than chopped up HTML. The reason why I introduced you to it is that I've seen some arduino web server code samples and all fall into the same trap, "you have to butcher your HTML into pieces in order to stick dynamic content in between". And I want to broadcast a different message being "No, webpages stay static and let javascript handle dynamic content".

If you want to do dynamic js method (my way) with PROGMEM, you can do:

PROGMEM prog_char js_code_line_0[]="document.getElementById(\"int_temp\").innerHTML=%d;"; .. char buffer[128]; char format_buffer[64]; strcpy_P(format_buffer,js_code_line_0[],int_temp); sprintf(buffer,"document.getElementById(\"int_temp\").innerHTML=%d;",int_temp); client.println(buffer); ...

Note the sample web server code also has a buffer of 128 bytes. You gotta have some buffers for formatting anyway. The code looks a few levels more elegant and preserves complete sentences such as document.getElementById(\"int_temp\").innerHTML=%d; instead of it in 3 pieces. You can chop it into document.getElementById(\"int_temp\").innerHTML= and do something more memory saving too.

Let's say you want to change your web page layout, which way is easier, redoing the chopped up pieces or just redo a complete web page? You can save the web page in PROGMEM and print out one chunk at a time or do SD card.

First off I am a noob to all of this. Plain and simple, but we all have to start somewhere.

So I made this diagram of what I think is going to happen.

  • Thermometer-Simple probe
  • Arduino-Do I have to have a datalogger shield to log my data? Or is it possible to use strcpy to "get" live data?
  • Static Webpage-Would be a simple file saved on the SD card, such as in your example with the HTML that I would call upon when needed. Would never change.
  • Logged Temp-I imagine that this would just be a file with an array in it that would store any data I have collected.
  • Final Webpage-This would call the static webpage and specific lines in logged temp data to present a final webpage.

Since I am not that fluent with a lot of the code. I have been trying to take it one step at a time. Reading what each line does, and googling it if need be.

sprintf() made sense after I read through this link (I thought it was funny that this is what comes up on google when I search sprintf. Written by the same guy helping me right now.):

http://liudr.wordpress.com/2012/01/16/sprintf/

Helped me out a lot actually.

Another question I have is about this "document.getElementById(\"int_temp\").innerHTML=%d". What you are saying here is "file.location"(What/where in file location).(file type)=%(1 integer). It is probably wrong, but I am just giving it my best guess.

Lastly, I read through Arduinos tutorial on PROGMEM, and haven't found many other guides on using it. Do you think I should use this code as a tool to design mine?

http://playground.arduino.cc/Code/WebServer

I would also like to say thank you for helping me through this. I am sorry if I am in way over my head. I just want to learn, and it is hard with little to no knowledge of C or related languages.

-Miles

Miles,

You are welcome. I’ll help you as much as I can. I do have two open and demanding projects FYI.

The diagram you drew is ok but at every junction that have one line in and two or more out, you need to say under which condition you take one of the outs.

If you are logging internally to SD card, you can do that in a while loop.

acquire data->log data->check for client connection--(no clients)-->repeat the loop
                                                   |--(client connected)-->which file they ask for--(a valid file name found on SD card)->serve the file from SD card->repeat the loop
                                                                                                  |--(js1.js)->use sprintf to generate the javascript code and return them to client->repeat the loop

What your client will do is that it will first retrieve the static page such as index.htm. Then as it receives it, it realizes it also needs js1.js That’s when it will ask for it. Your arduino will not respond to this until it finishes serving the static page. Then next loop it will find a connection from the client asking for the js1.js and will construct it on the fly with sprintf and send it to the client. Then the client will finish rendering the web page and fill in the blank containers in the static page.

That web server you provided the link to is quite complicated. I started my code with the wifi server sample from arduino. My code is too complicated to be useful to you. It has an interpreter for HTTP requests and will recognize whether a javascript file needs substitution and does substitution according to a rule and sends a modified javascript to client. Here are some pieces useful to you:

Here is where you store client request in memory:

      if (client.available()) 
      {
        char c = client.read();
        Serial.write(c);
        //Save character c to a buffer
      }

Here is where you can go ahead to determine what was requested:

        if (c == '\n' && currentLineIsBlank)
        { // Determine what was requested here and serve it.
        }

I don’t use String class but if you do, you can do buffer.contains(“js1.js”) to find if the request is about this file or buffer.contains(“index.htm”) etc. so you don’t have to construct a generic code to allow all files on SD card to be request-able.

For the js1.js:
What the following does is to first find the HTML element by its id “int_temp”, then replaces its innerHTML with 25.

document.getElementById(“int_temp”).innerHTML=25;

So if you have Loading…, then before the js1.js is loaded, Loading… is displayed on the web page. After the js1.js is loaded, 25 will replace Loading…

Then the following arduino code basically uses the entire sentence and replace the 25 with the actual temperature so the spot of 25 is taken by a directive %d, or “replace me with an integer” directive. The value of ABC will replace the %d in final buffer:

sprintf(buffer,“document.getElementById(“int_temp”).innerHTML=%d;”,ABC);

I got rid of int_temp in the above line to reduce confusion. :slight_smile:

My feet got somewhat wet today. I have never gotten the SD card to work. Did so today.

Along with, got my server to upload my static Index.htm document from the SD. Although, I couldn’t get it to say 25. I made the js1.js and saved that and Index.htm to my SD card. I know this was multiple posts ago, but it took me a while to understand. I really should have just followed your steps from the beginning. I still don’t understand this part from your second post, where should I place the sprintf:

So when your client asks for js1.js, you don’t just send it to the client, you generate one yourself, replacing the 25 with actual readings like:

sprintf(buffer,"document.getElementById(\"int_temp\").innerHTML=%d;",int_temp);

Secondly, I attempted to use the PROGMEM tool and apply it to the Webserver example. Here is the error:

WebServer.ino: In function ‘void loop()’:
WebServer:80: error: expected primary-expression before ‘]’ token

I used all of your little tid-bits and applied them to my code. It doesn’t like the ] in this line:

strcpy_P(format_buffer,js_code_line_0[],Current_Internal_Temp);

Here is my code:

#include <SPI.h> //For Ethernet Shield
#include <Ethernet.h> //For Ethernet Shield
#include <avr/pgmspace.h> //For PROGMEM
#include <SD.h>
//*******************************Mac, IP Addresses and Port**************************************
byte mac[] = { 
  0x90, 0xA2, 0xDA, 0x0D, 0x15, 0xC6 };
IPAddress ip(192,168,1, 1);

EthernetServer server(80);
EthernetClient client;

//*********************Index.htm***********************************************
File Index;
//*******************js1.js-Reference******************************************************

PROGMEM prog_char js_code_line_0[]="document.getElementById(\"Current_Internal_Temp\").innerHTML=%d;";
  char buffer[128];
  char format_buffer[64];
  int Current_Internal_Temp;

//*************************************Setup**********************************************
void setup() {
  Serial.begin(9600);         // Open serial communications and wait for port to open:
   while (!Serial) {         // wait for serial port to connect. Needed for Leonardo only
      ;
     }
 //********************SD Initialization****************************
  Serial.print("Initializing SD card...");  //Starting SD
   pinMode(53, OUTPUT);   //Mega2650 Pin for SD

   if (!SD.begin(4)) {    //SD Check
  Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");  //SD Completion



 //****************Ethernet and Server Initialization*******************
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("Server is at:");
  Serial.println(Ethernet.localIP());
  
} //End of Setup

//**************************************Loop***********************************
void loop()
{
  
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println();
                   //*************************************Reference Index for Client******************************
                    Index = SD.open("Index.htm");          // Open web page file
                    if (Index) {                           //If File exists
                        while(Index.available()) {         //While client available
                            client.write(Index.read());    // Send web page to client
                        }
                        Index.close();                      //Close Document
                        
                    //********************Javascript Dynamic Data**************************************
                          strcpy_P(format_buffer,js_code_line_0[],Current_Internal_Temp);
                          sprintf(buffer,"document.getElementById(\"Current_Internal_Temp\").innerHTML=%d;",Current_Internal_Temp);
                      client.println(buffer);
                    }
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
} // End of Loop

After reading through some tutorials about strcpy_P. I was wondering what the int_temp part of this line means:

strcpy_P(format_buffer,js_code_line_0[],int_temp);

What I conclude is:

strcpy_P(array_name,reference_to_cpy,name_of_item);

In the next post are my Index.htm and js1.js.

Liudr, your so helpful. Take time on your projects. I can wait. Thanks again.

Index.htm

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Reef Controller</title>
    
    <style type="text/css">
    <!--
    body {
      color:#FFFFFF;
      background-color:#000000;
      background-image:url('Background[1].jpg');

    }
    a  { color:#0000FF; }
    a:visited { color:#800080; }
    a:hover { color:#008000; }
    a:active { color:#FF0000; }
    -->
    </style>
    <!--[if IE]>
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
  </head>
  <body>
  

  

  

  

  

  

  

  

  

  

  

  
<table border="1"  width="100%">
  <tr><!-- Row 1 -->
     <td></td><!-- Col 1 -->
     <td>Daily High</td><!-- Col 2 -->
     <td>Daily Low</td><!-- Col 3 -->
     <td>Current</td><!-- Col 4 -->
  </tr>
  <tr><!-- Row 2 -->
     <td>Internal Temperature</td><!-- Col 1 -->
     <td><span id="High_Internal_Temp">Loading...</span></td><!-- Col 2 -->
     <td><span id="Low_Internal_Temp">Loading...</span></td><!-- Col 3 -->
     <td><span id="Current_Internal_Temp">Loading...</span></td><!-- Col 4 -->
  </tr>
  <tr><!-- Row 3 -->
     <td>External Temperature</td><!-- Col 1 -->
     <td><span id="High_External_Temp">Loading...</span></td><!-- Col 2 -->
     <td><span id="Low_External_Temp">Loading...</span></td><!-- Col 3 -->
     <td><span id="Current_External_Temp">Loading...</span></td><!-- Col 4 -->
  </tr>
  <tr><!-- Row 4 -->
     <td>pH</td><!-- Col 1 -->
     <td><span id="High_pH">Loading...</span></td><!-- Col 2 -->
     <td><span id="Low_pH">Loading...</span></td><!-- Col 3 -->
     <td><span id="Current_pH">Loading...</span></td><!-- Col 4 -->
  </tr>
</table>




<table border="1"  width="100%">
  <tr><!-- Row 1 -->
     <td>Return Pump</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 2 -->
     <td>Skimmer</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 3 -->
     <td>Actinics</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 4 -->
     <td>Halides</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 5 -->
     <td>Pump 1</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
  <tr><!-- Row 6 -->
     <td>Pump 2</td><!-- Col 1 -->
     <td><input type="Submit" name="Submit" value="On"></td><!-- Col 2 -->
     <td><input type="Submit" name="Submit" value="Off"></td><!-- Col 3 -->
  </tr>
</table>
<script type="text/javascript" src="js1.js"></script>
  </body>

js1.js:

document.getElementById("Current_Internal_Temp").innerHTML=25;

My mistake. Correct code:

strcpy_P(format_buffer,js_code_line_0);

Alrighty. It has been a few days, but finally got back to my arduino.

So, I tried using all my knowledge of troubleshooting and realized it is still not the best. :stuck_out_tongue:

Found out that in:

PROGMEM prog_char js_code_line_0[]="document.getElementById(\"int_temp\").innerHTML=%d;";
..
char buffer[128];
char format_buffer[64];
strcpy_P(format_buffer,js_code_line_0[],int_temp);
sprintf(buffer,"document.getElementById(\"int_temp\").innerHTML=%d;",int_temp);
client.println(buffer);
...

client.println(buffer); is not printing the buffer.

I think it is because that the SD card is not calling the value 25 from js1.js. You spoke of writing code to make all of the files on the SD card available. How would I do so? I didn’t write in the code for the SD card to call js1.js because I assumed that the html file would do so automatically.

Secondly, the value 25 is not printing for:

<span id="int_temp">Loading...</span>

…and again I think this is because the SD card is not calling the value from js1.js.

Here is my code; very basic*******************************

#include <SPI.h> //For Ethernet Shield
#include <Ethernet.h> //For Ethernet Shield
#include <avr/pgmspace.h> //For PROGMEM
#include <SD.h>
//*******************************Mac, IP Addresses and Port**************************************
byte mac[] = { 
  0x90, 0xA2, 0xDA, 0x0D, 0x15, 0xC6 };
IPAddress ip(192,168,1, 1);



EthernetServer server(80);
EthernetClient client;

//*********************Index.htm***********************************************
File Index;
//*******************js1.js-Reference******************************************************
  int int_temp;
  PROGMEM prog_char js_code_line_0[]="document.getElementById(\"int_temp\").innerHTML=%d;";
  char buffer[128];
  char format_buffer[64];

  
 

//*************************************Setup**********************************************
void setup() {
  Serial.begin(9600);         // Open serial communications and wait for port to open:
   while (!Serial) {         // wait for serial port to connect. Needed for Leonardo only
      ;
     }
 //********************SD Initialization****************************
  Serial.print("Initializing SD card...");  //Starting SD
   pinMode(53, OUTPUT);   //Mega2650 Pin for SD

   if (!SD.begin(4)) {    //SD Check
  Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");  //SD Completion



 //****************Ethernet and Server Initialization*******************
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("Server is at:");
  Serial.println(Ethernet.localIP());
  
} //End of Setup

//**************************************Loop***********************************
void loop()
{ test ();
  
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println();
                   //*************************************Reference Index for Client******************************
                    Index = SD.open("Index.htm");          // Open web page file
                    if (Index) {                           //If File exists
                        while(Index.available()) {         //While client available
                            client.write(Index.read());    // Send web page to client
                        }
                        Index.close();     

                    //********************Javascript Dynamic Data**************************************
                        strcpy_P(format_buffer,js_code_line_0);
                        sprintf(buffer,"document.getElementById(\"int_temp\").innerHTML=%d;",Current_Internal_Temp);
                        
                      client.println(buffer);
                    }
                    break;
                }
                
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read

                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)

}// End of Loop
//**********Added this to see if value of int_temp changed*****************************************
void test () {
  int_temp = millis();
}

js1.js and Index.html are the same as prior.

Where does the web browser get this file? I don’t see in your code where it is sent when requested by your web browser. I see only the index.htm file returned.

<script type="text/javascript" src="js1.js"></script>

edit: What do you get when you request that file with the browser?
http://192.168.1.1/js1.js

SurferTim:
Where does the web browser get this file? I don’t see in your code where it is sent when requested by your web browser. I see only the index.htm file returned.

<script type="text/javascript" src="js1.js"></script>

I am confused about this question. The web browser gets the file off my SD card. It is called in the HTML (code you quoted). I think, but am not sure, that I am supposed to call it in my arduino script, but not sure where or how.

SurferTim:
edit: What do you get when you request that file with the browser?
http://192.168.1.1/js1.js

I get the same exact thing as when I load the general website: 192.168.1.1.
js1.js is supposed to replace the 'Loading…" with “25” and am pretty sure I am just not making a connection somewhere.

I researched document.getelementbyID in HTML, but I could only find tutorials that use 1 file, while I am using 2 and hopefully more eventually.

Not sure where you are with your project, but below is some web server test code you can try that keeps the main web page files on the SD card. Links to the files used are listed in the top code comments so you can download them, put them on your SD card, and then test the arduino code (you don’t actually need the servos to test). Use the serial monitor to see what is received from the web browser.

edit: below link will show how the served page will look

http://web.comporium.net/~shb/servoslider.htm

//zoomkat 2/26/13
//SD server slider test code
//open serial monitor to see what the arduino receives
//browser address will look like http://192.168.1.102:84/servosld.htm when submited
//for use with W5100 based ethernet shields
//put the servosld.htm, slider.js, bluev_sl.gif,
//and bluev_bg.gif on the SD card
//download flies at:
// http://web.comporium.net/~shb/pix/servosld.htm
// http://web.comporium.net/~shb/pix/slider.js
// http://web.comporium.net/~shb/pix/bluev_bg.gif
// http://web.comporium.net/~shb/pix/bluev_sl.gif
// 

#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>

#include <Servo.h> 
Servo myservoa, myservob, myservoc, myservod;  // create servo object to control a servo 
Servo myservoe, myservof, myservog; // myservoh not used due to lack of another free pin
String readString, pos;

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port

//////////////////////

void setup(){

  Serial.begin(9600);

  // disable w5100 while setting up SD
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);
  Serial.print("Starting SD..");
  if(!SD.begin(4)) Serial.println("failed");
  else Serial.println("ok");

  Ethernet.begin(mac, ip, gateway, gateway, subnet);

  //delay(2000);
  server.begin();
  Serial.println("Ready");

  myservoa.attach(2);  //the pin for the servoa control
  myservob.attach(3);  //the pin for the servob control
  myservoc.attach(5);  //the pin for the servoc control
  myservod.attach(6);  //the pin for the servod control 
  myservoe.attach(7);  //the pin for the servoa control
  myservof.attach(8);  //the pin for the servob control
  myservog.attach(9);  //the pin for the servoc control
  //myservoh.attach(10);  //the pin for the servod control 

}

void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {
          //store characters to string 
          readString += c; 
          //Serial.print(c);
        } 
        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString); //print to serial monitor for debuging

            //select proper header for file to be sent to browser

          client.println("HTTP/1.1 200 OK"); //send new page
          if(readString.indexOf("servosld") >=0) {
            client.println("Content-Type: text/html");
            client.println(); 
          }

          if(readString.indexOf("slider") >=0) {
            client.println("Content-Type: application/x-javascript");
            client.println(); 
          }

          if(readString.indexOf("bluev") >=0) {
            client.println("Content-Type: image/gif");
            client.println(); 
          }

          //select file to send to browser
          if(readString.indexOf("servosld") >=0) {
            File myFile = SD.open("SERVOSLD.HTM");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;              

              while (myFile.available()) 
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }                
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);            
              myFile.close();
            }
          }

          if(readString.indexOf("slider") >=0) {
            File myFile = SD.open("slider.js");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;              

              while (myFile.available()) 
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }                
              }
              if(clientCount > 0) client.write(clientBuf,clientCount); 
              myFile.close();
            }
          }

          if(readString.indexOf("bluev_sl") >=0) {
            File myFile = SD.open("bluev_sl.gif");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;              

              while (myFile.available()) 
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }                
              }
              if(clientCount > 0) client.write(clientBuf,clientCount); 
              myFile.close();
            }
          }

          if(readString.indexOf("bluev_bg") >=0) {
            File myFile = SD.open("bluev_bg.gif");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;              

              while (myFile.available()) 
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }                
              }
              if(clientCount > 0) client.write(clientBuf,clientCount); 
              myFile.close();
            }
          }

          delay(1);
          //stopping client
          client.stop();

          //process GET string request from client and and position servo

          pos = readString.substring(8, 12); //get the first four characters         
          //Serial.println(pos);
          int n = pos.toInt();  //convert readString into a number   
          Serial.println(n); 
          Serial.println();

          if(readString.indexOf("?0") >0) myservoa.writeMicroseconds(n);
          if(readString.indexOf("?1") >0) myservob.writeMicroseconds(n);
          if(readString.indexOf("?2") >0) myservoc.writeMicroseconds(n);
          if(readString.indexOf("?3") >0) myservod.writeMicroseconds(n);
          if(readString.indexOf("?4") >0) myservoe.writeMicroseconds(n);
          if(readString.indexOf("?5") >0) myservof.writeMicroseconds(n);
          if(readString.indexOf("?6") >0) myservog.writeMicroseconds(n);
          //only seven servo pins, so back to myservoa for testing
          if(readString.indexOf("?7") >0) myservoa.writeMicroseconds(n);

          //clearing string for next read
          readString="";
          pos="";
        }
      }
    }
  } 
}

Ok, after looking through your code I understand the method and technique for requesting files needed for a webserver.

In your technique Zoomkat, you used a string class to call needed files:

if(readString.indexOf("servosld") >=0) {
            File myFile = SD.open("SERVOSLD.HTM");

This makes a lot of sense after your posted it. I probably will use readString. for my webserver.

Liudr previously spoke of a way to write code so all files on the SD card are available, without using strings. How would I go about this?

I don't use String class but if you do, you can do buffer.contains("js1.js") to find if the request is about this file or buffer.contains("index.htm") etc. so you don't have to construct a generic code to allow all files on SD card to be request-able.

I think it might be easier with the amount of files I am going to need to request. A total of 9, plus the static HTML.

I guess I don’t understand it enough…I really thought that it was going to work.

I even simply replaced all of your files ZoomKat with my files and got rid of all the servo stuff. Still didn’t work.

I just don’t know what to do…anyone got a tutorial on requesting multiple files with an arduino webserver?

Here is my altered code to request 2 files and run my webserver…just get a white page.

#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>


String readString;

byte mac[] = {  0x90, 0xA2, 0xDA, 0x0D, 0x15, 0xC6  }; //physical mac address
byte ip[] = {192,168,1, 200 }; // ip in lan
byte gateway[] = {192,168,1, 1}; // internet access via router
byte subnet[] = {255, 255, 255, 0}; //subnet mask
EthernetServer server(8081); //server port



void setup(){

  Serial.begin(9600);

  // disable w5100 while setting up SD
  pinMode(53,OUTPUT);
   digitalWrite(53,HIGH);
  Serial.print("Starting SD..");
  if(!SD.begin(4)) Serial.println("failed");
  else Serial.println("ok");

  Ethernet.begin(mac, ip, subnet, gateway);

  //delay(2000);
  server.begin();
  Serial.println("Ready");

}

void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {
          //store characters to string 
          readString += c; 
          //Serial.print(c);
        } 
        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString); //print to serial monitor for debuging

            //select proper header for file to be sent to browser

          client.println("HTTP/1.1 200 OK"); //send new page
          if(readString.indexOf("Static") >=0) {
            client.println("Content-Type: text/html");
            client.println(); 
          }

          if(readString.indexOf("js1") >=0) {
            client.println("Content-Type: application/x-javascript");
            client.println(); 
          }



          //select file to send to browser
          if(readString.indexOf("Static") >=0) {
            File myFile = SD.open("Index.HTM");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;              

              while (myFile.available()) 
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }                
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);            
              myFile.close();
            }
          }

          if(readString.indexOf("js1") >=0) {
            File myFile = SD.open("js1.js");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;              

              while (myFile.available()) 
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }                
              }
              if(clientCount > 0) client.write(clientBuf,clientCount); 
              myFile.close();
            }
          }

          delay(1);
          //stopping client
          client.stop();

          //process GET string request from client and and position servo

          readString="";
       
        }
      }
    }
  } 
}

js1.js and Index.htm are same as prior posts…