Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WiFi Mesh Update 2.1 #5157

Merged
merged 9 commits into from
Sep 24, 2018
4 changes: 2 additions & 2 deletions libraries/ESP8266WiFiMesh/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseH

* This library can use static IP:s for the nodes to speed up connection times. To enable this, use the `setStaticIP` method after calling the `begin` method, as in the included example. Ensure that nodes connecting to the same AP have distinct static IP:s. Node IP:s need to be at the same subnet as the server gateway (192.168.4 for this library by default). It may also be worth noting that station gateway IP must match the IP for the server on the nodes, though this is the default setting for the library.

At the moment static IP is a global setting, meaning that all ESP8266WiFiMesh instances on a single ESP8266 share the same static IP settings.
At the moment static IP is a global setting, meaning that all ESP8266WiFiMesh instances on the same ESP8266 share the same static IP settings.

* When Arduino core for ESP8266 version 2.4.2 or higher is used, there are optimizations available for WiFi scans and static IP use to reduce the time it takes for nodes to connect to each other. These optimizations are enabled by default. To take advantage of the static IP optimizations you also need to use lwIP2. The lwIP version can be changed in the Tools menu of Arduino IDE.

Expand All @@ -74,7 +74,7 @@ General Information

* This library uses the standard Arduino core for ESP8266 WiFi functions. Therefore, other code that also uses these WiFi functions may cause conflicts with the library, resulting in strange behaviour.

* A maximum of 5 stations can be connected at a time to each AP.
* By default, a maximum of 4 stations can be connected at a time to each AP. This can be changed to a value in the range 0 to 8 via the `setMaxAPStations` method. 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.

* Unlike `WiFi.mode(WIFI_AP)`, the `WiFi.mode(WIFI_AP_STA)` which is used in this library allows nodes to stay connected to an AP they connect to while in STA mode, at the same time as they can receive connections from other stations. Nodes cannot send data to an AP while in STA_AP mode though, that requires STA mode. Switching to STA mode will sometimes disconnect stations connected to the node AP (though they can request a reconnect even while the previous AP node is in STA mode).

Expand Down
105 changes: 68 additions & 37 deletions libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMesh.h>
#include <TypeConversionFunctions.h>
#include <assert.h>

String exampleMeshName("MeshNode_");
/**
NOTE: Although we could define the strings below as normal String variables,
here we are using PROGMEM combined with the FPSTR() macro (and also just the F() macro further down in the file).
The reason is that this approach will place the strings in flash memory which will help save RAM during program execution.
Reading strings from flash will be slower than reading them from RAM,
but this will be a negligible difference when printing them to Serial.

More on F(), FPSTR() and PROGMEM:
https://github.com/esp8266/Arduino/issues/1143
https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html
*/
const char exampleMeshName[] PROGMEM = "MeshNode_";
const char exampleWiFiPassword[] PROGMEM = "ChangeThisWiFiPassword_TODO";

unsigned int requestNumber = 0;
unsigned int responseNumber = 0;
Expand All @@ -11,7 +25,7 @@ transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &me
void networkFilter(int numberOfNetworks, ESP8266WiFiMesh &meshInstance);

/* Create the mesh node object */
ESP8266WiFiMesh meshNode = ESP8266WiFiMesh(manageRequest, manageResponse, networkFilter, "ChangeThisWiFiPassword_TODO", exampleMeshName, "", true);
ESP8266WiFiMesh meshNode = ESP8266WiFiMesh(manageRequest, manageResponse, networkFilter, FPSTR(exampleWiFiPassword), FPSTR(exampleMeshName), "", true);

