1

I'm using ArduinoJson to parse a file full of JSON strings that contain the SSID and password for the registered networks. I have a little web interface that runs in soft AP mode so you can scan for networks and add them to the file. Adding networks to the file works fine, but reading them back and using them as input for WiFi.begin doesn't work. It moves to status code 1, which means it failed to find a network with that SSID.

I have compared the value of the result of const char* ssid = networks[network]["ssid"]; with const char* _ssid = "MySSID"; using strcmp and it returns 0, so I can't figure out why it's not working. It works if I replace networks[network]["ssid] with my SSID (though I need to replace the password with the string literal as well, otherwise it stays on status code 6, disconnected).

I can't figure out what it is about ArduinoJson, but it seems that the result of grabbing a string doesn't return a string that is formatted correctly for WiFi.begin, but it satisfies strcmp?

Edit: I modified the code quite a bit in an effort to get it to work. I am no longer passing the ArduinoJson object, I'm now passing a struct with the data, and it still doesn't work. Is this the work of some advanced c++ constants/pointers stuff that I don't seem to understand?

main.cpp:

#include <ArduinoJson.h>
#include <ESPAsyncWebServer.h>
#include <ESPmDNS.h>
#include <SPIFFS.h>
#include <vector>
#include <elapsedMillis.h>

#include "config.h"
#include "restserver.h"
#include "scanwifiserver.h"

AsyncWebServer *Server = new AsyncWebServer(80);

ScanWifiServer *scanWifi;
RestServer *restServer;

struct Network {
    const char* ssid;
    const char* password;
};

std::vector<Network> readAP(fs::FS &fs) {
    //fs.remove("/ap.txt");
    File file = fs.open("/ap.txt");
    std::vector<Network> networks;
    if (!file) {
#ifdef DEBUG
        Serial.println("Failed to open file for reading");
#endif
        return networks;
    }

    while (file.available()) {
        DynamicJsonDocument n(JSON_CAPACITY);
        auto s = file.readStringUntil('\n');
        deserializeJson(n, s);
        struct Network network = {n["ssid"], n["password"]};
        networks.push_back(network);
        Serial.println(networks.back().ssid);
    }

    file.close();
    return networks;
}

void setup() {
#ifdef DEBUG
    Serial.begin(BAUDRATE);
    delay(2000);
#endif

    SPIFFS.begin();
    auto networks = readAP(SPIFFS);
    if (networks.size() > 0) {
        Serial.println("Networks:");
        int network = 0;
        Serial.println(networks.size());
        while (WiFi.status() != WL_CONNECTED && network < networks.size()) {
            const char* ssid = networks[network].ssid;
            const char* password = networks[network].password;
            Serial.printf("%s, %s\n", ssid, password);

            WiFi.begin(ssid, password);

            while (WiFi.status() != WL_CONNECTED) {
                if (WiFi.status() == WL_CONNECT_FAILED || WiFi.status() == WL_NO_SSID_AVAIL)
                    break;
                delay(500);
                Serial.print(WiFi.status());
            }
            Serial.println("");
            network++;
        }   
        if (WiFi.status() == WL_CONNECTED) Serial.println("Connected");
        else networks.clear();
    }
    if (networks.size() == 0) {
        Serial.println("Starting ScanWifiServer");
        WiFi.mode(WIFI_AP);

        scanWifi = new ScanWifiServer(Server);

        Server->begin();

        MDNS.begin("grow");
        MDNS.addService("http", "tcp", 80);
    }
}

void loop() {}

1
  • add WiFi.persistent(false); and WiFi.setAutoConnect(false) – Juraj Mar 15 '20 at 11:14
1

I found the solution myself. I switched from using struct Network network = {n["ssid"], n["password"]}; to declare the struct and const char pointers to using char arrays and strcpy

struct Network network;
strcpy(network.ssid, n["ssid"]);
strcpy(network.password, n["password"]);

Seems like the pointers were getting freed or something right at the same time that I tried to use the value to connect to the network?

-1

std::vector<JsonDocument> doesn't store a copy of the complete document, but just a copy of the internal pointers of JsonDocument. Therefore, at the time you use the value, it points to an invalid location.

This is clearly a bug, that's why I removed the copy constructor of JsonDocument, but the change hasn't been published yet.

You can fix your program by replacing the std::vector<JsonDocument> with std::vector<DynamicJsonDocument>.

1
  • 1
    Thanks for the response, though I modified my code a bunch and it still doesn't work. Do you know what's going on? – CurieOS Mar 15 '20 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.