Webduino & AJAX

First, the big picture... I want to use AJAX with the web browser as client and an arduino running a webduino webserver as the server. I don't want to waste valuable memory generating web pages out of the arduino. I'd like to send either get or post variables to the arduino which the arduino can interpret as commands, carry out those commands, gather some sensor data, form that data into a response and send it back to the browser. The response could be as simple as "batteryLevel:13.2|Temperature:72|LightState:ON"

Imagine having access to your in-home robot with an IP camera. It would be a simple thing to embed the camera stream into the same web page.

If you've looked into AJAX at all, you've seen some javascript like this...

		//  AJAX Functions
		function createRequestObject() 
		{
			var ro;
			var browser = navigator.appName;
			if(browser == "Microsoft Internet Explorer"){
				ro = new ActiveXObject("Microsoft.XMLHTTP");
			}else{
				ro = new XMLHttpRequest();
			}
			return ro;
		}
		
		var http = createRequestObject();
		
		function sendReq(theCommands) 
		{
			var url = "192.168.3.111/arduino.html?" + theCommands;
			http.open('get', url);
			http.onreadystatechange = getResponse;
			http.send();
		}
		
		function getResponse() 
		{
			if(http.readyState == 4)
			{
				var response = http.responseText;
                                                         ...

In the above example, the variable getCommands becomes the query string. It could be something like this... light=on&move=forward. the complete url within the AJAX functions would be "192.168.3.111/arduino.html?light=on&move=forward".

Here's the Problem... If I put the above url into the address bar of my browser, the arduino responds as expected. If I have the AJAX functions attempt to contact the arduino with the same url, the AJAX response is essentially "object not found" (that page doesn't exist). I don't know if the webduino server isn't responding correctly to the AJAX request or not.

I really like the way webduino handles post & get variables and would love to stick with it as my ultimate solution. I've been trying to figure this out for a week now and I just can't google any more.

My Arduino sketch as it stands right now...

#define WEBDUINO_SERIAL_DEBUGGING 1

#include "Ethernet.h"
#include "WebServer.h"
#include "SPI.h"
#include "avr/pgmspace.h"
#include "stdlib.h";


static uint8_t mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x07, 0xBC };
static uint8_t ip[] = { 192, 168, 3, 111 };

#define PREFIX ""
#define NAMELEN 32
#define VALUELEN 32
WebServer webserver(PREFIX, 80);

//  Define Pin Names Here
//  #define BUZZER_PIN 3

//  Game Pad State Variables
int LX = 0; int LY = 0;
int RX = 0; int RY = 0;
int LT = 0; int RT = 0;
bool AB = false; bool BB = false; bool XB = false; bool YB = false;
bool RS = false; bool LS = false;
bool DU = false; bool DD = false; bool DL = false; bool DR = false; 
bool ST = false; bool BK = false;
bool LJ = false; bool RJ = false;
bool BG = false;