/**
Callback for when other nodes send you a request
Expand All @@ -21,6 +35,11 @@ ESP8266WiFiMesh meshNode = ESP8266WiFiMesh(manageRequest, manageResponse, networ
@returns The string to send back to the other node
*/
String manageRequest(const String &request, ESP8266WiFiMesh &meshInstance) {
// We do not store strings in flash (via F()) in this function.
// The reason is that the other node will be waiting for our response,
// so keeping the strings in RAM will give a (small) improvement in response time.
// Of course, it is advised to adjust this approach based on RAM requirements.

/* Print out received message */
Serial.print("Request received: ");
Serial.println(request);
Expand All @@ -29,28 +48,6 @@ String manageRequest(const String &request, ESP8266WiFiMesh &meshInstance) {
return ("Hello world response #" + String(responseNumber++) + " from " + meshInstance.getMeshName() + meshInstance.getNodeID() + ".");
}

/**
Callback used to decide which networks to connect to once a WiFi scan has been completed.

@param numberOfNetworks The number of networks found in the WiFi scan.
@param meshInstance The ESP8266WiFiMesh instance that called the function.
*/
void networkFilter(int numberOfNetworks, ESP8266WiFiMesh &meshInstance) {
for (int i = 0; i < numberOfNetworks; ++i) {
String currentSSID = WiFi.SSID(i);
int meshNameIndex = currentSSID.indexOf(meshInstance.getMeshName());

/* Connect to any _suitable_ APs which contain meshInstance.getMeshName() */
if (meshNameIndex >= 0) {
uint64_t targetNodeID = ESP8266WiFiMesh::stringToUint64(currentSSID.substring(meshNameIndex + meshInstance.getMeshName().length()));

if (targetNodeID < ESP8266WiFiMesh::stringToUint64(meshInstance.getNodeID())) {
ESP8266WiFiMesh::connectionQueue.push_back(NetworkInfo(i));
}
}
}
}

/**
Callback for when you get a response from other nodes

Expand All @@ -62,18 +59,41 @@ transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &me
transmission_status_t statusCode = TS_TRANSMISSION_COMPLETE;

/* Print out received message */
Serial.print("Request sent: ");
Serial.print(F("Request sent: "));
Serial.println(meshInstance.getMessage());
Serial.print("Response received: ");
Serial.print(F("Response received: "));
Serial.println(response);

// Our last request got a response, so time to create a new request.
meshInstance.setMessage("Hello world request #" + String(++requestNumber) + " from " + meshInstance.getMeshName() + meshInstance.getNodeID() + ".");
meshInstance.setMessage(String(F("Hello world request #")) + String(++requestNumber) + String(F(" from "))
+ meshInstance.getMeshName() + meshInstance.getNodeID() + String(F(".")));

// (void)meshInstance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else.
return statusCode;
}

/**
Callback used to decide which networks to connect to once a WiFi scan has been completed.

@param numberOfNetworks The number of networks found in the WiFi scan.
@param meshInstance The ESP8266WiFiMesh instance that called the function.
*/
void networkFilter(int numberOfNetworks, ESP8266WiFiMesh &meshInstance) {
for (int networkIndex = 0; networkIndex < numberOfNetworks; ++networkIndex) {
String currentSSID = WiFi.SSID(networkIndex);
int meshNameIndex = currentSSID.indexOf(meshInstance.getMeshName());

/* Connect to any _suitable_ APs which contain meshInstance.getMeshName() */
if (meshNameIndex >= 0) {
uint64_t targetNodeID = stringToUint64(currentSSID.substring(meshNameIndex + meshInstance.getMeshName().length()));

if (targetNodeID < stringToUint64(meshInstance.getNodeID())) {
ESP8266WiFiMesh::connectionQueue.push_back(NetworkInfo(networkIndex));
}
}
}
}

void setup() {
// Prevents the flash memory from being worn out, see: https://github.com/esp8266/Arduino/issues/1054 .
// This will however delay node WiFi start-up by about 700 ms. The delay is 900 ms if we otherwise would have stored the WiFi network we want to connect to.
Expand All @@ -84,15 +104,19 @@ void setup() {

//yield(); // Use this if you don't want to wait for Serial.

// The WiFi.disconnect() ensures that the WiFi is working correctly. If this is not done before receiving WiFi connections,
// those WiFi connections will take a long time to make or sometimes will not work at all.
WiFi.disconnect();

Serial.println();
Serial.println();

Serial.println("Note that this library can use static IP:s for the nodes to speed up connection times.\n"
"Use the setStaticIP method as shown in this example to enable this.\n"
"Ensure that nodes connecting to the same AP have distinct static IP:s.\n"
"Also, remember to change the default mesh network password!\n\n");
Serial.println(F("Note that this library can use static IP:s for the nodes to speed up connection times.\n"
"Use the setStaticIP method as shown in this example to enable this.\n"
"Ensure that nodes connecting to the same AP have distinct static IP:s.\n"
"Also, remember to change the default mesh network password!\n\n"));

Serial.println("Setting up mesh node...");
Serial.println(F("Setting up mesh node..."));

/* Initialise the mesh node */
meshNode.begin();
Expand All @@ -104,22 +128,29 @@ int32_t timeOfLastScan = -10000;
void loop() {
if (millis() - timeOfLastScan > 3000 // Give other nodes some time to connect between data transfers.
|| (WiFi.status() != WL_CONNECTED && millis() - timeOfLastScan > 2000)) { // Scan for networks with two second intervals when not already connected.
String request = "Hello world request #" + String(requestNumber) + " from " + meshNode.getMeshName() + meshNode.getNodeID() + ".";
String request = String(F("Hello world request #")) + String(requestNumber) + String(F(" from ")) + meshNode.getMeshName() + meshNode.getNodeID() + String(F("."));
meshNode.attemptTransmission(request, false);
timeOfLastScan = millis();

// One way to check how attemptTransmission worked out
if (ESP8266WiFiMesh::latestTransmissionSuccessful()) {
Serial.println(F("Transmission successful."));
}

// Another way to check how attemptTransmission worked out
if (ESP8266WiFiMesh::latestTransmissionOutcomes.empty()) {
Serial.println("No mesh AP found.");
Serial.println(F("No mesh AP found."));
} else {
for (TransmissionResult &transmissionResult : ESP8266WiFiMesh::latestTransmissionOutcomes) {
if (transmissionResult.transmissionStatus == TS_TRANSMISSION_FAILED) {
Serial.println("Transmission failed to mesh AP " + transmissionResult.SSID);
Serial.println(String(F("Transmission failed to mesh AP ")) + transmissionResult.SSID);
} else if (transmissionResult.transmissionStatus == TS_CONNECTION_FAILED) {
Serial.println("Connection failed to mesh AP " + transmissionResult.SSID);
Serial.println(String(F("Connection failed to mesh AP ")) + transmissionResult.SSID);
} else if (transmissionResult.transmissionStatus == TS_TRANSMISSION_COMPLETE) {
// No need to do anything, transmission was successful.
} else {
Serial.println("Invalid transmission status for " + transmissionResult.SSID + "!");
Serial.println(String(F("Invalid transmission status for ")) + transmissionResult.SSID + String(F("!")));
assert(F("Invalid transmission status returned from responseHandler!") && false);
}
}
}
Expand Down
28 changes: 23 additions & 5 deletions libraries/ESP8266WiFiMesh/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,48 @@ transmission_status_t KEYWORD1

connectionQueue KEYWORD2
latestTransmissionOutcomes KEYWORD2
latestTransmissionSuccessful KEYWORD2
begin KEYWORD2
activateAP KEYWORD2
deactivateAP KEYWORD2
restartAP KEYWORD2
getAPController KEYWORD2
isAPController KEYWORD2
getWiFiChannel KEYWORD2
setWiFiChannel KEYWORD2
getMeshName KEYWORD2
getWiFiChannel KEYWORD2
setMeshName KEYWORD2
getNodeID KEYWORD2
getMeshName KEYWORD2
setNodeID KEYWORD2
getNodeID KEYWORD2
setSSID KEYWORD2
getMessage KEYWORD2
getSSID KEYWORD2
setMessage KEYWORD2
getMessage KEYWORD2
attemptTransmission KEYWORD2
acceptRequest KEYWORD2
setStaticIP KEYWORD2
getStaticIP KEYWORD2
disableStaticIP->KEYWORD2
uint64ToString KEYWORD2
stringToUint64 KEYWORD2
getNetworkFilter KEYWORD2
setRequestHandler KEYWORD2
getRequestHandler KEYWORD2
setResponseHandler KEYWORD2
getResponseHandler KEYWORD2
setNetworkFilter KEYWORD2
getNetworkFilter KEYWORD2
setScanHidden KEYWORD2
getScanHidden KEYWORD2
setAPHidden KEYWORD2
getAPHidden KEYWORD2
setMaxAPStations KEYWORD2
getMaxAPStations KEYWORD2
setConnectionAttemptTimeout KEYWORD2
getConnectionAttemptTimeout KEYWORD2
setStationModeTimeout KEYWORD2
getStationModeTimeout KEYWORD2
setAPModeTimeout KEYWORD2
getAPModeTimeout KEYWORD2

#######################################
# Constants (LITERAL1)
Expand Down
2 changes: 1 addition & 1 deletion libraries/ESP8266WiFiMesh/library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=ESP8266WiFiMesh
version=2.0
version=2.1
author=Julian Fell
maintainer=Anders Löfgren
sentence=Mesh network library
Expand Down
Loading