Webserver


Since May 2014, the Dyn company stopped its free DynDNS service.
Very sad, indeed.
And even worse: in most of the routers firmware shipped up to now, in the Dynamic DNS menu you can only select providers which are no longer free of charge.

So, if you want to set your webcam or your Arduino online, you have to find a solution.
Of course, you can pay $25 a year to Dyn.com or some other company for their service.
Or you can go for a new router the offers that offers the option to select other providers.

Well, how can Arduino solve this problem?

Actually, it is not too difficoult.
Firstly, you need to know your router's WAN ip address. You know: if you google for "what is my ip address" there are myriads of servers who can tell you.
So, if you own some web space, where PHP is supported, you can upload a file ipaddress.php containing these four lines:

<?php
$ip=$_SERVER['REMOTE_ADDR'];
echo "$ip";
?>

and make it executable (see chmod).

If you enter the URL of this file in your browser, the public ip address of your router will be printed.

O.k., that was an easy one. Now you don't want to do that each day just to obtain that information.

Well, your Arduino can work as a web client (just as you do when browsing the web). You can find the code for doing that in the Tutorial .

What you actually have to do is four things:

  1. upload a redirector HTML file with a fixed URL to your webspace which contains the momentary ip address of your router
  2. install a PHP program to adjust the ip address in (1.). Actually, it has to rewrite the complete HTML file.
  3. restart your Arduino on a regular basis. So if your public ip address changes at midnight restart it by means of a clock timer shortly after.
  4. install a forwarding rule in your router's menu, routing requests at port 80 to the ip address of your Arduino webserver. That is why you need a fixed ip address rather than a DHCP.
The PHP program to get your ip address and modify the redirector (we named it arduino_measure.html) is this:

<?php
$datei = fopen("arduino_measure.html","r+");
rewind($datei);
$ip=$_SERVER['REMOTE_ADDR'];
fwrite($datei, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">");
fwrite($datei, "<html>");
fwrite($datei, "<head>");
fwrite($datei, "<meta http-equiv=\"refresh\" content=\"3; URL=http://");
fwrite($datei, $ip);
fwrite($datei, "/\">");
fwrite($datei, "<title> Redirect to ARDUINO measure </title>");
fwrite($datei, "</head>");
fwrite($datei, "");
fwrite($datei, "If your browser does not support redirection click <a href=\"http://");
fwrite($datei, $ip);
fwrite($datei, "/\"> here .");
fwrite($datei, "</body>");
fwrite($datei, "</html>");
fclose($datei);
echo "done";
?>

After you uploaded this file you have to make it executable. But mind you: give it a secret name, as anybody who enters its URL will cause the execution but the redirection will point to his/her public ip address. That is not what you want.
For safety reasons you could even install a password which is checked by the PHP script.

You also have to provide a dummy redirector file first, because the PHP program will not create it.
The complete Arduino webserver program is based on this and could look like this (sorry for the length due to the SVG graphic commands):

#define FILENAME "Webserver2a"

// tested 25.6.14: o.k.
// for online access there seems to be a limit of file size
// so I removed all characters which were not essentially necessary
#define quiet

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h> // if you don't include this it only works when NO SD-card is present

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168, 0 , 152);                               
int port = 80;
EthernetServer server(port); // (port 80 is default for HTTP):
EthernetClient client;
char webServer[] = "my-public-webspace.tld";   
int dt = 2;

void setup() {
  Serial.begin(9600);
  Serial.println(FILENAME);
  Ethernet.begin(mac, ip);
  
  //======================================================
  
  delay(1000);
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());
  Serial.println("connecting...");
  boolean success = false;
  int cnt = 0;
  while (!success) {
    cnt++;
    if (client.connect(webServer, 80)) {
      success = true;
      Serial.println("connected");
      client.println("GET /secret123.php HTTP/1.1");
      client.print("Host: ");
      client.println(webServer);
      client.println("Connection: close");
      client.println();
      getResponse();
      Serial.println("the end");
    }
    else Serial.println("connection failed");
  }
  Serial.print("number of trials: ");
  Serial.println(cnt);  
  
  //======================================================
  
  server.begin();
  Serial.print("server is at ");
  Serial.print(Ethernet.localIP());
  Serial.print(":");
  Serial.println(port);
}

