Get WiFi Credentials, but not from arduino_secrets.h

Hi Arduino Makers!

I used the Arduino Create (Web IDE) Ecosystem with my various MKR Boards. Now I would like to store the WiFi Credentials (SSID & KEY) on a flash, to give others the chance to adapt the SSID and the Key to different WLANs without the need of the Arduino Web IDE.

Yesterday I searched for a solution to put the Credentials from my Sketch to the <thingProperties.h> or to the <arduino_secrets.h>. I thought it was easy, but it was not (at least for me as newbie and basic skilled programmer).

So my question is:

  • Is there a way to get an variable from my sketch into the thingProperties.h or to the arduino_secrets.h structure?
  • Or is there a other and better way for my need?

Any help is verry welcome!
Andreas

The typical approach is to program the WiFi device to act as an AP (access point) that presents a captive portal. So you connect your computer or mobile device to the AP of the Arduino board, then when you open the web browser on the connected computer, a web page automatically loads that allows you to set the SSID and password of your WiFi router. The Arduino board then stops acting as an AP and switches to STA (station) mode, connecting to the WiFi router using the credentials.

I found this library that provides this capability for the Arduino MKR WiFi 1010 and Arduino Nano 33 IoT boards:

I haven't ever tried the library.


andreas_waldherr:
Is there a way to get an variable from my sketch into the thingProperties.h or to the arduino_secrets.h structure?

It's not clear what you mean by that. thingProperties.h and arduino_secrets.h are part of your sketch. You are welcome to define your WiFi credentials in the primary .ino file rather than in the arduino_secrets.h, but it makes no functional difference and you lose the nice feature of the secret tab. It certainly won't provide the ability for people to configure the SSID and password without using Arduino Web Editor.

Hello pert,
thanks for your answer!

I tried to put the WiFi credentials in my .ino file above setup() and disable the two corresponding lines in the file thingProperties.h. But the WiFiConnectionHandler search for it in the thingProperties.h – see the info’s below. I thought I need to let the WiFi Credentials (both character arrays) where they normally are…

const char SSID = "MySSID";
const char PASS = "MyPASSWORD";

void setup() {
}

void loop() {
}

The error when compiling…
In file included from /tmp/246220177/BeeContr1_working_on/BeeContr1_working_on.ino:7:0:
/tmp/246220177/build/sketch/thingProperties.h:37:53: error: 'SSID' was not declared in this scope
WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);
^~~~
/tmp/246220177/build/sketch/thingProperties.h:37:53: note: suggested alternative: 'SS1'
WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);
^~~~
SS1
/tmp/246220177/build/sketch/thingProperties.h:37:59: error: 'PASS' was not declared in this scope
WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);
^~~~
/tmp/246220177/build/sketch/thingProperties.h:37:59: note: suggested alternative: 'DAYS'
WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);
^~~~
DAYS
exit status 1

Where is my fault?
Thanks Andreas

Finally, I have found a solution with a side effect…

I have expanded the thingProperties.h with a Function, which I call from the .ino file and by passing the WiFi credentials …

thingPreperties.h ============================

char SSID[33]; // = SECRET_SSID; // Network SSID (name)
char PASS[64]; // = SECRET_PASS; // Network password (use for WPA, or use as key for WEP)

void MyNwCredetials(char MySSID[33], char MyKEY[64]){
strcpy(SSID, MySSID);
strcpy(PASS, MyKEY);
}

.ino =====================================

void setup() {
MyNwCredetials("Home-SSID", "MyPassword");
}

void loop() {

}

Works fine but the automatically generated thingProperties.h will be overwritten with the defaults when I reload my Browser

hi @andreas_waldherr

I'd like to try and help you but I'm not sure I understand the whole scope of your objective.
What do you mean with storing your credentials on a flash?

The solutions you seem to have reached still involve using the IDE to burn the firmware, so no user will be able to just change those without recompiling.

