Trying to set Wifi credentials from serial

Hi,
I am currently struggling with setting wiFi credentials from serial.

Here is my serial routine:

    case '~':  //Redio Report / WiFi and enter wiFi credentials if not connected
      if (WiFi.status() == WL_CONNECTED)
      {
        Console2.printf ("\nWiFi Status\n");
        serialPage = '~';
      } else {
        // unconnected, need credentials
        Console2.printf ("\nEnter SSID,Password");
        while (Console0.available() == 0) {}
        ssid = Console0.readStringUntil(',');        // store SSID
        pass = Console0.readStringUntil('\n');       // store password
        Console2.printf("\nTry conn' to %s (%u) , %s (%u) \n", ssid.c_str(), ssid.length(), pass.c_str(), pass.length());
#ifdef TELNET
        TelnetStream.println("bye bye");
        TelnetStream.flush();
        TelnetStream.stop();
#endif
        WiFi.disconnect();
        delay(1000);
        Console0.flush();
        getWiFi();
      }
      break;

It prints the correct ssid and password,however the length is given with one byte more (the null character, I assume).

The getWiFi() routine is not successful:

void getWiFi()
{
  if ((WiFi.status() != WL_CONNECTED))
  {
    WiFi.mode(WIFI_STA);
    if (ssid.length() && pass.length()) 
    {
      WiFi.begin(ssid.c_str(), pass.c_str());
    }else{
      WiFi.begin();
    }
//    WiFi.begin(WIFI_SSID, WIFI_PASS);
    //    WiFi.begin();
    wifiConnectCounter = 1;
    while (WiFi.status() != WL_CONNECTED)
    {
      delay(wifiRepeatInterval);
      Console4.print(".");
      wifiConnectCounter++;
      if (wifiConnectCounter > wifiMaxTries)
      {
        Console4.printf("\nIs %s , %s OK? -> Menu, enter ""~""", ssid.c_str(), pass.c_str());
        WiFi.disconnect();
        Console4.printf("\nRunning offline\n");
        WiFi.softAP("SoftPower", WIFI_PASS);
        ip = WiFi.softAPIP();
        break;
      }
    }
    delay(50);
    WiFi.setHostname(DEVICE_NAME);
  }
  if (WiFi.status() == WL_CONNECTED)
  {
    ip = WiFi.localIP();
  } else {
    Console4.printf("\nStarting Access point\n");
    WiFi.softAP("SoftPower", WIFI_PASS);
    ip = WiFi.softAPIP();
  }
  Console4.print("\nDone: RRSI= ");   Console4.print(WiFi.RSSI());
  myIP();  Console4.printf(charbuff);
}

I assume that it takes over the null character into the

WiFi.begin(ssid.c_str(), pass.c_str());

and it fails due to that null character.

How could I formulate the WiFi.begin() call to get it right?

Thank you for your help.
Laszlo

Put your strings in quotes or something so you can see what else you have in the string. Maybe a CR if your line endings are CR+LF since you read until LF

Console2.printf("\nTry conn' to '%s' (%u) , '%s' (%u) \n", ssid.c_str(), ssid.length(), pass.c_str(), pass.length());

An easier way it to use the WiFiManager library. It tries to connect and if not sucessful, it creates a hotspot and webserver for you to connect and enter the credentials. Pretty slick

Thank you, but i don't want to use a web server.
I already have a Telnet at disposal to do a lot of things and don't want to waste memory with HTML and a completely different process.

I don't think you are correct. According to the documentation
https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/length/

Returns the length of the String, in characters. (Note that this doesn’t include a trailing null character.)

There is likely something unexpected additionally in the String, and you were already given this advice by @blh64

Put your strings in quotes or something so you can see what else you have in the string. Maybe a CR if your line endings are CR+LF since you read until LF

Thank you.
I got it.

I had a parasitic \n before the ssid.
Left some shit in the toilet and did not flush...
:rofl:
This code works.

        Console0.flush();
        Console2.printf ("\nEnter SSID,Password");
        while (Console0.available() == 0) {}  
        ssid = Console0.readStringUntil(',');        // store SSID
        pass = Console0.readStringUntil('\n');        // store password
        Console2.printf("\nTry conn' to '%s' (%u) , '%s' (%u) \n", ssid.c_str(), ssid.length(), pass.c_str(), pass.length());

Now up and flying...

Hi, can someone recommend a lean library to Set WiFi credentials from Serial Monitor?
Thank you.
Laszlo

What would that library need to do?

This looks to me like an application problem. You print some statements to the Serial Monitor and read values to a char array. You can make this simple e.g., the user has to type SSID and password or you provide a list of SSIDs nearby and ask the user to pick one by typing a number. Then you ask for the password.

