Help with how sprintf works with strings and integers

Hello all, I am trying to understand how to use the sprintf buffer to build a string of data to pass to an LED matrix.

Im having trouble with my output showing up as garbage:

⸮⸮?\⸮⸮?t⸮⸮?T⸮⸮?D⸮⸮?⸮⸮⸮? ⸮⸮?ly⸮?omD⸮⸮⸮⸮⸮⸮?⸮m @⸮⸮⸮?

here is that part of the code, whole code below…

// Try to make sprintf work with JSON data...
      Serial.println("\n\n Result of buffer print");
      char CurrentPeriodBuffer[50];
      sprintf(CurrentPeriodBuffer, "%s", doc["creationDateLocal"]);
      Serial.println(CurrentPeriodBuffer);

I understood that using %s would return the buffer value as a string… but I think the JSON parsing wants it as a char*

so I guess my real question is how do I use sprintf with a returned JSON element?

-J

Whole Code:

/**
NOAA forcast for San Antonio using JSON data from https://api.weather.gov
to parse datasets use http://json.parser.online.fr/
*/
#include <ArduinoJson.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>

// Current fingerprint for https://api.weather.gov
const uint8_t fingerprint[20] = {0x1C, 0xE6, 0x10, 0xE0, 0x6D, 0x39, 0x26, 0x74, 0xEE, 0x44, 0x3A, 0x46, 0x9B, 0x44, 0x99, 0x77, 0xAC, 0xA3, 0xD4, 0x72};

ESP8266WiFiMulti WiFiMulti;

void setup() {

  Serial.begin(115200);
  Serial.println();
  Serial.println();
  Serial.println();

  for (uint8_t t = 4; t > 0; t--) {
    Serial.printf("[SETUP] WAIT %d...\n", t);
    Serial.flush();
    delay(1000);
  }
  Serial.println("[WiFi] Set Mode -> Station");
  WiFi.mode(WIFI_STA);
  Serial.println("[WiFi] Mode = Station");
  WiFiMulti.addAP("-----ssid----", "----key----");
  Serial.println("[WiFi] Send authentication data...");
}
void loop() {
  // wait for WiFi connection
  if ((WiFiMulti.run() == WL_CONNECTED)) {
    Serial.println("[WiFi] connected!");
    std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
    client->setFingerprint(fingerprint);
    HTTPClient https;
    Serial.print("[HTTPS] begin...\n");
    if (https.begin(*client, "https://forecast.weather.gov/MapClick.php?lat=29.584&lon=-98.553&FcstType=json")) {
      Serial.print("[HTTPS] GET...\n");
      int httpCode = https.GET();
      if (httpCode > 0) {
        Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
    if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
      //pass GET results to doc
      //Serial.println(https.getString());
      String payload = https.getString();
      //print payload
      //Serial.print("Print payload: ");
      //Serial.println(payload);
      // assign memory pool expression based on https://arduinojson.org/v6/assistant/
      const size_t capacity = 2*JSON_ARRAY_SIZE(0) + 8*JSON_ARRAY_SIZE(13) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(11) + JSON_OBJECT_SIZE(12) + JSON_OBJECT_SIZE(20);
     //print the capacity
      Serial.printf("[JSON] capacity: %d\n" , capacity);
      // set the capacity of 'doc' 
      DynamicJsonDocument doc(6000);
      //Deserialize the payload
      //deserializeJson(doc, payload);
      DeserializationError error = deserializeJson(doc, payload);
      if (error) {
        Serial.print(F("deserializeJson() failed: "));
        Serial.println(error.c_str());
        return;
      }  
      Serial.println();
      //Serial.print("Weather for ");
      //Serial.print(doc["periods"][0].as<char*>());
      //Serial.print(": ");  
      Serial.println();
      //Current period and forcast
      Serial.print(doc["time"]["startPeriodName"][0].as<char*>()); 
      Serial.print(", ");
      Serial.print(doc["data"]["text"][0].as<char*>()); 
      //Next period and forcast
      Serial.print(doc["time"]["startPeriodName"][1].as<char*>()); 
      Serial.print(", ");
      Serial.print(doc["data"]["text"][1].as<char*>()); 
      Serial.print(" As of: ");
      Serial.print(doc["creationDateLocal"].as<char*>());
      
      // Try to make sprintf work with JSON data...
      Serial.println("\n\n Result of buffer print");
      char CurrentPeriodBuffer[50];
      sprintf(CurrentPeriodBuffer, "%s", doc["creationDateLocal"]);
      Serial.println(CurrentPeriodBuffer);

          
       }
      } else {
        Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
      }
 
      https.end();
    } else {
      Serial.printf("[HTTPS] Unable to connect\n");
    }
  }
  Serial.println("\n\n Wait 1hour before next round...");
  delay(3600000);
}

