Problem with ArduinoJson

Hi,

I get an error trying to deserialize a JSON response from my JavaScript backend.

The error from ArduinoJson says: NoMemory();

An example response would be:

{"from":"Bern","to":"Zürich HB","gleis":12,"lateInMinutes":0,"departure":"20:34","waggonsCount":14,"vias":0

My Code:

/*
  WiFi Web Server LED Blink

  A simple web server that lets you blink an LED via the web.
  This sketch will print the IP address of your WiFi module (once connected)
  to the Serial Monitor. From there, you can open that address in a web browser
  to turn on and off the LED on pin 9.

  If the IP address of your board is yourAddress:
  http://yourAddress/H turns the LED on
  http://yourAddress/L turns it off

  This example is written for a network using WPA encryption. For
  WEP or WPA, change the WiFi.begin() call accordingly.

  Circuit:
   Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2)
   LED attached to pin 9

  created 25 Nov 2012
  by Tom Igoe
*/
#include <SPI.h>
#include <WiFiNINA.h>
#include <ArduinoJson.h>
#include <ArduinoHttpClient.h>
#include <stdio.h>
#include <string.h>

#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/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)

char serverAddress[] = "172.20.10.2"; // server address from Wifi. You can look up this adress in the settings
int port = 8080;
WiFiServer server(80);

DynamicJsonDocument postMessage(2048);
String jsonBody;
String contentType = "application/json";

DynamicJsonDocument doc(2720);

WiFiClient wifi;
HttpClient http = HttpClient(wifi, serverAddress, port);

char webpage[] = R"=====(
<html>

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SBB Fahrplan</title>
</head>

<body>
    <script>
        const handleSubmit = () => {
            const radioButtons = document.querySelectorAll('input[name="zug"]');

            const abfahrt = document.getElementById('abfahrt').value
            const ankunft = document.getElementById('ankunft').value
            
            let selectedButton;

            for (const radioButton of radioButtons) {
                if (radioButton.checked) {
                    selectedButton = radioButton.value;
                    if (selectedButton === 'false') {
                        selectedButton = false
                    }

                    if (selectedButton === 'true') {
                        selectedButton = true
                    }
                }
            }

            var myHeaders = new Headers();
            myHeaders.append("Content-Type", "application/json");

            var raw = JSON.stringify({
                from: abfahrt,
                to: ankunft,
                lastOne: selectedButton
            });

            var requestOptions = {
                method: 'POST',
                headers: myHeaders,
                body: raw,
                redirect: 'follow'
            };

            fetch("http://localhost:8080/getDataByTrip", requestOptions)
                .then(response => response.json())
                .then(result => console.log(result)) 
                .then(fetch(`http://172.20.10.4/H?from=${abfahrt}&to=${ankunft}&lastOne=${selectedButton}`, {
                    method: "GET"
                }))
        }
    </script>
    <h2>SBB Fahrplan</h2>

    <label for="abbh">Abfahrts Bahnhof:</label>
    <input type="text" id="abfahrt" name="Abfahrts Bahnhof" placeholder="Abfahrts Bahnhof">

    <label for="anbh">Ankunfts Bahnhof:</label>
    <input type="text" id="ankunft" name="Ankunfts Bahnhof" placeholder="Ankunfts Bahnhof">

    <input type="radio" id="nzug" name="zug" value="false">
    <label for="nzug">nächster Zug</label>
    <input type="radio" id="lzug" name="zug" value="true">
    <label for="lzug">letzter Zug</label>
    <br><br>
    <button onclick="handleSubmit()">ok</button>
     <br><br>
    <button onclick="handleTest()">Test</button>

</body>

</html>
)=====";

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");
    // print where to go in a browser:
    Serial.print("To see this page in action, open a browser to http://");
    Serial.println(ip);
}

void percentDecode(char *src)
{
    char *dst = src;

    while (*src)
    {
        if (*src == '+')
        {
            src++;
            *dst++ = ' ';
        }
        else if (*src == '%')
        {
            // handle percent escape

            *dst = '\0';
            src++;

            if (*src >= '0' && *src <= '9')
            {
                *dst = *src++ - '0';
            }
            else if (*src >= 'A' && *src <= 'F')
            {
                *dst = 10 + *src++ - 'A';
            }
            else if (*src >= 'a' && *src <= 'f')
            {
                *dst = 10 + *src++ - 'a';
            }

            // this will cause %4 to be decoded to ascii @, but %4 is invalid
            // and we can't be expected to decode it properly anyway

            *dst <<= 4;

            if (*src >= '0' && *src <= '9')
            {
                *dst |= *src++ - '0';
            }
            else if (*src >= 'A' && *src <= 'F')
            {
                *dst |= 10 + *src++ - 'A';
            }
            else if (*src >= 'a' && *src <= 'f')
            {
                *dst |= 10 + *src++ - 'a';
            }

            dst++;
        }
        else
        {
            *dst++ = *src++;
        }
    }
    *dst = '\0';
}

int parseUrlParams(char *queryString, char *results[][2], int resultsMaxCt, boolean decodeUrl)
{
    int ct = 0;

    while (queryString && *queryString && ct < resultsMaxCt)
    {
        results[ct][0] = strsep(&queryString, "&");
        results[ct][1] = strchrnul(results[ct][0], '=');
        if (*results[ct][1])
            *results[ct][1]++ = '\0';

        if (decodeUrl)
        {
            percentDecode(results[ct][0]);
            percentDecode(results[ct][1]);
        }

        ct++;
    }

    return ct;
}

int status = WL_IDLE_STATUS;

