converting .json script to something the arduino can use

Hi folks,
So I have an arduino uno with a CC3000 shield connected and I want to push data to my xively account:
https://xively.com/develop/yS4XfViIIEEkB94MJ4zs
I’ve got the board talking to the server ok but I keep getting this message

Connected!
Request DHCP
api.xively.com -> 64.94.18.120
Data Lengthz

PUT /v2/feeds/97346308.json HTTP/1.1
Host: api.xively.com
X-ApiKey:mykey
Content-Length: z
Connection: close


{"version":"1.0.0","datastreams" : [ {"id" : "Longitude","current_value" : ""},{"id" : "Latitude","current_value" : ""}]}
Connected to Xively server.
--------------------------------------
HTTP/1.1 411 Length Required
Date: Fri, 08 Aug 2014 13:19:33 GMT
Content-Type: text/html
Content-Length: 181
Connection: close

<html>
<head><title>411 Length Required</title></head>
<body bgcolor="white">
<center><h1>411 Length Required</h1></center>
<hr><center>nginx/1.1.19</center>
</body>
</html>

I gather this is because the Server isn’t happy with the Content-Length declaration. I think this is because the .json script that xively uses:

{
  "version":"1.0.0",
   "datastreams" : [ {
    "id" : "example",
      "current_value" : "333"
    },
    { 
    "id" : "key",
    "current_value" : "value"      
    },
    { 
      "id" : "datastream",
    "current_value" : "1337"
    }
  ]
}

isn’t being transleted well into Arduino’s language:

//JSON data
  String data = "";
  data = data + "\n" + "{\"version\":\"1.0.0\",\"datastreams\" : [ "
  + "{\"id\" : \"Longitude\",\"current_value\" : \"" + String(Longitude) + "\"},"
  + "{\"id\" : \"Latitude\",\"current_value\" : \"" + String(Latitude) + "\"}]}";

Is this because I havent’ defined the json data properly or is it some other problem?
Cheers Folks,

The "Content-Length" parameter needs to be in an ascii value. This will not work:

Content-Length: z

z is not a valid content length.

I think this is because the .json script that xively uses:

JSON is a mechanism for formatting data. It is NOT a scripting mechanism.

Data Lengthz

Does that look like reasonable information to you?

  String data = "";

I think that your problem starts there.

Is this because I havent' defined the json data properly or is it some other problem?

Most likely.

Of course, we'd need to see your code. But, I'd start with dumping the String class, and using a NULL terminated array of chars instead, using sprintf() to populate the array. Far easier, in my opinion to get the quotes right.

Well here’s my code:

//Libraries
#include <SPI.h>
#include <string.h>
#include <Adafruit_CC3000.h>
#include <Adafruit_CC3000_Server.h>
#include <ccspi.h>
#include "utility/debug.h"
#include <stdlib.h>
#include <SoftwareSerial.h>

//Set Harware Configuration Pins etc.
SoftwareSerial gps_comms(6, 7);     //Two pins that were free and not used for SPI commms
#define ADAFRUIT_CC3000_IRQ    3    // Must be an interrupt pin!
#define ADAFRUIT_CC3000_VBAT   5    
#define ADAFRUIT_CC3000_CS     10
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT, SPI_CLOCK_DIVIDER);

//Define GPS Parameters
const int data_size = 80;
char data[data_size];
char Latitude = 0;
char Longitude = 0;
char length = 0;

//Define wifi parameters
#define WLAN_SSID              "MagelliumLtd"
#define WLAN_PASS              "mag2013uk;"
#define WLAN_SECURITY          WLAN_SEC_WPA2

//Xively Parameters
#define WEBSITE "api.xively.com"
#define API_key "4V6OFmfs8YVnjB9GllRuwBWzne4XVXGk0xyaA3YIKmlGfiVU"
#define feedID "97346308"

uint32_t ip = 0;

void setup() {
  //Initialise GPS
  Serial.begin(9600);
  gps_comms.begin(9600);
  
  //Initialize CC3000
  Serial.begin(115200);
  
  Serial.println(F("Initializing..."));
  if (!cc3000.begin()) {
    Serial.println(F("Couldn't begin()!"));
    while(1);
  }
}

void loop(void) {
  static int i = 0;
  if (gps_comms.available()) {
    char ch = gps_comms.read();
    if (ch != '\n' && i < data_size) {
      data[i] = ch;
      i++;
    }
    else {
      data[i] = '\0';
      i = 0;
      char field[20];
      getField(field,0);
      if (strcmp(field, "$GPRMC") == 0) {
        Serial.println("|| TIMESTAMP: ");
        getField(field,1);
        Serial.println(field);
    }
  }
  
  //Connect to WiFi network
  cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
  Serial.println(F("Connected!"));
  
  /*Wait for DHCP to complete */
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP()) {
    delay(100);
  }
  
  //Get the website IP and Print it
  ip = 0;
  Serial.print(WEBSITE); Serial.print(F(" -> "));
  while (ip == 0) {
    if (!cc3000.getHostByName(WEBSITE, &ip)) {
      Serial.println(F("Couldn't resolve!"));
    }
    delay(500);
  }
  cc3000.printIPdotsRev(ip);
    
  //Get data & transform to integers
  //int latitude = getField(field,3);
  //int longitude = getField(field,5); 
  
  //JSON data
  String data = "";
  data = data + "{\"version\":\"1.0.0\",\"datastreams\" : [ "
  + "{\"id\" : \"Longitude\",\"current_value\" : \"" + String(Longitude) + "\"},"
  + "{\"id\" : \"Latitude\",\"current_value\" : \"" + String(Latitude) + "\"}]}";
    
  //Get Length
  length = data.length();
  Serial.print("\nData Length");
  Serial.println(String(length));
  Serial.println();
  
  //Print request for debug purposes
  Serial.print("PUT /v2/feeds/");
  Serial.print(feedID);
  Serial.println(".json HTTP/1.0");
  Serial.println("Host: api.xively.com");
  Serial.print("X-ApiKey: ");
  Serial.print(API_key);
  Serial.print("\nContent-Length: ");
  Serial.print(String(length));
  Serial.println("\nConnection: close");
  Serial.println();
  Serial.print(data);
  Serial.println();
  
  //Send Request
  Adafruit_CC3000_Client client = cc3000.connectTCP(ip, 80);
  if (client.connected()) {
    Serial.println("Connected to Xively server.");
    client.println("PUT /v2/feeds/" + String(feedID) + ".json HTTP/1.0");
    client.println("X-ApiKey: " + String(API_key));
    client.println("Content-Length: " + String(length));
    client.println("Host: api.xively.com");    
    client.print("Connection: close");
    client.println();
    client.print(data);
    client.println();
  } else {
    Serial.println(F("You Failed"));
    return;
  }
  
  Serial.println(F("--------------------------------------"));
  while (client.connected()) {
    //Serial.print("Xively @");
    //Serial.print(ip);
    while (client.available()) {
      char c = client.read();
      Serial.print(c);
    }
  }
  client.close();
  Serial.println(F("\nDisconnecting"));
  cc3000.disconnect();
  
  //Wait 60 seconds until next update
  delay(60000);
  }
}

void getField(char* buffer, int index) {
  int data_pos = 0;
  int field_pos = 0;
  int comma = 0;
  while (data_pos < data_size) {
    if (data[data_pos] == ',') {
      comma ++;
      data_pos ++;
    }
    if (comma == index) {
      buffer[field_pos] = data[data_pos];
      field_pos ++;
    }
    data_pos ++;
  }
  buffer[field_pos] = '\0';
}

The intention is to eventually push GPS data from my Cn-06 Ublox Neo 6m however I’m simply just trying to communicate with my account at the moment.

That String(length) is your problem. I presume your data length is 122 characters. That is the ascii number for a lower case z. http://www.asciitable.com/

  //Connect to WiFi network
  cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
  Serial.println(F("Connected!"));
  
  /*Wait for DHCP to complete */
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP()) {
    delay(100);
  }

On every pass through loop()? Why? The connection to the WiFi network is persistent.

char Latitude = 0;
char Longitude = 0;

So, Latitude and Longitude are NULLs.

  String data = "";
  data = data + "{\"version\":\"1.0.0\",\"datastreams\" : [ "
  + "{\"id\" : \"Longitude\",\"current_value\" : \"" + String(Longitude) + "\"},"
  + "{\"id\" : \"Latitude\",\"current_value\" : \"" + String(Latitude) + "\"}]}";

You've just embedded NULLs in your data String.

  length = data.length();

Now, you find the position of the first NULL.

Do you suppose that the packet that you are (mal)forming is correct? Complete?

Cheers PaulS, Yeah I only wanted it to connect to the server once, I actually wasn't to sure how to take the connect aspect out of the loop. I have yet to work our how to grab the Lat, long from the GPS and feed it into the put request because truth be told up until now the hardest thing I've done on an arduino is throttle a motor using a potentiometer :p I'm still trying to get my head around the more complicated stuff to do with communication protocols etc.

will the string(length ) be invalid if keep Null values in it?

You are not sending a valid Content-Length. That is what this error is telling you!

HTTP/1.1 411 Length Required

http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

I get that I’m not sending the right Content-Length but I don’t know what the right Content-Length format is :frowning:
I don’t know how to convert ASCII to DEC in arduino

itoa() or sprintf().