Sharing your entire code would help me help you.
Seems weird to me that your thingProperties.h file changes when you refresh, because it doesn't happen to me.
It can happen that the thingProperties file gets modified when you edit your Cloud Thing, but not on browser refresh.

If you want you can remove these two lines

const char SSID[]     = SECRET_SSID;    // Network SSID (name)
const char PASS[]     = SECRET_PASS;    // Network password (use for WPA, or use as key for WEP)

from that file and paste them directly before the include and directly assign them a value as a string

const char SSID[]     = "my house network (2.4GHz)";    // Network SSID (name)
const char PASS[]     = "my secret password";    // Network password (use for WPA, or use as key for WEP)
#include "thingProperties.h"

this won't change that the code will still need to be compiled and uploaded, of course

Dear ubidefeo, thanks for your answer!

First regarding the thingProperties.h and the browser refresh. I have test again and you are right, the contents of thingProperties.h stays in place as log no changes are made on the create thing properties…

Now to my code. Maybe in the future I will sell my project (Bee Hive monitoring/controlling) to customers - hopefully. And therefore, I need the possibility to save some credentials in the SAMD flash of the Arduino MKRs. I know that the flash will be flushed during uploading of a sketch, but this is not problematic for me.
When the Hive Controller was first powered on the customer must enter a password, the controller name and the WiFi Setting by using the CLI on the serial port. Later a “Service Menu” let the customer change the password or the WiFi SSID/Key or debug the controller. I have also implemented a session timeout and some code to "factory reset" the Controller if the customer forgot his password.

My code already works, but I am unsure if this was a good idea push the WiFi credentials with the function MyNwCredentials to the thingsProperties.h. What do you think?

Thanks in Advance
Andreas

Her also the complete sketch:

#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>

const char THING_ID[] = "024cd546-cc89-4790-b670-a36033796994";

char SSID[33];       // = SECRET_SSID;    // Network SSID (name)
char PASS[64];       // = SECRET_PASS;    // Network password (use for WPA, or use as key for WEP)

void MyNwCredetials(String MySSID, String MyKEY){
  MySSID.toCharArray(SSID, 33);
  MyKEY.toCharArray(PASS, 64);
}

void onRestartCpuChange();

float BeesINpm;
float BeesOUTpm;
float BeesOutside;
float HiveHumi;
float HiveTemp;
int OnlinePing;
int WiFiSignalStrength;
CloudLocation HiveLoc;
bool RestartCpu;

void initProperties(){

  ArduinoCloud.setThingId(THING_ID);
  ArduinoCloud.addProperty(BeesINpm, READ, 60 * SECONDS, NULL);
  ArduinoCloud.addProperty(BeesOUTpm, READ, 60 * SECONDS, NULL);
  ArduinoCloud.addProperty(BeesOutside, READ, 60 * SECONDS, NULL);
  ArduinoCloud.addProperty(HiveHumi, READ, 60 * SECONDS, NULL);
  ArduinoCloud.addProperty(HiveTemp, READ, 60 * SECONDS, NULL);
  ArduinoCloud.addProperty(OnlinePing, READ, 300 * SECONDS, NULL);
  ArduinoCloud.addProperty(WiFiSignalStrength, READ, 60 * SECONDS, NULL);
  ArduinoCloud.addProperty(HiveLoc, READ, 60 * SECONDS, NULL);
  ArduinoCloud.addProperty(RestartCpu, READWRITE, ON_CHANGE, onRestartCpuChange);

}

WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);
// Definitions to use the SAMD flash
boolean SerSess = false;
String Password;
String Hostname;
String HCssid;
String HCkey;
const int MaxPw = 32;
const int MinPw = 6;
const int MaxSerRx = 64;
unsigned long SesTimeout = 60000; 
typedef struct {
  boolean valid;
  char name[33];
  char pw[41];
  char ssid[33];
  char key[64];
} SetupStore;
FlashStorage(cpu_flash, SetupStore);
SetupStore Setup;
// thingProperties.h needs this setup...