void loop() {
  //EthernetClient 
  client = server.available(); // listen for incoming clients
  if (client) {
#ifndef quiet    
    Serial.println("new client");
#endif    
    boolean currentLineIsBlank = true; // an http request ends with a blank line
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
#ifndef quiet        
        Serial.write(c);
#endif        
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
/* */        
//-------------------------------------------------------------------------------------------------------------------------------
client.println("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">");
client.print("<meta http-equiv=\"refresh\" content=");
client.print(dt);
client.println(">");
client.println("<svg xmlns=\"http://www.w3.org/2000/svg\" width=500 height=500>");
client.println("<rect x=40 y=40 rx=20 ry=20 width=420 height=420 style=\"fill:white;stroke:black;stroke-width:5;opacity:1.0\"/>");

//<!-- lines: -->
int cnt = 0;
for (int i = 0; i < 1024; i = i + 50) {
  float phi = 0.75*PI - i * PI/2/1000;
  int sw;
  int r1 = 200;
  int r2;
  if (cnt % 4 == 0) { r2 = 240; sw = 4; } else
  if (cnt % 2 == 0) { r2 = 230; sw = 3; } 
  else { r2 = 220; sw = 2; }
  String s = "";
  if (cnt % 4 == 0) s = String(i);
  line(r1, r2, phi, false, sw, s);
  cnt++;
}

int value = analogRead(A1);
line(0, 222, 0.75*PI - value * PI/2/1000, true, 2, "");

client.println("<circle cx=250 cy=320 r=60 fill='grey' />");// </circle>");

//<!-- Text: -->
client.print("<text x=195 y=450 fill='red'>current value is: ");
client.print(value);
client.println("</text>");
client.println("</svg>");
//--------------------------------------------------------------------------------------------------------------------------------
        break;
        }
        if (c == '\n') {
          currentLineIsBlank = true; // you're starting a new line
        }
        else if (c != '\r') {
          currentLineIsBlank = false; // you've gotten a character on the current line
        }
      }
    } 
    delay(10);         // give the web browser time to receive the data
    client.stop();     // close the connection:
#ifndef quiet    
    Serial.println("client disonnected");
#endif    
  }
}

void line(int r1, int r2, float phi, boolean col, int sw, String s) {
  int x1 = 250 + r1 * cos(phi);
  int y1 = 320 - r1 * sin(phi);
  int x2 = 250 + r2 * cos(phi);
  int y2 = 320 - r2 * sin(phi);
  client.print("<line x1=");
  client.print(x1);
  client.print(" y1=");
  client.print(y1);
  client.print(" x2=");
  client.print(x2);
  client.print(" y2=");
  client.print(y2);
  client.print(" style=\"stroke:");
  if (col) client.print("red");
  else client.print("black");
  client.print(";stroke-width:");  
  client.print(sw);
  client.println("\"/>");
  if (s.length() == 0) return;
  client.print("<text x=");
  client.print(x2-15);
  client.print(" y=");
  client.print(y2-5);
  client.print(" fill=0>"); 
  client.print(s);
  client.println("</text>");
}

//==================================
void getResponse() {  
  while (client.connected()) {
    if (client.available()) {
      char c = client.read();
      Serial.print(c);
    }
  }
  Serial.println();
  Serial.println("disconnecting.");
  client.stop();
}

Don't forget to check that the mac address must be unique and the Arduino's ip address must match you local network.
Replace the file name secret123.php by whatever you think is secret enough.
And replace my-public-webspace.tld by your own one.
If you want the Serial terminal to show what happens on your webserver just delete the #define quiet.

In case you only want your ip camera to be presented online you can drop all the code inside the loop function. But still you need to setup the correct port forwarding setup with both camera and router. Perform a search for something like "how to set up an ip camera to view online" and read the manuals of your camera and your router.

The final result might look like this showing the voltage at analog input A1:


 



0




200




400




600




800




1000


current value is: 708




contact: nji(at)gmx.de