If you want to make this clean you add some check to protect against users typing too many characters.

The usual way to get WiFi credentials on to such a device is to run a web server on that device while it functions as an access point. A user simply connects to the device's own WLAN and enters these credentials through a web browser.
There are some libraries to assist with this, example for the ESP8266 : GitHub - tzapu/WiFiManager: ESP8266 WiFi Connection manager with web captive portal (but note the warnings)

@RIN67630
I've merged your 2 topics on the same subject.

I'm not going to give you the usual stuff about not starting 2 topics on the same subject as you've been here ages and should know!

Thanks,

I must correct myself:
This code ONLY works FOR THE ESP32 .

        Console0.flush();
        Console2.printf ("\nEnter SSID,Password");
        while (Console0.available() == 0) {}  

It only worked because the ESP32 compiler is buggy and erroneously flushes the input serial buffer.
Serial.flush() should (despite its misleading name) not flush anything, but (blocking!) WAIT until the OUTPUT Serial buffer has finished.

The right code is:

        String dumpme = Console0.readStringUntil('\n');        // empty the read buffer
        Console2.printf ("\nEnter SSID,Password");
        while (Console0.available() == 0) {}  

Even simplier/better

while( Console0.available() ) { Console0.read(); }

There is no point in building up a String just to throw it away.

Yes, but this appeared to be more tricky than one would expect.

Does that clean the last \n as well?
I got problems with remnants of previous operations wrapped with
while( Console0.available() )
which left a \n in the buffer.

That's why it is better to follow this advice: Serial Input Basics - updated
And use markers around your data.

Of course read() will consume a '\n' since it does't know/care what the actual data is. The issue is that Serial is sloooooooooow compared to the speed of the MCU. At 9600 baud, it take about 1ms to clock in a single char. In that same time, your MCU can do hundreds, if not thousands of instructions. imagine you you tranmitting "A\n" to your MCU. The first 'A' arrives so .available() returns 1. You then read that char and check again. This second check happens in less than 1 ms, so .available() will return 0 since the '\n' has not finished being clocked into the serial buffer and "available"

code I use on an ESP32 to receive serial, works great:

void fReceiveSerial_LIDAR( void * parameters  )
{
  bool BeginSentence = false;
  char OneChar;
  char *str;
  str = (char *)ps_calloc(300, sizeof(char) ); // put str buffer into PSRAM
  // log_i("Free PSRAM before String: %d", ESP.getFreePsram());
  for ( ;; )
  {
    EventBits_t xbit = xEventGroupWaitBits (eg, evtReceiveSerial_LIDAR, pdTRUE, pdTRUE, portMAX_DELAY);
    if ( LIDARSerial.available() >= 1 )
    {
      while ( LIDARSerial.available() )
      {
        OneChar = LIDARSerial.read();
        if ( BeginSentence )
        {
          if ( OneChar == '>')
          {
            if ( xSemaphoreTake( sema_ParseLIDAR_ReceivedSerial, xSemaphoreTicksToWait10 ) == pdTRUE )
            {
               xQueueOverwrite( xQ_LIDAR_Display_INFO, ( void * ) &str );
              xEventGroupSetBits( eg, evtParseLIDAR_ReceivedSerial );
              //
            }
            BeginSentence = false;
            break;
          }
          strncat( str, &OneChar, 1 );
        }
        else
        {
          if ( OneChar == '<' )
          {
            strcpy( str, ""); // clear string buffer
            BeginSentence = true; // found beginning of sentence
          }
        }
      } //  while ( LIDARSerial.available() )
    } //if ( LIDARSerial.available() >= 1 )
    xSemaphoreGive( sema_ReceiveSerial_LIDAR );
    //        log_i( "fReceiveSerial_LIDAR " );
    //        log_i(uxTaskGetStackHighWaterMark( NULL ));
  }
  free(str);
  vTaskDelete( NULL );
} //void fParseSerial( void * parameters  )

Does that mean that the ESP32 implementation of the Stream class as told in the Arduino reference is just not working at all and the only solution is to parse manually on char arrays?
:thinking:

I do not know, I've not tried it.

No, you don't ever need a String. At some point, it is far better to learn how to use char arrays

There is really no way for the Arduino to know what is in the incoming serial buffer unless it reads it into some variable or structure (char, char array, String) it can programmatically analyse.

.peek() only looks at the next character in the input buffer but does not read it from the buffer. It does not scan the entire input buffer looking for a character.

If you know the size of a complete line you are looking for, you can use if (Serial.available() == line length) before you read.

WiFi credentials are Strings.