Http client help

I am trying to combine the httpclient and the GPS tracker.
However when I attempt to

request.hostname = "ServerIP";
request.port = 1234;
request.path = ("/?id=123456&lat="+(t.readLatDeg())
+"&lon="+(t.readLonDeg())
);

When I try to compile it I get:

/workspace//src/gps-tracker-alpha.cpp:96:67: error: invalid operands of types 'const char [17]' and 'float' to binary 'operator+'
if (transmittingData) {

I have a mix of static data to send in the request and then a couple variables. What is the correct way to do this?

Complete Code:

// This #include statement was automatically added by the Particle IDE.
#include <HttpClient.h>
#include <application.h>
#include "AssetTracker.h"
/* -----------------------------------------------------------
This example shows a lot of different features. As configured here
it will check for a good GPS fix every 10 minutes and publish that data
if there is one. If not, it will save you data by staying quiet. It also
registers 3 Particle.functions for changing whether it publishes,
reading the battery level, and manually requesting a GPS reading.
---------------------------------------------------------------*/

// httpclient paste start

unsigned int nextTime = 0;    // Next time to contact the server
HttpClient http;

// Headers currently need to be set at init, useful for API keys etc.
http_header_t headers[] = {
    //  { "Content-Type", "application/json" },
    //  { "Accept" , "application/json" },
    { "Accept" , "*/*"},
    { NULL, NULL } // NOTE: Always terminate headers will NULL
};

http_request_t request;
http_response_t response;

// httpclient paste end


// Set whether you want the device to publish data to the internet by default here.
// 1 will Particle.publish AND Serial.print, 0 will just Serial.print
// Extremely useful for saving data while developing close enough to have a cable plugged in.
// You can also change this remotely using the Particle.function "tmode" defined in setup()
int transmittingData = 1;

// Used to keep track of the last time we published data
long lastPublish = 0;

// How many minutes between publishes? 10+ recommended for long-time continuous publishing!
int delayMinutes = 1;

// Creating an AssetTracker named 't' for us to reference
AssetTracker t = AssetTracker();

// A FuelGauge named 'fuel' for checking on the battery state
FuelGauge fuel;

// setup() and loop() are both required. setup() runs once when the device starts
// and is used for registering functions and variables and initializing things
void setup() {
    // Sets up all the necessary AssetTracker bits
    t.begin();

    // Enable the GPS module. Defaults to off to save power.
    // Takes 1.5s or so because of delays.
    t.gpsOn();

    // Opens up a Serial port so you can listen over USB
    Serial.begin(9600);

    // These three functions are useful for remote diagnostics. Read more below.
    Particle.function("tmode", transmitMode);
    Particle.function("batt", batteryStatus);
    Particle.function("gps", gpsPublish);
}

// loop() runs continuously
void loop() {
    // You'll need to run this every loop to capture the GPS output
    t.updateGPS();

    // if the current time - the last time we published is greater than your set delay...
    if (millis()-lastPublish > delayMinutes*60*1000) {
        // Remember when we published
        lastPublish = millis();

        //String pubAccel = String::format("%d,%d,%d", t.readX(), t.readY(), t.readZ());
        //Serial.println(pubAccel);
        //Particle.publish("A", pubAccel, 60, PRIVATE);

        // Dumps the full NMEA sentence to serial in case you're curious
        Serial.println(t.preNMEA());

        // GPS requires a "fix" on the satellites to give good data,
        // so we should only publish data if there's a fix
        if (t.gpsFix()) {

            if (transmittingData) {
                // Short publish names save data!
                Particle.publish("G", t.readLatLon(), 60, PRIVATE);
                
                request.hostname = "ServerIP";
                request.port = 1234;
                request.path = ("/?id=123456&lat="+(t.readLatDeg())
                +"&lon="+(t.readLonDeg())
                );
//                request.path = "/?id=123456&lat=(t.readLatDeg()&lon=(t.readLonDeg()&speed=(t.getSpeed()&altitude=(t.getAltitude()&batt=String(fuel.getSoC()";
//                http.get(request, response, headers);
//                Serial.print("Application>\tResponse status: ");
//                Serial.println(response.status);

//                Serial.print("Application>\tHTTP Response Body: ");
//                Serial.println(response.body);
            }
            // but always report the data over serial for local development
            Serial.println(t.readLatLon());
        }
    }
}

// Allows you to remotely change whether a device is publishing to the cloud
// or is only reporting data over Serial. Saves data when using only Serial!
// Change the default at the top of the code.
int transmitMode(String command) {
    transmittingData = atoi(command);
    return 1;
}

// Actively ask for a GPS reading if you're impatient. Only publishes if there's
// a GPS fix, otherwise returns '0'
int gpsPublish(String command) {
    if (t.gpsFix()) {
        Particle.publish("G", t.readLatLon(), 60, PRIVATE);
        
        // uncomment next line if you want a manual publish to reset delay counter
        // lastPublish = millis();
        return 1;
    } else {
      return 0;
    }
}

// Lets you remotely check the battery status by calling the function "batt"
// Triggers a publish with the info (so subscribe or watch the dashboard)
// and also returns a '1' if there's >10% battery left and a '0' if below
int batteryStatus(String command){
    // Publish the battery voltage and percentage of battery remaining
    // if you want to be really efficient, just report one of these
    // the String::format("%f.2") part gives us a string to publish,
    // but with only 2 decimal points to save space
    Particle.publish("B",
          "v:" + String::format("%.2f",fuel.getVCell()) +
          ",c:" + String::format("%.2f",fuel.getSoC()),
          60, PRIVATE
    );
    // if there's more than 10% of the battery left, then return 1
    if (fuel.getSoC()>10){ return 1;}
    // if you're running out of battery, return 0
    else { return 0;}
}

Thanks!

Could you post your entire code?

@nrobinson2000 I edited my post to include the complete code. Thanks

1 Like

I would try something like this:

request.hostname = "ServerIP";
request.port = 1234;
char path[64];
snprintf(path,64,"/?id=123456&lat=%f&lon=%f",t.readLatDeg(),t.readLonDeg());
request.path = path;

You can control how the floating point lat and lon get printed but this should get you started.

3 Likes

@bko Thank You! It works as desired. What is the best starting point for learning the proper formatting / syntax?

If I want to also include fuel.getSoC() in that path what would be the correct way?

All the printf/sprintf/snprintf directives are the same, so it is worth learning them. Here is one reference but there are many more online if you search:

http://www.cplusplus.com/reference/cstdio/printf/

To add another item, you just have to figure out what the type returned by fuel.getSoC() is and add another % format directive. In this case, it also returns a float, so %f is the right choice:

snprintf(path,64,"/?id=123456&lat=%f&lon=%f&fuel=%f",t.readLatDeg(),t.readLonDeg(), fuel.getSoC());

1 Like

Thank you @bko! I appreciate the help,

1 Like