What's your baud rate setting in Serial Monitor?

115200, all the other text shows up perfectly...

Wouldn’t you cast it as a char *, just like you do several lines previously when you print things out to Serial?

          Serial.print(doc["creationDateLocal"].as<char*>());
sprintf(CurrentPeriodBuffer, "%s", doc["creationDateLocal"].as<char*>());

:o yes... yes I would!! i could have sworn I tried that in on of my first iterations of testing.

thanks!

should i be able to string two elements together something like this?

printf(CurrentPeriodBuffer, "this is the current period name %s this is the forecast %s" , doc["time"]["startPeriodName"][0].as<char*>() , doc["data"]["text"][0].as<char*>());

You should. Depending on what you are going to do with the resulting buffer, it may be easier/simpler to just have multiple print statements...

I want to eventually send the buffer stream to an LED matrix, as a scrolling message. I think I need to increase the buffer size as I add in the second part (the text forecast) . I forgot to do that!

-J

nope… still no joy with adding bytes the the buffer…

      // Try to make sprintf work with JSON data...
      Serial.println("\n\n Result of buffer print");
      char CurrentPeriodBuffer[800];
      //sprintf(CurrentPeriodBuffer, "%s", doc["time"]["startPeriodName"][0].as<char*>() );  //this one works
      printf(CurrentPeriodBuffer, "%s ,%s" , doc["time"]["startPeriodName"][0].as<char*>() , doc["data"]["text"][0].as<char*>());  //this one returns nothing
      char NextPeriodBuffer[800];
      printf(NextPeriodBuffer, "%s ,%s" , doc["time"]["startPeriodName"][1].as<char*>() , doc["data"]["text"][1].as<char*>());   //this one returns nothing
      Serial.println(NextPeriodBuffer);

Are you sure the .as() function is returning a pointer to an actual string and not a null pointer?
Does this work:

char CurrentPeriodBuffer[800];
strcpy(CurrentPeriodBuffer, doc["time"]["startPeriodName"][0].as<char*>());
strcpy(CurrentPeriodBuffer + strlen(CurrentPeriodBuffer), doc["data"]["text"][0].as<char*>());
Serial.println(CurrentPeriodBuffer);

oh Yes gfvalvo, that does work… can I introduce a comma to seperate the returned data?

this

strcpy(CurrentPeriodBuffer, doc["time"]["startPeriodName"][0].as<char*>());
      strcpy(CurrentPeriodBuffer + strlen(CurrentPeriodBuffer), doc["data"]["text"][0].as<char*>());
      Serial.println(CurrentPeriodBuffer);

produced this result:

 Result of buffer print
This AfternoonMostly sunny, with a high near 87. Northeast wind around 5 mph.

I’d lke a comma added between doc[“time”][“startPeriodName”][0].as<char*> and doc[“data”][“text”][0].as<char*>

thanks for the assist!

char CurrentPeriodBuffer[800];
strcpy(CurrentPeriodBuffer, doc["time"]["startPeriodName"][0].as<char*>());
strcat(CurrentPeriodBuffer, ",");
strcat(CurrentPeriodBuffer, doc["data"]["text"][0].as<char*>());
Serial.println(CurrentPeriodBuffer);

Oh that makes it pretty easy :slight_smile:

thanks!