HTTPClient Help (How to "assemble" URI)?

I have device on my local network and am trying to get a status page as well as issue basic commands via GET. I understand the headers I need, the URL to call but would like to dynamically create the request path based on logic in my app. I broke the full uri down to its pieces and know where I would insert numbers 0-4 depending on the need but don’t know how to combine it all into a single line. I think SPRINTF might be the right answer I am not entirely sure.

Here are the baseline components of the URI path I need to call, 0-4 would be added behind each =. Thoughts?

#define ThingProgBase "thing.cgi?"
#define ThingNumURI "num="
#define ThingProgURI "&val="

Yup, my first thought would be sprintf() too (or snprintf() if you can’t be sure of resulting length).

Alternatively you could use String::format() (:stuck_out_tongue_closed_eyes: personal opinion)
Or strcpy() + strcat() + itoa() (:stuck_out_tongue_winking_eye:)

const char ThingProgURI[] = "thing.cgi?num=%d&val=%d";

char uri[32];

void loop()
{
  int n = 9999;
  int v = 8888;
  sprintf(uri, ThingProgURI, n, v);
}
1 Like

I am keeping it simple with hard coded stuff for now but was hoping you could help me with this. I am using the HTTPClient lib from within my own lib. Here is what I have and the compile error message I am getting, any ideas?
The HTTPClient lib is there as a Public object which is how I have seen other libs do this but I have also seen some use the new keyword like this ds = new OneWire(pin). What is the difference?

class Thing
  {
  private:
  //Private functions
  //bool parse();
  //Private variables
  uint8_t thingNum;
  http_request_t request;
  http_response_t response;
  // Headers currently need to be set at init, useful for API keys etc.
  http_header_t headers[] = {
      { "Accept" , "*/*" },
      { "Authorization" , "Basic Base64EncodedUser:Pass" },
      { NULL, NULL }
  };

  public:
  HttpClient thingWeb;

Function that uses thingWeb HTTPClient.

void Thing::update()
{
  request.ip = SERVER_IP;
  request.port = SERVER_PORT;
  request.path = THINGXML;
  thingWeb.get(request, response, headers);
  Serial.println(response.status);
  Serial.println(response.body);
}

Pinging @peekay123 too…

new is used to allocate a class or array and return a pointer (so you’ll need -> to access members), similar to alloc() but for a class it calls the constructor. Always remember to delete it as well after use, which calls the destructor and frees the memory, which won’t occur on exit of a routine like when instantiated without the new (on the stack).

You could also use a String object to build a URI, like…

String uri = "http://";
uri += "www.mysite.com/";
uri += "?val1=";
uri += number1;
uri += "&val2=";
uri += number2;
1 Like

@LukeUSMC, since the objects will be instantiated dynamically, you might want to write http_header_t headers[3] = { ... } instead, otherwise you’ll get a zero length array.

Or you declare it static

class Thing
{
  private:
  //Private functions
  //bool parse();
  //Private variables
  uint8_t thingNum;
  http_request_t request;
  http_response_t response;
  // Headers currently need to be set at init, useful for API keys etc.

  static http_header_t headers[]; 

public:
  Thing();
  void update();
  
  HttpClient thingWeb;
  
};

and initialize in the .cpp

http_header_t Thing::headers[] = {
      { "Accept" , "*/*" },
      { "Authorization" , "Basic Base64EncodedUser:Pass" },
      { NULL, NULL }
};

Thank you sir! Went with [3] for now but they are static so may use the other approach long term. Where can I read about dynamic inits so I understand this a bit better? Or even better if you have a fav C++ book I’m all ears.