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(;;)
      ;
  }
}

8 comments:

  1. I accidentally found this..
    Thanks for clearing this up :)

    ReplyDelete
  2. Hello!

    I really thank you for posting this solution, I was struggling with that for a while....
    Just one question, how do you manage the fact that google changes it's IP sometimes? My application stop sending HTTP requests after a while, and I think its due to this problem....

    Thank u again!

    ReplyDelete
  3. there is an arduino library out there called dhcp.h and dns.h that you can use to get the current IP for google.com or appspot.com. I use it but I thought i would keep this sample simpler. Hope this helped.

    check out my app engine data logging service: www.nimbits.com - you can plug arduino into it.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Thanks! Is the ethernet client able to handle gzipped content?

    ReplyDelete
  6. Just a quick note, I tried to use the appspot.com IP (209.85.147.141) and it would always fail to connect but when I switched it to google.com (209.85.143.99) it works fine.

    ReplyDelete
  7. Thanks alot for this post, it is very useful. A response to the many questions regarding the IP address, look at the DnsWebClient example in Arduino, they use:

    char serverName[] = "www.google.com";

    ReplyDelete
  8. When I compiled this program got the message
    "The client class has been renamed EthernetClient"
    Renamed that. now getting another error
    No matching function for call to 'EthernetClient:EthernetClient(byte[4],int)'

    could you please upload the code here after fixing the error?

    ReplyDelete