void setup()
{
    Serial.begin(9600); // initialize serial communication
    pinMode(9, OUTPUT); // set the LED pin mode

    // char *string =  "?from=Zurich-HB&to=Bern&lastOne=false";

    // 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 Network named: ");
        Serial.println(ssid); // print the network name (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);
    }
    server.begin();    // start the web server on port 80
    printWifiStatus(); // you're connected now, so print out the status
}

char url[70];

boolean done = false;

char responseCopy = "";

void loop()
{
    WiFiClient client = server.available(); // listen for incoming clients

    char buf[100];
    char *params[5][2];

    if (client)
    {                                 // if you get a client,
        Serial.println("new client"); // print a message out the serial port
        String currentLine = "";      // make a String to hold incoming data from the client
        String httpGetUrl = "";
        while (client.connected())
        { // loop while the client's connected
            if (client.available())
            {                           // if there's bytes to read from the client,
                char c = client.read(); // read a byte, then
                                        // Serial.write(c);                    // print it out the serial monitor
                if (c == '\n')
                { // if the byte is a newline character

                    // if the current line is blank, you got two newline characters in a row.
                    // that's the end of the client HTTP request, so send a response:
                    if (currentLine.length() == 0)
                    {
                        // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
                        // and a content-type so the client knows what's coming, then a blank line:
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-type:text/html");
                        client.println();

                        // the content of the HTTP response follows the header:
                        // client.print("Click <a href=\"/H\">here</a> turn the LED on pin 9 on<br>");
                        client.print(webpage);

                        // The HTTP response ends with another blank line:
                        client.println();
                        // break out of the while loop:
                        break;
                    }
                    else
                    { // if you got a newline, then clear currentLine:
                        currentLine = "";
                    }
                }
                else if (c != '\r')
                {                     // if you got anything else but a carriage return character,
                    currentLine += c; // add it to the end of the currentLine
                }
                else
                {

                    if (currentLine.startsWith("GET /H?from="))
                    {

                        httpGetUrl += currentLine;

                        httpGetUrl.remove(0, 7);
                        int http = httpGetUrl.indexOf(" HTTP/1.1");
                        httpGetUrl.remove(http, 9);

                        httpGetUrl.toCharArray(url, 100);

                        char *tests[] = {
                            url,
                        };

                        for (int i = 0; i < sizeof(tests) / sizeof(*tests); i++)
                        {
                            Serial.print("parsing \"");
                            Serial.print(tests[i]);

                            // copy test[i] into the buffer
                            // because the parser overwrites what is i the string it is passed.
                            strcpy(buf, tests[i]);

                            // parse the buffer into params[][]
                            int resultsCt = parseUrlParams(buf, params, 5, true);

                            // print off the results;

                            Serial.print("\" produced ");
                            Serial.print(resultsCt);
                            Serial.print(" parameters:");
                            Serial.println();

                            for (int i = 0; i < resultsCt; i++)
                            {
                                Serial.print("param ");
                                Serial.print(i);
                                Serial.print(" name \"");
                                Serial.print(params[i][0]);
                                Serial.print("\", param \"");
                                Serial.print(params[i][1]);
                                Serial.print("\".");
                                Serial.println();
                                postMessage["from"] = params[0][1];
                                postMessage["to"] = params[0][3];
                                postMessage["lastOne"] = params[0][5];
                            }

                            serializeJson(postMessage, jsonBody);

                            Serial.println("making POST request");

                            Serial.println();

                            done = true;
                        }
                    }
                }

                // Check to see if the client request was "GET /H" or "GET /L":
                //  if (currentLine.endsWith("GET /H")) {
                while (done)
                {
                    http.post("/getDataByTrip", contentType, jsonBody);

                    // read the status code and body of the response
                    int statusCode = http.responseStatusCode();
                    String responseRequest = http.responseBody();
                    
                    Serial.print("Json Body: ");
                    Serial.println(jsonBody);

                    Serial.print("Status code: ");
                    Serial.println(statusCode);
                    Serial.print("Response: ");
                    Serial.println(responseRequest);

                    DeserializationError error = deserializeJson(doc, responseRequest);

                    if (error) {
  Serial.print(F("deserializeJson() failed: "));
  Serial.println(error.f_str());
  return;
}

                    const char* from = doc["from"];

                    Serial.print("From Request: ");
                    Serial.println(from);

                    jsonBody = "";
                  

                    if (responseRequest.length() > 10)
                    {
                        done = false;
                    }
                    else
                    {

                        done = false;
                    }
                    responseRequest = "";
                }
                //}
            }
        }
        // close the connection:
        client.stop();
        Serial.println("client disconnected");
    }
}

Could someone help me solve this problem?

Use a board with enough memory. You didn't tell us what Arduino your is intended to run on but I guess it doesn't have enough RAM for the huge needs of your sketch.
An Arduino is not a general purpose web server platform. Your sketch doesn't do anything an MCU is needed but does things a small Linux board (as the Raspberry Pi) is much better suited for.

That example isn't a complete JSON document.

Yeah I have a Arduino UNO Wifi

The "Arduino UNO WiFi Rev2" (ATmega4809 processor) has 6,144 Bytes of SRAM.

You are setting aside almost 5000 bytes of SRAM just for JSON documents:

DynamicJsonDocument postMessage(2048);
DynamicJsonDocument doc(2720);

As I told you in your other post on the same subject, you are allocating WAY too much space. Use the ArduinoJSON 'Assistant' to tell you how big your JSON documents really need to be.

Yeah. It just worked with that. Sorry for the mistake

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.