Help with Electron Code for GPS lat/lon coordinates to Ubidots

Hi. I have managed to get my Electron/Asset Tracker to update some Ubidots variables. My electron/tracker is running the TinyGPS code.

With the following code:

    ubidots.add("Lat", lat);  // Change for your variable name
    ubidots.add("Lon", lon);
    ubidots.add("Speed (Kn)", speed_knots);
    ubidots.sendAll();

and the Ubidots.h and Ubidots.cpp included it works fine.
Within Ubidots three variables called “Lat”, “Lon” and “Speed (Kn)” all get created.
Thats great… except to map the data, Ubidots expects the lat/lon data as “context” of a single variable.

Can anybody help with the Electron code that “adds” a single Ubidots variable with lat and long as context - that permits mapping in Ubidots?

(I have looked through the Ubidots help, forum etc but the explanations are beyond my beginners level of understanding).

Do you have a link to the ubidots documentation. Also you got the asset tracker working with the TinyGPS library. Do you have more info on that?

@GreyMonkey Sounds like your going to need to take the data your getting from the TinyGPS and string it together into a single variable.

Here is how somebody else is sending gps data to ubidots:

boolean ParseLocation() 
// Refer to http://www.gpsinformation.org/dale/nmea.htm#GGA
// Sample data: $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
{
  char Latitude[10];
  char Longitude[10];
  float Lat = gps.latitude;
  float Lon = gps.longitude;
  dtostrf(Lat,5,2,Latitude);
  dtostrf(Lon,5,2,Longitude);
  Location = "{\"lat\":" + String(Latitude) + ",\"lng\":" + String(Longitude) + "}";
  //Serial.println(Location);
} 

And here is the code they used to send the location data to Ubidots:

