Skip to content

Commit 88bd26b

Browse files
aerlondevyte
authored andcommitted
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.
1 parent d8a7a34 commit 88bd26b

9 files changed

+457
-174
lines changed

libraries/ESP8266WiFiMesh/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseH
5050

5151
* 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.
5252

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

5555
* 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.
5656

@@ -74,7 +74,7 @@ General Information
7474

7575
* 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.
7676

77-
* A maximum of 5 stations can be connected at a time to each AP.
77+
* 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.
7878

7979
* 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).
8080

libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino

+68-37
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
#include <ESP8266WiFi.h>
22
#include <ESP8266WiFiMesh.h>
3+
#include <TypeConversionFunctions.h>
4+
#include <assert.h>
35

4-
String exampleMeshName("MeshNode_");
6+
/**
7+
NOTE: Although we could define the strings below as normal String variables,
8+
here we are using PROGMEM combined with the FPSTR() macro (and also just the F() macro further down in the file).
9+
The reason is that this approach will place the strings in flash memory which will help save RAM during program execution.
10+
Reading strings from flash will be slower than reading them from RAM,
11+
but this will be a negligible difference when printing them to Serial.
12+
13+
More on F(), FPSTR() and PROGMEM:
14+
https://github.com/esp8266/Arduino/issues/1143
15+
https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html
16+
*/
17+
const char exampleMeshName[] PROGMEM = "MeshNode_";
18+
const char exampleWiFiPassword[] PROGMEM = "ChangeThisWiFiPassword_TODO";
519

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

1327
/* Create the mesh node object */
14-
ESP8266WiFiMesh meshNode = ESP8266WiFiMesh(manageRequest, manageResponse, networkFilter, "ChangeThisWiFiPassword_TODO", exampleMeshName, "", true);
28+
ESP8266WiFiMesh meshNode = ESP8266WiFiMesh(manageRequest, manageResponse, networkFilter, FPSTR(exampleWiFiPassword), FPSTR(exampleMeshName), "", true);
1529