// HiveController Status LEDs Setup
// CUTTED OUT - the attachment MySketch.ino is complete...                        // LED connected to pin A6

// Debugging option
boolean DebugBC = false;                      // BeeCounter debug display on serial monitor
boolean DebugNO = false;                      // Normal operation debug display on serial monitor

// SHT35 Grove Temp Humi Sensor initialization
// For SAMD core
#// CUTTED OUT - the attachment MySketch.ino is complete...


// Main SETUP
// ====================================================================================================================

void setup() {
  
  // Initialize LED Pins
// CUTTED OUT - the attachment MySketch.ino is complete...


  // Reset to factory defaults if the status button was pressed during startup...
  pinMode(PushButtonPin, INPUT_PULLUP);
  if (digitalRead(PushButtonPin) == LOW) {
      Hostname = " ";
      Password = " ";
      HCssid = " ";
      HCkey = " ";
      Password.toCharArray(Setup.pw, 41);
      Hostname.toCharArray(Setup.name, 33);
      HCssid.toCharArray(Setup.ssid, 33);
      HCkey.toCharArray(Setup.key, 64);
      Setup.valid = false;
      cpu_flash.write(Setup);
    }

  // Controller Setup - get the stored Setup 
  Setup = cpu_flash.read();
  Password = Setup.pw;
  Hostname = Setup.name;
  HCssid = Setup.ssid;
  HCkey = Setup.key;
  MyNwCredetials(HCssid, HCkey);

  // Initialize serial and wait for port to open:
  Serial.begin(38400);
  while (Setup.valid == false) {                        // No valid Setup in the SAMD flash?
    while (!Serial) {                                   // Wait until serial IF is ready
      Led_NoPw();
    } 
    Init_Setup();                                       // Now ask for initial informations - serial is ready now
    MyNwCredetials(HCssid, HCkey);                      // Put ssid and key to thingProperties.h 
  }

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  setDebugMessageLevel(0);
  ArduinoCloud.printDebugInfo();
  
}


// Main LOOP
// ====================================================================================================================