boolean Send2Ubidots(String value)
{
  char replybuffer[64];          // this is a large buffer for replies
  int count = 0;
  int complete = 0;
  String var = "";
  String le = "";
  ParseLocation();              // Update the location value from the GPS feed
  var="{\"value\":"+ value + ", \"context\":"+ Location + "}";
  int num=var.length();                                       // How long is the payload
  le=String(num);                                             //this is to calcule the length of var
  // Make a TCP connection to remote host
  Serial.println(F("Sending Data to Ubidots"));
  Adafruit_CC3000_Client client = cc3000.connectTCP(ip, 80);
   if (!client.connected()) {
     Serial.println(F("Error: Could not make a TCP connection"));
   }   

They did this on a Teensy 3.1.

Hi @Jean-Pierre.
Yes I have links to (and have read) the Ubidots doco. I found it a bit (actually a lot!) confusing. Its a great platform though, at least as a springboard for newbees like myself who would struggle to create, manage and code web based databases and mapping applications.
I found this:
http://ubidots.com/docs/devices/particlePhoton.html#particle-photon
But (a) They only have a photon devices section. The doco on the electron is apparently in planning. and (b) the photon help only describes the code for (1) Writing a variable from device to Ubidots, (2) Reading a variable from Ubidots to device and (3) Writing multiple discrete variables from device to Ubidots.

In the Git Hub Photon/Ubidots library (https://github.com/ubidots/ubidots-particle). There is a Ubidots.cpp and Ubidots.h file for inclusion in your spark project. It seemed to work fine in my electron (even if written for a photon).

This thread on Ubidots forum is also helpful:


So is this: http://community.ubidots.com/t/format-of-context-message-from-particle-library-to-get-a-map-dashboard

After posting my request, I did manage to solve the problem and have been able to get mapping of my Electron Asset Tracker running tinyGPS code on Ubidots working!! :grinning: :+1:

They key is that Ubidots to display consecutive values from an Electron on a map and chart its track, must get a value as a variable, which has two “context” elements associated with it, namely “lat” (obviously latitude) and “lng” (longitude).

This will not work if you have (say) 2 or 3 discrete variables for (say) Speed, Lat and Lon - or event Lat and Lon. Whilst Ubidots can display these nicely as Lat and Lon variables on their dashboard - it will not map them in their map or tracking widgets.

The Particle code for this is something like this (NB: This code is in parallel publishing to Particle allowing GPS Lat/Lon to be read there too):

// MD: Increment version number each edit and compile.  Allows read of version number loaded to electron.
// MD: See below for particle variable allowing remote reading in Particle Dev and from CLI.
char *version = "0.6";
//v0.5: 30/04/2016:  Includes Ubidots and Ubidot write of data
//v0.6: 01/05/2016:  General tidy up.

// This #include statement was automatically added by the Spark IDE.
#include "TinyGPS.h"
// Ubidots include
#include "Ubidots.h"
#define TOKEN "token#"  // Put here your Ubidots TOKEN
Ubidots ubidots(TOKEN); // A data source with name "Particle" name will be created in your Ubidots account

TinyGPS gps;
char szInfo[64];
// Every 15 minutes
// MD: changed to 10 minutes
int sleep = 10 * 60 * 1000;
float lat, lon, speed_knots;
unsigned long age;
char ubidots_string[150];

void setup(){
    // MD: Copied from Asset Tracker library.  Power to the GPS is controlled by a FET connected to D6
    pinMode(D6,OUTPUT);
    digitalWrite(D6,LOW);

    Serial1.begin(9600);
    Serial.begin(9600);

    // MD: Allow version of electron application code to be read remotely.
    Particle.variable("Version", version);

    ubidots.setDatasourceName("ParticleDeviceName"); // Uncomment this line to change the datasource Name.
}

void loop(){
    bool isValidGPS = false;

    for (unsigned long start = millis(); millis() - start < 1000;){
        // Check GPS data is available
        while (Serial1.available()){
            char c = Serial1.read();

            // parse GPS data
            if (gps.encode(c))
                isValidGPS = true;
        }
    }

    // If we have a valid GPS location then publish it
    if (isValidGPS){

        gps.f_get_position(&lat, &lon, &age);
        speed_knots=gps.f_speed_knots();// MD:  Added to provide a single variable to pass to Ubidots for mapping.

        sprintf(szInfo, "%.6f,%.6f", (lat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : lat), (lon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : lon));
        sprintf(ubidots_string,"lat=%.6f$lng=%.6f",lat,lon);
    }
    else{
        // Not a valid GPS location, so just pass 0.0,0.0
        // This is not really correct because 0.0,0.0 actually is a valid GPS location,
        // so we have to pass a invalid GPS location and check it at the client side

        sprintf(szInfo, "0.0,0.0");
        sprintf(ubidots_string, "lat=0.0$lng=0.0");
    }

    Spark.publish("gpsloc", szInfo);

    ubidots.add("Lat", lat); // Discrete variable for display on Ubidots dashboard (but not for mapping).
    ubidots.add("Lon", lon); // Discrete variable for display on Ubidots dashboard (but not for mapping).
    ubidots.add("Speed (Kn)", speed_knots,ubidots_string); //This variable, has "context" string of lat and lng which is read by Ubidots and used for position data in mapping  widget.
    ubidots.sendAll();

    // Sleep for some time
    delay(sleep);
}

I hope this helps someone else.
@Jean-Pierre I hope this also answers your question over getting the TinyGPS library to run on the Electron (with the Asset Tracker). I found this a more straightforward way than the Adafruit GPS library.

Sweet!

I have not tried doing this yet but plan on it in the future so I am glad you posted the working code so I know it’s there and working when I need it :smiley:

Hi @RWB. Thanks. Our posts just crossed, was just replying to @Jean-Pierre when your post landed. Yes I did see that nice code on Hackster. I forgot to mention that. It looked very nice but my very beginner level coding brain couldn’t quickly work out the format of the string it was creating for Ubidots.

Instead I followed some of the advice of @Metavix on the Ubidots forum. It just took a bit of trial and error to compose the string (I am a complete C++ beginner, so half the time I am reading code tutorials to work out what things mean! Can be a slow process this way… :sweat:). Anyway even if my code is a bit of a mess, I have map plotting on Ubidots working! Here’s my GPS’s track overnight from the Ubidots dashboard (it was actually stationary in my house!) For scale purposes the houses have a street frontage of about 15 metres (48 feet).

Yeah I think that gps module does not work very well it’s all over the place When I test my unit the gps point was off by 150 to 250 and more feet way never in the 5meters radios that the unit spec sheet :confused:

Yea I am beginner also so I’m watching plenty of tutorials also :smiley: Thank god for Youtube!

It’s normal for the GPS to bounce around while stationary from my experience.

hey! everyone
You need some help with Ubidots functions?

Remember to post latitude and longitude you need to pass it to add function as a context, and these values has a declaration form like: lat=1.232 and lng=2.1231. Ubidots map recognize that it is latitude and longitude if the name of the context is lat and lng.
Then for use it in add function of ubidots library is like:

add(variableName, variableValue, context);

Where:
variableName is an string that contains the name of your variable
variableValue is a float that contains the value of the variable
context is the message that you want to add to your variable.
If you want to add a message that indicate the gprs possition you need to assemble the context like this:

context = "lat=123213$lng=1.123123"

Because you need to send two context latitude and longitude, with values.

You can add infinite context to add function, to do it you just put a “$” symbol between every context

This is very interesting but still mysterious. How does this code:

ubidots.add("Lat", lat); // Discrete variable for display on Ubidots dashboard (but not for mapping).
ubidots.add("Lon", lon); // Discrete variable for display on Ubidots dashboard (but not for mapping).
ubidots.add("Speed (Kn)", speed_knots,ubidots_string); //This variable, has "context" string of lat and lng which is read by Ubidots and used for position data in mapping  widget.

Associate the “context” to Lat and Lon. It would appear to associate it to Speed?

I did a variant of this that seems a bit more straightforward to understand. It submits individual variables for lat, lon, altitude, atmospheric pressure and number of GPS satellites in view … and creates a composite geopoint variable for displaying on Ubidots maps.

void sendUbi () {
    char geopoint[50];
    
    sprintf(geopoint,"lat=%.6f$lng=%.6f",pq.lat,pq.lon);
    ubidots.add("lat",pq.lat);
    ubidots.add("lon",pq.lon);
    ubidots.add("alt",pq.galt);
    ubidots.add("pressure",pq.pressure);
    ubidots.add("sats",pq.sats);
    ubidots.add("geopoint",pq.lat,geopoint);
    ubidots.sendAll();
    diagnostic("send ubi");
}

It seems to work and make sense to me - with exception that the pq.lat variable in the “geopoint” .add seems completely gratuitous. All the content of the geopoint variable is in the context string.

I presume lat and lng in the context string are special Ubidots defined variables that the Ubidots map widget understands.

Thanks to @GreyMonkey for leading the way.

Hi @KenBiba, glad to hear you got that going. I too wondered about the Ubidots format of that add statement (like you, why is there a gratuitous variable, with the lat/lon in a string?). The way I rationalised it is you generally want to have/display/log a variable at the GPS point. It isnt always the case, sometimes just knowing where something is enough. But you might want a sensor value (eg O2 values, speed, engine parameter…) to be known and plotted at each GPS point. This is what I figure the intent of the Ubidots variable structure (and add statement) is.

My rationalising this seemed all good, but not actually reflected in the Ubidots map widget. It isnt possible to read the value of the variable at each mapped point! I will send a comment to Ubidots to ask why not. The value is visible in the “Raw Data” section of the source in tabular form, but I dont see it on the map. None of the previous data points on the map are interrogatable by cursor position and click. This seems like a weakness in the Ubidots widget.

Thanks @Metavix. Got it.

And the “hidden” variables of lat and lng - and setting their value via “context” seems very poorly explained on the Ubidots website.

All that being said … I am very impressed by the Ubidots platform. I wonder if Particle plans something similar?

You will see a statistical variance in the reported location. This comes from a variety of physical issues - this is a good analysis of the statistical variation. And not all GPS are identical. Since I use mine often for rocketry and high altitude balloons - the only GPS of choice is a uBlox - which has the ability to adjust for 3D dynamic motion. Most consumer GPS have poor sensitivity and filtering algorithms tuned for the problem of 2D location.

Hi @KenBiba. Thanks for that link on the GPS error/variance sources. That is a really good reference. For 2D applications do you believe the uBlox would achieve higher accuracy than that achieved by the MTK3339/PA6H that comes with the Electron Asset Tracker (or is what we get from that GPS about as good as can be achieved)?

Yes you are right for that i put here the explanation of that because we are doing a refactor of all website :smiley:

Yes they are predefined at Ubidots, it is like this because you can send, for example, a variable of temperature, but your sensor is moving around a place then you can take different temperatures of different place and indexing it in a map

Consumer grade GPS is about that good. It is important to remember that GPS location is very stochastic. The 3-5m horizontal “accuracy” often quoted is quite variable. That number happens in about 2/3rds of the cases … and in the remaining third you might see samples with quite different locations ranging 100s of meters. For a stationary tracker, a good Kalman filter on the location will help keep a consistent reading. For a mobile tracker, a good filter is essential as well for getting accurate tracking.

High end commercial or differential GPS can improve accuracy to a few 10s of cm … but much more expensive.

Think filters … though I still uBlox better chipset overall.

Interesting. Are there then operations, like kridging, that can be done on this dataset?