[SOLVED] How can i send GPS lat & long to ubidots using GSM client & Bridge Libraries

Hi Thanks in advance… I am a programming novice.

I am trying to send my GPS Data to my “Position” variable. I would like to send the lat & long in the context format to create a map.

However i am only able to send the “Value” (which is just a 1 currently) to my variable.

I’ve seen many posts in which the fix was to use the ubidots gprs library. However this calls upon software serial which i cannot use as the gsm library conflicts with the use of software serial. (i’m having to use my gps with Altsoftserial as a result).

I believe the code should be similar to:

void setup(){
          // initialize serial communications and wait for port to open:
          Serial.begin(9600);
          while (!Serial){
            ; // wait for serial port to connect. Needed for Leonardo only
          }
          Serial.println("Starting Arduino web client.");
          // connection state
          boolean notConnected = true;
          // After starting the modem with GSM.begin()
          // attach the shield to the GPRS network with the APN, login and password
          while (notConnected){
            if ((gsmAccess.begin(PINNUMBER) == GSM_READY) &
                (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)){
              notConnected = false;
            }else{
              Serial.println("Not connected");
              delay(1000);
            }
          }       
        }

        void loop(){
          int value = analogRead(A0);
          if(save_value(value)){
          }
          else{
            reset++;
            if (reset == 10){
              asm volatile ("  jmp 0");    // reset the Arduino board if the data transmission fail
            }
          }       
          // if the server's disconnected, stop the client:
          if (!client.available() && !client.connected()){
            Serial.println();
            Serial.println("disconnecting.");
            client.stop();
            // do nothing forevermore:        
          }
        }
        boolean save_value(int value){
          Serial.println("connecting...");        
          int num=0;
          String var = "{\"value\":"+ String(value) + "}";
          num = var.length();
          // if you get a connection, report back via serial:
          if (client.connect("things.ubidots.com", 80)){
            Serial.println("connected");
            // Make a HTTP request:
            client.print("POST /api/v1.6/variables/"+idvariable+"/values HTTP/1.1\nContent-Type: application/json\nContent-Length: "+String(num)+"\nX-Auth-Token: "+token+"\nHost: things.ubidots.com\n\n");
            client.println(var);
            client.println();           
          }else{
            // if you didn't get a connection to the server:
            Serial.println("connection failed");
            return false;
          } 
            while (client.available())
          {         
            char c = client.read();
            Serial.print(c);
          }
        }

But with the context added, should i use a sprintf function for this? converting my latitude and longitude floats to chars using the dtostrf function ?

