Issue with WiFiNINA to get JSON data

Viewed 560

I'm trying to do a GET request to my weather forecast API service with an Arduino nano 33 IoT but I can't parse JSON data because the code output also other information inside the string, is there a way to "clean" the string with only the JSON data? Here's my code

#include <ArduinoJson.h>
#include <SPI.h>
#include <WiFiNINA.h>
#include "arduino_secrets.h" 

char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key index number (needed only for WEP)

int status = WL_IDLE_STATUS;

char server[] = "api.weatherapi.com";    // name address for Google (using DNS)

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiClient client;

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to WiFi");
  printWifiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected to server");
    // Make a HTTP request:
    client.println("GET /v1/forecast.json?key=9c5df5870ht454gsd0fdd8194739211006&q=Rimini&days=2&aqi=no&alerts=no HTTP/1.0");
    client.println("Host: api.weatherapi.com");
    client.println("Connection: close");
    client.println();
  }
}
void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  while (client.available()) {
    String payload = client.readString();
    Serial.println(payload);
    
    DynamicJsonDocument doc(4000);
    DeserializationError error = deserializeJson(doc, payload);
    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.f_str());
      client.stop();
      return;
    }
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting from server.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

The output:

Starting connection to server...
connected to server
HTTP/1.1 200 OK
Date: Wed, 14 Jul 2021 16:58:42 GMT
Content-Type: application/json
Connection: close
Vary: Accept-Encoding
Server: BunnyCDN-IT1-555
CDN-PullZone: 93447
CDN-Uid: 8fa3a04a-75d9-4707-8056-b7b33c8ac7fe
CDN-RequestCountryCode: IT
CDN-EdgeStorageId: 555
CDN-CachedAt: 2021-07-14 18:58:42
CDN-RequestPullSuccess: True
CDN-RequestPullCode: 200
Cache-Control: public, max-age=180
CDN-RequestId: d6bc580dc2a234693a1ad59cb34aabcb
CDN-Cache: EXPIRED

{"location":{"name":"Rimini","region":"Emilia-Romagna","country":"Italy","lat":44.06,"lon":12.58,"tz_id":"Europe/Rome","localtime_epoch":1626281922,"localtime":"2021-07-14 18:58"},"current":{"condition":{},"uv":7.0},"forecast":{"forecastday":[{"date":"2021-07-14","day":{"daily_will_it_rain":0,"daily_chance_of_rain":"67","daily_will_it_snow":0,"daily_chance_of_snow":"0","condition":{}},"astro":{},"hour":[{"condition":{},"chance_of_rain":"45"},{"condition":{},"chance_of_rain":"67"},{"condition":{},"chance_of_rain":"45"},{"condition":{},"chance_of_rain":"22"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"29"},{"condition":{},"chance_of_rain":"58"},{"condition":{},"chance_of_rain":"87"},{"condition":{},"chance_of_rain":"84"},{"condition":{},"chance_of_rain":"81"},{"condition":{},"chance_of_rain":"78"},{"condition":{},"chance_of_rain":"52"},{"condition":{},"chance_of_rain":"26"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"}]},{"date":"2021-07-15","day":{"daily_will_it_rain":0,"daily_chance_of_rain":"0","daily_will_it_snow":0,"daily_chance_of_snow":"0","condition":{}},"astro":{},"hour":[{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"},{"condition":{},"chance_of_rain":"0"}]}]}}
deserializeJson() failed: InvalidInput

disconnecting from server.

The string "payload" start from 'HTTP/1.1 200 OK' and it should start from '{"location"....' Thanks to all who will help me.

1 Answers

A simple solution is to modify the string.

Looking at the Arduino documentation for String, it seems you have several functions available to you that can help solve this.

For example, you could use indexOf, lastIndexOf and substring to get everything between the first '{' and last '}':

int start = payload.indexOf('{');
int end = payload.lastIndexOf('}');
String body = payload.substring(start, end + 1);

This is not necessarily the most robust solution (e.g. you should check whether it is possible for '{' and '}' to appear in the HTTP header), but this should give you some hints towards a solution. Then again, if this is a small project, this may well be good enough for your use case.

Alternatively, you could cut cut the string up based on the newline:

int start = payload.indexOf('\n');
int body = payload.substring(start + 1);

Again, this makes assumptions about the payload format and you may wish to do some testing to verify those assumptions.

(I can't test this code, so you may need to debug this and make corrections.)

Related