void changeState(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  Serial.print("made it into changeState Function\r\n\r\n");
  //server.httpSuccess();
  server.print("HTTP/1.1 200 OK\r\n");
  server.print("Content-Type: text/html");
  Serial.print("httpSuccess Header Sent\r\n\r\n");
  
  URLPARAM_RESULT rc;
  char name[NAMELEN];
  int name_len;
  char value[VALUELEN];
  int value_len;
  
  if (strlen(url_tail))
  {
    while (strlen(url_tail))
    {
      rc = server.nextURLparam(&url_tail, name, NAMELEN, value, VALUELEN);
      Serial.print(name);
      Serial.print(":");
      Serial.print(value);
      Serial.print("\r\n");
      if (strcmp(name, "LX") == 0){LX = atoi(value);}      
      if (strcmp(name, "LY") == 0){LY = atoi(value);}
      if (strcmp(name, "RX") == 0){RX = atoi(value);}
      if (strcmp(name, "RY") == 0){RY = atoi(value);}
      if (strcmp(name, "LT") == 0){LT = atoi(value);}
      if (strcmp(name, "RT") == 0){RT = atoi(value);}
      if (strcmp(name, "AB") == 0){AB = (value == "1") ? true : false;}
      if (strcmp(name, "BB") == 0){BB = (value == "1") ? true : false;}
      if (strcmp(name, "XB") == 0){XB = (value == "1") ? true : false;}
      if (strcmp(name, "YB") == 0){YB = (value == "1") ? true : false;}
      if (strcmp(name, "LS") == 0){LS = (value == "1") ? true : false;}
      if (strcmp(name, "RS") == 0){RS = (value == "1") ? true : false;}
      if (strcmp(name, "DU") == 0){DU = (value == "1") ? true : false;}
      if (strcmp(name, "DD") == 0){DD = (value == "1") ? true : false;}
      if (strcmp(name, "DL") == 0){DL = (value == "1") ? true : false;}
      if (strcmp(name, "DR") == 0){DR = (value == "1") ? true : false;}
      if (strcmp(name, "ST") == 0){ST = (value == "1") ? true : false;}
      if (strcmp(name, "BK") == 0){BK = (value == "1") ? true : false;}
      if (strcmp(name, "LJ") == 0){LJ = (value == "1") ? true : false;}
      if (strcmp(name, "RJ") == 0){RJ = (value == "1") ? true : false;}
      if (strcmp(name, "BG") == 0){BG = (value == "1") ? true : false;}
    }
  }
 
  //  Apply GamePad State Variables Here...
  //  if (AB) ? digitalWrite(BUZZER_PIN, HIGH) : digitalWrite(BUZZER_PIN, LOW);
  
  //  Gather Telemetrics and Publish them Here...
  //  Telemetric Variables
  int LV = 0;
  int RV = 0;
  float PS = 14.56;
  String _LT = String(LT);  //  Left Vibrate 0 to 255
  String _RT = String(RT);  //  Right Vibrate 0 to 255
  char buffer[10];
  String _PS = dtostrf(PS, 8, 2, buffer);  //  Power Supply Voltage Float to fixed 2

  String telemetrics = "LV:" + _LT + "|RV:" + _RT + "|PS:" + _PS;
  //server.print("HTTP/1.1 200 OK");
  //server.print("Content-Type: text/html");
  server.print(telemetrics);
  Serial.print(telemetrics);
  Serial.print("\r\n\r\n");

}
void setup()
{
  Serial.begin(9600);
  Serial.print("Debugging\r\n\r\n");
  //  Set Pins Here...
  //  pinMode(BUZZER_PIN, OUTPUT);

  Ethernet.begin(mac, ip);
  webserver.setDefaultCommand(&changeState);
  webserver.addCommand("arduino.html", &changeState);
  webserver.begin();
}
void loop()
{
  char buff[256];  //  May Need to Bump these values up to accomodate full query string
  int len = 256;
  webserver.processConnection(buff, &len);
 }

You'll notice lines commented out and several Serial.prints. I've tried everything I can think of.

Thanks for listening,

Don

Previous ajax post:

http://www.google.com/search?as_q=ajax&as_epq=&as_oq=&as_eq=&as_nlo=&as_nhi=&cr=&as_qdr=all&as_sitesearch=http%3A%2F%2Farduino.cc%2Fforum%2Findex.php&as_occt=any&tbs=&as_filetype=&as_rights=

Are you wanting me to look at your iframe solution?

Are you wanting me to look at your iframe solution?

You can look at what ever you want to get the job done. My very limited experience with ajax found that ajax required the browser to down load ajax files in order for the browser to be able to display the ajax involved web page. Does your code require additional ajax files to support the browser displaying your html page?

Those three javascript functions are all you need on the web page to dynamically add html to your page without having to hit the refresh button. Those functions open whatever file on the server you tell them and whatever that file would have output to the screen on its own is captured in the response variable. The file on the other end has typically been php or asp so you could maybe dynamically grab data from a database. But that file could just as easily be html. The response doesn't have to be formatted html either. It's a string in a variable when it gets back to the ajax function. If it was well-formed html you might use it like this... document.GetElementByID("dynamic_div").innerHTML = response. Maybe the response looks like this... A=1|B=2|C=3 and you'd write some javascript to parse it into individual variables. I like the latter for the arduino so I can keep it's code as lean as possible.