void loop() {
  int value = 1;
  float latitude = 1.2345;
  float longitude = 54.334;
  char latoutput[15];
  char longoutput[15];
  String var = ("{\"value\":" + String(value) + ", ");
  dtostrf(latitude, 9, 7, latoutput);
  dtostrf(longitude, 9, 7, longoutput);
  char context[40];
  sprintf(context, " \"context\":{\"lat\":%s, \"lng\":%s""}}", (latoutput), (longoutput));
  int num = 76;
  num = var.length();

  if (client.connect(server, port)) {
    Serial.println("connected");
    // Make a HTTP request:
    client.println("POST /api/v1.6/devices/my-gps-data/Position/values HTTP/1.1\nContent-Type: application/json\nContent-Length: " + String(num) + "\nX-Auth-Token: " + token + "\nHost: things.ubidots.com\n\n");
    client.print(var);
    Serial.print(var);
    client.println(context);
    Serial.println(context);
    client.println();
    client.println("Connection: close");
    Serial.println("Connection: close");

Currently this isn’t working at all however when i remove the context element i will work adding int value = 1 to my variable in ubidots.

Below is the serial display:

Starting Arduino web client.
connecting...
connected
{"value":1,  "context":{"lat":1.2345001, "lng":54.3340000}}
Connection: close
Reponse from Server:
H

Dear @Zac_uk,

As I can see in your code you are structuring and posting the variable value plus the variable context separately, for this reason you are just able to receive the variable value.

The all payload/body to be post should look like:

{"location": {"value":1, "context": {"lat": xxx, "lng": xxx}}}

Where location is the variable label to be sent.

The payload should be pointing to the following endpoint:

/api/v1.6/devices/{LABEL_DEVICE}

For more information, please reference to the Ubidots RESP API Reference. Also, the guides bellow will help you to understand the difference between Variable ID’s & Variable Labels.

As developer tip, I recommend you build the payload using chart (sprintf method) instead using Strings. This will make your code efficiently, and it will take less memory space.

Hi @mariahernandez

I’ve implemented the suggestions you have made. However your path and payload are slightly different to both the api’s docs and the link:
http://help.ubidots.com/faqs-and-troubleshooting/automatically-provision-devices-and-variables-with-ubidots-api-labels

Both codes i have created still do not work, and i’m not too sure why.

Here is my code using the device label as per: http://help.ubidots.com/faqs-and-troubleshooting/automatically-provision-devices-and-variables-with-ubidots-api-labels

 float value = 1.00;
  float latitude = 1.2345;
  float longitude = 54.334;
  char latoutput[15];
  char longoutput[15];
  char valueoutput[5];
  Serial.println("compiling sprintf");
  dtostrf(value, 5, 1, valueoutput);
  dtostrf(latitude, 9, 7, latoutput);
  dtostrf(longitude, 9, 7, longoutput);
  char context[117];
  int num = 76;
  sprintf(context, "{\"position\":{\"value\":%s, \"context\":{\"lat\":%s, \"lng\":%s""}}", (valueoutput), (latoutput), (longoutput));

  Serial.println("checking server/port");
  if (client.connect("things.ubidots.com", 80)) {
    Serial.println("connected");
    delay(5000);
    // Make a HTTP request:
    client.println( "POST /api/v1.6/devices/my-gps-data/?token=A1E-SSEfnjVt2Img45byscwejug7cPBtDR HTTP/1.1\nHost: things.ubidots.com\nContent-Type: application/json\nContent-Length:117\n");
    client.print(context);
    Serial.println("POST /api/v1.6/devices/my-gps-data/?token=A1E-SSEfnjVt2Img45byscwejug7cPBtDR HTTP/1.1\nHost: things.ubidots.com\nContent-Type: application/json\nContent-Length:117\n");
    Serial.println(context);
    client.println();
    Serial.println();
    client.println("Connection: close");
    Serial.println("Connection: close");
    delay(10000);

And here is my code using the variable label as per the Ubidots api docs > Send values to one variable

  float value = 1.00;
  float latitude = 1.2345;
  float longitude = 54.334;
  char latoutput[15];
  char longoutput[15];
  char valueoutput[5];
  Serial.println("compiling sprintf");
  dtostrf(value, 5, 1, valueoutput);
  dtostrf(latitude, 9, 7, latoutput);
  dtostrf(longitude, 9, 7, longoutput);
  char context[117];
  sprintf(context, "{\"value\":%s, \"context\":{\"lat\":%s, \"lng\":%s""}}", (valueoutput), (latoutput), (longoutput));
  int num = 76;
  Serial.println("checking server and port");
  if (client.connect(server, port)) {
    Serial.println("connected");
    delay(5000);
    // Make a HTTP request:

    client.println( "POST /api/v1.6/devices/my-gps-data/position/values/?token=A1E-KycVLWIqbxY1IaUEEU2kjflpGT2LhI \nHTTP/1.1\nHost: things.ubidots.com\nContent-Type: application/json\nContent-Length:117\n");
    client.println(context);

    Serial.println("POST /api/v1.6/devices/my-gps-data/position/values/?token=A1E-SSEfnjVt2Img45byscwejug7cPBtDR \nHTTP/1.1\nHost: things.ubidots.com\nContent-Type: application/json\nContent-Length:117\n");
    Serial.println(context);
    client.println();
    Serial.println();
    client.println("Connection: close");
    Serial.println("Connection: close");

is there any obvious mistakes i have made?

Hello,

Are you receiving any response from the Ubidots Server? If you are, the answer should be a bad request.

As I can note in your code the request is including some blank spaces, plus some extra new lines(\n), and they are not need it because they are included in the client.println. To get a better idea how to build it, please reference this section of one of the Ubidots Library.

I hope this would help you.

All the best,
Maria C.

Im am not currently getting a response from the server, when using the serial monitor the http request is formatted as required on the api docs webpage, but i’m getting zero response.

If you are not able to received any response I recommend you try with a WebClient example pointing to a google, in order to verify if your board is capable of reach out the connection with the server.

Once you are able to get a success request modify the request to the Ubidots server. Remember follow the structure sent above, plus the Ubidots REST API Reference.

All the best,
Maria C.

@mariahernandez

Hi Maria,

Thanks for your help i am please to say that it is now working.

My last question is regarding the widget i’ve created on the dashboard. The GPS trace isn’t very good.
Currently i am keeping the “value” the same and the only change in data is the lat and lng within the “context”

Should i change the value each time ( 1 2 3 4 etc) for a better trace ? or will that make no difference?

Hello @Zac_uk,

I’m glad to read that! :grinning:

Change the value posted for the position variable will not make any difference in the widget visualization. The Ubidots backend is in charge of take the context of the variables called postion, gps, and location to automatically assign the coordinates in the map widget and in the device map, so the value here is not relevant.

All the best,
Maria C.