Monday, October 11, 2010

Arduino Ethernet To App Engine Direct

So: An Arduino Ethernet Shield on your network and a Google App Engine Web Service out on the cloud, Eh?

Over the next couple of days i'm going to be writing all about how the Nimbits Data Logger Service on app engine can talk to an Arduino Micro controller directly from Google using and relay data feeds to Twitter, Facebook, Android, Excel, etc.

This Blog posting is a simplified discussion for those of you who want to talk to your own projects.  The challenge is the networking limitations of an Arduino device - even with EthernetDNS you still need to do your http POST and GET starting with an IP address.  You can use EthernetDNS to get the IP address of App Engine or Google.com but there is no IP address that points directly to your program; it's on the cloud.

I did solve this problem at first by putting an Ubuntu Server on my LAN and creating a Reverse Proxy to my App Engine URL http://nimbits1.appspot.com - So I could just hardcode the IP of my server into the Arduino.  But I wanted to go directly to App Engine without another tier.

The solution was very simple. If you do an HTTP POST or GET to google.com or appspot.com but provide the HOST Header in your request, google's infrastructure will direct your request correctly from there.


The Following Arduino code will do a GET from a Nimbits web service on App Engine. To keep it simple, I hard coded the IP of google.com. You could use EthernetDNS to get the current IP of Google.  The GET request will be sent to the appspot.com url list in the HOST: yourapp.appspot.com section below.   This is based on the Ethernet Client Example.



#include


byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 178 }; // a valid IP on your LAN
byte server[] =  {72, 14, 204, 104}; // Google.com or Appspot.com's IP


Client client(server, 80);


void setup()
{
  Ethernet.begin(mac, ip);
  Serial.begin(9600);
  
  delay(1000);
  
  Serial.println("connecting...");
  
  if (client.connect()) {
    Serial.println("connected");
//this is a call to nimbits for the current value of a data point, but it can be any URL on app engine 
client.println("GET /service/currentvalue?point=test&email=bsautner@gmail.com HTTP/1.1");
client.println("Host:nimbits1.appspot.com");  //here is your app engine url
client.println("Accept-Language:en-us,en;q=0.5");
client.println("Accept-Encoding:gzip,deflate");
client.println("Connection:close");
client.println("Cache-Control:max-age=0");
client.println();
  } else {
    Serial.println("connection failed");
  }
}


void loop()
{
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
  
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    for(;;)
      ;
  }
}