ESP32 WiFi setup over BLE (ESP32 code)
Most small applications that we write have the WiFi credentials integrated in the code. But sometimes you do not want to have your WiFi credentials in the source code, specially if it is open source and maybe accessible as a repository on Github or Bitbucket. Having the WiFi credentials in the code is as well not practical if you sell your devices to others that need to setup the WiFi credentials according to their local network.
There are several solutions available like Espressifs Smartconfig or WiFiManager.
My approach is not to use WiFi to configure the WiFi credentials of an ESP32 module, but to do it over Bluetooth Low Energy (BLE).
To achieve this, the code includes a BLE server that is advertising a custom service. An Android phone or tablet (sorry, I cannot write apps for Iphones) then can connect to this BLE server and the user can setup the WiFi configuration of the phone.
So we need beside the code for the ESP32 as well an application for Android that can connect over BLE to the module. I wrote this small Android application and it is available for download from
- Google Play for automatic installation
- APKfiles if you do not have Google Play on your device
- from here for manual installation
- or you can build the Android app by yourself from the sources in my Bitbucket repo.
How does it work?
When the ESP32 is powered up it starts a BLE server and advertises a custom service to setup, check or erase the WiFi credentials. The Android app will find the ESP32 BLE server or ESP32 with active Bluetooth Serial:
By clicking on the device name the configuration screen opens. If there are already some WiFi credentials stored on the ESP32, they will be read from the device and displayed:
The configuration screen has 3 buttons to read the existing configuration, write a new configuration to the ESP32 or to erase any configuration on the device.
In case you want to use two AP settings, the switch button “Enable two AP” will show the edit boxes for the second AP:
The SSID and password for the WiFi APs should be entered in the text edit fields. Then a push on the “Send WiFi config” will send the new WiFi credentials to the ESP32.
The small text field at the bottom will show some debug messages during the process.
The source code
This post concentrates on the software that has to run on the ESP32. The complete source code is available in my Bitbucket repo.
I wrote the code with PlatformIO on Visual Studio Code, but as the code is all in one file, you can simply copy the code into a .ino file and use ArduinoIDE to test it.
The example needs to be able to encode and decode JSON objects and my favorite library for this is bblanchon‘s ArduinoJSON library. You need to install this library in your ArduinoIDE or with PlatformIO. Beside of that we need only three standard Arduino includes:
1 2 3 4 5 6 7 8 9 10 |
// Default Arduino includes #include <Arduino.h> #include <WiFi.h> #include <Preferences.h> // Includes for JSON object handling // Requires ArduinoJson library // https://arduinojson.org // https://github.com/bblanchon/ArduinoJson #include <ArduinoJson.h> |
The Preferences library include is needed because I am using the preferences to store the WiFi credentials on the ESP32.
For the BLE Server I used the code from my ESP32 BLE server example and modified it for this application. We use the same include files to get access to BLE:
1 2 3 4 5 |
// Includes for BLE #include <BLEUtils.h> #include <BLEServer.h> #include <BLEDevice.h> #include <BLEAdvertising.h> |
One difference is that instead of using “official” BLE services and characteristics I defined a custom service UUID and a custom characteristic UUID. This is to make sure that there is no collision or misunderstanding with existing BLE devices:
1 2 3 |
// List of Service and Characteristic UUIDs #define SERVICE_UUID "0000aaaa-ead2-11e7-80c1-9a214cf093ae" #define WIFI_UUID "00005555-ead2-11e7-80c1-9a214cf093ae" |
If you want to use different UUID’s, please note two things:
- Do not just write some numbers and letters into the UUID but instead use an online UUID creator like Online UUID Generator
- You need to change the Android source code and recompile it as well, because the UUIDs are hardcoded in the Android application (I put this on my TODO list already)
Next we need to define some Strings to hold the SSID’s and PW’s and pointers to the BLE server, service, advertisers and characteristic
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/** SSIDs of local WiFi networks */ String ssidPrim; String ssidSec; /** Password for local WiFi network */ String pwPrim; String pwSec; /** Characteristic for digital output */ BLECharacteristic *pCharacteristicWiFi; /** BLE Advertiser */ BLEAdvertising* pAdvertising; /** BLE Service */ BLEService *pService; /** BLE Server */ BLEServer *pServer; |
As you can see I defined a primary and secondary set of credentials. This is because I use here the possibility to connect to one of two allowed WiFi AP’s as described in ESP8266 – Switch automatically between 2 access points. If you do not need this, you can simply change the code to delete the references to the secondary AP.
As shown in the BLE Server tutorial, we need to define some callbacks for the BLE events. The first set of callbacks is for client connection and disconnection events. If a client connects the BLE advertising of the service stops automatically. So in case a client disconnects, we start the advertising here again.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/** * MyServerCallbacks * Callbacks for client connection and disconnection */ class MyServerCallbacks: public BLEServerCallbacks { // TODO this doesn't take into account several clients being connected void onConnect(BLEServer* pServer) { Serial.println("BLE client connected"); }; void onDisconnect(BLEServer* pServer) { Serial.println("BLE client disconnected"); pAdvertising->start(); } }; |
The next set of callbacks is for characteristic read and write events.
The characteristic write events receives the WiFi credentials from the Android app. The data is decoded with a simple method (XOR with a key) to make the data unreadable for sniffers. First step is to encode the received data.
The credentials are sent within a JSON object that makes it easy to parse through the data and extract the SSID names and passwords. The JSON object is in the form
1 |
{"ssidPrim":"SSID1name","pwPrim":"SSID1password","ssidSec":"SSID2name","pwSec":"SSID2password"} |
The code checks that all keys are in the JSON object, extracts them and saves the values in the ESP32 preferences.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
/** * MyCallbackHandler * Callbacks for BLE client read/write requests */ class MyCallbackHandler: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string value = pCharacteristic->getValue(); if (value.length() == 0) { return; } Serial.println("Received over BLE: " + String((char *)&value[0])); // Decode data int keyIndex = 0; for (int index = 0; index < value.length(); index ++) { value[index] = (char) value[index] ^ (char) apName[keyIndex]; keyIndex++; if (keyIndex >= strlen(apName)) keyIndex = 0; } /** Json object for incoming data */ JsonObject& jsonIn = jsonBuffer.parseObject((char *)&value[0]); if (jsonIn.success()) { if (jsonIn.containsKey("ssidPrim") && jsonIn.containsKey("pwPrim") && jsonIn.containsKey("ssidSec") && jsonIn.containsKey("pwSec")) { ssidPrim = jsonIn["ssidPrim"].as<String>(); pwPrim = jsonIn["pwPrim"].as<String>(); ssidSec = jsonIn["ssidSec"].as<String>(); pwSec = jsonIn["pwSec"].as<String>(); Preferences preferences; preferences.begin("WiFiCred", false); preferences.putString("ssidPrim", ssidPrim); preferences.putString("ssidSec", ssidSec); preferences.putString("pwPrim", pwPrim); preferences.putString("pwSec", pwSec); preferences.putBool("valid", true); preferences.end(); Serial.println("Received over bluetooth:"); Serial.println("primary SSID: "+ssidPrim+" password: "+pwPrim); Serial.println("secondary SSID: "+ssidSec+" password: "+pwSec); connStatusChanged = true; hasCredentials = true; |
There is as well the possibility to delete the previously stored WiFi credentials by a simple JSON object containing the key “erase”.
1 |
{"erase":true} |
Here is the code part for the erase:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
} else if (jsonIn.containsKey("erase")) { Serial.println("Received erase command"); Preferences preferences; preferences.begin("WiFiCred", false); preferences.clear(); preferences.end(); connStatusChanged = true; hasCredentials = false; ssidPrim = ""; pwPrim = ""; ssidSec = ""; pwSec = ""; int err; err=nvs_flash_init(); Serial.println("nvs_flash_init: " + err); err=nvs_flash_erase(); Serial.println("nvs_flash_erase: " + err); |
The last part of the erase procedure is actually optional and you might want to remove it. By erasing the complete NVS partition all stored preferences are deleted, that includes as well Bluetooth pairing informations.
And there is as well the possibility to restart the ESP32
1 |
{"reset":"true"} |
with this code part:
1 2 3 4 5 6 7 8 9 |
} else if (jsonIn.containsKey("reset")) { WiFi.disconnect(); esp_restart(); } } else { Serial.println("Received invalid JSON"); } jsonBuffer.clear(); }; |
And the rest is some cleanup and debug output.
The characteristic read event is used to report back the current WiFi credentials to the Android app. The stored values for the two AP’s is converted into an JSON object, then decoded (XOR with a key) and then sent back to the Android App.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
void onRead(BLECharacteristic *pCharacteristic) { Serial.println("BLE onRead request"); String wifiCredentials; /** Json object for outgoing data */ JsonObject& jsonOut = jsonBuffer.createObject(); jsonOut["ssidPrim"] = ssidPrim; jsonOut["pwPrim"] = pwPrim; jsonOut["ssidSec"] = ssidSec; jsonOut["pwSec"] = pwSec; // Convert JSON object into a string jsonOut.printTo(wifiCredentials); // encode the data int keyIndex = 0; Serial.println("Stored settings: " + wifiCredentials); for (int index = 0; index < wifiCredentials.length(); index ++) { wifiCredentials[index] = (char) wifiCredentials[index] ^ (char) apName[keyIndex]; keyIndex++; if (keyIndex >= strlen(apName)) keyIndex = 0; } pCharacteristicWiFi->setValue((uint8_t*)&wifiCredentials[0],wifiCredentials.length()); jsonBuffer.clear(); } }; |
After defining the callbacks come the code to initialize the BLE server.
First the BLE device is initializes, then we start the BLE server and assign the callbacks for connection and reconnection of clients.
After that BLE service and the characteristic for the WiFi credentials is created.
And then the server and the advertising is started:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/** * initBLE * Initialize BLE service and characteristic * Start BLE server and service advertising */ void initBLE() { // Initialize BLE and set output power BLEDevice::init(apName); BLEDevice::setPower(ESP_PWR_LVL_P7); // Create BLE Server pServer = BLEDevice::createServer(); // Set server callbacks pServer->setCallbacks(new MyServerCallbacks()); // Create BLE Service pService = pServer->createService(BLEUUID(SERVICE_UUID),20); // Create BLE Characteristic for WiFi settings pCharacteristicWiFi = pService->createCharacteristic( BLEUUID(WIFI_UUID), // WIFI_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); pCharacteristicWiFi->setCallbacks(new MyCallbackHandler()); // Create initial characteristic value String wifiCredentials; /** Buffer for outgoing JSON string */ DynamicJsonBuffer jsonOutBuffer; /** Json object for outgoing data */ JsonObject& jsonOut = jsonOutBuffer.createObject(); jsonOut["ssidPrim"] = ssidPrim; jsonOut["pwPrim"] = pwPrim; jsonOut["ssidSec"] = ssidSec; jsonOut["pwSec"] = pwSec; // Convert JSON object into a string jsonOut.printTo(wifiCredentials); pCharacteristicWiFi->setValue((uint8_t*)&wifiCredentials[0],wifiCredentials.length()); // Start the service pService->start(); // Start advertising pAdvertising = pServer->getAdvertising(); pAdvertising->start(); } |
setup() and loop() code blocks
Inside the setup() function the first thing is to create a unique device name to distinguish between several ESP32 modules. This unique device name is created by using the MAC address of the module in the function createName() and stored in the global variable apName.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/** Unique device name */ char apName[] = "ESP32-xxxxxxxxxxxx"; /** * Create unique device name from MAC address **/ void createName() { uint8_t baseMac[6]; // Get MAC address for WiFi station esp_read_mac(baseMac, ESP_MAC_WIFI_STA); // Write unique name into apName sprintf(apName, "ESP32-%02X%02X%02X%02X%02X%02X", baseMac[0], baseMac[1], baseMac[2], baseMac[3], baseMac[4], baseMac[5]); } |
After the unique device name is created, the serial port is initialized and some debug info is send out
1 2 3 4 5 6 7 8 9 |
void setup() { // Create unique device name createName(); // Initialize Serial port Serial.begin(115200); // Send some device info Serial.print("Build: "); Serial.println(compileDate); |
Next the preferences are checked to see if there are any WiFi credentials are stored already. If credentials are found, they are stored in the global variables ssidPrim, pwPrim, ssidSec and pwSec. The flag hasCredentials is set to TRUE if credentials were found or FALSE if no credentials were saved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Preferences preferences; preferences.begin("WiFiCred", false); bool hasPref = preferences.getBool("valid", false); if (hasPref) { ssidPrim = preferences.getString("ssidPrim",""); ssidSec = preferences.getString("ssidSec",""); pwPrim = preferences.getString("pwPrim",""); pwSec = preferences.getString("pwSec",""); if (ssidPrim.equals("") || pwPrim.equals("") || ssidSec.equals("") || pwPrim.equals("")) { Serial.println("Found preferences but credentials are invalid"); } else { Serial.println("Read from preferences:"); Serial.println("primary SSID: "+ssidPrim+" password: "+pwPrim); Serial.println("secondary SSID: "+ssidSec+" password: "+pwSec); hasCredentials = true; } } else { Serial.println("Could not find preferences, need send data over BLE"); } preferences.end(); |
The next step initializes the BLE server
1 2 |
// Start BLE server initBLE(); |
Then, if WiFi credentials were found, the connection to the WiFi AP is started.
1 2 3 4 5 6 7 8 9 10 |
if (hasCredentials) { // Check for available AP's if (!scanWiFi) { Serial.println("Could not find any AP"); } else { // If AP was found, start connection connectWiFi(); } } } |
The loop() function is doing nothing here than checking if a WiFi connection status change has occured. The connStatusChanged flag can be set true when
- the BLE server has received WiFi credentials
- a WiFi connection has been established
- a WiFi connection has been lost
If a connection status change has been detected and the status isConnected shows that the device is connected to a WiFi network, the WiFi AP info are sent for debugging over the Serial port.
1 2 3 4 5 6 7 8 9 |
void loop() { if (connStatusChanged) { if (isConnected) { Serial.print("Connected to AP: "); Serial.print(WiFi.SSID()); Serial.print(" with IP: "); Serial.print(WiFi.localIP()); Serial.print(" RSSI: "); Serial.println(WiFi.RSSI()); |
else a check for WiFi credentials is done and if true an initial connect (in case the device got new WiFi credentials) or a reconnect to WiFi is initiated
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
} else { if (hasCredentials) { Serial.println("Lost WiFi connection"); // Received WiFi credentials if (!scanWiFi) { // Check for available AP's Serial.println("Could not find any AP"); } else { // If AP was found, start connection connectWiFi(); } } } connStatusChanged = false; } } |
Handle WiFi connections
I use the same technique as descibed in ESP8266 – Switch automatically between 2 access points for the ESP32. Two valid AP credentials are stored in the device. The function scanWiFi() searches the available WiFi AP’s if one or two of them match the stored AP’s. If no matching AP is found, the function returns false.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/** scanWiFi Scans for available networks and decides if a switch between allowed networks makes sense @return <code>bool</code> True if at least one allowed network was found */ bool scanWiFi() { /** RSSI for primary network */ int8_t rssiPrim; /** RSSI for secondary network */ int8_t rssiSec; /** Result of this function */ bool result = false; Serial.println("Start scanning for networks"); WiFi.disconnect(true); WiFi.enableSTA(true); WiFi.mode(WIFI_STA); // Scan for AP int apNum = WiFi.scanNetworks(false,true,false,1000); if (apNum == 0) { Serial.println("Found no networks?????"); return false; } byte foundAP = 0; bool foundPrim = false; for (int index=0; index<apNum; index++) { String ssid = WiFi.SSID(index); Serial.println("Found AP: " + ssid + " RSSI: " + WiFi.RSSI(index)); if (!strcmp((const char*) &ssid[0], (const char*) &ssidPrim[0])) { Serial.println("Found primary AP"); foundAP++; foundPrim = true; rssiPrim = WiFi.RSSI(index); } if (!strcmp((const char*) &ssid[0], (const char*) &ssidSec[0])) { Serial.println("Found secondary AP"); foundAP++; rssiSec = WiFi.RSSI(index); } } |
Which of the stored AP’s should be used depends then on the signal strength. If there is the possibility to connect to either of the stored AP’s, the one with the stronger signal is selected.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
switch (foundAP) { case 0: result = false; break; case 1: if (foundPrim) { usePrimAP = true; } else { usePrimAP = false; } result = true; break; default: Serial.printf("RSSI Prim: %d Sec: %d\n", rssiPrim, rssiSec); if (rssiPrim > rssiSec) { usePrimAP = true; // RSSI of primary network is better } else { usePrimAP = false; // RSSI of secondary network is better } result = true; break; } return result; } |
Based on the results of scanWiFi() the function connectWiFi() then tries to connect to an AP. But before connecting, two WiFi event callbacks are initiated that will alarm the loop() if a connection change has occured.
gotIP() is called after the WiFi was assigned an IP address by the AP
1 2 3 4 5 |
/** Callback for receiving IP address from AP */ void gotIP(system_event_id_t event) { isConnected = true; connStatusChanged = true; } |
lostCon() is called if the WiFi got disconnected
1 2 3 4 5 |
/** Callback for connection loss */ void lostCon(system_event_id_t event) { isConnected = false; connStatusChanged = true; } |
After initializing the callbacks, connectWiFi() checks which AP should be used and initiates the connection to this AP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/** * Start connection to AP */ void connectWiFi() { // Setup callback function for successful connection WiFi.onEvent(gotIP, SYSTEM_EVENT_STA_GOT_IP); // Setup callback function for lost connection WiFi.onEvent(lostCon, SYSTEM_EVENT_STA_DISCONNECTED); WiFi.disconnect(true); WiFi.enableSTA(true); WiFi.mode(WIFI_STA); Serial.println(); Serial.print("Start connection to "); if (usePrimAP) { Serial.println(ssidPrim); WiFi.begin(ssidPrim.c_str(), pwPrim.c_str()); } else { Serial.println(ssidSec); WiFi.begin(ssidSec.c_str(), pwSec.c_str()); } } |







15:12
hi there,
very interesting post , thanks for sharing your devs 🙂
this technics sounds really usefull yet I have one question regarding BLE security :
how do you handle the fact that WIFI credentials are sent in clear via the BLE charateristics?
Am I wrong by saying that anyone connecting with a BLE app like nrfBLE can get the values too ?
best
Rico
17:46
Thanks for your positive feedback and pointing out the security flaw.
In the next version which was released today I am actually encoding the credentials before sending them. It is a simple encoding, but makes the data unreadable for sniffers or apps like nrfBLE.
I will add today as well a new example where I use Bluetooth Serial instead of BLE. This has the encoding as well.
23:44
Hi,
Tried to compile your code on arduino ide 1.8.5 (latest version) with included esp32 libraries. However there seems to be a problem with the preferences.h, see error listed below during compile.
When I used #include Arduino could not find the library, even though it says the library is installed.
When I used the #include “….. complete path of install/preferences.h” the library was indeed found, but the linker seems to have a problem.
Can you please let me know if there is a work around..?
Thank you for a great write up and sharing,
UD
———- error messages below ———
—- With include —-
C:\esp32\code\arduino\esp32wifible\esp32wifible.ino:18:25: fatal error: preferences.h: No such file or directory
compilation terminated
—- With #include “C:\Program Files (x86)\Arduino\hardware\espressif\esp32\libraries\Preferences\src\preferences.h”
sketch\esp32wifible.ino.cpp.o:(.literal._ZN17MyCallbackHandler7onWriteEP17BLECharacteristic[MyCallbackHandler::onWrite(BLECharacteristic*)]+0x38): undefined reference to
Preferences::Preferences()'
sketch\esp32wifible.ino.cpp.o:(.literal._ZN17MyCallbackHandler7onWriteEP17BLECharacteristic[MyCallbackHandler::onWrite(BLECharacteristic*)]+0x3c): undefined reference to Preferences::begin(char const*, bool)’
sketch\esp32wifible.ino.cpp.o:(.literal._ZN17MyCallbackHandler7onWriteEP17BLECharacteristic[MyCallbackHandler::onWrite(BLECharacteristic*)]+0x40): undefined reference to
Preferences::putString(char const*, String)'
sketch\esp32wifible.ino.cpp.o:(.literal._ZN17MyCallbackHandler7onWriteEP17BLECharacteristic[MyCallbackHandler::onWrite(BLECharacteristic*)]+0x44): undefined reference to Preferences::putBool(char const*, bool)’
sketch\esp32wifible.ino.cpp.o:(.literal._ZN17MyCallbackHandler7onWriteEP17BLECharacteristic[MyCallbackHandler::onWrite(BLECharacteristic*)]+0x48): undefined reference to
Preferences::end()'
sketch\esp32wifible.ino.cpp.o:(.literal._ZN17MyCallbackHandler7onWriteEP17BLECharacteristic[MyCallbackHandler::onWrite(BLECharacteristic*)]+0x4c): undefined reference to Preferences::clear()’
sketch\esp32wifible.ino.cpp.o:(.literal._ZN17MyCallbackHandler7onWriteEP17BLECharacteristic[MyCallbackHandler::onWrite(BLECharacteristic*)]+0x50): undefined reference to
Preferences::~Preferences()'
sketch\esp32wifible.ino.cpp.o:(.literal._Z5setupv+0x1c): undefined reference to Preferences::getBool(char const*, bool)’
sketch\esp32wifible.ino.cpp.o:(.literal._Z5setupv+0x20): undefined reference to
Preferences::getString(char const*, String)'
sketch\esp32wifible.ino.cpp.o: In function MyCallbackHandler::onWrite(BLECharacteristic*)’:
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:109: undefined reference to
Preferences::Preferences()'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:110: undefined reference to Preferences::begin(char const*, bool)’
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:111: undefined reference to
Preferences::putString(char const*, String)'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:112: undefined reference to Preferences::putString(char const*, String)’
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:113: undefined reference to
Preferences::putString(char const*, String)'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:114: undefined reference to Preferences::putString(char const*, String)’
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:115: undefined reference to
Preferences::putBool(char const*, bool)'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:116: undefined reference to Preferences::end()’
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:125: undefined reference to
Preferences::Preferences()'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:126: undefined reference to Preferences::begin(char const*, bool)’
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:127: undefined reference to
Preferences::clear()'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:128: undefined reference to Preferences::end()’
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:125: undefined reference to
Preferences::~Preferences()'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:125: undefined reference to Preferences::~Preferences()’
sketch\esp32wifible.ino.cpp.o: In function
setup()':
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:324: undefined reference to Preferences::Preferences()’
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:325: undefined reference to
Preferences::begin(char const*, bool)'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:326: undefined reference to Preferences::getBool(char const*, bool)’
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:328: undefined reference to
Preferences::getString(char const*, String)'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:329: undefined reference to Preferences::getString(char const*, String)’
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:330: undefined reference to
Preferences::getString(char const*, String)'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:331: undefined reference to Preferences::getString(char const*, String)’
Multiple libraries were found for “WiFi.h”
Used: C:\Program Files (x86)\Arduino\hardware\espressif\esp32\libraries\WiFi
Not used: C:\Program Files (x86)\Arduino\libraries\WiFi
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:347: undefined reference to
Preferences::end()'
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:324: undefined reference to Preferences::~Preferences()’
C:\esp32\code\arduino\esp32wifible/esp32wifible.ino:324: undefined reference to `Preferences::~Preferences()’
collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling for board ESP32 Dev Module.
23:58
Hi,
OK, please delete my previous post. I found that the following works:
For compiling in Arduino ide:
change
#include preferences.h
to
# include Preferences.h
Note: the left and right brackets have been left out of this text line as the web page appears to delete what ever is between them
Thank you
UD
14:32
Hi UD
Are you running Arduino IDE on Linux? That might explain the problem. I am on a Windows 7 platform and there is no case sensitivity for the library names.
But it is a good finding and I will update the code. Thank you!
06:51
I’m on Windows and had the same issue with “preferences.h”. Capitalizing it to “Preferences.h” fixed the issue. The previous commenter’s large comment could be massively trimmed for readability as well.
13:55
Code on Github and explanation here has been corrected. Sorry for causing the issue with uppercase/lowercase mismatch.
16:19
Hi beegee
Great post thank you. Have you never had issues with the memory consumption using both BLE and WiFi libraries? Using both in parallel – especially also using ethernet (ETH.h) – causes out of memory crashes for me and many others (at least on the wroom, maybe it’s better with additional PSRAM).
18:08
Yes, I have the same problems. Heap is running out fast when you try to use BLE and WiFi together, not to mention if additional sensors are attached to the system.
Arduino-ESP32 framework and the underlying ESP-IDF is still in development. Hopefully at some point in the future the required libraries are better optimized.
Additional PSRAM could be a solution, but I couldn’t get my hands yet on a Wroover module to test it.
08:25
Olá. Parabens e obrigado por compartilhar o seu trabalho.
Eu migrei para o wifimulti.
Ficou muito melhor. Segue link para download.
https://drive.google.com/file/d/1VibVT8oGr1ha1BY5VVbKzRt1ExVzUxtc/view
Abraço.
09:54
Thank you for sharing, but please post in English. It is difficult to read Portugese.
19:11
Excuse me. Now in English.
I made some modifications to your code to implement the library
It was very good. Worked perfectly. In my opinion it got better.
Link:
https://drive.google.com/file/d/1VibVT8oGr1ha1BY5VVbKzRt1ExVzUxtc/view
I’m working on a prototype with Blynk for sensor monitoring. Today I use WiFiManager, but I plan on migrating to this BLE soon. However, for this, I need to register the Token ID of the device through APP. I have to create another field in the application to enter this information. Any idea?
I also need to have an APP for Iphone.
Thank you in advance for your contribution.
21:57
You һave mɑde some decent ⲣoints there. I checkеd on the net to find out more about the issue and found most individualѕ
will go along with yoսr views on this web site.
12:16
Hello, I tried your code to upload my esp module,
but I am facing the problem of insufficient memory.
I complied on arduino, then it almost using 1400000 bytes code size and the limit of module is 1300000 bytes.
Does anybody have same issue?
12:33
You need to change the partition sizes to get more space for the app.
Check Change partition size (Arduino IDE) or change partition scheme in tools menu.
21:49
Hi,
Great project! Also thanks for sharing.
I have however ran into an issue. After flashing the code to the ESP32, I get the following messages printed in the Serial monitor:
The first few times booting it’s this: “Fatal exception (0): IllegalInstruction”
After a booting a few times, it’s either: “Fatal exception (28): LoadProhibited” or “Fatal exception 29(StoreProhibitedCause)”
I have googled these errors but I can’t find a solution that works. Do you have any idea?
Thanks
22:00
Sorry. Without seeing your code I have no idea what could cause that.
22:16
Sorry, I should have mentioned that it’s exactly the same as yours, I’m just running the code I downloaded from your gitbucket, I didn’t change anything.
22:19
Also, what I said was incomplete. Below every error message was also the following:
epc1=0x40080338, epc2=0x00000000, epc3=0x00000000, excvaddr=0x000008ff, depc=0x00000000
So for example, the error message would be:
Fatal exception (29): StoreProhibited
epc1=0x40080338, epc2=0x00000000, epc3=0x00000000, excvaddr=0x000008ff, depc=0x00000000
22:24
Thats strange. I just reused the code in a customers project and it works fine.
23:26
I figured it out. I thought it had something to do with the code as it all compiled and flashed fine, but it turns out it had something to do with the partitioning. In another comment you refer to this guide: https://desire.giesecke.tk/index.php/2018/04/20/change-partition-size-arduino-ide/
I think I did something wrong there because if I instead select “Minimal SPIFFS”, the program runs just fine without any errors.
Thanks for the quick replies anyways though! Great work
03:02
Hi,
it work Fine but when i was using Firebase Library (for example, its the same with MQTT Client):
void loop() {
if (connStatusChanged) {
if (isConnected) {
Serial.print(“Connected to AP: “);
Serial.print(WiFi.SSID());
Serial.print(” with IP: “);
Serial.print(WiFi.localIP());
Serial.print(” RSSI: “);
Serial.println(WiFi.RSSI());
//Connection Firebase Host and Password
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); //Firebase_host and Firebase_aut , its environment variable
Firebase.stream(“/temp/event”, streamCallback); //streamCallback its define later.
delay(40000);
} else {
……………
Firebase Library is Here:
https://github.com/mobizt/Firebase-ESP32
the Result It´s
Error !, Http stream was failed: -1
Because ESP32 no Connect to Firebase, Its the Same with MQTT Cliente
Can you Help me, please?.
10:15
Not sure what the WiFi connection problem has to do with the WiFi setup over BLE or Bluetooth.
If your http client fails, you should check if the AP is correct.
08:58
Please can you send me your email, i have a question but is with personal information in my code.
this is my email:
ruizgonzaleschristian@gmail.com
Thanks.
BR
00:31
You can post a question or an issue on my repository https://bitbucket.org/beegee1962/esp32_wifi_ble_esp32/issues?status=new&status=open
15:53
Hi, Do you have the android code?
20:34
Yes the Android code is available: Source Code
02:25
“jsonBuffer’ was not declared in this scope” , i have this problem when i compile de code , how to solved?
09:29
Sorry for the problem, the reason is that ArduinoJson library changed. I need to update the code. Here Migrating from version 5 to 6 is an explanation what needs to be changed.
00:41
I migrate to ArduinoJson version 6, the new source code is at:
main.cpp https://drive.google.com/file/d/1CoVNxOCVTDRohDQ-JqO8JqmPLmyWuBzw/view?usp=sharing
or
BLE_WiFi.ino https://drive.google.com/file/d/18m319XsK1A5f1caWKFHMc-LUo4CSXkUn/view?usp=sharing
I don’t know if the sketch size were bigger than 1.2Mb (max on default partition scheme), so I changed the partition scheme to “Minimal SPIFFS”
21:05
Thank you very much. I will update the code as soon as I find time.
07:42
Dear beegee1962, thanks for your work.
I have a similar problem. I have a ESP32-CAM that sends emails with photos but needs WiFi connection.
Asking users to remove the SD card to configure WiFi credentials is quite a pain, most cannot do it.
So I decided that I could use Bluetooth to setup a config.txt file with the necessary credentials and the problem would be solved.
The problem is that I cannot make ESP32 WiFi and Bluetooth (serial) work simultaneously.
I have been trying to avoid Bluetooth BLE because I do not need the extra complexity.
I would like to keep Bluetooth on for about 2 minutes when the the system is powered up then switch off Bluetooth and let WiFi take over.
I can indeed switch off Bluetooth using the command btStop(); but, although Bluetooth disconnects and WiFi can connect back to the router connection with the mail server always fail.
08:24
Hi, it is said above that using BT and WiFi at the same time as long as they are not used simultaneously may work.
I cannot make it work even when only one is used at any one time.
I have a ESP32-CAM that sends emails with photos but needs WiFi connection.
Wifi credentials are stored on SD card.
Asking users to remove the SD card to configure WiFi credentials is quite a pain, most cannot do it.
So I decided that I could use Bluetooth to setup a config.txt file with the necessary credentials and the problem would be solved.
The problem is that I cannot make ESP32 WiFi and Bluetooth (serial) work activated (even not transmuting) at the same time.
I would like to keep Bluetooth on for about 2 minutes when the the system is powered up then switch off Bluetooth and let WiFi take over.
I can indeed switch off Bluetooth using the command btStop(); but, although Bluetooth disconnects and WiFi can connect back to the router connection with the mail server always fail.
Removiing the following line from Setup() solves the problem.
// inti Bluetooth
SerialBT.begin(“myBT”); //Bluetooth device name
Assistance welcome.
Thanks
Paulo
09:32
You are most likely running out of heap memory.
I do not know much about the ESP32 CAM boards, but if they are based on ESP32 WROVER modules they have additional RAM that will be used by Bluetooth and WiFi if enabled. The ESP32 WROOM has a too less available heap to run both Bluetooth and WiFi and some application stuff if the application needs a lot of heap memory. I guess this is the case on the ESP32 CAM modules.
To enable PSRAM in ArduinoIDE goto Tools and set PSRAM to enabled.
In PlatformIO put
build_flags =
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
into the platformio.ini file.
You can check your available heap and PSRAM with
#include "Esp.h"
SerialCMD.println("\n\n[HEA] ##################################");
SerialCMD.println("[HEA] on start: ");
SerialCMD.printf("[HEA] Internal Total heap %d, internal Free Heap %d\n", ESP.getHeapSize(), ESP.getFreeHeap());
SerialCMD.printf("[HEA] SPIRam Total heap %d, SPIRam Free Heap %d\n", ESP.getPsramSize(), ESP.getFreePsram());
SerialCMD.printf("[HEA] ChipRevision %d, Cpu Freq %d, SDK Version %s\n", ESP.getChipRevision(), ESP.getCpuFreqMHz(), ESP.getSdkVersion());
SerialCMD.printf("[HEA] Flash Size %d, Flash Speed %d\n", ESP.getFlashChipSize(), ESP.getFlashChipSpeed());
SerialCMD.println("[HEA] ##################################\n\n");
Put this before and after your SerialBT to see if you have enough RAM available.
Beside of this example, the only modules I got to work with both Bluetooth and WiFi running are the ESP32 WROVER modules
01:16
Hi beegee1962, thanks for sharing your work!
I have an error after i uploaded the code, the Serial Monitor shows the next:
ets Jun 8 2016 00:22:57
rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:1100
load:0x40078000,len:9232
load:0x40080400,len:6412
entry 0x400806a8
Do you know how can I solve the problem?
Thanks.
08:21
What error?
You posted an ESP32 boot message that says it rebooted from a SW reset.
Did you try to upload the code again?
02:09
Hi I came across your apps on the Play store whilst looking for a FOSS bluetooth app that could be used to interface with this long-range LoRa mesh project https://github.com/sudomesh/disaster-radio/
Currently, access is via wifi/ web app which works but is not very friendly to the batteries.
Having a BLE option as well so you could turn the wifi off would be interesting. It has some basic serial capabilities https://github.com/sudomesh/disaster-radio/#testing-firmware
It seems like it crosses over with some of your interests, so I’m posting here in the vague hope you might think it’s a good project and help to build the Android/ BLE serial interface. There’s no money as it’s a open-source volunteer project.
It currently runs on these boards https://www.aliexpress.com/item/4000396836096.html more are planned.
14:07
Hi Sam,
I was actually looking before into your Disaster-Radio project (I am living in the Philippines, and something like that can be life saving here).
But you didn’t release the source codes, so I didn’t follow it anymore. I am playing around with LoRa right now, but focusing on the new Semtech SX1262 chips. Right now I am testing a LoRa Mesh implementation based on my SX1262 library.
I would be very interested to support your project for the BLE interface. I will send you an email to the address you have given.
01:14
Hi mate,
I tried my hand at writing a simple web-ble interface to allow configuration of esp32 from a web browser, relying on your code.
The rationale is that a laptop user could configure the esp32’s WiFi credentials without changing the network defined to which he/she is connected atm. Besides, web-ble works on several OSs (no iOS unfortunately) , and the web app does not require installation.
Anyway, the code is on my github at https://github.com/UriShX/esp32_web-ble_wifi_config, and the app can be accessed from https://urishx.github.io/esp32_web-ble_wifi_config/.
Thanks for sharing your code, and I really hope my addition is OK with you, and is useful for you and others.
22:26
Hi,
That’s a great extension to the application, thank you for posting it. I never looked into Web-BLE before.
15:06
Hi in line 358
if (ssidPrim.equals(“”)
|| pwPrim.equals(“”)
|| ssidSec.equals(“”)
|| pwPrim.equals(“”)) {
you have pwPrim twice. I think the last one is meant to be pwSec?
16:19
Correct, second pwPrim should be pwSec. Will correct the sources. Thanks for pointing to this bug.
20:26
Hello sir, i have facing some issue, can you please help me out?
my system flashing the code to the ESP32. The first few times booting it’s this.
can you please solve my issue, thanks
20:49
Please open an issue on my Bitbucket repo. I cannot help you without additional information.
Open new issue here: https://bitbucket.org/beegee1962/esp32_wifi_ble_esp32/issues?status=new&status=open
00:10
This is exactly what’s needed to make products deployable, but as a novice to Arduino and ESP ( Not to general programming though ), I get the error message:
Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it.
Error compiling for board ESP32 Wrover Module.
Now I have a 4MB Flash and *8MB PSRAM on my module. Additionally, I will need space for the actual wifi code which is already using half the available memory.
Am I missing a trick here?
Many thanks
09:51
It is always the same problem, Espressifs BLE library is too big. You have three options:
– On ArduinoIDE choose a different partition scheme from Tools–>Partition Scheme menu
– On PlatformIO create a custom partition table
– I am right now working to switch the code to use NimBLE library which is much smaller and as well uses lesser memory during runtime.
For the NimBLE library, I have a converted code example which is using the NimBLE library and reduces used code space by around 20-30%.
15:26
Yes.. Thanks. As a complete beginner using this part I wasn’t aware about the options to customise the memory usage.
I believe I read about having BT AND Wifi together causing some problems.. is it wise / sensible / possible to run one or the other depending if a Wifi connection is present or is it now stable to run both concurrently?
19:57
On a Wrover module it should be ok to run both BLE and WiFi at the same time. But still the BLE library will take a lot of your free heap.
If your application is running short on memory, you should take a look at NimBLE library as mentioned. It is 99% compatible with the ESP32 BLE library and much better on memory usage.
22:36
Well, this is great. But I cannot deploy a product that emulates another companies product.
Trying to follow amazons guides are a nightmare.
Is there anybody willing to work with me on doing it correctly??
23:50
What do you mean with “emulates another companies product”?