My issue is with webduino as it stands now. For whatever reason, when the AJAX functions go looking for the file on the arduino webserver, it can't find it. One thing I haven't tried yet is using a prefix on the arduino side. Something like 192.168.3.111/arduino/arduino.html?GET_VARIABLES.

I have a Logitech F510 Rumble Pad. It's able to emulate an XBox controller. I've written a simple ActiveX object based on the XNA Framework that's able to interact with the controller. There are 21 different variables on it (buttons, joystick axes) and I can put them all in a query string.

If webduino isn't ultimately my answer, I'm going to look at sockets.io.js next.

donjuevo

My apologies Zoom... I'm an idiot. The reason the AJAX functions couldn't find the webduino server was because I didn't preface the url with http://. I think I'm in business now. Idiot.

thanks again!

donjuevo

If you've read this far hoping this might be your solution, I've had to abandon this as a viable method for controlling an arduino through a web page where all the html was client-side. the issue is with the rules governing how AJAX behaves and how it hates cross-domain scripting. What I ended up doing was throw out the webduino library and add some TcpSocket code to my ActiveX Object to communicate with the Arduino. It's mostly working now except for a memory leak I haven't found yet. I'm going to post my sketch and hopefully get some insight on that. The ActiveX object is still a bit of a work in progress as well. I haven't gotten it to where Internet Explorer sees it as safe for scripting yet.

You might want to try out "AJAX similar" approaches. For example JSONp (which stands for JSON padded)
Basically, you'll format the result in such way that it is wrapped in a native Javascript function call. There's plenty of info to be found on the net on JSONp.

It all helps solving the cross-domain barrier that "normal" AJAX calls suffer from, and it is easy to implement.

You'd just have to format your result like:

theNameOfYourCallbackFunctionDefinedInYourCallerPage({
  "batteryLevel": "13.2",
  "temperature": "7",
  "LightState": "ON"
});

Granted, it is a bit more overhead than just outputting "batteryLevel:13.2|Temperature:72|LightState:ON", but it's not that much more, especially if you'd trim whitespaces and new-lines.

Yeah, I kinda glanced at that. By that point though, I was already feeling like there was enough bloat on both sides. I realized that because I had to have that ActiveX object to capture the state of the game controller, I could just add the bits I needed there to do plain old tcp socket communication with the arduino. If anything changes on the controller, it's current state gets sent off to the arduino while still in the Activex dll. The arduino forms a response and sends it back to the dll and then it gets returned to my javascript.

...but only on MS Internet Explorer ]:slight_smile:

I haven't tried it yet, but I recall seeing something about being able to use ActiveX Objects in Firefox.

found it here... http://www.ehow.com/how_5242435_turn-active-firefox.html

Hmm. Not my idea of an ideal situation. I just don't like proprietary software - if used for internet based things - that is.

Imagine using this setup from your mobile phone. Not possible without ActiveX™. Using Android or iOS? Forget it! :wink:

Really, using JSONp is easy. I'd take a look on jQuery or such for the caller page. Nice library that takes a lot of other nasty cross-browser issues away as well.

Also on the arduino side, it's just wrapping your result in a - always the same (!) - basic and easy format. A few bytes extra at most :slight_smile:

I completely agree with you when it comes to things like mobile phones that AJAX and JSONp are a viable solution. But, I've found no other way to bring a 360 controller into a web page other than building my own ActiveX. XNA Framework is needed for interaction with the controller. It's funny, but if you google XNA and javascript, you'll find a lot of references to Windows 8 and metro style javascript apps which tells me there's a lot of interest somewhere in the marriage of a controller and a web page. This would eliminate my need for ActiveX altogether. I'm just not in any hurry to go buy a new version of Windows. As far as proprietary software goes, I completely agree with this too. If anyone has any interest though, I'm more than willing to share my Visual Studio solution. Tweak it to suit you and compile it yourself. It is in C# though. Just sayin'.