1630
/**
1731
Callback for when other nodes send you a request
@@ -21,6 +35,11 @@ ESP8266WiFiMesh meshNode = ESP8266WiFiMesh(manageRequest, manageResponse, networ
2135
@returns The string to send back to the other node
2236
*/
2337
String manageRequest(const String &request, ESP8266WiFiMesh &meshInstance) {
38+
// We do not store strings in flash (via F()) in this function.
39+
// The reason is that the other node will be waiting for our response,
40+
// so keeping the strings in RAM will give a (small) improvement in response time.
41+
// Of course, it is advised to adjust this approach based on RAM requirements.
42+
2443
/* Print out received message */
2544
Serial.print("Request received: ");
2645
Serial.println(request);
@@ -29,28 +48,6 @@ String manageRequest(const String &request, ESP8266WiFiMesh &meshInstance) {
2948
return ("Hello world response #" + String(responseNumber++) + " from " + meshInstance.getMeshName() + meshInstance.getNodeID() + ".");
3049
}
3150

32-
/**
33-
Callback used to decide which networks to connect to once a WiFi scan has been completed.
34-
35-
@param numberOfNetworks The number of networks found in the WiFi scan.
36-
@param meshInstance The ESP8266WiFiMesh instance that called the function.
37-
*/
38-
void networkFilter(int numberOfNetworks, ESP8266WiFiMesh &meshInstance) {
39-
for (int i = 0; i < numberOfNetworks; ++i) {
40-
String currentSSID = WiFi.SSID(i);
41-
int meshNameIndex = currentSSID.indexOf(meshInstance.getMeshName());
42-
43-
/* Connect to any _suitable_ APs which contain meshInstance.getMeshName() */
44-
if (meshNameIndex >= 0) {
45-
uint64_t targetNodeID = ESP8266WiFiMesh::stringToUint64(currentSSID.substring(meshNameIndex + meshInstance.getMeshName().length()));
46-
47-
if (targetNodeID < ESP8266WiFiMesh::stringToUint64(meshInstance.getNodeID())) {
48-
ESP8266WiFiMesh::connectionQueue.push_back(NetworkInfo(i));
49-
}
50-
}
51-
}
52-
}
53-
5451
/**
5552
Callback for when you get a response from other nodes
5653
@@ -62,18 +59,41 @@ transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &me
6259
transmission_status_t statusCode = TS_TRANSMISSION_COMPLETE;
6360

6461
/* Print out received message */
65-
Serial.print("Request sent: ");
62+
Serial.print(F("Request sent: "));
6663
Serial.println(meshInstance.getMessage());
67-
Serial.print("Response received: ");
64+
Serial.print(F("Response received: "));
6865
Serial.println(response);
6966

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

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

75+
/**
76+
Callback used to decide which networks to connect to once a WiFi scan has been completed.
77+
78+
@param numberOfNetworks The number of networks found in the WiFi scan.
79+
@param meshInstance The ESP8266WiFiMesh instance that called the function.
80+
*/
81+
void networkFilter(int numberOfNetworks, ESP8266WiFiMesh &meshInstance) {
82+
for (int networkIndex = 0; networkIndex < numberOfNetworks; ++networkIndex) {
83+
String currentSSID = WiFi.SSID(networkIndex);
84+
int meshNameIndex = currentSSID.indexOf(meshInstance.getMeshName());
85+
86+
/* Connect to any _suitable_ APs which contain meshInstance.getMeshName() */
87+
if (meshNameIndex >= 0) {
88+
uint64_t targetNodeID = stringToUint64(currentSSID.substring(meshNameIndex + meshInstance.getMeshName().length()));
89+
90+
if (targetNodeID < stringToUint64(meshInstance.getNodeID())) {
91+
ESP8266WiFiMesh::connectionQueue.push_back(NetworkInfo(networkIndex));
92+
}
93+
}
94+
}
95+
}
96+
7797
void setup() {
7898
// Prevents the flash memory from being worn out, see: https://github.com/esp8266/Arduino/issues/1054 .
7999
// 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.
@@ -84,15 +104,19 @@ void setup() {
84104

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

107+
// The WiFi.disconnect() ensures that the WiFi is working correctly. If this is not done before receiving WiFi connections,
108+
// those WiFi connections will take a long time to make or sometimes will not work at all.
109+
WiFi.disconnect();
110+
87111
Serial.println();
88112
Serial.println();
89113

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

95-
Serial.println("Setting up mesh node...");
119+
Serial.println(F("Setting up mesh node..."));
96120

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

135+
// One way to check how attemptTransmission worked out
136+
if (ESP8266WiFiMesh::latestTransmissionSuccessful()) {
137+
Serial.println(F("Transmission successful."));
138+
}
139+
140+
// Another way to check how attemptTransmission worked out
111141
if (ESP8266WiFiMesh::latestTransmissionOutcomes.empty()) {
112-
Serial.println("No mesh AP found.");
142+
Serial.println(F("No mesh AP found."));
113143
} else {
114144
for (TransmissionResult &transmissionResult : ESP8266WiFiMesh::latestTransmissionOutcomes) {
115145
if (transmissionResult.transmissionStatus == TS_TRANSMISSION_FAILED) {
116-
Serial.println("Transmission failed to mesh AP " + transmissionResult.SSID);
146+
Serial.println(String(F("Transmission failed to mesh AP ")) + transmissionResult.SSID);
117147
} else if (transmissionResult.transmissionStatus == TS_CONNECTION_FAILED) {
118-
Serial.println("Connection failed to mesh AP " + transmissionResult.SSID);
148+
Serial.println(String(F("Connection failed to mesh AP ")) + transmissionResult.SSID);
119149
} else if (transmissionResult.transmissionStatus == TS_TRANSMISSION_COMPLETE) {
120150
// No need to do anything, transmission was successful.
121151
} else {
122-
Serial.println("Invalid transmission status for " + transmissionResult.SSID + "!");
152+
Serial.println(String(F("Invalid transmission status for ")) + transmissionResult.SSID + String(F("!")));
153+
assert(F("Invalid transmission status returned from responseHandler!") && false);
123154
}
124155
}
125156
}

libraries/ESP8266WiFiMesh/keywords.txt

+23-5
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,48 @@ transmission_status_t KEYWORD1
2323

2424
connectionQueue KEYWORD2
2525
latestTransmissionOutcomes KEYWORD2
26+
latestTransmissionSuccessful KEYWORD2
2627
begin KEYWORD2
2728
activateAP KEYWORD2
2829
deactivateAP KEYWORD2
2930
restartAP KEYWORD2
3031
getAPController KEYWORD2
3132
isAPController KEYWORD2
32-
getWiFiChannel KEYWORD2
3333
setWiFiChannel KEYWORD2
34-
getMeshName KEYWORD2
34+
getWiFiChannel KEYWORD2
3535
setMeshName KEYWORD2
36-
getNodeID KEYWORD2
36+
getMeshName KEYWORD2
3737
setNodeID KEYWORD2
38+
getNodeID KEYWORD2
3839
setSSID KEYWORD2
39-
getMessage KEYWORD2
40+
getSSID KEYWORD2
4041
setMessage KEYWORD2
42+
getMessage KEYWORD2
4143
attemptTransmission KEYWORD2
4244
acceptRequest KEYWORD2
4345
setStaticIP KEYWORD2
4446
getStaticIP KEYWORD2
4547
disableStaticIP->KEYWORD2
4648
uint64ToString KEYWORD2
4749
stringToUint64 KEYWORD2
48-
getNetworkFilter KEYWORD2
50+
setRequestHandler KEYWORD2
51+
getRequestHandler KEYWORD2
52+
setResponseHandler KEYWORD2
53+
getResponseHandler KEYWORD2
4954
setNetworkFilter KEYWORD2
55+
getNetworkFilter KEYWORD2
56+
setScanHidden KEYWORD2
57+
getScanHidden KEYWORD2
58+
setAPHidden KEYWORD2
59+
getAPHidden KEYWORD2
60+
setMaxAPStations KEYWORD2
61+
getMaxAPStations KEYWORD2
62+
setConnectionAttemptTimeout KEYWORD2
63+
getConnectionAttemptTimeout KEYWORD2
64+
setStationModeTimeout KEYWORD2
65+
getStationModeTimeout KEYWORD2
66+
setAPModeTimeout KEYWORD2
67+
getAPModeTimeout KEYWORD2
5068

5169
#######################################
5270
# Constants (LITERAL1)

libraries/ESP8266WiFiMesh/library.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=ESP8266WiFiMesh
2-
version=2.0
2+
version=2.1
33
author=Julian Fell
44
maintainer=Anders Löfgren
55
sentence=Mesh network library

0 commit comments

Comments
 (0)