mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-13 13:01:55 +03:00
WiFi Mesh Update 2.1 (#5157)
* - Add assert in HelloMesh.ino for invalid transmission status. - Make uint64ToString and stringToUint64 methods into stand-alone type conversion functions. - Add getters and setters for requestHandler and responseHandler. - Polish HelloMesh.ino code by adding networkIndex as networkFilter loop variable and switching networkFilter definition position. - Add initial WiFi.disconnect() in HelloMesh.ino setup() function to ensure smooth WiFi operation. - Add latestTransmissionSuccessful() convenience method. - Change default WiFi mode to WIFI_STA and improve handling of WiFi mode (fixes issue #5071). - Add checks to methods that change AP properties to avoid unnecessary AP restarts. - Add getter for ESP8266WiFiMesh SSID and getters and setters for ESP8266WiFiMesh settings related to hidden SSID usage, max station connections allowed per AP and WiFi timeouts. - Make waitForClientTransmission method use more accurate timekeeping. - Improve type usage. - Improve comments. - Update README.md, keywords.txt and library.properties. * Make getter and setter order consistent throughout code. * - Fix active AP getting turned off when calling begin(). - Fix crash bug due to WiFiServer duplication when using the ESP8266WiFiMesh copy constructor with the AP controller as argument, under certain circumstances. * - Move non performance-sensitive Strings to flash memory to save RAM. - Add comments explaining F(), FPSTR() and PROGMEM. - Fix README.md formatting. * Remove the uint64ToString and stringToUint64 methods from the ESP8266WiFiMesh class since they are now stand-alone functions in the TypeConversionFunctions files. * Change the minimum valid argument value of the setMaxAPStations method to 0, since this value is also supported by the ESP8266. * Fix compiler warning.
This commit is contained in:
@ -24,6 +24,7 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "ESP8266WiFiMesh.h"
|
||||
#include "TypeConversionFunctions.h"
|
||||
|
||||
#define SERVER_IP_ADDR "192.168.4.1"
|
||||
|
||||
@ -44,15 +45,12 @@ std::vector<TransmissionResult> ESP8266WiFiMesh::latestTransmissionOutcomes = {}
|
||||
|
||||
ESP8266WiFiMesh::~ESP8266WiFiMesh()
|
||||
{
|
||||
if(isAPController())
|
||||
{
|
||||
apController = nullptr;
|
||||
}
|
||||
deactivateAP();
|
||||
}
|
||||
|
||||
ESP8266WiFiMesh::ESP8266WiFiMesh(ESP8266WiFiMesh::requestHandlerType requestHandler, ESP8266WiFiMesh::responseHandlerType responseHandler,
|
||||
ESP8266WiFiMesh::networkFilterType networkFilter, const String &meshPassword, const String &meshName,
|
||||
const String &nodeID, bool verboseMode, uint8 meshWiFiChannel, int serverPort)
|
||||
const String &nodeID, bool verboseMode, uint8 meshWiFiChannel, uint16_t serverPort)
|
||||
: _server(serverPort), _lwipVersion{0, 0, 0}
|
||||
{
|
||||
storeLwipVersion();
|
||||
@ -73,12 +71,17 @@ void ESP8266WiFiMesh::updateNetworkNames(const String &newMeshName, const String
|
||||
_meshName = newMeshName;
|
||||
if(newNodeID != "")
|
||||
_nodeID = newNodeID;
|
||||
|
||||
_SSID = _meshName + _nodeID;
|
||||
|
||||
// Apply SSID changes to active AP.
|
||||
if(isAPController())
|
||||
restartAP();
|
||||
String newSSID = _meshName + _nodeID;
|
||||
|
||||
if(_SSID != newSSID)
|
||||
{
|
||||
_SSID = newSSID;
|
||||
|
||||
// Apply SSID changes to active AP.
|
||||
if(isAPController())
|
||||
restartAP();
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266WiFiMesh::begin()
|
||||
@ -93,16 +96,17 @@ void ESP8266WiFiMesh::begin()
|
||||
else
|
||||
{
|
||||
////////////////////////////</DEPRECATED> TODO: REMOVE IN 2.5.0////////////////////////////
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
if(!ESP8266WiFiMesh::getAPController()) // If there is no active AP controller
|
||||
WiFi.mode(WIFI_STA); // WIFI_AP_STA mode automatically sets up an AP, so we can't use that as default.
|
||||
|
||||
#ifdef ENABLE_STATIC_IP_OPTIMIZATION
|
||||
if(atLeastLwipVersion(lwipVersion203Signature))
|
||||
{
|
||||
verboseModePrint("lwIP version is at least 2.0.3. Static ip optimizations enabled.\n");
|
||||
verboseModePrint(F("lwIP version is at least 2.0.3. Static ip optimizations enabled.\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
verboseModePrint("lwIP version is less than 2.0.3. Static ip optimizations DISABLED.\n");
|
||||
verboseModePrint(F("lwIP version is less than 2.0.3. Static ip optimizations DISABLED.\n"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -139,8 +143,11 @@ void ESP8266WiFiMesh::activateAP()
|
||||
// Deactivate active AP to avoid two servers using the same port, which can lead to crashes.
|
||||
if(ESP8266WiFiMesh *currentAPController = ESP8266WiFiMesh::getAPController())
|
||||
currentAPController->deactivateAP();
|
||||
|
||||
WiFi.softAP( _SSID.c_str(), _meshPassword.c_str(), _meshWiFiChannel ); // Note that a maximum of 5 stations can be connected at a time to each AP
|
||||
|
||||
WiFi.softAP( _SSID.c_str(), _meshPassword.c_str(), _meshWiFiChannel, _apHidden, _maxAPStations ); // Note that a maximum of 8 stations can be connected at a time to each AP
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
|
||||
_server = WiFiServer(_serverPort); // Fixes an occasional crash bug that occurs when using the copy constructor to duplicate the AP controller.
|
||||
_server.begin(); // Actually calls _server.stop()/_server.close() first.
|
||||
|
||||
apController = this;
|
||||
@ -152,6 +159,7 @@ void ESP8266WiFiMesh::deactivateAP()
|
||||
{
|
||||
_server.stop();
|
||||
WiFi.softAPdisconnect();
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
// Since there is no active AP controller now, make the apController variable point to nothing.
|
||||
apController = nullptr;
|
||||
@ -176,46 +184,130 @@ bool ESP8266WiFiMesh::isAPController()
|
||||
return (this == apController);
|
||||
}
|
||||
|
||||
uint8 ESP8266WiFiMesh::getWiFiChannel()
|
||||
{
|
||||
return _meshWiFiChannel;
|
||||
}
|
||||
|
||||
void ESP8266WiFiMesh::setWiFiChannel(uint8 newWiFiChannel)
|
||||
{
|
||||
assert(1 <= newWiFiChannel && newWiFiChannel <= 13);
|
||||
|
||||
_meshWiFiChannel = newWiFiChannel;
|
||||
|
||||
// Apply changes to active AP.
|
||||
if(isAPController())
|
||||
restartAP();
|
||||
// WiFi.channel() will change if this node connects to an AP with another channel,
|
||||
// so there is no guarantee we are using _meshWiFiChannel.
|
||||
// Also, we cannot change the WiFi channel while we are still connected to the other AP.
|
||||
if(WiFi.channel() != _meshWiFiChannel && WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
// Apply changes to active AP.
|
||||
if(isAPController())
|
||||
restartAP();
|
||||
}
|
||||
}
|
||||
|
||||
String ESP8266WiFiMesh::getMeshName() {return _meshName;}
|
||||
uint8 ESP8266WiFiMesh::getWiFiChannel()
|
||||
{
|
||||
return _meshWiFiChannel;
|
||||
}
|
||||
|
||||
void ESP8266WiFiMesh::setMeshName(const String &newMeshName)
|
||||
{
|
||||
updateNetworkNames(newMeshName);
|
||||
}
|
||||
|
||||
String ESP8266WiFiMesh::getNodeID() {return _nodeID;}
|
||||
String ESP8266WiFiMesh::getMeshName() {return _meshName;}
|
||||
|
||||
void ESP8266WiFiMesh::setNodeID(const String &newNodeID)
|
||||
{
|
||||
updateNetworkNames("", newNodeID);
|
||||
}
|
||||
|
||||
String ESP8266WiFiMesh::getNodeID() {return _nodeID;}
|
||||
|
||||
void ESP8266WiFiMesh::setSSID(const String &newMeshName, const String &newNodeID)
|
||||
{
|
||||
updateNetworkNames(newMeshName, newNodeID);
|
||||
}
|
||||
|
||||
String ESP8266WiFiMesh::getMessage() {return _message;}
|
||||
void ESP8266WiFiMesh::setMessage(const String &newMessage) {_message = newMessage;}
|
||||
String ESP8266WiFiMesh::getSSID() {return _SSID;}
|
||||
|
||||
void ESP8266WiFiMesh::setMessage(const String &newMessage) {_message = newMessage;}
|
||||
String ESP8266WiFiMesh::getMessage() {return _message;}
|
||||
|
||||
void ESP8266WiFiMesh::setRequestHandler(ESP8266WiFiMesh::requestHandlerType requestHandler) {_requestHandler = requestHandler;}
|
||||
ESP8266WiFiMesh::requestHandlerType ESP8266WiFiMesh::getRequestHandler() {return _requestHandler;}
|
||||
|
||||
void ESP8266WiFiMesh::setResponseHandler(ESP8266WiFiMesh::responseHandlerType responseHandler) {_responseHandler = responseHandler;}
|
||||
ESP8266WiFiMesh::responseHandlerType ESP8266WiFiMesh::getResponseHandler() {return _responseHandler;}
|
||||
|
||||
ESP8266WiFiMesh::networkFilterType ESP8266WiFiMesh::getNetworkFilter() {return _networkFilter;}
|
||||
void ESP8266WiFiMesh::setNetworkFilter(ESP8266WiFiMesh::networkFilterType networkFilter) {_networkFilter = networkFilter;}
|
||||
ESP8266WiFiMesh::networkFilterType ESP8266WiFiMesh::getNetworkFilter() {return _networkFilter;}
|
||||
|
||||
void ESP8266WiFiMesh::setScanHidden(bool scanHidden)
|
||||
{
|
||||
_scanHidden = scanHidden;
|
||||
}
|
||||
|
||||
bool ESP8266WiFiMesh::getScanHidden() {return _scanHidden;}
|
||||
|
||||
void ESP8266WiFiMesh::setAPHidden(bool apHidden)
|
||||
{
|
||||
if(_apHidden != apHidden)
|
||||
{
|
||||
_apHidden = apHidden;
|
||||
|
||||
// Apply changes to active AP.
|
||||
if(isAPController())
|
||||
restartAP();
|
||||
}
|
||||
}
|
||||
|
||||
bool ESP8266WiFiMesh::getAPHidden() {return _apHidden;}
|
||||
|
||||
void ESP8266WiFiMesh::setMaxAPStations(uint8_t maxAPStations)
|
||||
{
|
||||
assert(maxAPStations <= 8); // Valid values are 0 to 8, but uint8_t is always at least 0.
|
||||
|
||||
if(_maxAPStations != maxAPStations)
|
||||
{
|
||||
_maxAPStations = maxAPStations;
|
||||
|
||||
// Apply changes to active AP.
|
||||
if(isAPController())
|
||||
restartAP();
|
||||
}
|
||||
}
|
||||
|
||||
bool ESP8266WiFiMesh::getMaxAPStations() {return _maxAPStations;}
|
||||
|
||||
void ESP8266WiFiMesh::setConnectionAttemptTimeout(int32_t connectionAttemptTimeoutMs)
|
||||
{
|
||||
_connectionAttemptTimeoutMs = connectionAttemptTimeoutMs;
|
||||
}
|
||||
|
||||
int32_t ESP8266WiFiMesh::getConnectionAttemptTimeout() {return _connectionAttemptTimeoutMs;}
|
||||
|
||||
void ESP8266WiFiMesh::setStationModeTimeout(int stationModeTimeoutMs)
|
||||
{
|
||||
_stationModeTimeoutMs = stationModeTimeoutMs;
|
||||
}
|
||||
|
||||
int ESP8266WiFiMesh::getStationModeTimeout() {return _stationModeTimeoutMs;}
|
||||
|
||||
void ESP8266WiFiMesh::setAPModeTimeout(uint32_t apModeTimeoutMs)
|
||||
{
|
||||
_apModeTimeoutMs = apModeTimeoutMs;
|
||||
}
|
||||
|
||||
uint32_t ESP8266WiFiMesh::getAPModeTimeout() {return _apModeTimeoutMs;}
|
||||
|
||||
bool ESP8266WiFiMesh::latestTransmissionSuccessful()
|
||||
{
|
||||
if(ESP8266WiFiMesh::latestTransmissionOutcomes.empty())
|
||||
return false;
|
||||
else
|
||||
for(TransmissionResult &transmissionResult : ESP8266WiFiMesh::latestTransmissionOutcomes)
|
||||
if(transmissionResult.transmissionStatus != TS_TRANSMISSION_COMPLETE)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect completely from a network.
|
||||
@ -234,16 +326,20 @@ void ESP8266WiFiMesh::fullStop(WiFiClient &currClient)
|
||||
* @returns: True if the client is ready, false otherwise.
|
||||
*
|
||||
*/
|
||||
bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient &currClient, int maxWait)
|
||||
bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient &currClient, uint32_t maxWait)
|
||||
{
|
||||
int wait = maxWait;
|
||||
while(currClient.connected() && !currClient.available() && wait--)
|
||||
delay(3);
|
||||
uint32_t connectionStartTime = millis();
|
||||
uint32_t waitingTime = millis() - connectionStartTime;
|
||||
while(currClient.connected() && !currClient.available() && waitingTime < maxWait)
|
||||
{
|
||||
delay(1);
|
||||
waitingTime = millis() - connectionStartTime;
|
||||
}
|
||||
|
||||
/* Return false if the client isn't ready to communicate */
|
||||
if (WiFi.status() == WL_DISCONNECTED && !currClient.available())
|
||||
{
|
||||
verboseModePrint("Disconnected!");
|
||||
verboseModePrint(F("Disconnected!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -260,12 +356,12 @@ bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient &currClient, int maxW
|
||||
*/
|
||||
transmission_status_t ESP8266WiFiMesh::exchangeInfo(WiFiClient &currClient)
|
||||
{
|
||||
verboseModePrint("Transmitting");
|
||||
verboseModePrint("Transmitting"); // Not storing strings in flash (via F()) to avoid performance impacts when using the string.
|
||||
|
||||
currClient.print(getMessage() + "\r");
|
||||
yield();
|
||||
|
||||
if (!waitForClientTransmission(currClient, 1000))
|
||||
if (!waitForClientTransmission(currClient, _stationModeTimeoutMs))
|
||||
{
|
||||
fullStop(currClient);
|
||||
return TS_CONNECTION_FAILED;
|
||||
@ -273,7 +369,7 @@ transmission_status_t ESP8266WiFiMesh::exchangeInfo(WiFiClient &currClient)
|
||||
|
||||
if (!currClient.available())
|
||||
{
|
||||
verboseModePrint("No response!");
|
||||
verboseModePrint(F("No response!"));
|
||||
return TS_TRANSMISSION_FAILED; // WiFi.status() != WL_DISCONNECTED so we do not want to use fullStop(currClient) here since that would force the node to scan for WiFi networks.
|
||||
}
|
||||
|
||||
@ -295,10 +391,11 @@ transmission_status_t ESP8266WiFiMesh::attemptDataTransfer()
|
||||
// Unlike WiFi.mode(WIFI_AP);, WiFi.mode(WIFI_AP_STA); allows us to stay connected to the AP we connected to in STA mode, at the same time as we can receive connections from other stations.
|
||||
// We cannot send data to the AP in STA_AP mode though, that requires STA mode.
|
||||
// Switching to STA mode will disconnect all stations connected to the node AP (though they can request a reconnect even while we are in STA mode).
|
||||
WiFiMode_t storedWiFiMode = WiFi.getMode();
|
||||
WiFi.mode(WIFI_STA);
|
||||
delay(1);
|
||||
transmission_status_t transmissionOutcome = attemptDataTransferKernel();
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
WiFi.mode(storedWiFiMode);
|
||||
delay(1);
|
||||
|
||||
return transmissionOutcome;
|
||||
@ -312,19 +409,20 @@ transmission_status_t ESP8266WiFiMesh::attemptDataTransfer()
|
||||
transmission_status_t ESP8266WiFiMesh::attemptDataTransferKernel()
|
||||
{
|
||||
WiFiClient currClient;
|
||||
|
||||
currClient.setTimeout(_stationModeTimeoutMs);
|
||||
|
||||
/* Connect to the node's server */
|
||||
if (!currClient.connect(SERVER_IP_ADDR, _serverPort))
|
||||
{
|
||||
fullStop(currClient);
|
||||
verboseModePrint("Server unavailable");
|
||||
verboseModePrint(F("Server unavailable"));
|
||||
return TS_CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
transmission_status_t transmissionOutcome = exchangeInfo(currClient);
|
||||
if (transmissionOutcome <= 0)
|
||||
{
|
||||
verboseModePrint("Transmission failed during exchangeInfo.");
|
||||
verboseModePrint(F("Transmission failed during exchangeInfo."));
|
||||
return transmissionOutcome;
|
||||
}
|
||||
|
||||
@ -361,36 +459,37 @@ transmission_status_t ESP8266WiFiMesh::connectToNode(const String &targetSSID, i
|
||||
if(atLeastLwipVersion(lwipVersion203Signature))
|
||||
{
|
||||
// Can be used with Arduino core for ESP8266 version 2.4.2 or higher with lwIP2 enabled to keep static IP on even during network switches.
|
||||
WiFiMode_t storedWiFiMode = WiFi.getMode();
|
||||
WiFi.mode(WIFI_OFF);
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
WiFi.mode(storedWiFiMode);
|
||||
yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable static IP so that we can connect to other servers via DHCP (DHCP is slower but required for connecting to more than one server, it seems (possible bug?)).
|
||||
disableStaticIP();
|
||||
verboseModePrint("\nConnecting to a different network. Static IP deactivated to make this possible.");
|
||||
verboseModePrint(F("\nConnecting to a different network. Static IP deactivated to make this possible."));
|
||||
}
|
||||
#else
|
||||
// Disable static IP so that we can connect to other servers via DHCP (DHCP is slower but required for connecting to more than one server, it seems (possible bug?)).
|
||||
disableStaticIP();
|
||||
verboseModePrint("\nConnecting to a different network. Static IP deactivated to make this possible.");
|
||||
verboseModePrint(F("\nConnecting to a different network. Static IP deactivated to make this possible."));
|
||||
#endif
|
||||
}
|
||||
lastSSID = targetSSID;
|
||||
|
||||
verboseModePrint("Connecting... ", false);
|
||||
verboseModePrint(F("Connecting... "), false);
|
||||
initiateConnectionToAP(targetSSID, targetChannel, targetBSSID);
|
||||
|
||||
int connectionStartTime = millis();
|
||||
int attemptNumber = 1;
|
||||
|
||||
int waitingTime = millis() - connectionStartTime;
|
||||
while((WiFi.status() == WL_DISCONNECTED) && waitingTime <= 10000)
|
||||
while((WiFi.status() == WL_DISCONNECTED) && waitingTime <= _connectionAttemptTimeoutMs)
|
||||
{
|
||||
if(waitingTime > attemptNumber * 10000) // 10000 can be lowered if you want to limit the time allowed for each connection attempt.
|
||||
if(waitingTime > attemptNumber * _connectionAttemptTimeoutMs) // _connectionAttemptTimeoutMs can be replaced (lowered) if you want to limit the time allowed for each connection attempt.
|
||||
{
|
||||
verboseModePrint("... ", false);
|
||||
verboseModePrint(F("... "), false);
|
||||
WiFi.disconnect();
|
||||
yield();
|
||||
initiateConnectionToAP(targetSSID, targetChannel, targetBSSID);
|
||||
@ -405,7 +504,7 @@ transmission_status_t ESP8266WiFiMesh::connectToNode(const String &targetSSID, i
|
||||
/* If the connection timed out */
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
verboseModePrint("Timeout");
|
||||
verboseModePrint(F("Timeout"));
|
||||
return TS_CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
@ -433,7 +532,7 @@ void ESP8266WiFiMesh::attemptTransmission(const String &message, bool concluding
|
||||
{
|
||||
if(!noScan)
|
||||
{
|
||||
verboseModePrint("Scanning... ", false);
|
||||
verboseModePrint(F("Scanning... "), false);
|
||||
|
||||
/* Scan for APs */
|
||||
connectionQueue.clear();
|
||||
@ -444,15 +543,15 @@ void ESP8266WiFiMesh::attemptTransmission(const String &message, bool concluding
|
||||
#ifdef ENABLE_WIFI_SCAN_OPTIMIZATION
|
||||
if(scanAllWiFiChannels)
|
||||
{
|
||||
n = WiFi.scanNetworks();
|
||||
n = WiFi.scanNetworks(false, _scanHidden);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scan function argument overview: scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL)
|
||||
n = WiFi.scanNetworks(false, false, _meshWiFiChannel);
|
||||
n = WiFi.scanNetworks(false, _scanHidden, _meshWiFiChannel);
|
||||
}
|
||||
#else
|
||||
n = WiFi.scanNetworks();
|
||||
n = WiFi.scanNetworks(false, _scanHidden);
|
||||
#endif
|
||||
|
||||
_networkFilter(n, *this); // Update the connectionQueue.
|
||||
@ -483,15 +582,15 @@ void ESP8266WiFiMesh::attemptTransmission(const String &message, bool concluding
|
||||
|
||||
if(_verboseMode) // Avoid string generation if not required
|
||||
{
|
||||
verboseModePrint("AP acquired: " + currentSSID + ", Ch:" + String(currentWiFiChannel) + " ", false);
|
||||
verboseModePrint(String(F("AP acquired: ")) + currentSSID + String(F(", Ch:")) + String(currentWiFiChannel) + " ", false);
|
||||
|
||||
if(currentNetwork.networkIndex != NETWORK_INFO_DEFAULT_INT)
|
||||
{
|
||||
verboseModePrint("(" + String(WiFi.RSSI(currentNetwork.networkIndex)) + "dBm) " +
|
||||
(WiFi.encryptionType(currentNetwork.networkIndex) == ENC_TYPE_NONE ? "open" : ""), false);
|
||||
verboseModePrint("(" + String(WiFi.RSSI(currentNetwork.networkIndex)) + String(F("dBm) ")) +
|
||||
(WiFi.encryptionType(currentNetwork.networkIndex) == ENC_TYPE_NONE ? String(F("open")) : ""), false);
|
||||
}
|
||||
|
||||
verboseModePrint("... ", false);
|
||||
verboseModePrint(F("... "), false);
|
||||
}
|
||||
|
||||
transmission_status_t transmissionResult = connectToNode(currentSSID, currentWiFiChannel, currentBSSID);
|
||||
@ -502,7 +601,7 @@ void ESP8266WiFiMesh::attemptTransmission(const String &message, bool concluding
|
||||
|
||||
if(WiFi.status() == WL_CONNECTED && staticIP != emptyIP && !staticIPActivated)
|
||||
{
|
||||
verboseModePrint("Reactivating static IP to allow for faster re-connects.");
|
||||
verboseModePrint(F("Reactivating static IP to allow for faster re-connects."));
|
||||
setStaticIP(staticIP);
|
||||
}
|
||||
|
||||
@ -524,7 +623,7 @@ void ESP8266WiFiMesh::acceptRequest()
|
||||
if (!_client)
|
||||
break;
|
||||
|
||||
if (!waitForClient(_client, 1500)) {
|
||||
if (!waitForClient(_client, _apModeTimeoutMs)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -548,7 +647,7 @@ void ESP8266WiFiMesh::acceptRequest()
|
||||
if (!_client)
|
||||
break;
|
||||
|
||||
if (!waitForClientTransmission(_client, 1500) || !_client.available()) {
|
||||
if (!waitForClientTransmission(_client, _apModeTimeoutMs) || !_client.available()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -562,7 +661,7 @@ void ESP8266WiFiMesh::acceptRequest()
|
||||
/* Send the response back to the client */
|
||||
if (_client.connected())
|
||||
{
|
||||
verboseModePrint("Responding");
|
||||
verboseModePrint("Responding"); // Not storing strings in flash (via F()) to avoid performance impacts when using the string.
|
||||
_client.print(response + "\r");
|
||||
_client.flush();
|
||||
yield();
|
||||
|
@ -39,7 +39,7 @@ private:
|
||||
String _SSID;
|
||||
String _meshName;
|
||||
String _nodeID;
|
||||
int _serverPort;
|
||||
uint16_t _serverPort;
|
||||
String _meshPassword;
|
||||
uint8 _meshWiFiChannel;
|
||||
bool _verboseMode;
|
||||
@ -47,6 +47,12 @@ private:
|
||||
uint32_t _lwipVersion[3];
|
||||
static const uint32_t lwipVersion203Signature[3];
|
||||
String _message = WIFI_MESH_EMPTY_STRING;
|
||||
bool _scanHidden = false;
|
||||
bool _apHidden = false;
|
||||
uint8_t _maxAPStations = 4;
|
||||
int32_t _connectionAttemptTimeoutMs = 10000;
|
||||
int _stationModeTimeoutMs = 5000; // int is the type used in the Arduino core for this particular API, not uint32_t, which is why we use int here.
|
||||
uint32_t _apModeTimeoutMs = 4500;
|
||||
|
||||
static String lastSSID;
|
||||
static bool staticIPActivated;
|
||||
@ -69,7 +75,7 @@ private:
|
||||
void initiateConnectionToAP(const String &targetSSID, int targetChannel = NETWORK_INFO_DEFAULT_INT, uint8_t *targetBSSID = NULL);
|
||||
transmission_status_t connectToNode(const String &targetSSID, int targetChannel = NETWORK_INFO_DEFAULT_INT, uint8_t *targetBSSID = NULL);
|
||||
transmission_status_t exchangeInfo(WiFiClient &currClient);
|
||||
bool waitForClientTransmission(WiFiClient &currClient, int maxWait);
|
||||
bool waitForClientTransmission(WiFiClient &currClient, uint32_t maxWait);
|
||||
transmission_status_t attemptDataTransfer();
|
||||
transmission_status_t attemptDataTransferKernel();
|
||||
void storeLwipVersion();
|
||||
@ -153,7 +159,7 @@ public:
|
||||
*/
|
||||
ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter,
|
||||
const String &meshPassword, const String &meshName = "MeshNode_", const String &nodeID = WIFI_MESH_EMPTY_STRING, bool verboseMode = false,
|
||||
uint8 meshWiFiChannel = 1, int serverPort = 4011);
|
||||
uint8 meshWiFiChannel = 1, uint16_t serverPort = 4011);
|
||||
|
||||
/**
|
||||
* A vector that contains the NetworkInfo for each WiFi network to connect to.
|
||||
@ -171,6 +177,11 @@ public:
|
||||
*/
|
||||
static std::vector<TransmissionResult> latestTransmissionOutcomes;
|
||||
|
||||
/**
|
||||
* @returns True if latest transmission was successful (i.e. latestTransmissionOutcomes is not empty and all entries have transmissionStatus TS_TRANSMISSION_COMPLETE). False otherwise.
|
||||
*/
|
||||
static bool latestTransmissionSuccessful();
|
||||
|
||||
/**
|
||||
* Initialises the node.
|
||||
*/
|
||||
@ -202,11 +213,9 @@ public:
|
||||
*/
|
||||
bool isAPController();
|
||||
|
||||
uint8 getWiFiChannel();
|
||||
|
||||
/**
|
||||
* Change the WiFi channel used by this ESP8266WiFiMesh instance.
|
||||
* Will also change the AP WiFi channel if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
* Will also change the WiFi channel for the active AP if this ESP8266WiFiMesh instance is the current AP controller and it is possible to change channel.
|
||||
*
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
* This can cause problems if several ESP8266WiFiMesh instances exist on the same ESP8266 and use different WiFi channels.
|
||||
@ -218,44 +227,43 @@ public:
|
||||
*
|
||||
*/
|
||||
void setWiFiChannel(uint8 newWiFiChannel);
|
||||
|
||||
String getMeshName();
|
||||
uint8 getWiFiChannel();
|
||||
|
||||
/**
|
||||
* Change the mesh name used by this ESP8266WiFiMesh instance.
|
||||
* Will also change the AP mesh name (SSID prefix) if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
* Will also change the mesh name (SSID prefix) for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param newMeshName The mesh name to change to.
|
||||
*/
|
||||
void setMeshName(const String &newMeshName);
|
||||
|
||||
String getNodeID();
|
||||
|
||||
String getMeshName();
|
||||
|
||||
/**
|
||||
* Change the node id used by this ESP8266WiFiMesh instance.
|
||||
* Will also change the AP node id (SSID suffix) if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
* Will also change the node id (SSID suffix) for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param newNodeID The node id to change to.
|
||||
*/
|
||||
void setNodeID(const String &newNodeID);
|
||||
|
||||
String getNodeID();
|
||||
|
||||
/**
|
||||
* Change the SSID (mesh name + node id) used by this ESP8266WiFiMesh instance.
|
||||
* Will also change the AP SSID if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
* Will also change the SSID for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param newMeshName The mesh name to change to. Will be the SSID prefix.
|
||||
* @param newNodeID The node id to change to. Will be the SSID suffix.
|
||||
*/
|
||||
void setSSID(const String &newMeshName, const String &newNodeID);
|
||||
|
||||
String getMessage();
|
||||
|
||||
String getSSID();
|
||||
|
||||
/**
|
||||
* Set the message that will be sent to other nodes when calling attemptTransmission.
|
||||
*
|
||||
* @param newMessage The message to send.
|
||||
*/
|
||||
void setMessage(const String &newMessage);
|
||||
String getMessage();
|
||||
|
||||
/**
|
||||
* If AP connection already exists, and the initialDisconnect argument is set to false, send message only to the already connected AP.
|
||||
@ -282,7 +290,6 @@ public:
|
||||
* The static IP needs to be at the same subnet as the server's gateway.
|
||||
*/
|
||||
void setStaticIP(const IPAddress &newIP);
|
||||
|
||||
IPAddress getStaticIP();
|
||||
void disableStaticIP();
|
||||
|
||||
@ -291,11 +298,77 @@ public:
|
||||
*/
|
||||
static const IPAddress emptyIP;
|
||||
|
||||
static String uint64ToString(uint64_t number, byte base = 16);
|
||||
static uint64_t stringToUint64(const String &string, byte base = 16);
|
||||
|
||||
networkFilterType getNetworkFilter();
|
||||
void setRequestHandler(requestHandlerType requestHandler);
|
||||
requestHandlerType getRequestHandler();
|
||||
|
||||
void setResponseHandler(responseHandlerType responseHandler);
|
||||
responseHandlerType getResponseHandler();
|
||||
|
||||
void setNetworkFilter(networkFilterType networkFilter);
|
||||
networkFilterType getNetworkFilter();
|
||||
|
||||
/**
|
||||
* Set whether scan results from this ESP8266WiFiMesh instance will include WiFi networks with hidden SSIDs.
|
||||
* This is false by default.
|
||||
* The SSID field of a found hidden network will be blank in the scan results.
|
||||
* WiFi.isHidden(networkIndex) can be used to verify that a found network is hidden.
|
||||
*
|
||||
* @param scanHidden If true, WiFi networks with hidden SSIDs will be included in scan results.
|
||||
*/
|
||||
void setScanHidden(bool scanHidden);
|
||||
bool getScanHidden();
|
||||
|
||||
/**
|
||||
* Set whether the AP controlled by this ESP8266WiFiMesh instance will have a WiFi network with hidden SSID.
|
||||
* This is false by default.
|
||||
* Will also change the setting for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param apHidden If true, the WiFi network created will have a hidden SSID.
|
||||
*/
|
||||
void setAPHidden(bool apHidden);
|
||||
bool getAPHidden();
|
||||
|
||||
/**
|
||||
* Set the maximum number of stations that can simultaneously be connected to the AP controlled by this ESP8266WiFiMesh instance.
|
||||
* This number is 4 by default.
|
||||
* Once the max number has been reached, any other station that wants to connect will be forced to wait until an already connected station disconnects.
|
||||
* The more stations that are connected, the more memory is required.
|
||||
* Will also change the setting for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param maxAPStations The maximum number of simultaneous station connections allowed. Valid values are 0 to 8.
|
||||
*/
|
||||
void setMaxAPStations(uint8_t maxAPStations);
|
||||
bool getMaxAPStations();
|
||||
|
||||
/**
|
||||
* Set the timeout for each attempt to connect to another AP that occurs through the attemptTransmission method by this ESP8266WiFiMesh instance.
|
||||
* The timeout is 10 000 ms by default.
|
||||
*
|
||||
* @param connectionAttemptTimeoutMs The timeout for each connection attempt, in milliseconds.
|
||||
*/
|
||||
void setConnectionAttemptTimeout(int32_t connectionAttemptTimeoutMs);
|
||||
int32_t getConnectionAttemptTimeout();
|
||||
|
||||
/**
|
||||
* Set the timeout to use for transmissions when this ESP8266WiFiMesh instance acts as a station (i.e. when connected to another AP).
|
||||
* This will affect the timeout of the attemptTransmission method once a connection to an AP has been established.
|
||||
* The timeout is 5 000 ms by default.
|
||||
*
|
||||
* @param stationModeTimeoutMs The timeout to use, in milliseconds.
|
||||
*/
|
||||
void setStationModeTimeout(int stationModeTimeoutMs);
|
||||
int getStationModeTimeout();
|
||||
|
||||
/**
|
||||
* Set the timeout to use for transmissions when this ESP8266WiFiMesh instance acts as an AP (i.e. when receiving connections from other stations).
|
||||
* This will affect the timeout of the acceptRequest method.
|
||||
* The timeout is 4 500 ms by default.
|
||||
* Will also change the setting for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param apModeTimeoutMs The timeout to use, in milliseconds.
|
||||
*/
|
||||
void setAPModeTimeout(uint32_t apModeTimeoutMs);
|
||||
uint32_t getAPModeTimeout();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
58
libraries/ESP8266WiFiMesh/src/TypeConversionFunctions.cpp
Normal file
58
libraries/ESP8266WiFiMesh/src/TypeConversionFunctions.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* TypeConversionFunctions
|
||||
* Copyright (C) 2018 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "TypeConversionFunctions.h"
|
||||
|
||||
String uint64ToString(uint64_t number, byte base)
|
||||
{
|
||||
assert(2 <= base && base <= 36);
|
||||
|
||||
String result = "";
|
||||
|
||||
while(number > 0)
|
||||
{
|
||||
result = String((uint32_t)(number % base), base) + result;
|
||||
number /= base;
|
||||
}
|
||||
|
||||
return (result == "" ? "0" : result);
|
||||
}
|
||||
|
||||
uint64_t stringToUint64(const String &string, byte base)
|
||||
{
|
||||
assert(2 <= base && base <= 36);
|
||||
|
||||
uint64_t result = 0;
|
||||
|
||||
char currentCharacter[1];
|
||||
for(uint32_t i = 0; i < string.length(); i++)
|
||||
{
|
||||
result *= base;
|
||||
currentCharacter[0] = string.charAt(i);
|
||||
result += strtoul(currentCharacter, NULL, base);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
50
libraries/ESP8266WiFiMesh/src/TypeConversionFunctions.h
Normal file
50
libraries/ESP8266WiFiMesh/src/TypeConversionFunctions.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* TypeConversionFunctions
|
||||
* Copyright (C) 2018 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __TYPECONVERSIONFUNCTIONS_H__
|
||||
#define __TYPECONVERSIONFUNCTIONS_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
* Note that using a base higher than 16 increases likelihood of randomly generating SSID strings containing controversial words.
|
||||
*
|
||||
* @param number The number to convert to a string with radix "base".
|
||||
* @param base The radix to convert "number" into. Must be between 2 and 36.
|
||||
* @returns A string of "number" encoded in radix "base".
|
||||
*/
|
||||
String uint64ToString(uint64_t number, byte base = 16);
|
||||
|
||||
/**
|
||||
* Note that using a base higher than 16 increases likelihood of randomly generating SSID strings containing controversial words.
|
||||
*
|
||||
* @param string The string to convert to uint64_t. String must use radix "base".
|
||||
* @param base The radix of "string". Must be between 2 and 36.
|
||||
* @returns A uint64_t of the string, using radix "base" during decoding.
|
||||
*/
|
||||
uint64_t stringToUint64(const String &string, byte base = 16);
|
||||
|
||||
#endif
|
@ -23,8 +23,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "TypeConversionFunctions.h"
|
||||
#include "ESP8266WiFiMesh.h"
|
||||
#include <assert.h>
|
||||
|
||||
void ESP8266WiFiMesh::verboseModePrint(const String &stringToPrint, bool newline)
|
||||
{
|
||||
@ -37,52 +37,6 @@ void ESP8266WiFiMesh::verboseModePrint(const String &stringToPrint, bool newline
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that using a base higher than 16 increases likelihood of randomly generating SSID strings containing controversial words.
|
||||
*
|
||||
* @param number The number to convert to a string with radix "base".
|
||||
* @param base The radix to convert "number" into. Must be between 2 and 36.
|
||||
* @returns A string of "number" encoded in radix "base".
|
||||
*/
|
||||
String ESP8266WiFiMesh::uint64ToString(uint64_t number, byte base)
|
||||
{
|
||||
assert(2 <= base && base <= 36);
|
||||
|
||||
String result = "";
|
||||
|
||||
while(number > 0)
|
||||
{
|
||||
result = String((uint32_t)(number % base), base) + result;
|
||||
number /= base;
|
||||
}
|
||||
|
||||
return (result == "" ? "0" : result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that using a base higher than 16 increases likelihood of randomly generating SSID strings containing controversial words.
|
||||
*
|
||||
* @param string The string to convert to uint64_t. String must use radix "base".
|
||||
* @param base The radix of "string". Must be between 2 and 36.
|
||||
* @returns A uint64_t of the string, using radix "base" during decoding.
|
||||
*/
|
||||
uint64_t ESP8266WiFiMesh::stringToUint64(const String &string, byte base)
|
||||
{
|
||||
assert(2 <= base && base <= 36);
|
||||
|
||||
uint64_t result = 0;
|
||||
|
||||
char currentCharacter[1];
|
||||
for(uint32_t i = 0; i < string.length(); i++)
|
||||
{
|
||||
result *= base;
|
||||
currentCharacter[0] = string.charAt(i);
|
||||
result += strtoul(currentCharacter, NULL, base);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current lwIP version number and store the numbers in the _lwipVersion array.
|
||||
* lwIP version can be changed in the "Tools" menu of Arduino IDE.
|
||||
|
Reference in New Issue
Block a user