void loop() {
  
  // Get Beehive (temperature, humidity) and send HiveLocation 
  // Get WiFi Signal Level 
  // Get Ctrl Status push button state 
  // Switch Off all Status LEDs every 5 Seconds
  // CUTTED OUT - the attachment MySketch.ino is complete...


  // Controller Menue - ask for the password
  if (Setup.valid == true && SerSess == false && Serial.available()) {
    Serial.println("");
    Serial.print(Hostname.substring(0,32));
    Serial.println(" - Hive Controller Service Menue");
    Serial.println("");
    Serial.print("Password: ");
    String temp = Ser_Rx(false);
    if (Password == Ser_Rx(true)) {
      SerSess = true;
    }
    else {
      Serial.println("");
      Serial.println("Wrong password! Press <Enter> to try again...");
      Serial.println("");
    }
  }
  
  // Controller Menue - get serial input and start sub-menues
  while (SerSess == true) {
    HC_Menue();
    String MenueChoice = Ser_Rx(false);
      
    if      (MenueChoice == "1") {HC_SerStat();}
    else if (MenueChoice == "2") {Change_Pw();}
    else if (MenueChoice == "3") {Change_Hn();}
    else if (MenueChoice == "4") {Change_WiFi();}
    else if (MenueChoice == "5") {Show_TempHumi();}
    else if (MenueChoice == "6") {Debug_NO();}
    else if (MenueChoice == "0") {
      SerSess = false;
      SerPri_ClScr();
      SerPri_NoOpe();
    }
  }


  // Send and get updates from the Arduino IoT Cloud 
  unsigned long currentMillisIOT = millis();
  if (currentMillisIOT - previousMillisIOT >= intervalIOT) {
   // CUTTED OUT - the attachment MySketch.ino is complete...
}


// Get initial Password   
void Init_Setup() {
// CUTTED OUT - the attachment MySketch.ino is complete...
}


// Serial Communication - get characters from Serial (USB) Port
String Ser_Rx(boolean HideEcho) {
  // CUTTED OUT - the attachment MySketch.ino is complete...  
}

// Controller Menue - change HiveContrl name
void Change_WiFi() {
  if (Setup.valid == true) {
    SerPri_ClScr();
    Serial.println("You can change the Hive Controller WiFi setup now.");
    Serial.println("");
    Serial.print("WiFi SSID: ");
    HCssid = Ser_Rx(false);
    Serial.println("");
    Serial.print("WiFi  Key: ");
    HCkey = Ser_Rx(false);
    Password.toCharArray(Setup.pw, 41);
    Hostname.toCharArray(Setup.name, 33);
    HCssid.toCharArray(Setup.ssid, 33);
    HCkey.toCharArray(Setup.key, 64);
    Setup.valid = true;
    cpu_flash.write(Setup);
    Serial.println("");
    Serial.println("");
    Serial.println("The WiFi Setup was stored sucessfully!");
    delay(2000);
    MyNwCredetials(HCssid, HCkey);
    WiFiConnectionHandler ArduinoIoTPreferredConnection(Setup.ssid, Setup.key);
    SerPri_ClScr();
  }
}

MySketch.ino (27 KB)

@andreas_waldherr

I love the CLI approach over serial, I was about to suggest it and quickly reading through yours it looks well implemented and functional.

This is a good way to update the SSID and PSK but I'd suggest you a different approach which is easy to implement and won't be affected by the changes in thingProperties.h

You can create your own WiFIConnectionHandler and completely ignore the one that is created by default in the properties file.

WiFiConnectionHandler MySavedConnection(Setup.ssid, Setup.key);

and later on just initiate the ArduinoCloud passing that object.
It should just work as normal. You'll have some RAM used by the existing ArduinoIoTPreferredConnection object but it should not interfere at all with the workings of your project.

Great job, I hope you'll want to publish something about it once you're done :slight_smile:

let me know how it goes
u.

Hi ubidefeo,

thanks for your praise and recognition and off course thanks for the tip and the explanations!!!

Yes, I will share this shortly on the Arduino Project HUB. I am proud to give something back to this great community...

Again, thanks and have I nice Weekend
Andreas

Hi Andreas,

I don't know if this suggestion can be useful, but if you are using an Arduino MKR 1010 you could use the crypto-hardware ATECC508A to store persistently some data in the slots (9 - 14, but the slots 10, 11 and 12 are used by Arduino IoT Cloud for the certificate).

Best regards,
Luigi

Hi Luigi, thanks for this Tip!!

I had already checked this possibility. The three free Slots with 72 Bytes of storage capacity is enough for the example before, but because I expect some more things to store I decided to use the much bigger (256KB) flash on the SAMD21G18 CPU.

All the best
Andreas

Dear ubidefeo!

I have published my Serial Service Menu (CLI) shortly. Her is the Link: https://create.arduino.cc/projecthub/andreas_waldherr/serial-service-menu-91c5c1

I tried to use this command in my sketch:
WiFiConnectionHandler MySavedConnection(Setup.ssid, Setup.key);

but I ran into troubles when using this command from the void setup() function. The Arduino hungs. After resetting the the CPU everything works good, but I could not find a solution...

No problem, I used my void MyNwCredetials(String MySSID, String MyKEY) function...

Cheers
Andreas

hey @andreas_waldherr

nice to see the project on Project Hub, it's a great first!
Luigi and I have already passed it to our social media people and hopefully it'll get reposted soon :slight_smile:

let's stay in touch, I'd love to see more from you
ubi

ps: my comment on PH has a weird user name, I guess there are some issues in the back end

Thanks ubi :slight_smile: