From 8e9a2d2377502760bf50932db264251bcf5e0ae3 Mon Sep 17 00:00:00 2001 From: Anders Date: Thu, 10 May 2018 12:40:42 +0200 Subject: [PATCH 01/20] Make mesh network actually usable. Make mesh network use static IP during initial connection to speed up connection time. Add separate handlers for requests and responses. Add network password. Provide more detailed code example. Add optional verbose mode. Improve comments. Add readme file. --- libraries/ESP8266WiFiMesh/README.rst | 26 ++ .../examples/HelloMesh/HelloMesh.ino | 81 +++-- libraries/ESP8266WiFiMesh/keywords.txt | 4 +- libraries/ESP8266WiFiMesh/library.properties | 4 +- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 311 +++++++++++++----- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 96 +++--- 6 files changed, 380 insertions(+), 142 deletions(-) create mode 100644 libraries/ESP8266WiFiMesh/README.rst diff --git a/libraries/ESP8266WiFiMesh/README.rst b/libraries/ESP8266WiFiMesh/README.rst new file mode 100644 index 0000000000..8e688a4071 --- /dev/null +++ b/libraries/ESP8266WiFiMesh/README.rst @@ -0,0 +1,26 @@ +ESP8266 WiFi Mesh +================= + +A library for turning your ESP8266 into a mesh network node. + +The library has been tested and works with Arduino core for ESP8266 version 2.3.0 (with default lwIP) and 2.4.1 (with lwIP 1.4). Random disconnects and crashes seem to happen with the most recent master branch, so better stick to the release builds for now. + +Usage +----- + +See the included example. The main functions to modify are manageRequest and manageResponse. + +If using Arduino core for ESP8266 version 2.4.1, opt for lwIP v1.4 for now (can be changed in the Tools menu of Arduino IDE). Nodes seem to be unable to connect to more than one other node when using lwIP 2.0! + +Note that this library uses static IP:s for the nodes to speed up initial connection. Please use the setStaticIP method to 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). Station gateway IP must match the IP for the server on the nodes. + +Also, remember to change the default mesh network password! + +Some things to keep in mind +--------------------------- + +A maximum of 5 stations can be connected at a time to each AP. + +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 disconnect all stations connected to the node AP (though they can request a reconnect even while the previous AP node is in STA mode). + +Scanning for networks (e.g. via the attemptTransmission method) causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index efbbeb7e92..6d9fb25fc6 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -5,19 +5,21 @@ unsigned int request_i = 0; unsigned int response_i = 0; String manageRequest(String request); +void manageResponse(String response); /* Create the mesh node object */ -ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(ESP.getChipId(), manageRequest); +ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(ESP.getChipId(), manageRequest, manageResponse, true); /** - Callback for when other nodes send you data - - @request The string received from another node in the mesh - @returns The string to send back to the other node -*/ -String manageRequest(String request) { + * Callback for when other nodes send you a request + * + * @request The request string received from another node in the mesh + * @returns The string to send back to the other node + */ +String manageRequest(String request) +{ /* Print out received message */ - Serial.print("received: "); + Serial.print("Request received: "); Serial.println(request); /* return a string to send back */ @@ -26,25 +28,66 @@ String manageRequest(String request) { return response; } -void setup() { +/** + * Callback for when you get a response from other nodes + * + * @response The response string received from another node in the mesh + */ +void manageResponse(String response) +{ + /* Print out received message */ + Serial.print("Response received: "); + Serial.println(response); + + request_i++; // Our last request got a response, so time to create a new request. +} + +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. + WiFi.persistent(false); + Serial.begin(115200); - delay(10); + delay(50); // Wait for Serial. + //yield(); // Use this if you don't want to wait for Serial. + Serial.println(); Serial.println(); + + Serial.println("Note that this library uses static IP:s for the nodes to speed up initial connection.\n" + "Please use the setStaticIP method to 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("Please use lwIP v1.4 with this library for now (can be changed in the Tools menu of Arduino IDE).\n" + "Nodes seem to be unable to connect to more than one other node when using lwIP 2.0!\n\n"); + Serial.println("Setting up mesh node..."); /* Initialise the mesh node */ + mesh_node.setStaticIP(IPAddress(192,168,4,22)); mesh_node.begin(); } -void loop() { - /* Accept any incoming connections */ - mesh_node.acceptRequest(); - - /* Scan for other nodes and send them a message */ - char request[60]; - sprintf(request, "Hello world request #%d from Mesh_Node%d.", request_i++, ESP.getChipId()); - mesh_node.attemptScan(request); - delay(1000); +int32_t time_of_last_scan = -10000; +void loop() +{ + if(millis() - time_of_last_scan > 3000 // Give other nodes some time to connect between data transfers. + || (WiFi.status() != WL_CONNECTED && millis() - time_of_last_scan > 1000)) // Scan for networks once per second when not already connected. + { + /* + * attemptTransmission(request) will either scan for other nodes and send the request to the first node it connects to + * or if connection to an AP already exists just send the request to that AP. + */ + char request[60]; + sprintf(request, "Hello world request #%d from Mesh_Node%d.", request_i, ESP.getChipId()); + mesh_node.attemptTransmission(request); + time_of_last_scan = millis(); + } + else + { + /* Accept any incoming connections */ + mesh_node.acceptRequest(); + } } diff --git a/libraries/ESP8266WiFiMesh/keywords.txt b/libraries/ESP8266WiFiMesh/keywords.txt index 14657d805c..f532236a52 100644 --- a/libraries/ESP8266WiFiMesh/keywords.txt +++ b/libraries/ESP8266WiFiMesh/keywords.txt @@ -19,5 +19,7 @@ ESP8266WiFiMesh KEYWORD1 ####################################### begin KEYWORD2 -attemptScan KEYWORD2 +attemptTransmission KEYWORD2 acceptRequest KEYWORD2 +setStaticIP KEYWORD2 +getStaticIP KEYWORD2 diff --git a/libraries/ESP8266WiFiMesh/library.properties b/libraries/ESP8266WiFiMesh/library.properties index dc6ba9a4da..5dc4dec11a 100644 --- a/libraries/ESP8266WiFiMesh/library.properties +++ b/libraries/ESP8266WiFiMesh/library.properties @@ -1,7 +1,7 @@ name=ESP8266WiFiMesh -version=1.0 +version=2.0 author=Julian Fell -maintainer= +maintainer=Anders Löfgren sentence=Mesh network library paragraph=The library sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. category=Communication diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index 6d3e544d7c..52c5066116 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -4,6 +4,7 @@ is passed in both directions, but it is up to the user what the data sent is and how it is dealt with. Copyright (c) 2015 Julian Fell. All rights reserved. + Updated 2018 by Anders Löfgren. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -25,24 +26,55 @@ #include "ESP8266WiFiMesh.h" -#define SSID_PREFIX "Mesh_Node" -#define SERVER_IP_ADDR "192.168.4.1" -#define SERVER_PORT 4011 +#define SSID_PREFIX "Mesh_Node" +#define SERVER_IP_ADDR "192.168.4.1" +#define SERVER_PORT 4011 -ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, std::function handler) -: _server(SERVER_PORT) +const char mesh_password[] = "TODOChangeToSomethingBetter"; + +ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, std::function requestHandler, std::function responseHandler, bool verbose_mode) +: _server(SERVER_PORT), DHCP_activated(false), last_ssid(""), static_IP(192,168,4,22), gateway(192,168,4,1), subnet_mask(255,255,255,0) // IP needs to be at the same subnet as server gateway (192.168.4 in this case). Station gateway ip must match ip for server. +{ + _chip_id = chip_id; + _ssid = String( String( SSID_PREFIX ) + String( _chip_id ) ); + _ssid_prefix = String( SSID_PREFIX ); + _requestHandler = requestHandler; + _responseHandler = responseHandler; + _verbose_mode = verbose_mode; +} + +void ESP8266WiFiMesh::setStaticIP(IPAddress new_ip) +{ + static_IP = new_ip; +} + +IPAddress ESP8266WiFiMesh::getStaticIP() { - _chip_id = chip_id; - _ssid = String( String( SSID_PREFIX ) + String( _chip_id ) ); - _ssid_prefix = String( SSID_PREFIX ); - _handler = handler; + return static_IP; } void ESP8266WiFiMesh::begin() { - WiFi.mode(WIFI_AP_STA); - WiFi.softAP( _ssid.c_str() ); - _server.begin(); + WiFi.mode(WIFI_AP_STA); + WiFi.softAP( _ssid.c_str(), mesh_password ); // Note that a maximum of 5 stations can be connected at a time to each AP + _server.begin(); + + // Comment out the line below to remove static IP and use DHCP instead. + // DHCP makes WiFi connection happen slower, but there is no need to care about manually giving different IPs to the nodes and less need to worry about used IPs giving "Server unavailable" issues. + // Static IP is faster and will make sending of data to a node that is already transmitting data happen more reliably. + // Note that after WiFi.config(static_IP, gateway, subnet_mask) is used, static IP will always be active, even for new connections, unless WiFi.config(0u,0u,0u); is called. + WiFi.config(static_IP, gateway, subnet_mask); +} + +/** + * Disconnect completely from a network. + */ +void ESP8266WiFiMesh::fullStop(WiFiClient curr_client) +{ + curr_client.stop(); + yield(); + WiFi.disconnect(); + yield(); } /** @@ -53,20 +85,24 @@ void ESP8266WiFiMesh::begin() */ bool ESP8266WiFiMesh::waitForClient(WiFiClient curr_client, int max_wait) { - int wait = max_wait; - while(curr_client.connected() && !curr_client.available() && wait--) - delay(3); - - /* Return false if the client isn't ready to communicate */ - if (WiFi.status() == WL_DISCONNECTED || !curr_client.connected()) - return false; - - return true; + int wait = max_wait; + while(curr_client.connected() && !curr_client.available() && wait--) + delay(3); + + /* Return false if the client isn't ready to communicate */ + if (WiFi.status() == WL_DISCONNECTED || !curr_client.connected()) + { + if(_verbose_mode) + Serial.println("Disconnected!"); + return false; + } + + return true; } /** * Send the supplied message then read back the other node's response - * and pass that to the user-supplied handler. + * and pass that to the user-supplied responseHandler. * * @target_ssid The name of the AP the other node has set up. * @message The string to send to the node. @@ -75,94 +111,203 @@ bool ESP8266WiFiMesh::waitForClient(WiFiClient curr_client, int max_wait) */ bool ESP8266WiFiMesh::exchangeInfo(String message, WiFiClient curr_client) { - curr_client.println( message.c_str() ); + if(_verbose_mode) + Serial.println("Transmitting"); + + curr_client.print(message + "\r"); + yield(); - if (!waitForClient(curr_client, 1000)) - return false; + if (!waitForClient(curr_client, 1000)) + { + fullStop(curr_client); + return false; + } - String response = curr_client.readStringUntil('\r'); - curr_client.readStringUntil('\n'); + String response = curr_client.readStringUntil('\r'); + yield(); + curr_client.flush(); - if (response.length() <= 2) - return false; + if (response.length() <= 2) + { + if(_verbose_mode) + Serial.println("Small response!"); + return false; + } - /* Pass data to user callback */ - _handler(response); - return true; + /* Pass data to user callback */ + _responseHandler(response); + return true; } /** - * Connect to the AP at ssid, send them a message then disconnect. + * Handle data transfer process with a connected AP. + * + * @message The string to send to the AP. + * @returns: True if data transfer process successful, false otherwise. + */ +bool ESP8266WiFiMesh::attemptDataTransfer(String message) +{ + // 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). + WiFi.mode(WIFI_STA); + delay(100); + bool result = attemptDataTransferKernel(message); + WiFi.mode(WIFI_AP_STA); + delay(100); + + return result; +} + +/** + * Helper function that contains the core functionality for the data transfer process with a connected AP. + * + * @message The string to send to the AP. + * @returns: True if data transfer process successful, false otherwise. + */ +bool ESP8266WiFiMesh::attemptDataTransferKernel(String message) +{ + WiFiClient curr_client; + + /* Connect to the node's server */ + if (!curr_client.connect(SERVER_IP_ADDR, SERVER_PORT)) + { + fullStop(curr_client); + if(_verbose_mode) + Serial.println("Server unavailable"); + return false; + } + + if (!exchangeInfo(message, curr_client)) + { + if(_verbose_mode) + Serial.println("Transmission failed during exchangeInfo."); + return false; + } + + curr_client.stop(); + yield(); + + return true; +} + +/** + * Connect to the AP at ssid and send them a message. * * @target_ssid The name of the AP the other node has set up. * @message The string to send to the node. + * @target_channel The WiFI channel of the AP the other node has set up. + * @target_bssid The mac address of the AP the other node has set up. * */ -void ESP8266WiFiMesh::connectToNode(String target_ssid, String message) +void ESP8266WiFiMesh::connectToNode(String target_ssid, String message, int target_channel, uint8_t *target_bssid) { - WiFiClient curr_client; - WiFi.begin( target_ssid.c_str() ); + if(!DHCP_activated && last_ssid != "" && last_ssid != target_ssid) + { + WiFi.config(0u,0u,0u); // Deactivate 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?)). + yield(); + DHCP_activated = true; // So we only do this once, in case there is a performance impact. + if(_verbose_mode) + Serial.println("\nConnecting to a second network. Static IP deactivated."); + } + last_ssid = target_ssid; - int wait = 1500; - while((WiFi.status() == WL_DISCONNECTED) && wait--) - delay(3); + if(_verbose_mode) + Serial.print("Connecting... "); + WiFi.begin( target_ssid.c_str(), mesh_password, target_channel, target_bssid ); // Without giving channel and bssid, connection time is longer. - /* If the connection timed out */ - if (WiFi.status() != 3) - return; + int connection_start_time = millis(); + int attempt_number = 1; - /* Connect to the node's server */ - if (!curr_client.connect(SERVER_IP_ADDR, SERVER_PORT)) - return; + int waiting_time = millis() - connection_start_time; + while((WiFi.status() == WL_DISCONNECTED) && waiting_time <= 10000) + { + if(waiting_time > attempt_number * 10000) // 10000 can be lowered if you want to limit the time allowed for each connection attempt. + { + if(_verbose_mode) + Serial.print("... "); + WiFi.disconnect(); + yield(); + WiFi.begin( target_ssid.c_str(), mesh_password, target_channel, target_bssid ); // Without giving channel and bssid, connection time is longer. + attempt_number++; + } + delay(1); + waiting_time = millis() - connection_start_time; + } - if (!exchangeInfo(message, curr_client)) - return; + if(_verbose_mode) + Serial.println(waiting_time); + + /* If the connection timed out */ + if (WiFi.status() != WL_CONNECTED) + { + if(_verbose_mode) + Serial.println("Timeout"); + return; + } - curr_client.stop(); - WiFi.disconnect(); + attemptDataTransfer(message); } -void ESP8266WiFiMesh::attemptScan(String message) +void ESP8266WiFiMesh::attemptTransmission(String message) { - /* Scan for APs */ - int n = WiFi.scanNetworks(); - - for (int i = 0; i < n; ++i) { - String current_ssid = WiFi.SSID(i); - int index = current_ssid.indexOf( _ssid_prefix ); - uint32_t target_chip_id = (current_ssid.substring(index + _ssid_prefix.length())).toInt(); - - /* Connect to any _suitable_ APs which contain _ssid_prefix */ - if (index >= 0 && (target_chip_id < _chip_id)) { - - WiFi.mode(WIFI_STA); - delay(100); - connectToNode(current_ssid, message); - WiFi.mode(WIFI_AP_STA); - delay(100); - } - } + if(WiFi.status() == WL_CONNECTED) + { + attemptDataTransfer(message); + } + else + { + if(_verbose_mode) + Serial.print("Scanning... "); + + /* Scan for APs */ + int n = WiFi.scanNetworks(); // Scanning causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. + + for (int i = 0; i < n; ++i) + { + String current_ssid = WiFi.SSID(i); + int index = current_ssid.indexOf( _ssid_prefix ); + uint32_t target_chip_id = (current_ssid.substring(index + _ssid_prefix.length())).toInt(); + + /* Connect to any _suitable_ APs which contain _ssid_prefix */ + if (index >= 0 && (target_chip_id < _chip_id)) + { + if(_verbose_mode) + Serial.printf("First match: %s, Ch:%d (%ddBm) %s... ", WiFi.SSID(i).c_str(), WiFi.channel(i), WiFi.RSSI(i), WiFi.encryptionType(i) == ENC_TYPE_NONE ? "open" : ""); + + connectToNode(current_ssid, message, WiFi.channel(i), WiFi.BSSID(i)); + + break; + } + } + } } void ESP8266WiFiMesh::acceptRequest() { - while (true) { - _client = _server.available(); - if (!_client) - break; + while (true) { + _client = _server.available(); + if (!_client) + break; - if (!waitForClient(_client, 1500)) { - continue; - } + if (!waitForClient(_client, 1500)) { + continue; + } - /* Read in request and pass it to the supplied handler */ - String request = _client.readStringUntil('\r'); - _client.readStringUntil('\n'); + /* Read in request and pass it to the supplied requestHandler */ + String request = _client.readStringUntil('\r'); + yield(); + _client.flush(); - String response = _handler(request); + String response = _requestHandler(request); - /* Send the response back to the client */ - if (_client.connected()) - _client.println(response); - } + /* Send the response back to the client */ + if (_client.connected()) + { + if(_verbose_mode) + Serial.println("Responding"); + _client.print(response + "\r"); + yield(); + } + } } diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index dd959731bb..8e2f8e161e 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -4,6 +4,7 @@ is passed in both directions, but it is up to the user what the data sent is and how it is dealt with. Copyright (c) 2015 Julian Fell. All rights reserved. + Updated 2018 by Anders Löfgren. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -28,48 +29,69 @@ class ESP8266WiFiMesh { private: - String _ssid; - String _ssid_prefix; - uint32_t _chip_id; + String _ssid; + String _ssid_prefix; + uint32_t _chip_id; + bool _verbose_mode; - std::function _handler; - - WiFiServer _server; - WiFiClient _client; + bool DHCP_activated; - void connectToNode(String target_ssid, String message); - bool exchangeInfo(String message, WiFiClient curr_client); - bool waitForClient(WiFiClient curr_client, int max_wait); + IPAddress static_IP; + IPAddress gateway; + IPAddress subnet_mask; + + String last_ssid; + + std::function _requestHandler; + std::function _responseHandler; + + WiFiServer _server; + WiFiClient _client; + + void fullStop(WiFiClient curr_client); + void connectToNode(String target_ssid, String message, int target_channel, uint8_t *target_bssid); + bool exchangeInfo(String message, WiFiClient curr_client); + bool waitForClient(WiFiClient curr_client, int max_wait); + bool attemptDataTransfer(String message); + bool attemptDataTransferKernel(String message); public: - /** - * WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised. - * - * @chip_id A unique identifier number for the node. - * @handler The callback handler for dealing with received messages. Takes a string as an argument which - * is the string received from another node and returns the string to send back. - * - */ - ESP8266WiFiMesh(uint32_t chip_id, std::function handler); - - /** - * Initialises the node. - */ - void begin(); - - /** - * Scan for other nodes, and exchange the chosen message with any that are found. - * - * @message The message to send to all other nodes. - * - */ - void attemptScan(String message); - - /** - * If any clients are connected, accept their requests and call the hander function for each one. - */ - void acceptRequest(); + /** + * WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised. + * + * @chip_id A unique identifier number for the node. + * @requestHandler The callback handler for dealing with received requests. Takes a string as an argument which + * is the request string received from another node and returns the string to send back. + * @responseHandler The callback handler for dealing with received responses. Takes a string as an argument which + * is the response string received from another node. + * @verbose_mode Determines if we should print the events occurring in the library to Serial. Off by default. + * + */ + ESP8266WiFiMesh(uint32_t chip_id, std::function requestHandler, std::function responseHandler, bool verbose_mode = false); + + /** + * Initialises the node. + */ + void begin(); + + /** + * If AP connection exists, send message to AP. + * Otherwise, scan for other nodes and exchange the chosen message with any that are found. + * + * @message The message to send to other nodes. + * + */ + void attemptTransmission(String message); + + /** + * If any clients are connected, accept their requests and call the requestHandler function for each one. + */ + void acceptRequest(); + + // IP needs to be at the same subnet as server gateway + void setStaticIP(IPAddress new_ip); + IPAddress getStaticIP(); }; #endif From 139c4deac2cec2e99be8854217e9439d447f7aee Mon Sep 17 00:00:00 2001 From: Anders Date: Thu, 10 May 2018 14:45:38 +0200 Subject: [PATCH 02/20] Fix compiler warnings. Fix code style of HelloMesh.ino to avoid upsetting Travis. --- .../examples/HelloMesh/HelloMesh.ino | 57 ++++++++----------- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 9 ++- 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index 6d9fb25fc6..922683a754 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -11,13 +11,12 @@ void manageResponse(String response); ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(ESP.getChipId(), manageRequest, manageResponse, true); /** - * Callback for when other nodes send you a request - * - * @request The request string received from another node in the mesh - * @returns The string to send back to the other node + Callback for when other nodes send you a request + + @request The request string received from another node in the mesh + @returns The string to send back to the other node */ -String manageRequest(String request) -{ +String manageRequest(String request) { /* Print out received message */ Serial.print("Request received: "); Serial.println(request); @@ -29,64 +28,58 @@ String manageRequest(String request) } /** - * Callback for when you get a response from other nodes - * - * @response The response string received from another node in the mesh + Callback for when you get a response from other nodes + + @response The response string received from another node in the mesh */ -void manageResponse(String response) -{ +void manageResponse(String response) { /* Print out received message */ Serial.print("Response received: "); Serial.println(response); - + request_i++; // Our last request got a response, so time to create a new request. } -void setup() -{ +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. WiFi.persistent(false); - + Serial.begin(115200); delay(50); // Wait for Serial. //yield(); // Use this if you don't want to wait for Serial. - + Serial.println(); Serial.println(); - + Serial.println("Note that this library uses static IP:s for the nodes to speed up initial connection.\n" - "Please use the setStaticIP method to 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"); + "Please use the setStaticIP method to 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("Please use lwIP v1.4 with this library for now (can be changed in the Tools menu of Arduino IDE).\n" - "Nodes seem to be unable to connect to more than one other node when using lwIP 2.0!\n\n"); - + "Nodes seem to be unable to connect to more than one other node when using lwIP 2.0!\n\n"); + Serial.println("Setting up mesh node..."); /* Initialise the mesh node */ - mesh_node.setStaticIP(IPAddress(192,168,4,22)); + mesh_node.setStaticIP(IPAddress(192, 168, 4, 22)); mesh_node.begin(); } int32_t time_of_last_scan = -10000; -void loop() -{ - if(millis() - time_of_last_scan > 3000 // Give other nodes some time to connect between data transfers. - || (WiFi.status() != WL_CONNECTED && millis() - time_of_last_scan > 1000)) // Scan for networks once per second when not already connected. - { +void loop() { + if (millis() - time_of_last_scan > 3000 // Give other nodes some time to connect between data transfers. + || (WiFi.status() != WL_CONNECTED && millis() - time_of_last_scan > 1000)) { // Scan for networks once per second when not already connected. /* - * attemptTransmission(request) will either scan for other nodes and send the request to the first node it connects to - * or if connection to an AP already exists just send the request to that AP. + attemptTransmission(request) will either scan for other nodes and send the request to the first node it connects to + or if connection to an AP already exists just send the request to that AP. */ char request[60]; sprintf(request, "Hello world request #%d from Mesh_Node%d.", request_i, ESP.getChipId()); mesh_node.attemptTransmission(request); time_of_last_scan = millis(); - } - else - { + } else { /* Accept any incoming connections */ mesh_node.acceptRequest(); } diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 8e2f8e161e..01e843a75f 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -34,19 +34,18 @@ class ESP8266WiFiMesh { uint32_t _chip_id; bool _verbose_mode; + WiFiServer _server; + WiFiClient _client; + bool DHCP_activated; + String last_ssid; IPAddress static_IP; IPAddress gateway; IPAddress subnet_mask; - String last_ssid; - std::function _requestHandler; std::function _responseHandler; - - WiFiServer _server; - WiFiClient _client; void fullStop(WiFiClient curr_client); void connectToNode(String target_ssid, String message, int target_channel, uint8_t *target_bssid); From b1c32367cd543f4b57ace63b9f56e386f50048e4 Mon Sep 17 00:00:00 2001 From: Anders Date: Thu, 10 May 2018 15:19:10 +0200 Subject: [PATCH 03/20] Remove stray spaces. --- .../ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index 922683a754..8c36866db2 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -15,7 +15,7 @@ ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(ESP.getChipId(), manageRequest, mana @request The request string received from another node in the mesh @returns The string to send back to the other node - */ +*/ String manageRequest(String request) { /* Print out received message */ Serial.print("Request received: "); @@ -31,7 +31,7 @@ String manageRequest(String request) { Callback for when you get a response from other nodes @response The response string received from another node in the mesh - */ +*/ void manageResponse(String response) { /* Print out received message */ Serial.print("Response received: "); @@ -41,7 +41,7 @@ void manageResponse(String response) { } void setup() { - // Prevents the flash memory from being worn out, see: https://github.com/esp8266/Arduino/issues/1054 . + // 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. WiFi.persistent(false); @@ -57,7 +57,7 @@ void setup() { "Please use the setStaticIP method to 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("Please use lwIP v1.4 with this library for now (can be changed in the Tools menu of Arduino IDE).\n" + Serial.println("Please use lwIP v1.4 with this library for now (can be changed in the Tools menu of Arduino IDE).\n" "Nodes seem to be unable to connect to more than one other node when using lwIP 2.0!\n\n"); Serial.println("Setting up mesh node..."); @@ -71,7 +71,7 @@ int32_t time_of_last_scan = -10000; void loop() { if (millis() - time_of_last_scan > 3000 // Give other nodes some time to connect between data transfers. || (WiFi.status() != WL_CONNECTED && millis() - time_of_last_scan > 1000)) { // Scan for networks once per second when not already connected. - /* + /* attemptTransmission(request) will either scan for other nodes and send the request to the first node it connects to or if connection to an AP already exists just send the request to that AP. */ From c6397f5869d3297f3413b8d7ec2e3a357bb4d430 Mon Sep 17 00:00:00 2001 From: Anders Date: Fri, 11 May 2018 16:21:54 +0200 Subject: [PATCH 04/20] Make mesh network WiFi password settable via the ESP8266WiFiMesh constructor. Make use of static IP optional by moving static IP initialization code to setStaticIP method. Increase scanning interval from one to two seconds in the HelloMesh.ino example to increase chances of successful connections. Update comments. Update README.rst. --- libraries/ESP8266WiFiMesh/README.rst | 4 +-- .../examples/HelloMesh/HelloMesh.ino | 6 ++-- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 35 ++++++++++--------- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 13 ++++--- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/README.rst b/libraries/ESP8266WiFiMesh/README.rst index 8e688a4071..c883553738 100644 --- a/libraries/ESP8266WiFiMesh/README.rst +++ b/libraries/ESP8266WiFiMesh/README.rst @@ -12,9 +12,9 @@ See the included example. The main functions to modify are manageRequest and man If using Arduino core for ESP8266 version 2.4.1, opt for lwIP v1.4 for now (can be changed in the Tools menu of Arduino IDE). Nodes seem to be unable to connect to more than one other node when using lwIP 2.0! -Note that this library uses static IP:s for the nodes to speed up initial connection. Please use the setStaticIP method to 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). Station gateway IP must match the IP for the server on the nodes. +Note that this library can use static IP:s for the nodes to speed up initial connection. 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. -Also, remember to change the default mesh network password! +Also, remember to change the default mesh network WiFi password! Some things to keep in mind --------------------------- diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index 8c36866db2..ccc77d5aaa 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -8,7 +8,7 @@ String manageRequest(String request); void manageResponse(String response); /* Create the mesh node object */ -ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(ESP.getChipId(), manageRequest, manageResponse, true); +ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(ESP.getChipId(), manageRequest, manageResponse, "ChangeThisWiFiPassword_TODO", true); /** Callback for when other nodes send you a request @@ -63,14 +63,14 @@ void setup() { Serial.println("Setting up mesh node..."); /* Initialise the mesh node */ - mesh_node.setStaticIP(IPAddress(192, 168, 4, 22)); mesh_node.begin(); + mesh_node.setStaticIP(IPAddress(192, 168, 4, 22)); // Activate static IP mode for faster initial connection. } int32_t time_of_last_scan = -10000; void loop() { if (millis() - time_of_last_scan > 3000 // Give other nodes some time to connect between data transfers. - || (WiFi.status() != WL_CONNECTED && millis() - time_of_last_scan > 1000)) { // Scan for networks once per second when not already connected. + || (WiFi.status() != WL_CONNECTED && millis() - time_of_last_scan > 2000)) { // Scan for networks with two second intervals when not already connected. /* attemptTransmission(request) will either scan for other nodes and send the request to the first node it connects to or if connection to an AP already exists just send the request to that AP. diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index 52c5066116..80b3be9eb2 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -30,22 +30,29 @@ #define SERVER_IP_ADDR "192.168.4.1" #define SERVER_PORT 4011 -const char mesh_password[] = "TODOChangeToSomethingBetter"; +const IPAddress empty_IP = IPAddress(); -ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, std::function requestHandler, std::function responseHandler, bool verbose_mode) -: _server(SERVER_PORT), DHCP_activated(false), last_ssid(""), static_IP(192,168,4,22), gateway(192,168,4,1), subnet_mask(255,255,255,0) // IP needs to be at the same subnet as server gateway (192.168.4 in this case). Station gateway ip must match ip for server. +ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, std::function requestHandler, std::function responseHandler, String mesh_password, bool verbose_mode) +: _server(SERVER_PORT), last_ssid(""), static_IP(empty_IP), gateway(192,168,4,1), subnet_mask(255,255,255,0) // IP needs to be at the same subnet as server gateway (192.168.4 in this case). Station gateway ip must match ip for server. { _chip_id = chip_id; _ssid = String( String( SSID_PREFIX ) + String( _chip_id ) ); _ssid_prefix = String( SSID_PREFIX ); _requestHandler = requestHandler; _responseHandler = responseHandler; + _mesh_password = mesh_password; _verbose_mode = verbose_mode; } -void ESP8266WiFiMesh::setStaticIP(IPAddress new_ip) +void ESP8266WiFiMesh::setStaticIP(IPAddress new_IP) { - static_IP = new_ip; + // Comment out the line below to remove static IP and use DHCP instead. + // DHCP makes WiFi connection happen slower, but there is no need to care about manually giving different IPs to the nodes and less need to worry about used IPs giving "Server unavailable" issues. + // Static IP is faster and will make sending of data to a node that is already transmitting data happen more reliably. + // Note that after WiFi.config(static_IP, gateway, subnet_mask) is used, static IP will always be active, even for new connections, unless WiFi.config(0u,0u,0u); is called. + WiFi.config(new_IP, gateway, subnet_mask); + + static_IP = new_IP; } IPAddress ESP8266WiFiMesh::getStaticIP() @@ -56,14 +63,8 @@ IPAddress ESP8266WiFiMesh::getStaticIP() void ESP8266WiFiMesh::begin() { WiFi.mode(WIFI_AP_STA); - WiFi.softAP( _ssid.c_str(), mesh_password ); // Note that a maximum of 5 stations can be connected at a time to each AP + WiFi.softAP( _ssid.c_str(), _mesh_password.c_str() ); // Note that a maximum of 5 stations can be connected at a time to each AP _server.begin(); - - // Comment out the line below to remove static IP and use DHCP instead. - // DHCP makes WiFi connection happen slower, but there is no need to care about manually giving different IPs to the nodes and less need to worry about used IPs giving "Server unavailable" issues. - // Static IP is faster and will make sending of data to a node that is already transmitting data happen more reliably. - // Note that after WiFi.config(static_IP, gateway, subnet_mask) is used, static IP will always be active, even for new connections, unless WiFi.config(0u,0u,0u); is called. - WiFi.config(static_IP, gateway, subnet_mask); } /** @@ -202,19 +203,19 @@ bool ESP8266WiFiMesh::attemptDataTransferKernel(String message) */ void ESP8266WiFiMesh::connectToNode(String target_ssid, String message, int target_channel, uint8_t *target_bssid) { - if(!DHCP_activated && last_ssid != "" && last_ssid != target_ssid) + if(static_IP != empty_IP && last_ssid != "" && last_ssid != target_ssid) { WiFi.config(0u,0u,0u); // Deactivate 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?)). yield(); - DHCP_activated = true; // So we only do this once, in case there is a performance impact. + static_IP = empty_IP; // So we only do this once, in case there is a performance impact. if(_verbose_mode) - Serial.println("\nConnecting to a second network. Static IP deactivated."); + Serial.println("\nConnecting to a second network. Static IP deactivated to make this possible."); } last_ssid = target_ssid; if(_verbose_mode) Serial.print("Connecting... "); - WiFi.begin( target_ssid.c_str(), mesh_password, target_channel, target_bssid ); // Without giving channel and bssid, connection time is longer. + WiFi.begin( target_ssid.c_str(), _mesh_password.c_str(), target_channel, target_bssid ); // Without giving channel and bssid, connection time is longer. int connection_start_time = millis(); int attempt_number = 1; @@ -228,7 +229,7 @@ void ESP8266WiFiMesh::connectToNode(String target_ssid, String message, int targ Serial.print("... "); WiFi.disconnect(); yield(); - WiFi.begin( target_ssid.c_str(), mesh_password, target_channel, target_bssid ); // Without giving channel and bssid, connection time is longer. + WiFi.begin( target_ssid.c_str(), _mesh_password.c_str(), target_channel, target_bssid ); // Without giving channel and bssid, connection time is longer. attempt_number++; } delay(1); diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 01e843a75f..6d31ec0a42 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -32,12 +32,12 @@ class ESP8266WiFiMesh { String _ssid; String _ssid_prefix; uint32_t _chip_id; + String _mesh_password; bool _verbose_mode; WiFiServer _server; WiFiClient _client; - bool DHCP_activated; String last_ssid; IPAddress static_IP; @@ -64,10 +64,11 @@ class ESP8266WiFiMesh { * is the request string received from another node and returns the string to send back. * @responseHandler The callback handler for dealing with received responses. Takes a string as an argument which * is the response string received from another node. + * @mesh_password The WiFi password for the mesh network. * @verbose_mode Determines if we should print the events occurring in the library to Serial. Off by default. * */ - ESP8266WiFiMesh(uint32_t chip_id, std::function requestHandler, std::function responseHandler, bool verbose_mode = false); + ESP8266WiFiMesh(uint32_t chip_id, std::function requestHandler, std::function responseHandler, String mesh_password, bool verbose_mode = false); /** * Initialises the node. @@ -88,8 +89,12 @@ class ESP8266WiFiMesh { */ void acceptRequest(); - // IP needs to be at the same subnet as server gateway - void setStaticIP(IPAddress new_ip); + /** + * Set a static IP address for the node and activate use of static IP. + * The static IP needs to be at the same subnet as the server's gateway. + */ + void setStaticIP(IPAddress new_IP); + IPAddress getStaticIP(); }; From 4fb131f223f17a72629d644392220d73e679b16b Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 5 Jun 2018 19:19:03 +0200 Subject: [PATCH 05/20] Increase specificity in the conditions of the waitForClientTransmission method (renamed from waitForClient) to avoid issues related to #4626 , #4728 and #4754 in the future. --- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 25 ++++++++++--------- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index 80b3be9eb2..90b4b10fe4 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -79,19 +79,19 @@ void ESP8266WiFiMesh::fullStop(WiFiClient curr_client) } /** - * Wait for a WiFiClient to connect + * Wait for a WiFiClient to transmit * * @returns: True if the client is ready, false otherwise. * */ -bool ESP8266WiFiMesh::waitForClient(WiFiClient curr_client, int max_wait) +bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient curr_client, int max_wait) { int wait = max_wait; while(curr_client.connected() && !curr_client.available() && wait--) delay(3); /* Return false if the client isn't ready to communicate */ - if (WiFi.status() == WL_DISCONNECTED || !curr_client.connected()) + if (WiFi.status() == WL_DISCONNECTED && !curr_client.available()) { if(_verbose_mode) Serial.println("Disconnected!"); @@ -118,23 +118,23 @@ bool ESP8266WiFiMesh::exchangeInfo(String message, WiFiClient curr_client) curr_client.print(message + "\r"); yield(); - if (!waitForClient(curr_client, 1000)) + if (!waitForClientTransmission(curr_client, 1000)) { fullStop(curr_client); return false; } - String response = curr_client.readStringUntil('\r'); - yield(); - curr_client.flush(); - - if (response.length() <= 2) + if (!curr_client.available()) { if(_verbose_mode) - Serial.println("Small response!"); - return false; + Serial.println("No response!"); + return false; // WiFi.status() != WL_DISCONNECTED so we do not want to use fullStop(curr_client) here since that would force the node to scan for WiFi networks. } + String response = curr_client.readStringUntil('\r'); + yield(); + curr_client.flush(); + /* Pass data to user callback */ _responseHandler(response); return true; @@ -291,7 +291,7 @@ void ESP8266WiFiMesh::acceptRequest() if (!_client) break; - if (!waitForClient(_client, 1500)) { + if (!waitForClientTransmission(_client, 1500) || !_client.available()) { continue; } @@ -308,6 +308,7 @@ void ESP8266WiFiMesh::acceptRequest() if(_verbose_mode) Serial.println("Responding"); _client.print(response + "\r"); + _client.flush(); yield(); } } diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 6d31ec0a42..428b61fd41 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -50,7 +50,7 @@ class ESP8266WiFiMesh { void fullStop(WiFiClient curr_client); void connectToNode(String target_ssid, String message, int target_channel, uint8_t *target_bssid); bool exchangeInfo(String message, WiFiClient curr_client); - bool waitForClient(WiFiClient curr_client, int max_wait); + bool waitForClientTransmission(WiFiClient curr_client, int max_wait); bool attemptDataTransfer(String message); bool attemptDataTransferKernel(String message); From b5ea4959c2b2ea37e3c0ff7cadc1d69cec1045f5 Mon Sep 17 00:00:00 2001 From: Anders Date: Mon, 9 Jul 2018 02:18:50 +0200 Subject: [PATCH 06/20] Improve most parts of the library to achieve better performance and greatly increase flexibility. Changes: * Make WiFi-connection related variables static to allow for the use of multiple ESP8266WiFiMesh instances on a single node (useful e.g. when communicating with several different mesh networks). * Make it possible to choose AP port, which is helpful when using multiple ESP8266WiFiMesh AP:s on a single node. * Add user-customizable network filter. * Make activation of own AP optional for each mesh node. * Add ways to change mesh network name and node id for existing ESP8266WiFiMesh instances. * Add verboseModePrint method to clean up the code. * Add reactivation of static IP after successful data transfers to speed up re-connection attempts. * Add empty_IP constant which can be used to check if static IP is disabled for a ESP8266WiFiMesh instance. * Remove the WiFiClient _client class variable in ESP8266WiFiMesh since there is no need to save _client in the class instance. * Add transmission status as a return value from attemptTransmission. * Pass calling ESP8266WiFiMesh instance pointer to callback functions to allow for greater range of actions in callbacks. * Make transmission message a class variable to allow it to be stored in the class and accessed from callbacks. * Add getters for mesh name and node id to ESP8266WiFiMesh. * Add getter and setter for networkFilter to ESP8266WiFiMesh. * Increase range of available node_id:s by changing the type to String and adding functions to convert between String and uint64_t using a customizable radix between 2 and 36. * Make it possible to connect to several nodes during each attemptTransmission call. * Add static connection_queue and latest_transmission_outcomes vectors to the ESP8266WiFiMesh class, a NetworkInfo class and a TransmissionResult class to aid in bookkeeping when connecting to several AP:s during one attemptTransmission call. * Make wifi_channel and BSSID optional when connecting to an AP (though excluding them will slow down the connection process). * Add optional scan and static ip optimizations available in Arduino core for ESP8266 version 2.4.2. * Add functions to check lwIP version in order to enable WiFi optimizations only available with lwIP2. * Add concluding_disconnect, initial_disconnect and no_scan options to the attemptTransmission method. * Update documentation. --- libraries/ESP8266WiFiMesh/README.rst | 24 +- .../examples/HelloMesh/HelloMesh.ino | 81 +++- libraries/ESP8266WiFiMesh/keywords.txt | 24 + .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 432 ++++++++++++++---- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 125 +++-- libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp | 77 ++++ libraries/ESP8266WiFiMesh/src/NetworkInfo.h | 69 +++ .../src/TransmissionResult.cpp | 42 ++ .../ESP8266WiFiMesh/src/TransmissionResult.h | 57 +++ 9 files changed, 780 insertions(+), 151 deletions(-) create mode 100644 libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp create mode 100644 libraries/ESP8266WiFiMesh/src/NetworkInfo.h create mode 100644 libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp create mode 100644 libraries/ESP8266WiFiMesh/src/TransmissionResult.h diff --git a/libraries/ESP8266WiFiMesh/README.rst b/libraries/ESP8266WiFiMesh/README.rst index c883553738..684416634e 100644 --- a/libraries/ESP8266WiFiMesh/README.rst +++ b/libraries/ESP8266WiFiMesh/README.rst @@ -3,24 +3,36 @@ ESP8266 WiFi Mesh A library for turning your ESP8266 into a mesh network node. -The library has been tested and works with Arduino core for ESP8266 version 2.3.0 (with default lwIP) and 2.4.1 (with lwIP 1.4). Random disconnects and crashes seem to happen with the most recent master branch, so better stick to the release builds for now. +The library has been tested and works with Arduino core for ESP8266 version 2.3.0 (with default lwIP) and 2.4.2 or higher (with lwIP 1.4 and lwIP2). Usage ----- -See the included example. The main functions to modify are manageRequest and manageResponse. +The basic operation of a mesh node is as follows: +The `attemptTransmission` method of the ESP8266WiFiMesh instance is called with a message to send to other nodes in the mesh network. If the node is already connected to an AP, the message is sent only to that AP. Otherwise a WiFi scan is performed. The scan results are sent to the `networkFilter` callback function of the ESP8266WiFiMesh instance which adds the AP:s of interest to the `connection_queue` vector. The message is then transmitted to the networks in the `connection_queue`, and the response from each AP is sent to the `responseHandler` callback of the ESP8266WiFiMesh instance. The outcome from each transmission attempt can be found in the `latest_transmission_outcomes` vector. +The node receives messages from other nodes by calling the `acceptRequest` method of the ESP8266WiFiMesh instance. These received messages are passed to the `requestHandler` callback of the mesh instance and the return value of `requestHandler` is sent as a response to the message. -If using Arduino core for ESP8266 version 2.4.1, opt for lwIP v1.4 for now (can be changed in the Tools menu of Arduino IDE). Nodes seem to be unable to connect to more than one other node when using lwIP 2.0! +For more details, see the included example. The main functions to modify in the example are manageRequest (`requestHandler`), manageResponse (`responseHandler`) and `networkFilter`. -Note that this library can use static IP:s for the nodes to speed up initial connection. 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. +Note that 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. + +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. If you are using a core version prior to 2.4.2 it is possible to disable the optimizations by commenting out the `ENABLE_STATIC_IP_OPTIMIZATION` and `ENABLE_WIFI_SCAN_OPTIMIZATION` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while the Mesh library example is opened to open the library folder (or click "Show Sketch Folder" in the Sketch menu). Edit ESP8266WiFiMesh.h with any text editor. + +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. + +It is possible to have several ESP8266WiFiMesh instances running on every ESP8266 (e.g. to communicate with different mesh networks). However, because the ESP8266 has one WiFi radio only one AP per ESP8266 can be active at a time. Also note that if the ESP8266WiFiMesh instances use different WiFi channels, active APs are forced to use the same WiFi channel as active stations, possibly causing AP disconnections. + +While it is possible to connect to other nodes only by giving their SSID, e.g. `ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo("NodeSSID"));`, it is recommended that AP WiFi channel and AP BSSID are given to minimize connection delay. Also, remember to change the default mesh network WiFi password! Some things to keep in mind --------------------------- +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. -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 disconnect all stations connected to the node AP (though they can request a reconnect even while the previous AP node is in STA mode). +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 disconnect all stations connected to the node AP (though they can request a reconnect even while the previous AP node is in STA mode). -Scanning for networks (e.g. via the attemptTransmission method) causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file +Scanning for networks (e.g. via the attemptTransmission method) without the WiFi scan optimizations for core version 2.4.2 mentioned above, causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index ccc77d5aaa..cd6b324fe0 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -1,43 +1,79 @@ #include #include +String mesh_name = "Mesh_Node"; + unsigned int request_i = 0; unsigned int response_i = 0; -String manageRequest(String request); -void manageResponse(String response); +String manageRequest(String request, ESP8266WiFiMesh *mesh_instance); +transmission_status_t manageResponse(String response, ESP8266WiFiMesh *mesh_instance); +void networkFilter(int number_of_networks, ESP8266WiFiMesh *mesh_instance); /* Create the mesh node object */ -ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(ESP.getChipId(), manageRequest, manageResponse, "ChangeThisWiFiPassword_TODO", true); +ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(manageRequest, manageResponse, networkFilter, "ChangeThisWiFiPassword_TODO", mesh_name, "", true); /** Callback for when other nodes send you a request @request The request string received from another node in the mesh + @mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. @returns The string to send back to the other node */ -String manageRequest(String request) { +String manageRequest(String request, ESP8266WiFiMesh *mesh_instance) { /* Print out received message */ Serial.print("Request received: "); Serial.println(request); /* return a string to send back */ char response[60]; - sprintf(response, "Hello world response #%d from Mesh_Node%d.", response_i++, ESP.getChipId()); + sprintf(response, "Hello world response #%d from %s%s.", response_i++, mesh_instance->getMeshName().c_str(), mesh_instance->getNodeID().c_str()); return response; } +/** + Callback used to decide which networks to connect to once a WiFi scan has been completed. + + @number_of_networks The number of networks found in the WiFi scan. + @mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. +*/ +void networkFilter(int number_of_networks, ESP8266WiFiMesh *mesh_instance) { + for (int i = 0; i < number_of_networks; ++i) { + String current_ssid = WiFi.SSID(i); + int mesh_name_index = current_ssid.indexOf(mesh_instance->getMeshName()); + + /* Connect to any _suitable_ APs which contain mesh_instance->getMeshName() */ + if (mesh_name_index >= 0) { + uint64_t target_node_id = ESP8266WiFiMesh::StringToUint64(current_ssid.substring(mesh_name_index + mesh_instance->getMeshName().length())); + + if (target_node_id < ESP8266WiFiMesh::StringToUint64(mesh_instance->getNodeID())) { + ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo(i)); + } + } + } +} + /** Callback for when you get a response from other nodes @response The response string received from another node in the mesh + @mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. + @returns The status code resulting from the response, as an int */ -void manageResponse(String response) { +transmission_status_t manageResponse(String response, ESP8266WiFiMesh *mesh_instance) { + transmission_status_t status_code = TS_TRANSMISSION_COMPLETE; + /* Print out received message */ + Serial.print("Request sent: "); + Serial.println(mesh_instance->getMessage()); Serial.print("Response received: "); Serial.println(response); - request_i++; // Our last request got a response, so time to create a new request. + // Our last request got a response, so time to create a new request. + mesh_instance->setMessage("Hello world request #" + String(++request_i) + " from " + mesh_instance->getMeshName() + mesh_instance->getNodeID() + "."); + + // (void)mesh_instance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else. + return status_code; } void setup() { @@ -53,32 +89,39 @@ void setup() { Serial.println(); Serial.println(); - Serial.println("Note that this library uses static IP:s for the nodes to speed up initial connection.\n" - "Please use the setStaticIP method to ensure that nodes connecting to the same AP have distinct static IP:s.\n" + Serial.println("Note that this library can use static IP:s for the nodes to speed up connection times.\n" + "Use the setStaticIP method to enable this and 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("Please use lwIP v1.4 with this library for now (can be changed in the Tools menu of Arduino IDE).\n" - "Nodes seem to be unable to connect to more than one other node when using lwIP 2.0!\n\n"); - Serial.println("Setting up mesh node..."); /* Initialise the mesh node */ mesh_node.begin(); - mesh_node.setStaticIP(IPAddress(192, 168, 4, 22)); // Activate static IP mode for faster initial connection. + mesh_node.activateAP(); // Each AP requires a separate server port. + mesh_node.setStaticIP(IPAddress(192, 168, 4, 22)); // Activate static IP mode to speed up connection times. } int32_t time_of_last_scan = -10000; void loop() { if (millis() - time_of_last_scan > 3000 // Give other nodes some time to connect between data transfers. || (WiFi.status() != WL_CONNECTED && millis() - time_of_last_scan > 2000)) { // Scan for networks with two second intervals when not already connected. - /* - attemptTransmission(request) will either scan for other nodes and send the request to the first node it connects to - or if connection to an AP already exists just send the request to that AP. - */ char request[60]; - sprintf(request, "Hello world request #%d from Mesh_Node%d.", request_i, ESP.getChipId()); - mesh_node.attemptTransmission(request); + sprintf(request, "Hello world request #%d from %s%s.", request_i, mesh_node.getMeshName().c_str(), mesh_node.getNodeID().c_str()); + mesh_node.attemptTransmission(request, false); time_of_last_scan = millis(); + + if (ESP8266WiFiMesh::latest_transmission_outcomes.empty()) { + Serial.println("No mesh AP found."); + } else { + for (TransmissionResult &transmission_result : ESP8266WiFiMesh::latest_transmission_outcomes) { + if (transmission_result.transmission_status == TS_TRANSMISSION_FAILED) { + Serial.println("Transmission failed to mesh AP " + transmission_result.ssid); + } else if (transmission_result.transmission_status == TS_CONNECTION_FAILED) { + Serial.println("Connection failed to mesh AP " + transmission_result.ssid); + } + } + } + Serial.println(); } else { /* Accept any incoming connections */ mesh_node.acceptRequest(); diff --git a/libraries/ESP8266WiFiMesh/keywords.txt b/libraries/ESP8266WiFiMesh/keywords.txt index f532236a52..47493500d5 100644 --- a/libraries/ESP8266WiFiMesh/keywords.txt +++ b/libraries/ESP8266WiFiMesh/keywords.txt @@ -13,13 +13,37 @@ ESP8266WiFiMesh KEYWORD3 ####################################### ESP8266WiFiMesh KEYWORD1 +NetworkInfo KEYWORD1 +TransmissionResult KEYWORD1 +transmission_status_t KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) ####################################### +connection_queue KEYWORD2 +latest_transmission_outcomes KEYWORD2 begin KEYWORD2 +activateAP KEYWORD2 +deactivateAP KEYWORD2 +restartAP KEYWORD2 +getMeshName KEYWORD2 +getNodeID KEYWORD2 +getMessage KEYWORD2 +setMessage KEYWORD2 attemptTransmission KEYWORD2 acceptRequest KEYWORD2 setStaticIP KEYWORD2 getStaticIP KEYWORD2 +disableStaticIP->KEYWORD2 +Uint64ToString KEYWORD2 +StringToUint64 KEYWORD2 +getNetworkFilter KEYWORD2 +setNetworkFilter KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +empty_IP LITERAL1 +NETWORK_INFO_DEFAULT_INT LITERAL1 diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index 90b4b10fe4..bd390b47ad 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -1,7 +1,6 @@ /* ESP8266WiFiMesh.cpp - Mesh network node - Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. All information - is passed in both directions, but it is up to the user what the data sent is and how it is dealt with. + Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. Copyright (c) 2015 Julian Fell. All rights reserved. Updated 2018 by Anders Löfgren. @@ -19,54 +18,221 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include #include #include #include "ESP8266WiFiMesh.h" -#define SSID_PREFIX "Mesh_Node" #define SERVER_IP_ADDR "192.168.4.1" -#define SERVER_PORT 4011 -const IPAddress empty_IP = IPAddress(); +const IPAddress ESP8266WiFiMesh::empty_IP = IPAddress(); +const uint32_t ESP8266WiFiMesh::lwip_version_203_signature[3] {2,0,3}; -ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, std::function requestHandler, std::function responseHandler, String mesh_password, bool verbose_mode) -: _server(SERVER_PORT), last_ssid(""), static_IP(empty_IP), gateway(192,168,4,1), subnet_mask(255,255,255,0) // IP needs to be at the same subnet as server gateway (192.168.4 in this case). Station gateway ip must match ip for server. +String ESP8266WiFiMesh::last_ssid = ""; +bool ESP8266WiFiMesh::static_IP_activated = false; + +// IP needs to be at the same subnet as server gateway (192.168.4 in this case). Station gateway ip must match ip for server. +IPAddress ESP8266WiFiMesh::static_IP = empty_IP; +IPAddress ESP8266WiFiMesh::gateway = IPAddress(192,168,4,1); +IPAddress ESP8266WiFiMesh::subnet_mask = IPAddress(255,255,255,0); + +std::vector ESP8266WiFiMesh::connection_queue = {}; +std::vector ESP8266WiFiMesh::latest_transmission_outcomes = {}; + +ESP8266WiFiMesh::ESP8266WiFiMesh(std::function requestHandler, std::function responseHandler, + std::function networkFilter, String mesh_password, String mesh_name, String node_id, bool verbose_mode, uint8 mesh_wifi_channel, int server_port) + : _server(server_port), _lwip_version{0, 0, 0} { - _chip_id = chip_id; - _ssid = String( String( SSID_PREFIX ) + String( _chip_id ) ); - _ssid_prefix = String( SSID_PREFIX ); + updateNetworkNames(mesh_name, (node_id != "" ? node_id : Uint64ToString(ESP.getChipId()))); _requestHandler = requestHandler; _responseHandler = responseHandler; + _mesh_wifi_channel = mesh_wifi_channel; + _server_port = server_port; _mesh_password = mesh_password; _verbose_mode = verbose_mode; + _networkFilter = networkFilter; + storeLwipVersion(); +} + +void ESP8266WiFiMesh::verboseModePrint(String string_to_print, bool newline) +{ + if(_verbose_mode) + { + if(newline) + Serial.println(string_to_print); + else + Serial.print(string_to_print); + } +} + +/** + * Note that using a base higher than 16 increases likelihood of randomly generating ssid strings containing controversial words. + * + * @number The number to convert to a string with radix "base". + * @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) +{ + 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. + * + * @string The string to convert to uint64_t. String must use radix "base". + * @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(String string, byte base) +{ + uint64_t result = 0; + + char current_character[1]; + for(uint32_t i = 0; i < string.length(); i++) + { + result *= base; + current_character[0] = string.charAt(i); + result += strtoul(current_character, NULL, base); + } + + return result; +} + +/** + * Calculate the current lwIP version number and store the numbers in the _lwip_version array. + * lwIP version can be changed in the "Tools" menu of Arduino IDE. + */ +void ESP8266WiFiMesh::storeLwipVersion() +{ + // ESP.getFullVersion() looks something like: + // SDK:2.2.1(cfd48f3)/Core:win-2.5.0-dev/lwIP:2.0.3(STABLE-2_0_3_RELEASE/glue:arduino-2.4.1-10-g0c0d8c2)/BearSSL:94e9704 + String full_version = ESP.getFullVersion(); + + int i = full_version.indexOf("lwIP:") + 5; + char current_char = full_version.charAt(i); + + for(int version_part = 0; version_part < 3; version_part++) + { + while(!isdigit(current_char)) + { + current_char = full_version.charAt(++i); + } + while(isdigit(current_char)) + { + _lwip_version[version_part] = 10 * _lwip_version[version_part] + (current_char - '0'); // Left shift and add digit value, in base 10. + current_char = full_version.charAt(++i); + } + } +} + +/** + * Check if the code is running on a version of lwIP that is at least min_lwip_version. + */ +bool ESP8266WiFiMesh::atLeastLwipVersion(const uint32_t min_lwip_version[3]) +{ + for(int version_part = 0; version_part < 3; version_part++) + { + if(_lwip_version[version_part] > min_lwip_version[version_part]) + return true; + else if(_lwip_version[version_part] < min_lwip_version[version_part]) + return false; + } + + return true; +} + +void ESP8266WiFiMesh::updateNetworkNames(String new_mesh_name, String new_node_id) +{ + _mesh_name = new_mesh_name; + _node_id = new_node_id; + _ssid = _mesh_name + _node_id; } void ESP8266WiFiMesh::setStaticIP(IPAddress new_IP) { // Comment out the line below to remove static IP and use DHCP instead. // DHCP makes WiFi connection happen slower, but there is no need to care about manually giving different IPs to the nodes and less need to worry about used IPs giving "Server unavailable" issues. - // Static IP is faster and will make sending of data to a node that is already transmitting data happen more reliably. + // Static IP has faster connection times (50 % of DHCP) and will make sending of data to a node that is already transmitting data happen more reliably. // Note that after WiFi.config(static_IP, gateway, subnet_mask) is used, static IP will always be active, even for new connections, unless WiFi.config(0u,0u,0u); is called. WiFi.config(new_IP, gateway, subnet_mask); - + static_IP_activated = true; static_IP = new_IP; } IPAddress ESP8266WiFiMesh::getStaticIP() { - return static_IP; + if(static_IP_activated) + return static_IP; + + return empty_IP; +} + +void ESP8266WiFiMesh::disableStaticIP() +{ + WiFi.config(0u,0u,0u); + yield(); + static_IP_activated = false; } void ESP8266WiFiMesh::begin() { WiFi.mode(WIFI_AP_STA); - WiFi.softAP( _ssid.c_str(), _mesh_password.c_str() ); // Note that a maximum of 5 stations can be connected at a time to each AP - _server.begin(); + + #ifdef ENABLE_STATIC_IP_OPTIMIZATION + if(atLeastLwipVersion(lwip_version_203_signature)) + { + verboseModePrint("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"); + } + #endif +} + +void ESP8266WiFiMesh::activateAP(String new_mesh_name, String new_node_id) +{ + if(new_mesh_name != "" || new_node_id != "") + updateNetworkNames(new_mesh_name != "" ? new_mesh_name : _mesh_name, new_node_id != "" ? new_node_id : _node_id); + + WiFi.softAP( _ssid.c_str(), _mesh_password.c_str(), _mesh_wifi_channel ); // Note that a maximum of 5 stations can be connected at a time to each AP + _server.begin(); // Actually calls _server.stop()/_server.close() first. } +void ESP8266WiFiMesh::deactivateAP(String new_mesh_name, String new_node_id) +{ + _server.stop(); + WiFi.softAPdisconnect(); + + if(new_mesh_name != "" || new_node_id != "") + updateNetworkNames(new_mesh_name != "" ? new_mesh_name : _mesh_name, new_node_id != "" ? new_node_id : _node_id); +} + +void ESP8266WiFiMesh::restartAP(String new_mesh_name, String new_node_id) +{ + deactivateAP(new_mesh_name, new_node_id); + activateAP(); +} + +String ESP8266WiFiMesh::getMeshName() {return _mesh_name;} +String ESP8266WiFiMesh::getNodeID() {return _node_id;} + +String ESP8266WiFiMesh::getMessage() {return _message;} +void ESP8266WiFiMesh::setMessage(String new_message) {_message = new_message;} + +std::function ESP8266WiFiMesh::getNetworkFilter() {return _networkFilter;} +void ESP8266WiFiMesh::setNetworkFilter(std::function networkFilter) {_networkFilter = networkFilter;} + /** * Disconnect completely from a network. */ @@ -93,8 +259,7 @@ bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient curr_client, int max_ /* Return false if the client isn't ready to communicate */ if (WiFi.status() == WL_DISCONNECTED && !curr_client.available()) { - if(_verbose_mode) - Serial.println("Disconnected!"); + verboseModePrint("Disconnected!"); return false; } @@ -102,33 +267,30 @@ bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient curr_client, int max_ } /** - * Send the supplied message then read back the other node's response + * Send the mesh instance's current message then read back the other node's response * and pass that to the user-supplied responseHandler. * - * @target_ssid The name of the AP the other node has set up. - * @message The string to send to the node. - * @returns: True if the exchange was a succes, false otherwise. + * @curr_client The client to which the message should be transmitted. + * @returns: A status code based on the outcome of the exchange. * */ -bool ESP8266WiFiMesh::exchangeInfo(String message, WiFiClient curr_client) +transmission_status_t ESP8266WiFiMesh::exchangeInfo(WiFiClient curr_client) { - if(_verbose_mode) - Serial.println("Transmitting"); + verboseModePrint("Transmitting"); - curr_client.print(message + "\r"); + curr_client.print(getMessage() + "\r"); yield(); if (!waitForClientTransmission(curr_client, 1000)) { fullStop(curr_client); - return false; + return TS_CONNECTION_FAILED; } if (!curr_client.available()) { - if(_verbose_mode) - Serial.println("No response!"); - return false; // WiFi.status() != WL_DISCONNECTED so we do not want to use fullStop(curr_client) here since that would force the node to scan for WiFi networks. + verboseModePrint("No response!"); + return TS_TRANSMISSION_FAILED; // WiFi.status() != WL_DISCONNECTED so we do not want to use fullStop(curr_client) here since that would force the node to scan for WiFi networks. } String response = curr_client.readStringUntil('\r'); @@ -136,86 +298,105 @@ bool ESP8266WiFiMesh::exchangeInfo(String message, WiFiClient curr_client) curr_client.flush(); /* Pass data to user callback */ - _responseHandler(response); - return true; + return _responseHandler(response, this); } /** * Handle data transfer process with a connected AP. * - * @message The string to send to the AP. - * @returns: True if data transfer process successful, false otherwise. + * @returns: A status code based on the outcome of the data transfer attempt. */ -bool ESP8266WiFiMesh::attemptDataTransfer(String message) +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). WiFi.mode(WIFI_STA); - delay(100); - bool result = attemptDataTransferKernel(message); + delay(1); + transmission_status_t transmission_outcome = attemptDataTransferKernel(); WiFi.mode(WIFI_AP_STA); - delay(100); + delay(1); - return result; + return transmission_outcome; } /** * Helper function that contains the core functionality for the data transfer process with a connected AP. * - * @message The string to send to the AP. - * @returns: True if data transfer process successful, false otherwise. + * @returns: A status code based on the outcome of the data transfer attempt. */ -bool ESP8266WiFiMesh::attemptDataTransferKernel(String message) +transmission_status_t ESP8266WiFiMesh::attemptDataTransferKernel() { WiFiClient curr_client; /* Connect to the node's server */ - if (!curr_client.connect(SERVER_IP_ADDR, SERVER_PORT)) + if (!curr_client.connect(SERVER_IP_ADDR, _server_port)) { fullStop(curr_client); - if(_verbose_mode) - Serial.println("Server unavailable"); - return false; + verboseModePrint("Server unavailable"); + return TS_CONNECTION_FAILED; } - - if (!exchangeInfo(message, curr_client)) + + transmission_status_t transmission_outcome = exchangeInfo(curr_client); + if (transmission_outcome <= 0) { - if(_verbose_mode) - Serial.println("Transmission failed during exchangeInfo."); - return false; + verboseModePrint("Transmission failed during exchangeInfo."); + return transmission_outcome; } curr_client.stop(); yield(); - return true; + return transmission_outcome; +} + +void ESP8266WiFiMesh::initiateConnectionToAP(String target_ssid, int target_channel, uint8_t *target_bssid) +{ + if(target_channel == NETWORK_INFO_DEFAULT_INT) + WiFi.begin( target_ssid.c_str(), _mesh_password.c_str() ); // Without giving channel and bssid, connection time is longer. + else if(target_bssid == NULL) + WiFi.begin( target_ssid.c_str(), _mesh_password.c_str(), target_channel ); // Without giving channel and bssid, connection time is longer. + else + WiFi.begin( target_ssid.c_str(), _mesh_password.c_str(), target_channel, target_bssid ); } /** - * Connect to the AP at ssid and send them a message. + * Connect to the AP at ssid and transmit the mesh instance's current message. * * @target_ssid The name of the AP the other node has set up. - * @message The string to send to the node. * @target_channel The WiFI channel of the AP the other node has set up. * @target_bssid The mac address of the AP the other node has set up. + * @returns: A status code based on the outcome of the connection and data transfer process. * */ -void ESP8266WiFiMesh::connectToNode(String target_ssid, String message, int target_channel, uint8_t *target_bssid) +transmission_status_t ESP8266WiFiMesh::connectToNode(String target_ssid, int target_channel, uint8_t *target_bssid) { - if(static_IP != empty_IP && last_ssid != "" && last_ssid != target_ssid) + if(static_IP_activated && last_ssid != "" && last_ssid != target_ssid) // So we only do this once per connection, in case there is a performance impact. { - WiFi.config(0u,0u,0u); // Deactivate 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?)). - yield(); - static_IP = empty_IP; // So we only do this once, in case there is a performance impact. - if(_verbose_mode) - Serial.println("\nConnecting to a second network. Static IP deactivated to make this possible."); + #ifdef ENABLE_STATIC_IP_OPTIMIZATION + if(atLeastLwipVersion(lwip_version_203_signature)) + { + // 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. + WiFi.mode(WIFI_OFF); + WiFi.mode(WIFI_AP_STA); + 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."); + } + #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."); + #endif } last_ssid = target_ssid; - - if(_verbose_mode) - Serial.print("Connecting... "); - WiFi.begin( target_ssid.c_str(), _mesh_password.c_str(), target_channel, target_bssid ); // Without giving channel and bssid, connection time is longer. + + verboseModePrint("Connecting... ", false); + initiateConnectionToAP(target_ssid, target_channel, target_bssid); int connection_start_time = millis(); int attempt_number = 1; @@ -225,69 +406,127 @@ void ESP8266WiFiMesh::connectToNode(String target_ssid, String message, int targ { if(waiting_time > attempt_number * 10000) // 10000 can be lowered if you want to limit the time allowed for each connection attempt. { - if(_verbose_mode) - Serial.print("... "); + verboseModePrint("... ", false); WiFi.disconnect(); yield(); - WiFi.begin( target_ssid.c_str(), _mesh_password.c_str(), target_channel, target_bssid ); // Without giving channel and bssid, connection time is longer. + initiateConnectionToAP(target_ssid, target_channel, target_bssid); attempt_number++; } delay(1); waiting_time = millis() - connection_start_time; } - if(_verbose_mode) - Serial.println(waiting_time); + verboseModePrint(String(waiting_time)); /* If the connection timed out */ if (WiFi.status() != WL_CONNECTED) { - if(_verbose_mode) - Serial.println("Timeout"); - return; + verboseModePrint("Timeout"); + return TS_CONNECTION_FAILED; } - attemptDataTransfer(message); + return attemptDataTransfer(); } -void ESP8266WiFiMesh::attemptTransmission(String message) +void ESP8266WiFiMesh::attemptTransmission(String message, bool concluding_disconnect, bool initial_disconnect, bool no_scan) { + setMessage(message); + + if(initial_disconnect) + { + WiFi.disconnect(); + yield(); + } + + latest_transmission_outcomes.clear(); + if(WiFi.status() == WL_CONNECTED) { - attemptDataTransfer(message); + transmission_status_t transmission_result = attemptDataTransfer(); + latest_transmission_outcomes.push_back(TransmissionResult(connection_queue.back(), transmission_result)); } else { - if(_verbose_mode) - Serial.print("Scanning... "); + if(!no_scan) + { + verboseModePrint("Scanning... ", false); + + /* Scan for APs */ + connection_queue.clear(); + + // If Arduino core for ESP8266 version < 2.4.2 scanning will cause the WiFi radio to cycle through all WiFi channels. + // This means existing WiFi connections are likely to break or work poorly if done frequently. + #ifdef ENABLE_WIFI_SCAN_OPTIMIZATION + // Scan function argument overview: scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL) + int n = WiFi.scanNetworks(false, false, _mesh_wifi_channel); + #else + int n = WiFi.scanNetworks(); + #endif + + _networkFilter(n, this); // Update the connection_queue. + } - /* Scan for APs */ - int n = WiFi.scanNetworks(); // Scanning causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. - - for (int i = 0; i < n; ++i) + for(NetworkInfo ¤t_network : connection_queue) { - String current_ssid = WiFi.SSID(i); - int index = current_ssid.indexOf( _ssid_prefix ); - uint32_t target_chip_id = (current_ssid.substring(index + _ssid_prefix.length())).toInt(); - - /* Connect to any _suitable_ APs which contain _ssid_prefix */ - if (index >= 0 && (target_chip_id < _chip_id)) + WiFi.disconnect(); + yield(); + + String current_ssid = ""; + int current_wifi_channel = NETWORK_INFO_DEFAULT_INT; + uint8_t *current_bssid = NULL; + + // If an SSID has been assigned, it is prioritized over an assigned network_index since the network_index is more likely to change. + if(current_network.ssid != "") { - if(_verbose_mode) - Serial.printf("First match: %s, Ch:%d (%ddBm) %s... ", WiFi.SSID(i).c_str(), WiFi.channel(i), WiFi.RSSI(i), WiFi.encryptionType(i) == ENC_TYPE_NONE ? "open" : ""); + current_ssid = current_network.ssid; + current_wifi_channel = current_network.wifi_channel; + current_bssid = current_network.bssid; + } + else // Use only network_index + { + current_ssid = WiFi.SSID(current_network.network_index); + current_wifi_channel = WiFi.channel(current_network.network_index); + current_bssid = WiFi.BSSID(current_network.network_index); + } + + if(_verbose_mode) // Avoid string generation if not required + { + verboseModePrint("AP acquired: " + current_ssid + ", Ch:" + String(current_wifi_channel) + " ", false); + + if(current_network.network_index != NETWORK_INFO_DEFAULT_INT) + { + verboseModePrint("(" + String(WiFi.RSSI(current_network.network_index)) + "dBm) " + + (WiFi.encryptionType(current_network.network_index) == ENC_TYPE_NONE ? "open" : ""), false); + } - connectToNode(current_ssid, message, WiFi.channel(i), WiFi.BSSID(i)); - - break; + verboseModePrint("... ", false); } + + transmission_status_t transmission_result = connectToNode(current_ssid, current_wifi_channel, current_bssid); + + latest_transmission_outcomes.push_back(TransmissionResult{.origin = current_network, .transmission_status = transmission_result}); } } + + if(WiFi.status() == WL_CONNECTED && static_IP != empty_IP && !static_IP_activated) + { + verboseModePrint("Reactivating static IP to allow for faster re-connects."); + setStaticIP(static_IP); + } + + // If we do not want to be connected at end of transmission, disconnect here so we can re-enable static IP first (above). + if(concluding_disconnect) + { + WiFi.disconnect(); + yield(); + } } void ESP8266WiFiMesh::acceptRequest() { while (true) { - _client = _server.available(); + WiFiClient _client = _server.available(); + if (!_client) break; @@ -300,13 +539,12 @@ void ESP8266WiFiMesh::acceptRequest() yield(); _client.flush(); - String response = _requestHandler(request); + String response = _requestHandler(request, this); /* Send the response back to the client */ if (_client.connected()) { - if(_verbose_mode) - Serial.println("Responding"); + verboseModePrint("Responding"); _client.print(response + "\r"); _client.flush(); yield(); diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 428b61fd41..8f053dc0b3 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -1,7 +1,6 @@ /* ESP8266WiFiMesh.h - Mesh network node - Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. All information - is passed in both directions, but it is up to the user what the data sent is and how it is dealt with. + Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. Copyright (c) 2015 Julian Fell. All rights reserved. Updated 2018 by Anders Löfgren. @@ -25,50 +24,91 @@ #include #include #include +#include +#include "NetworkInfo.h" +#include "TransmissionResult.h" + +#define ENABLE_STATIC_IP_OPTIMIZATION // Requires Arduino core for ESP8266 version 2.4.2 or higher and lwIP2 (lwIP can be changed in "Tools" menu of Arduino IDE). +#define ENABLE_WIFI_SCAN_OPTIMIZATION // Requires Arduino core for ESP8266 version 2.4.2 or higher. Scan time should go from about 2100 ms to around 60 ms if channel 1 (standard) is used. class ESP8266WiFiMesh { private: String _ssid; - String _ssid_prefix; - uint32_t _chip_id; + String _mesh_name; + String _node_id; + int _server_port; String _mesh_password; + uint8 _mesh_wifi_channel; bool _verbose_mode; - WiFiServer _server; - WiFiClient _client; - - String last_ssid; - - IPAddress static_IP; - IPAddress gateway; - IPAddress subnet_mask; - - std::function _requestHandler; - std::function _responseHandler; - + uint32_t _lwip_version[3]; + static const uint32_t lwip_version_203_signature[3]; + String _message = ""; + + static String last_ssid; + static bool static_IP_activated; + static IPAddress static_IP; + static IPAddress gateway; + static IPAddress subnet_mask; + + std::function _requestHandler; + std::function _responseHandler; + std::function _networkFilter; + + void updateNetworkNames(String new_mesh_name, String new_node_id); + void verboseModePrint(String string_to_print, bool newline = true); void fullStop(WiFiClient curr_client); - void connectToNode(String target_ssid, String message, int target_channel, uint8_t *target_bssid); - bool exchangeInfo(String message, WiFiClient curr_client); + void initiateConnectionToAP(String target_ssid, int target_channel = NETWORK_INFO_DEFAULT_INT, uint8_t *target_bssid = NULL); + transmission_status_t connectToNode(String target_ssid, int target_channel = NETWORK_INFO_DEFAULT_INT, uint8_t *target_bssid = NULL); + transmission_status_t exchangeInfo(WiFiClient curr_client); bool waitForClientTransmission(WiFiClient curr_client, int max_wait); - bool attemptDataTransfer(String message); - bool attemptDataTransferKernel(String message); - + transmission_status_t attemptDataTransfer(); + transmission_status_t attemptDataTransferKernel(); + void storeLwipVersion(); + bool atLeastLwipVersion(const uint32_t min_lwip_version[3]); + public: /** * WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised. * - * @chip_id A unique identifier number for the node. * @requestHandler The callback handler for dealing with received requests. Takes a string as an argument which * is the request string received from another node and returns the string to send back. * @responseHandler The callback handler for dealing with received responses. Takes a string as an argument which - * is the response string received from another node. + * is the response string received from another node. Returns a transmission status code as a transmission_status_t. + * @networkFilter The callback handler for deciding which WiFi networks to connect to. * @mesh_password The WiFi password for the mesh network. + * @mesh_name The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example network filter function. + * @node_id The id for this mesh node. Used as suffix for the node SSID. If set to "", the id will default to ESP.getChipId(). * @verbose_mode Determines if we should print the events occurring in the library to Serial. Off by default. + * @mesh_wifi_channel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1. + * 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. + * In such a case, whenever the station of one ESP8266WiFiMesh instance connects to an AP, it will silently force the + * WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly + * make it impossible for other stations to detect the APs whose WiFi channels have changed. + * @server_port The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port. + * If two AP:s on the same ESP8266 are using the same server port, you must call deactivateAP on the active AP before calling activateAP on the inactive AP. * */ - ESP8266WiFiMesh(uint32_t chip_id, std::function requestHandler, std::function responseHandler, String mesh_password, bool verbose_mode = false); + ESP8266WiFiMesh(std::function requestHandler, std::function responseHandler, std::function networkFilter, String mesh_password, String mesh_name = "Mesh_Node", String node_id = "", bool verbose_mode = false, uint8 mesh_wifi_channel = 1, int server_port = 4011); + + /** + * A vector that contains the WiFi-scan network indicies to connect to. + * The connection_queue vector is cleared before each new scan and filled via the networkFilter callback function once the scan completes. + * WiFi connections will start with connection_queue[0] and then incrementally proceed to higher vector positions. + * Note that old network indicies often are invalidated whenever a new WiFi network scan occurs. + */ + static std::vector connection_queue; + + /** + * A vector with the TransmissionResult for each AP to which a transmission was attempted during the latest attemptTransmission call. + * The latest_transmission_outcomes vector is cleared before each new transmission attempt. + * Connection attempts are indexed in the same order they were attempted. + * Note that old network indicies often are invalidated whenever a new WiFi network scan occurs. + */ + static std::vector latest_transmission_outcomes; /** * Initialises the node. @@ -76,13 +116,28 @@ class ESP8266WiFiMesh { void begin(); /** - * If AP connection exists, send message to AP. - * Otherwise, scan for other nodes and exchange the chosen message with any that are found. + * Each AP requires a separate server port. If two AP:s are using the same server port, you must call deactivateAP on the active AP before calling activateAP on the inactive AP. + */ + void activateAP(String new_mesh_name = "", String new_node_id = ""); + void deactivateAP(String new_mesh_name = "", String new_node_id = ""); + void restartAP(String new_mesh_name = "", String new_node_id = ""); + + String getMeshName(); + String getNodeID(); + + String getMessage(); + void setMessage(String new_message); + + /** + * If AP connection already exists, send message only to this AP. + * Otherwise, scan for other networks, send the scan result to networkFilter and then transmit the message to the networks found in connection_queue. * - * @message The message to send to other nodes. - * + * @message The message to send to other nodes. It will be stored in the class instance until replaced via attemptTransmission or setMessage. + * @concluding_disconnect Disconnect from AP once transmission is complete. + * @initial_disconnect Disconnect from any currently connected AP before attempting transmission. + * @no_scan Do not scan for new networks and do not call networkFilter function. Will only use the data already in connection_queue for the transmission. */ - void attemptTransmission(String message); + void attemptTransmission(String message, bool concluding_disconnect = true, bool initial_disconnect = false, bool no_scan = false); /** * If any clients are connected, accept their requests and call the requestHandler function for each one. @@ -96,6 +151,18 @@ class ESP8266WiFiMesh { void setStaticIP(IPAddress new_IP); IPAddress getStaticIP(); + void disableStaticIP(); + + /** + * An empty IPAddress. Used as default when no IP is set. + */ + static const IPAddress empty_IP; + + static String Uint64ToString(uint64_t number, byte base = 16); + static uint64_t StringToUint64(String string, byte base = 16); + + std::function getNetworkFilter(); + void setNetworkFilter(std::function networkFilter); }; #endif diff --git a/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp b/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp new file mode 100644 index 0000000000..8ee187acdf --- /dev/null +++ b/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp @@ -0,0 +1,77 @@ +/* + * NetworkInfo + * 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 "NetworkInfo.h" + +void NetworkInfo::copyBSSID(uint8_t new_bssid[6]) +{ + if(new_bssid != NULL) + { + if(bssid == NULL) + { + bssid = bssid_array; + } + + for(int i = 0; i < 6; i++) + { + bssid[i] = new_bssid[i]; + } + } + else + { + bssid = NULL; + } +} + +NetworkInfo::NetworkInfo(int new_network_index, bool autofill) : network_index(new_network_index) +{ + if(autofill) + { + ssid = WiFi.SSID(new_network_index); + wifi_channel = WiFi.channel(new_network_index); + copyBSSID(WiFi.BSSID(new_network_index)); + } +} + +NetworkInfo::NetworkInfo(String new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index) : + ssid(new_ssid), wifi_channel(new_wifi_channel), network_index(new_network_index) +{ + copyBSSID(new_bssid); +} + +NetworkInfo::NetworkInfo(const NetworkInfo &other) : ssid(other.ssid), wifi_channel(other.wifi_channel), network_index(other.network_index) +{ + copyBSSID(other.bssid); +} + +NetworkInfo & NetworkInfo::operator=(const NetworkInfo &other) +{ + ssid = other.ssid; + wifi_channel = other.wifi_channel; + copyBSSID(other.bssid); + network_index = other.network_index; + return *this; +} + diff --git a/libraries/ESP8266WiFiMesh/src/NetworkInfo.h b/libraries/ESP8266WiFiMesh/src/NetworkInfo.h new file mode 100644 index 0000000000..2e64358a9e --- /dev/null +++ b/libraries/ESP8266WiFiMesh/src/NetworkInfo.h @@ -0,0 +1,69 @@ +/* + * NetworkInfo + * 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 __NETWORKINFO_H__ +#define __NETWORKINFO_H__ + +#include + +const int NETWORK_INFO_DEFAULT_INT = -1; + +class NetworkInfo { + +private: + + uint8_t bssid_array[6] {0}; + +public: + + String ssid = ""; + int wifi_channel = NETWORK_INFO_DEFAULT_INT; + uint8_t *bssid = NULL; + int network_index = NETWORK_INFO_DEFAULT_INT; + + /** + * @autofill Automatically fill in the rest of the network info using _network_index and the WiFi scan results. + */ + NetworkInfo(int new_network_index, bool autofill = true); + + /** + * Without giving channel and bssid, connection time is longer. + */ + NetworkInfo(String new_ssid, int new_wifi_channel = NETWORK_INFO_DEFAULT_INT, uint8_t new_bssid[6] = NULL, int new_network_index = NETWORK_INFO_DEFAULT_INT); + + NetworkInfo(const NetworkInfo &other); + + NetworkInfo & operator=(const NetworkInfo &other); + + // No need for explicit destructor with current class design + + /** + * Copy new_bssid into bssid. + * Prefer this method for changing NetworkInfo BSSID, unless you actually want to change the BSSID pointer. + */ + void copyBSSID(uint8_t new_bssid[6]); +}; + +#endif diff --git a/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp b/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp new file mode 100644 index 0000000000..f1fdf58413 --- /dev/null +++ b/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp @@ -0,0 +1,42 @@ +/* + * TransmissionResult + * 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 "TransmissionResult.h" + +TransmissionResult::TransmissionResult(int new_network_index, transmission_status_t new_transmission_status, bool autofill) : + NetworkInfo(new_network_index, autofill), transmission_status(new_transmission_status) +{ } + +TransmissionResult::TransmissionResult(String new_ssid, int new_wifi_channel, uint8_t new_bssid[6], transmission_status_t new_transmission_status) : + NetworkInfo(new_ssid, new_wifi_channel, new_bssid), transmission_status(new_transmission_status) +{ } + +TransmissionResult::TransmissionResult(String new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index, transmission_status_t new_transmission_status) : + NetworkInfo(new_ssid, new_wifi_channel, new_bssid, new_network_index), transmission_status(new_transmission_status) +{ } + +TransmissionResult::TransmissionResult(const NetworkInfo& origin, transmission_status_t new_transmission_status) : + NetworkInfo(origin), transmission_status(new_transmission_status) +{ } diff --git a/libraries/ESP8266WiFiMesh/src/TransmissionResult.h b/libraries/ESP8266WiFiMesh/src/TransmissionResult.h new file mode 100644 index 0000000000..6165fd3084 --- /dev/null +++ b/libraries/ESP8266WiFiMesh/src/TransmissionResult.h @@ -0,0 +1,57 @@ +/* + * TransmissionResult + * 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 __TRANSMISSIONRESULT_H__ +#define __TRANSMISSIONRESULT_H__ + +#include +#include "NetworkInfo.h" + +typedef enum +{ + TS_CONNECTION_FAILED = -1, + TS_TRANSMISSION_FAILED = 0, + TS_TRANSMISSION_COMPLETE = 1 +} transmission_status_t; + +class TransmissionResult : public NetworkInfo { + +public: + + transmission_status_t transmission_status; + + /** + * @autofill Automatically fill in the rest of the network info using _network_index and the WiFi scan results. + */ + TransmissionResult(int new_network_index, transmission_status_t new_transmission_status, bool autofill = true); + + TransmissionResult(String new_ssid, int new_wifi_channel, uint8_t new_bssid[6], transmission_status_t new_transmission_status); + + TransmissionResult(String new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index, transmission_status_t new_transmission_status); + + TransmissionResult(const NetworkInfo& origin, transmission_status_t new_transmission_status); +}; + +#endif From 9c4ebc0694d902bfd5800148862f3e42b736a903 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 10 Jul 2018 11:47:26 +0200 Subject: [PATCH 07/20] Improve README.rst formatting. --- libraries/ESP8266WiFiMesh/README.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/README.rst b/libraries/ESP8266WiFiMesh/README.rst index 684416634e..e27b577d9a 100644 --- a/libraries/ESP8266WiFiMesh/README.rst +++ b/libraries/ESP8266WiFiMesh/README.rst @@ -9,20 +9,20 @@ Usage ----- The basic operation of a mesh node is as follows: -The `attemptTransmission` method of the ESP8266WiFiMesh instance is called with a message to send to other nodes in the mesh network. If the node is already connected to an AP, the message is sent only to that AP. Otherwise a WiFi scan is performed. The scan results are sent to the `networkFilter` callback function of the ESP8266WiFiMesh instance which adds the AP:s of interest to the `connection_queue` vector. The message is then transmitted to the networks in the `connection_queue`, and the response from each AP is sent to the `responseHandler` callback of the ESP8266WiFiMesh instance. The outcome from each transmission attempt can be found in the `latest_transmission_outcomes` vector. -The node receives messages from other nodes by calling the `acceptRequest` method of the ESP8266WiFiMesh instance. These received messages are passed to the `requestHandler` callback of the mesh instance and the return value of `requestHandler` is sent as a response to the message. +The ``attemptTransmission`` method of the ESP8266WiFiMesh instance is called with a message to send to other nodes in the mesh network. If the node is already connected to an AP, the message is sent only to that AP. Otherwise a WiFi scan is performed. The scan results are sent to the ``networkFilter`` callback function of the ESP8266WiFiMesh instance which adds the AP:s of interest to the ``connection_queue`` vector. The message is then transmitted to the networks in the ``connection_queue``, and the response from each AP is sent to the ``responseHandler`` callback of the ESP8266WiFiMesh instance. The outcome from each transmission attempt can be found in the ``latest_transmission_outcomes`` vector. +The node receives messages from other nodes by calling the ``acceptRequest`` method of the ESP8266WiFiMesh instance. These received messages are passed to the ``requestHandler`` callback of the mesh instance and the return value of ``requestHandler`` is sent as a response to the message. -For more details, see the included example. The main functions to modify in the example are manageRequest (`requestHandler`), manageResponse (`responseHandler`) and `networkFilter`. +For more details, see the included example. The main functions to modify in the example are manageRequest (``requestHandler``), manageResponse (``responseHandler``) and ``networkFilter``. -Note that 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. +Note that 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. -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. If you are using a core version prior to 2.4.2 it is possible to disable the optimizations by commenting out the `ENABLE_STATIC_IP_OPTIMIZATION` and `ENABLE_WIFI_SCAN_OPTIMIZATION` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while the Mesh library example is opened to open the library folder (or click "Show Sketch Folder" in the Sketch menu). Edit ESP8266WiFiMesh.h with any text editor. +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. If you are using a core version prior to 2.4.2 it is possible to disable the optimizations by commenting out the ``ENABLE_STATIC_IP_OPTIMIZATION`` and ``ENABLE_WIFI_SCAN_OPTIMIZATION`` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while the Mesh library example is opened to open the library folder (or click "Show Sketch Folder" in the Sketch menu). Edit ESP8266WiFiMesh.h with any text editor. 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. It is possible to have several ESP8266WiFiMesh instances running on every ESP8266 (e.g. to communicate with different mesh networks). However, because the ESP8266 has one WiFi radio only one AP per ESP8266 can be active at a time. Also note that if the ESP8266WiFiMesh instances use different WiFi channels, active APs are forced to use the same WiFi channel as active stations, possibly causing AP disconnections. -While it is possible to connect to other nodes only by giving their SSID, e.g. `ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo("NodeSSID"));`, it is recommended that AP WiFi channel and AP BSSID are given to minimize connection delay. +While it is possible to connect to other nodes only by giving their SSID, e.g. ``ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo("NodeSSID"));``, it is recommended that AP WiFi channel and AP BSSID are given to minimize connection delay. Also, remember to change the default mesh network WiFi password! @@ -33,6 +33,6 @@ This library uses the standard Arduino core for ESP8266 WiFi functions. Therefor A maximum of 5 stations can be connected at a time to each AP. -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 disconnect all stations connected to the node AP (though they can request a reconnect even while the previous AP node is in STA mode). +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 disconnect all stations connected to the node AP (though they can request a reconnect even while the previous AP node is in STA mode). Scanning for networks (e.g. via the attemptTransmission method) without the WiFi scan optimizations for core version 2.4.2 mentioned above, causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file From f03724a751470cf93c44d119a1c0a22f8ee7f159 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 10 Jul 2018 14:35:43 +0200 Subject: [PATCH 08/20] Further improve README.rst. --- libraries/ESP8266WiFiMesh/README.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/README.rst b/libraries/ESP8266WiFiMesh/README.rst index e27b577d9a..55f57f1152 100644 --- a/libraries/ESP8266WiFiMesh/README.rst +++ b/libraries/ESP8266WiFiMesh/README.rst @@ -10,15 +10,15 @@ Usage The basic operation of a mesh node is as follows: The ``attemptTransmission`` method of the ESP8266WiFiMesh instance is called with a message to send to other nodes in the mesh network. If the node is already connected to an AP, the message is sent only to that AP. Otherwise a WiFi scan is performed. The scan results are sent to the ``networkFilter`` callback function of the ESP8266WiFiMesh instance which adds the AP:s of interest to the ``connection_queue`` vector. The message is then transmitted to the networks in the ``connection_queue``, and the response from each AP is sent to the ``responseHandler`` callback of the ESP8266WiFiMesh instance. The outcome from each transmission attempt can be found in the ``latest_transmission_outcomes`` vector. -The node receives messages from other nodes by calling the ``acceptRequest`` method of the ESP8266WiFiMesh instance. These received messages are passed to the ``requestHandler`` callback of the mesh instance and the return value of ``requestHandler`` is sent as a response to the message. +The node receives messages from other nodes by calling the ``acceptRequest`` method of the ESP8266WiFiMesh instance. These received messages are passed to the ``requestHandler`` callback of the mesh instance. For each received message the return value of ``requestHandler`` is sent to the other node as a response to the message. -For more details, see the included example. The main functions to modify in the example are manageRequest (``requestHandler``), manageResponse (``responseHandler``) and ``networkFilter``. +For more details, see the included example. The main functions to modify in the example are ``manageRequest`` (``requestHandler``), ``manageResponse`` (``responseHandler``) and ``networkFilter``. Note that 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. -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. If you are using a core version prior to 2.4.2 it is possible to disable the optimizations by commenting out the ``ENABLE_STATIC_IP_OPTIMIZATION`` and ``ENABLE_WIFI_SCAN_OPTIMIZATION`` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while the Mesh library example is opened to open the library folder (or click "Show Sketch Folder" in the Sketch menu). Edit ESP8266WiFiMesh.h with any text editor. +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. -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. +If you are using a core version prior to 2.4.2 it is possible to disable the WiFi scan and static ip optimizations by commenting out the ``ENABLE_STATIC_IP_OPTIMIZATION`` and ``ENABLE_WIFI_SCAN_OPTIMIZATION`` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while an example from the mesh library is opened, to open the library folder (or click "Show Sketch Folder" in the Sketch menu). ESP8266WiFiMesh.h can then be found at ESP8266WiFiMesh/src. Edit the file with any text editor. It is possible to have several ESP8266WiFiMesh instances running on every ESP8266 (e.g. to communicate with different mesh networks). However, because the ESP8266 has one WiFi radio only one AP per ESP8266 can be active at a time. Also note that if the ESP8266WiFiMesh instances use different WiFi channels, active APs are forced to use the same WiFi channel as active stations, possibly causing AP disconnections. @@ -35,4 +35,4 @@ A maximum of 5 stations can be connected at a time to each AP. 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 disconnect all stations connected to the node AP (though they can request a reconnect even while the previous AP node is in STA mode). -Scanning for networks (e.g. via the attemptTransmission method) without the WiFi scan optimizations for core version 2.4.2 mentioned above, causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file +Scanning for networks (e.g. via the ``attemptTransmission`` method) without the WiFi scan optimizations for core version 2.4.2 mentioned above, causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file From b19f619735e8c52058b00199441ef7b436a2b0d1 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 10 Jul 2018 14:59:13 +0200 Subject: [PATCH 09/20] Even further improve README.rst. --- libraries/ESP8266WiFiMesh/README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/README.rst b/libraries/ESP8266WiFiMesh/README.rst index 55f57f1152..ce5953ca6e 100644 --- a/libraries/ESP8266WiFiMesh/README.rst +++ b/libraries/ESP8266WiFiMesh/README.rst @@ -14,7 +14,7 @@ The node receives messages from other nodes by calling the ``acceptRequest`` met For more details, see the included example. The main functions to modify in the example are ``manageRequest`` (``requestHandler``), ``manageResponse`` (``responseHandler``) and ``networkFilter``. -Note that 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. +Note that 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. 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. @@ -22,7 +22,7 @@ If you are using a core version prior to 2.4.2 it is possible to disable the WiF It is possible to have several ESP8266WiFiMesh instances running on every ESP8266 (e.g. to communicate with different mesh networks). However, because the ESP8266 has one WiFi radio only one AP per ESP8266 can be active at a time. Also note that if the ESP8266WiFiMesh instances use different WiFi channels, active APs are forced to use the same WiFi channel as active stations, possibly causing AP disconnections. -While it is possible to connect to other nodes only by giving their SSID, e.g. ``ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo("NodeSSID"));``, it is recommended that AP WiFi channel and AP BSSID are given to minimize connection delay. +While it is possible to connect to other nodes by only giving their SSID, e.g. ``ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo("NodeSSID"));``, it is recommended that AP WiFi channel and AP BSSID are given as well, to minimize connection delay. Also, remember to change the default mesh network WiFi password! From 3fccdf918315b5791c65731df1c06ebe288685f2 Mon Sep 17 00:00:00 2001 From: Anders Date: Sun, 22 Jul 2018 16:58:54 +0200 Subject: [PATCH 10/20] Make source code comments Doxygen compatible. Improve README file and change its file format to .md. --- libraries/ESP8266WiFiMesh/README.md | 69 +++++++++++++++++++ libraries/ESP8266WiFiMesh/README.rst | 38 ---------- .../examples/HelloMesh/HelloMesh.ino | 12 ++-- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 16 ++--- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 30 ++++---- libraries/ESP8266WiFiMesh/src/NetworkInfo.h | 2 +- .../ESP8266WiFiMesh/src/TransmissionResult.h | 2 +- 7 files changed, 101 insertions(+), 68 deletions(-) create mode 100644 libraries/ESP8266WiFiMesh/README.md delete mode 100644 libraries/ESP8266WiFiMesh/README.rst diff --git a/libraries/ESP8266WiFiMesh/README.md b/libraries/ESP8266WiFiMesh/README.md new file mode 100644 index 0000000000..4697995b54 --- /dev/null +++ b/libraries/ESP8266WiFiMesh/README.md @@ -0,0 +1,69 @@ +ESP8266 WiFi Mesh +================= + +A library for turning your ESP8266 into a mesh network node. + +The library has been tested and works with Arduino core for ESP8266 version 2.3.0 (with default lwIP) and 2.4.2 or higher (with lwIP 1.4 and lwIP2). + +Usage +----- + +The basic operation of a mesh node is as follows: + +The `attemptTransmission` method of the ESP8266WiFiMesh instance is called with a message to send to other nodes in the mesh network. If the node is already connected to an AP, the message is sent only to that AP. Otherwise a WiFi scan is performed. The scan results are sent to the `networkFilter` callback function of the ESP8266WiFiMesh instance which adds the AP:s of interest to the `connection_queue` vector. The message is then transmitted to the networks in the `connection_queue`, and the response from each AP is sent to the `responseHandler` callback of the ESP8266WiFiMesh instance. The outcome from each transmission attempt can be found in the `latest_transmission_outcomes` vector. + +The node receives messages from other nodes by calling the `acceptRequest` method of the ESP8266WiFiMesh instance. These received messages are passed to the `requestHandler` callback of the mesh instance. For each received message the return value of `requestHandler` is sent to the other node as a response to the message. + +For more details, see the included example. The main functions to modify in the example are `manageRequest` (`requestHandler`), `manageResponse` (`responseHandler`) and `networkFilter`. There is also more information to be found in the source code comments. An example is the ESP8266WiFiMesh constructor comment, which is shown below for reference: +``` +/** +* WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised. +* +* @param requestHandler The callback handler for dealing with received requests. Takes a string as an argument which +* is the request string received from another node and returns the string to send back. +* @param responseHandler The callback handler for dealing with received responses. Takes a string as an argument which +* is the response string received from another node. Returns a transmission status code as a transmission_status_t. +* @param networkFilter The callback handler for deciding which WiFi networks to connect to. +* @param mesh_password The WiFi password for the mesh network. +* @param mesh_name The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example network filter function. +* @param node_id The id for this mesh node. Used as suffix for the node SSID. If set to "", the id will default to ESP.getChipId(). +* @param verbose_mode Determines if we should print the events occurring in the library to Serial. Off by default. +* @param mesh_wifi_channel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1. +* 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. +* In such a case, whenever the station of one ESP8266WiFiMesh instance connects to an AP, it will silently force the +* WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly +* make it impossible for other stations to detect the APs whose WiFi channels have changed. +* @param server_port The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port. +* If two AP:s on the same ESP8266 are using the same server port, you must call deactivateAP on the active AP before calling activateAP on the inactive AP. +* +*/ +ESP8266WiFiMesh(std::function requestHandler, std::function responseHandler, + std::function networkFilter, String mesh_password, String mesh_name = "Mesh_Node", String node_id = "", + bool verbose_mode = false, uint8 mesh_wifi_channel = 1, int server_port = 4011); +``` + +### Note + +* 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. + +* 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. + + If you are using a core version prior to 2.4.2 it is possible to disable the WiFi scan and static ip optimizations by commenting out the `ENABLE_STATIC_IP_OPTIMIZATION` and `ENABLE_WIFI_SCAN_OPTIMIZATION` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while an example from the mesh library is opened, to open the library folder (or click "Show Sketch Folder" in the Sketch menu). ESP8266WiFiMesh.h can then be found at ESP8266WiFiMesh/src. Edit the file with any text editor. + +* It is possible to have several ESP8266WiFiMesh instances running on every ESP8266 (e.g. to communicate with different mesh networks). However, because the ESP8266 has one WiFi radio only one AP per ESP8266 can be active at a time. Also note that if the ESP8266WiFiMesh instances use different WiFi channels, active APs are forced to use the same WiFi channel as active stations, possibly causing AP disconnections. + +* While it is possible to connect to other nodes by only giving their SSID, e.g. `ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo("NodeSSID"));`, it is recommended that AP WiFi channel and AP BSSID are given as well, to minimize connection delay. + +* Also, remember to change the default mesh network WiFi password! + +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. + +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 disconnect all stations connected to the node AP (though they can request a reconnect even while the previous AP node is in STA mode). + +Scanning for networks (e.g. via the `attemptTransmission` method) without the WiFi scan optimizations for core version 2.4.2 mentioned above, causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file diff --git a/libraries/ESP8266WiFiMesh/README.rst b/libraries/ESP8266WiFiMesh/README.rst deleted file mode 100644 index ce5953ca6e..0000000000 --- a/libraries/ESP8266WiFiMesh/README.rst +++ /dev/null @@ -1,38 +0,0 @@ -ESP8266 WiFi Mesh -================= - -A library for turning your ESP8266 into a mesh network node. - -The library has been tested and works with Arduino core for ESP8266 version 2.3.0 (with default lwIP) and 2.4.2 or higher (with lwIP 1.4 and lwIP2). - -Usage ------ - -The basic operation of a mesh node is as follows: -The ``attemptTransmission`` method of the ESP8266WiFiMesh instance is called with a message to send to other nodes in the mesh network. If the node is already connected to an AP, the message is sent only to that AP. Otherwise a WiFi scan is performed. The scan results are sent to the ``networkFilter`` callback function of the ESP8266WiFiMesh instance which adds the AP:s of interest to the ``connection_queue`` vector. The message is then transmitted to the networks in the ``connection_queue``, and the response from each AP is sent to the ``responseHandler`` callback of the ESP8266WiFiMesh instance. The outcome from each transmission attempt can be found in the ``latest_transmission_outcomes`` vector. -The node receives messages from other nodes by calling the ``acceptRequest`` method of the ESP8266WiFiMesh instance. These received messages are passed to the ``requestHandler`` callback of the mesh instance. For each received message the return value of ``requestHandler`` is sent to the other node as a response to the message. - -For more details, see the included example. The main functions to modify in the example are ``manageRequest`` (``requestHandler``), ``manageResponse`` (``responseHandler``) and ``networkFilter``. - -Note that 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. - -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. - -If you are using a core version prior to 2.4.2 it is possible to disable the WiFi scan and static ip optimizations by commenting out the ``ENABLE_STATIC_IP_OPTIMIZATION`` and ``ENABLE_WIFI_SCAN_OPTIMIZATION`` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while an example from the mesh library is opened, to open the library folder (or click "Show Sketch Folder" in the Sketch menu). ESP8266WiFiMesh.h can then be found at ESP8266WiFiMesh/src. Edit the file with any text editor. - -It is possible to have several ESP8266WiFiMesh instances running on every ESP8266 (e.g. to communicate with different mesh networks). However, because the ESP8266 has one WiFi radio only one AP per ESP8266 can be active at a time. Also note that if the ESP8266WiFiMesh instances use different WiFi channels, active APs are forced to use the same WiFi channel as active stations, possibly causing AP disconnections. - -While it is possible to connect to other nodes by only giving their SSID, e.g. ``ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo("NodeSSID"));``, it is recommended that AP WiFi channel and AP BSSID are given as well, to minimize connection delay. - -Also, remember to change the default mesh network WiFi password! - -Some things to keep in mind ---------------------------- - -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. - -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 disconnect all stations connected to the node AP (though they can request a reconnect even while the previous AP node is in STA mode). - -Scanning for networks (e.g. via the ``attemptTransmission`` method) without the WiFi scan optimizations for core version 2.4.2 mentioned above, causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index cd6b324fe0..b7bb03ca63 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -16,8 +16,8 @@ ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(manageRequest, manageResponse, netwo /** Callback for when other nodes send you a request - @request The request string received from another node in the mesh - @mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. + @param request The request string received from another node in the mesh + @param mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. @returns The string to send back to the other node */ String manageRequest(String request, ESP8266WiFiMesh *mesh_instance) { @@ -34,8 +34,8 @@ String manageRequest(String request, ESP8266WiFiMesh *mesh_instance) { /** Callback used to decide which networks to connect to once a WiFi scan has been completed. - @number_of_networks The number of networks found in the WiFi scan. - @mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. + @param number_of_networks The number of networks found in the WiFi scan. + @param mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. */ void networkFilter(int number_of_networks, ESP8266WiFiMesh *mesh_instance) { for (int i = 0; i < number_of_networks; ++i) { @@ -56,8 +56,8 @@ void networkFilter(int number_of_networks, ESP8266WiFiMesh *mesh_instance) { /** Callback for when you get a response from other nodes - @response The response string received from another node in the mesh - @mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. + @param response The response string received from another node in the mesh + @param mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. @returns The status code resulting from the response, as an int */ transmission_status_t manageResponse(String response, ESP8266WiFiMesh *mesh_instance) { diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index bd390b47ad..768d5fec75 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -69,8 +69,8 @@ void ESP8266WiFiMesh::verboseModePrint(String string_to_print, bool newline) /** * Note that using a base higher than 16 increases likelihood of randomly generating ssid strings containing controversial words. * - * @number The number to convert to a string with radix "base". - * @base The radix to convert "number" into. Must be between 2 and 36. + * @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) @@ -89,8 +89,8 @@ String ESP8266WiFiMesh::Uint64ToString(uint64_t number, byte base) /** * Note that using a base higher than 16 increases likelihood of randomly generating ssid strings containing controversial words. * - * @string The string to convert to uint64_t. String must use radix "base". - * @base The radix of "string". Must be between 2 and 36. + * @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(String string, byte base) @@ -270,7 +270,7 @@ bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient curr_client, int max_ * Send the mesh instance's current message then read back the other node's response * and pass that to the user-supplied responseHandler. * - * @curr_client The client to which the message should be transmitted. + * @param curr_client The client to which the message should be transmitted. * @returns: A status code based on the outcome of the exchange. * */ @@ -363,9 +363,9 @@ void ESP8266WiFiMesh::initiateConnectionToAP(String target_ssid, int target_chan /** * Connect to the AP at ssid and transmit the mesh instance's current message. * - * @target_ssid The name of the AP the other node has set up. - * @target_channel The WiFI channel of the AP the other node has set up. - * @target_bssid The mac address of the AP the other node has set up. + * @param target_ssid The name of the AP the other node has set up. + * @param target_channel The WiFI channel of the AP the other node has set up. + * @param target_bssid The mac address of the AP the other node has set up. * @returns: A status code based on the outcome of the connection and data transfer process. * */ diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 8f053dc0b3..82aaf7e88b 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -73,26 +73,28 @@ class ESP8266WiFiMesh { /** * WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised. * - * @requestHandler The callback handler for dealing with received requests. Takes a string as an argument which + * @param requestHandler The callback handler for dealing with received requests. Takes a string as an argument which * is the request string received from another node and returns the string to send back. - * @responseHandler The callback handler for dealing with received responses. Takes a string as an argument which + * @param responseHandler The callback handler for dealing with received responses. Takes a string as an argument which * is the response string received from another node. Returns a transmission status code as a transmission_status_t. - * @networkFilter The callback handler for deciding which WiFi networks to connect to. - * @mesh_password The WiFi password for the mesh network. - * @mesh_name The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example network filter function. - * @node_id The id for this mesh node. Used as suffix for the node SSID. If set to "", the id will default to ESP.getChipId(). - * @verbose_mode Determines if we should print the events occurring in the library to Serial. Off by default. - * @mesh_wifi_channel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1. + * @param networkFilter The callback handler for deciding which WiFi networks to connect to. + * @param mesh_password The WiFi password for the mesh network. + * @param mesh_name The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example network filter function. + * @param node_id The id for this mesh node. Used as suffix for the node SSID. If set to "", the id will default to ESP.getChipId(). + * @param verbose_mode Determines if we should print the events occurring in the library to Serial. Off by default. + * @param mesh_wifi_channel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1. * 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. * In such a case, whenever the station of one ESP8266WiFiMesh instance connects to an AP, it will silently force the * WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly * make it impossible for other stations to detect the APs whose WiFi channels have changed. - * @server_port The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port. + * @param server_port The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port. * If two AP:s on the same ESP8266 are using the same server port, you must call deactivateAP on the active AP before calling activateAP on the inactive AP. * */ - ESP8266WiFiMesh(std::function requestHandler, std::function responseHandler, std::function networkFilter, String mesh_password, String mesh_name = "Mesh_Node", String node_id = "", bool verbose_mode = false, uint8 mesh_wifi_channel = 1, int server_port = 4011); + ESP8266WiFiMesh(std::function requestHandler, std::function responseHandler, + std::function networkFilter, String mesh_password, String mesh_name = "Mesh_Node", String node_id = "", + bool verbose_mode = false, uint8 mesh_wifi_channel = 1, int server_port = 4011); /** * A vector that contains the WiFi-scan network indicies to connect to. @@ -132,10 +134,10 @@ class ESP8266WiFiMesh { * If AP connection already exists, send message only to this AP. * Otherwise, scan for other networks, send the scan result to networkFilter and then transmit the message to the networks found in connection_queue. * - * @message The message to send to other nodes. It will be stored in the class instance until replaced via attemptTransmission or setMessage. - * @concluding_disconnect Disconnect from AP once transmission is complete. - * @initial_disconnect Disconnect from any currently connected AP before attempting transmission. - * @no_scan Do not scan for new networks and do not call networkFilter function. Will only use the data already in connection_queue for the transmission. + * @param message The message to send to other nodes. It will be stored in the class instance until replaced via attemptTransmission or setMessage. + * @param concluding_disconnect Disconnect from AP once transmission is complete. + * @param initial_disconnect Disconnect from any currently connected AP before attempting transmission. + * @param no_scan Do not scan for new networks and do not call networkFilter function. Will only use the data already in connection_queue for the transmission. */ void attemptTransmission(String message, bool concluding_disconnect = true, bool initial_disconnect = false, bool no_scan = false); diff --git a/libraries/ESP8266WiFiMesh/src/NetworkInfo.h b/libraries/ESP8266WiFiMesh/src/NetworkInfo.h index 2e64358a9e..93ce84dd78 100644 --- a/libraries/ESP8266WiFiMesh/src/NetworkInfo.h +++ b/libraries/ESP8266WiFiMesh/src/NetworkInfo.h @@ -44,7 +44,7 @@ class NetworkInfo { int network_index = NETWORK_INFO_DEFAULT_INT; /** - * @autofill Automatically fill in the rest of the network info using _network_index and the WiFi scan results. + * @param autofill Automatically fill in the rest of the network info using _network_index and the WiFi scan results. */ NetworkInfo(int new_network_index, bool autofill = true); diff --git a/libraries/ESP8266WiFiMesh/src/TransmissionResult.h b/libraries/ESP8266WiFiMesh/src/TransmissionResult.h index 6165fd3084..5a9d7abaed 100644 --- a/libraries/ESP8266WiFiMesh/src/TransmissionResult.h +++ b/libraries/ESP8266WiFiMesh/src/TransmissionResult.h @@ -43,7 +43,7 @@ class TransmissionResult : public NetworkInfo { transmission_status_t transmission_status; /** - * @autofill Automatically fill in the rest of the network info using _network_index and the WiFi scan results. + * @param autofill Automatically fill in the rest of the network info using _network_index and the WiFi scan results. */ TransmissionResult(int new_network_index, transmission_status_t new_transmission_status, bool autofill = true); From 367a680046642e02815802c113c6f6d9dc771f59 Mon Sep 17 00:00:00 2001 From: Anders Date: Sun, 22 Jul 2018 20:28:23 +0200 Subject: [PATCH 11/20] Add temporary compatibility layer to ensure backwards compatibility with the old mesh network library API until the next major core release (2.5.0). --- libraries/ESP8266WiFiMesh/README.md | 2 + .../src/CompatibilityLayer.cpp | 162 ++++++++++++++++++ .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 90 +++++++--- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 44 ++++- 4 files changed, 271 insertions(+), 27 deletions(-) create mode 100644 libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp diff --git a/libraries/ESP8266WiFiMesh/README.md b/libraries/ESP8266WiFiMesh/README.md index 4697995b54..13a9c8e253 100644 --- a/libraries/ESP8266WiFiMesh/README.md +++ b/libraries/ESP8266WiFiMesh/README.md @@ -5,6 +5,8 @@ A library for turning your ESP8266 into a mesh network node. The library has been tested and works with Arduino core for ESP8266 version 2.3.0 (with default lwIP) and 2.4.2 or higher (with lwIP 1.4 and lwIP2). +**Note:** This mesh library has been rewritten for core release 2.4.2. The old method signatures have been retained for compatibility purposes, but will be removed in core release 2.5.0. If you are still using these old method signatures please consider migrating to the new API shown in the `ESP8266WiFiMesh.h` source file. + Usage ----- diff --git a/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp b/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp new file mode 100644 index 0000000000..958ff52980 --- /dev/null +++ b/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp @@ -0,0 +1,162 @@ +/* + Old version of ESP8266WiFiMesh.cpp - Mesh network node + Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. All information + is passed in both directions, but it is up to the user what the data sent is and how it is dealt with. + + Copyright (c) 2015 Julian Fell. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + + + + + +/******************************************************************************************** +* NOTE! +* +* All method signatures in this file are deprecated and will be removed in core version 2.5.0. +* If you are still using these methods, please consider migrating to the new API shown in +* the ESP8266WiFiMesh.h source file. +* +* TODO: delete this file. +********************************************************************************************/ + + + + + +#include +#include +#include +#include + +#include "ESP8266WiFiMesh.h" + +#define SSID_PREFIX "Mesh_Node" +#define SERVER_IP_ADDR "192.168.4.1" +#define SERVER_PORT 4011 + +// DEPRECATED! +ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, std::function handler) +: _server(SERVER_PORT) +{ + _chip_id = chip_id; + _ssid = String( String( SSID_PREFIX ) + String( _chip_id ) ); + _ssid_prefix = String( SSID_PREFIX ); + _handler = handler; +} + +/** + * Wait for a WiFiClient to connect + * + * @returns: True if the client is ready, false otherwise. + * + */ +// DEPRECATED! +bool ESP8266WiFiMesh::waitForClient(WiFiClient curr_client, int max_wait) +{ + int wait = max_wait; + while(curr_client.connected() && !curr_client.available() && wait--) + delay(3); + + /* Return false if the client isn't ready to communicate */ + if (WiFi.status() == WL_DISCONNECTED || !curr_client.connected()) + return false; + + return true; +} + +/** + * Send the supplied message then read back the other node's response + * and pass that to the user-supplied handler. + * + * @target_ssid The name of the AP the other node has set up. + * @message The string to send to the node. + * @returns: True if the exchange was a succes, false otherwise. + * + */ +// DEPRECATED! +bool ESP8266WiFiMesh::exchangeInfo(String message, WiFiClient curr_client) +{ + curr_client.println( message.c_str() ); + + if (!waitForClient(curr_client, 1000)) + return false; + + String response = curr_client.readStringUntil('\r'); + curr_client.readStringUntil('\n'); + + if (response.length() <= 2) + return false; + + /* Pass data to user callback */ + _handler(response); + return true; +} + +/** + * Connect to the AP at ssid, send them a message then disconnect. + * + * @target_ssid The name of the AP the other node has set up. + * @message The string to send to the node. + * + */ +// DEPRECATED! +void ESP8266WiFiMesh::connectToNode(String target_ssid, String message) +{ + WiFiClient curr_client; + WiFi.begin( target_ssid.c_str() ); + + int wait = 1500; + while((WiFi.status() == WL_DISCONNECTED) && wait--) + delay(3); + + /* If the connection timed out */ + if (WiFi.status() != 3) + return; + + /* Connect to the node's server */ + if (!curr_client.connect(SERVER_IP_ADDR, SERVER_PORT)) + return; + + if (!exchangeInfo(message, curr_client)) + return; + + curr_client.stop(); + WiFi.disconnect(); +} + +// DEPRECATED! +void ESP8266WiFiMesh::attemptScan(String message) +{ + /* Scan for APs */ + int n = WiFi.scanNetworks(); + + for (int i = 0; i < n; ++i) { + String current_ssid = WiFi.SSID(i); + int index = current_ssid.indexOf( _ssid_prefix ); + uint32_t target_chip_id = (current_ssid.substring(index + _ssid_prefix.length())).toInt(); + + /* Connect to any _suitable_ APs which contain _ssid_prefix */ + if (index >= 0 && (target_chip_id < _chip_id)) { + + WiFi.mode(WIFI_STA); + delay(100); + connectToNode(current_ssid, message); + WiFi.mode(WIFI_AP_STA); + delay(100); + } + } +} \ No newline at end of file diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index 768d5fec75..8fff510495 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -186,18 +186,29 @@ void ESP8266WiFiMesh::disableStaticIP() void ESP8266WiFiMesh::begin() { - WiFi.mode(WIFI_AP_STA); - - #ifdef ENABLE_STATIC_IP_OPTIMIZATION - if(atLeastLwipVersion(lwip_version_203_signature)) + //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + if(_handler != NULL) { - verboseModePrint("lwIP version is at least 2.0.3. Static ip optimizations enabled.\n"); + WiFi.mode(WIFI_AP_STA); + WiFi.softAP( _ssid.c_str() ); + _server.begin(); } else { - verboseModePrint("lwIP version is less than 2.0.3. Static ip optimizations disabled.\n"); + //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + WiFi.mode(WIFI_AP_STA); + + #ifdef ENABLE_STATIC_IP_OPTIMIZATION + if(atLeastLwipVersion(lwip_version_203_signature)) + { + verboseModePrint("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"); + } + #endif } - #endif } void ESP8266WiFiMesh::activateAP(String new_mesh_name, String new_node_id) @@ -524,30 +535,57 @@ void ESP8266WiFiMesh::attemptTransmission(String message, bool concluding_discon void ESP8266WiFiMesh::acceptRequest() { - while (true) { - WiFiClient _client = _server.available(); - - if (!_client) - break; + //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + if(_handler != NULL) + { + while (true) { + _client = _server.available(); + if (!_client) + break; - if (!waitForClientTransmission(_client, 1500) || !_client.available()) { - continue; - } + if (!waitForClient(_client, 1500)) { + continue; + } - /* Read in request and pass it to the supplied requestHandler */ - String request = _client.readStringUntil('\r'); - yield(); - _client.flush(); + /* Read in request and pass it to the supplied handler */ + String request = _client.readStringUntil('\r'); + _client.readStringUntil('\n'); - String response = _requestHandler(request, this); + String response = _handler(request); - /* Send the response back to the client */ - if (_client.connected()) - { - verboseModePrint("Responding"); - _client.print(response + "\r"); - _client.flush(); + /* Send the response back to the client */ + if (_client.connected()) + _client.println(response); + } + } + else + { + //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + while (true) { + WiFiClient _client = _server.available(); + + if (!_client) + break; + + if (!waitForClientTransmission(_client, 1500) || !_client.available()) { + continue; + } + + /* Read in request and pass it to the supplied requestHandler */ + String request = _client.readStringUntil('\r'); yield(); + _client.flush(); + + String response = _requestHandler(request, this); + + /* Send the response back to the client */ + if (_client.connected()) + { + verboseModePrint("Responding"); + _client.print(response + "\r"); + _client.flush(); + yield(); + } } } } diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 82aaf7e88b..78a983fb02 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -41,7 +41,7 @@ class ESP8266WiFiMesh { String _mesh_password; uint8 _mesh_wifi_channel; bool _verbose_mode; - WiFiServer _server; + WiFiServer _server; uint32_t _lwip_version[3]; static const uint32_t lwip_version_203_signature[3]; String _message = ""; @@ -68,8 +68,50 @@ class ESP8266WiFiMesh { void storeLwipVersion(); bool atLeastLwipVersion(const uint32_t min_lwip_version[3]); + + + + //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + + String _ssid_prefix; + uint32_t _chip_id; + + std::function _handler = NULL; + + WiFiClient _client; + + void connectToNode(String target_ssid, String message); + bool exchangeInfo(String message, WiFiClient curr_client); + bool waitForClient(WiFiClient curr_client, int max_wait); + + //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + + + public: + //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + + /** + * WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised. + * + * @chip_id A unique identifier number for the node. + * @handler The callback handler for dealing with received messages. Takes a string as an argument which + * is the string received from another node and returns the string to send back. + * + */ + ESP8266WiFiMesh(uint32_t chip_id, std::function handler); + + /** + * Scan for other nodes, and exchange the chosen message with any that are found. + * + * @message The message to send to all other nodes. + * + */ + void attemptScan(String message); + + //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + /** * WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised. * From 59418c398c1223e3b964e5a8e30a42cecf20f493 Mon Sep 17 00:00:00 2001 From: Anders Date: Sun, 22 Jul 2018 21:38:44 +0200 Subject: [PATCH 12/20] Polish documentation slightly. --- libraries/ESP8266WiFiMesh/README.md | 2 +- libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/README.md b/libraries/ESP8266WiFiMesh/README.md index 13a9c8e253..4e7d755e56 100644 --- a/libraries/ESP8266WiFiMesh/README.md +++ b/libraries/ESP8266WiFiMesh/README.md @@ -66,6 +66,6 @@ This library uses the standard Arduino core for ESP8266 WiFi functions. Therefor A maximum of 5 stations can be connected at a time to each AP. -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 disconnect all stations connected to the node AP (though they can request a reconnect even while the previous AP node is in STA mode). +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). Scanning for networks (e.g. via the `attemptTransmission` method) without the WiFi scan optimizations for core version 2.4.2 mentioned above, causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index 8fff510495..24ea21929a 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -205,7 +205,7 @@ void ESP8266WiFiMesh::begin() } else { - verboseModePrint("lwIP version is less than 2.0.3. Static ip optimizations disabled.\n"); + verboseModePrint("lwIP version is less than 2.0.3. Static ip optimizations DISABLED.\n"); } #endif } From 7f853a5e0ab5eab0af89c5399fe6c115eede86e2 Mon Sep 17 00:00:00 2001 From: Anders Date: Mon, 23 Jul 2018 16:47:45 +0200 Subject: [PATCH 13/20] Add scan_all_wifi_channels option to attemptTransmission method. --- libraries/ESP8266WiFiMesh/README.md | 4 +++- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 16 ++++++++++++---- libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 6 +++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/README.md b/libraries/ESP8266WiFiMesh/README.md index 4e7d755e56..2f0d9bb3b2 100644 --- a/libraries/ESP8266WiFiMesh/README.md +++ b/libraries/ESP8266WiFiMesh/README.md @@ -51,7 +51,9 @@ ESP8266WiFiMesh(std::function requestHandler, * 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. - If you are using a core version prior to 2.4.2 it is possible to disable the WiFi scan and static ip optimizations by commenting out the `ENABLE_STATIC_IP_OPTIMIZATION` and `ENABLE_WIFI_SCAN_OPTIMIZATION` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while an example from the mesh library is opened, to open the library folder (or click "Show Sketch Folder" in the Sketch menu). ESP8266WiFiMesh.h can then be found at ESP8266WiFiMesh/src. Edit the file with any text editor. + If you are using a core version prior to 2.4.2 it is possible to disable the WiFi scan and static IP optimizations by commenting out the `ENABLE_STATIC_IP_OPTIMIZATION` and `ENABLE_WIFI_SCAN_OPTIMIZATION` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while an example from the mesh library is opened, to open the library folder (or click "Show Sketch Folder" in the Sketch menu). ESP8266WiFiMesh.h can then be found at ESP8266WiFiMesh/src. Edit the file with any text editor. + +* The WiFi scan optimization mentioned above works by making WiFi scans only search through the same WiFi channel as the ESP8266WiFiMesh instance is using. If you would like to scan all WiFi channels instead, set the `scan_all_wifi_channels` argument of the `attemptTransmission` method to `true`. Note that scanning all WiFi channels will slow down scans considerably and make it more likely that existing WiFi connections will break during scans. Also note that if the ESP8266 has an active AP, that AP will switch WiFi channel to match that of any other AP the ESP8266 connects to (compare next bullet point). This can make it impossible for other nodes to detect the AP if they are scanning the wrong WiFi channel. To remedy this, use the `restartAP` method to force the AP back on the original channel once the ESP8266 has disconnected from the other AP. * It is possible to have several ESP8266WiFiMesh instances running on every ESP8266 (e.g. to communicate with different mesh networks). However, because the ESP8266 has one WiFi radio only one AP per ESP8266 can be active at a time. Also note that if the ESP8266WiFiMesh instances use different WiFi channels, active APs are forced to use the same WiFi channel as active stations, possibly causing AP disconnections. diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index 24ea21929a..adffb48ef4 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -439,7 +439,7 @@ transmission_status_t ESP8266WiFiMesh::connectToNode(String target_ssid, int tar return attemptDataTransfer(); } -void ESP8266WiFiMesh::attemptTransmission(String message, bool concluding_disconnect, bool initial_disconnect, bool no_scan) +void ESP8266WiFiMesh::attemptTransmission(String message, bool concluding_disconnect, bool initial_disconnect, bool no_scan, bool scan_all_wifi_channels) { setMessage(message); @@ -467,11 +467,19 @@ void ESP8266WiFiMesh::attemptTransmission(String message, bool concluding_discon // If Arduino core for ESP8266 version < 2.4.2 scanning will cause the WiFi radio to cycle through all WiFi channels. // This means existing WiFi connections are likely to break or work poorly if done frequently. + int n = 0; #ifdef ENABLE_WIFI_SCAN_OPTIMIZATION - // Scan function argument overview: scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL) - int n = WiFi.scanNetworks(false, false, _mesh_wifi_channel); + if(scan_all_wifi_channels) + { + n = WiFi.scanNetworks(); + } + else + { + // Scan function argument overview: scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL) + n = WiFi.scanNetworks(false, false, _mesh_wifi_channel); + } #else - int n = WiFi.scanNetworks(); + n = WiFi.scanNetworks(); #endif _networkFilter(n, this); // Update the connection_queue. diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 78a983fb02..6f7f85bcc1 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -180,8 +180,12 @@ class ESP8266WiFiMesh { * @param concluding_disconnect Disconnect from AP once transmission is complete. * @param initial_disconnect Disconnect from any currently connected AP before attempting transmission. * @param no_scan Do not scan for new networks and do not call networkFilter function. Will only use the data already in connection_queue for the transmission. + * @param scan_all_wifi_channels Scan all WiFi channels during a WiFi scan, instead of just the channel the ESP8266WiFiMesh instance is using. + * Scanning all WiFi channels takes about 2100 ms, compared to just 60 ms if only channel 1 (standard) is scanned. + * Note that if the ESP8266 has an active AP, that AP will switch WiFi channel to match that of any other AP the ESP8266 connects to. + * This can make it impossible for other nodes to detect the AP if they are scanning the wrong WiFi channel. */ - void attemptTransmission(String message, bool concluding_disconnect = true, bool initial_disconnect = false, bool no_scan = false); + void attemptTransmission(String message, bool concluding_disconnect = true, bool initial_disconnect = false, bool no_scan = false, bool scan_all_wifi_channels = false); /** * If any clients are connected, accept their requests and call the requestHandler function for each one. From 751f9afb9f83e54de3cb8836d05115ca1fa7767f Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 31 Jul 2018 06:05:22 +0200 Subject: [PATCH 14/20] - Add getter and setter for the WiFi channel of a ESP8266WiFiMesh instance. - Separate methods for changing mesh name and node id from AP control methods. - Add methods getAPController and isAPController to better handle situations when multiple ESP8266WiFiMesh instances take turns to be in control of the AP. - Create separate UtilityMethods.cpp file for utility methods. - Improve code efficiency and robustness, e.g. by passing arguments by reference instead of by value for non-POD types and employing typedefs. - Update README.md. --- libraries/ESP8266WiFiMesh/README.md | 15 +- .../examples/HelloMesh/HelloMesh.ino | 50 ++-- libraries/ESP8266WiFiMesh/keywords.txt | 8 + .../src/CompatibilityLayer.cpp | 8 +- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 255 ++++++++---------- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 141 +++++++--- libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp | 4 +- libraries/ESP8266WiFiMesh/src/NetworkInfo.h | 4 +- .../src/TransmissionResult.cpp | 4 +- .../ESP8266WiFiMesh/src/TransmissionResult.h | 4 +- .../ESP8266WiFiMesh/src/UtilityMethods.cpp | 127 +++++++++ 11 files changed, 407 insertions(+), 213 deletions(-) create mode 100644 libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp diff --git a/libraries/ESP8266WiFiMesh/README.md b/libraries/ESP8266WiFiMesh/README.md index 2f0d9bb3b2..113d029994 100644 --- a/libraries/ESP8266WiFiMesh/README.md +++ b/libraries/ESP8266WiFiMesh/README.md @@ -53,7 +53,12 @@ ESP8266WiFiMesh(std::function requestHandler, If you are using a core version prior to 2.4.2 it is possible to disable the WiFi scan and static IP optimizations by commenting out the `ENABLE_STATIC_IP_OPTIMIZATION` and `ENABLE_WIFI_SCAN_OPTIMIZATION` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while an example from the mesh library is opened, to open the library folder (or click "Show Sketch Folder" in the Sketch menu). ESP8266WiFiMesh.h can then be found at ESP8266WiFiMesh/src. Edit the file with any text editor. -* The WiFi scan optimization mentioned above works by making WiFi scans only search through the same WiFi channel as the ESP8266WiFiMesh instance is using. If you would like to scan all WiFi channels instead, set the `scan_all_wifi_channels` argument of the `attemptTransmission` method to `true`. Note that scanning all WiFi channels will slow down scans considerably and make it more likely that existing WiFi connections will break during scans. Also note that if the ESP8266 has an active AP, that AP will switch WiFi channel to match that of any other AP the ESP8266 connects to (compare next bullet point). This can make it impossible for other nodes to detect the AP if they are scanning the wrong WiFi channel. To remedy this, use the `restartAP` method to force the AP back on the original channel once the ESP8266 has disconnected from the other AP. +* The WiFi scan optimization mentioned above works by making WiFi scans only search through the same WiFi channel as the ESP8266WiFiMesh instance is using. If you would like to scan all WiFi channels instead, set the `scan_all_wifi_channels` argument of the `attemptTransmission` method to `true`. Note that scanning all WiFi channels will slow down scans considerably and make it more likely that existing WiFi connections will break during scans. Also note that if the ESP8266 has an active AP, that AP will switch WiFi channel to match that of any other AP the ESP8266 connects to (compare next bullet point). This can make it impossible for other nodes to detect the AP if they are scanning the wrong WiFi channel. To remedy this, force the AP back on the original channel by using the `restartAP` method of the current AP controller once the ESP8266 has disconnected from the other AP. This would typically be done like so: + + ``` + if(ESP8266WiFiMesh *apController = ESP8266WiFiMesh::getAPController()) // Make sure apController is not nullptr + apController->restartAP(); + ``` * It is possible to have several ESP8266WiFiMesh instances running on every ESP8266 (e.g. to communicate with different mesh networks). However, because the ESP8266 has one WiFi radio only one AP per ESP8266 can be active at a time. Also note that if the ESP8266WiFiMesh instances use different WiFi channels, active APs are forced to use the same WiFi channel as active stations, possibly causing AP disconnections. @@ -64,10 +69,10 @@ ESP8266WiFiMesh(std::function requestHandler, 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. +* 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. +* A maximum of 5 stations can be connected at a time to each AP. -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). +* 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). -Scanning for networks (e.g. via the `attemptTransmission` method) without the WiFi scan optimizations for core version 2.4.2 mentioned above, causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file +* Scanning for networks (e.g. via the `attemptTransmission` method) without the WiFi scan optimizations for core version 2.4.2 mentioned above, causes the WiFi radio to cycle through all WiFi channels which means existing WiFi connections are likely to break or work poorly if done frequently. \ No newline at end of file diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index b7bb03ca63..68aa679242 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -1,52 +1,50 @@ #include #include -String mesh_name = "Mesh_Node"; +String meshName("MeshNode_"); unsigned int request_i = 0; unsigned int response_i = 0; -String manageRequest(String request, ESP8266WiFiMesh *mesh_instance); -transmission_status_t manageResponse(String response, ESP8266WiFiMesh *mesh_instance); -void networkFilter(int number_of_networks, ESP8266WiFiMesh *mesh_instance); +String manageRequest(const String &request, ESP8266WiFiMesh &mesh_instance); +transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &mesh_instance); +void networkFilter(int number_of_networks, ESP8266WiFiMesh &mesh_instance); /* Create the mesh node object */ -ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(manageRequest, manageResponse, networkFilter, "ChangeThisWiFiPassword_TODO", mesh_name, "", true); +ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(manageRequest, manageResponse, networkFilter, "ChangeThisWiFiPassword_TODO", meshName, "", true); /** Callback for when other nodes send you a request @param request The request string received from another node in the mesh - @param mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. + @param mesh_instance The ESP8266WiFiMesh instance that called the function. @returns The string to send back to the other node */ -String manageRequest(String request, ESP8266WiFiMesh *mesh_instance) { +String manageRequest(const String &request, ESP8266WiFiMesh &mesh_instance) { /* Print out received message */ Serial.print("Request received: "); Serial.println(request); /* return a string to send back */ - char response[60]; - sprintf(response, "Hello world response #%d from %s%s.", response_i++, mesh_instance->getMeshName().c_str(), mesh_instance->getNodeID().c_str()); - return response; + return ("Hello world response #" + String(response_i++) + " from " + mesh_instance.getMeshName() + mesh_instance.getNodeID() + "."); } /** Callback used to decide which networks to connect to once a WiFi scan has been completed. @param number_of_networks The number of networks found in the WiFi scan. - @param mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. + @param mesh_instance The ESP8266WiFiMesh instance that called the function. */ -void networkFilter(int number_of_networks, ESP8266WiFiMesh *mesh_instance) { +void networkFilter(int number_of_networks, ESP8266WiFiMesh &mesh_instance) { for (int i = 0; i < number_of_networks; ++i) { String current_ssid = WiFi.SSID(i); - int mesh_name_index = current_ssid.indexOf(mesh_instance->getMeshName()); + int mesh_name_index = current_ssid.indexOf(mesh_instance.getMeshName()); - /* Connect to any _suitable_ APs which contain mesh_instance->getMeshName() */ + /* Connect to any _suitable_ APs which contain mesh_instance.getMeshName() */ if (mesh_name_index >= 0) { - uint64_t target_node_id = ESP8266WiFiMesh::StringToUint64(current_ssid.substring(mesh_name_index + mesh_instance->getMeshName().length())); + uint64_t target_node_id = ESP8266WiFiMesh::StringToUint64(current_ssid.substring(mesh_name_index + mesh_instance.getMeshName().length())); - if (target_node_id < ESP8266WiFiMesh::StringToUint64(mesh_instance->getNodeID())) { + if (target_node_id < ESP8266WiFiMesh::StringToUint64(mesh_instance.getNodeID())) { ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo(i)); } } @@ -57,20 +55,20 @@ void networkFilter(int number_of_networks, ESP8266WiFiMesh *mesh_instance) { Callback for when you get a response from other nodes @param response The response string received from another node in the mesh - @param mesh_instance The "this" pointer of the ESP8266WiFiMesh instance that called the function. + @param mesh_instance The ESP8266WiFiMesh instance that called the function. @returns The status code resulting from the response, as an int */ -transmission_status_t manageResponse(String response, ESP8266WiFiMesh *mesh_instance) { +transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &mesh_instance) { transmission_status_t status_code = TS_TRANSMISSION_COMPLETE; /* Print out received message */ Serial.print("Request sent: "); - Serial.println(mesh_instance->getMessage()); + Serial.println(mesh_instance.getMessage()); Serial.print("Response received: "); Serial.println(response); // Our last request got a response, so time to create a new request. - mesh_instance->setMessage("Hello world request #" + String(++request_i) + " from " + mesh_instance->getMeshName() + mesh_instance->getNodeID() + "."); + mesh_instance.setMessage("Hello world request #" + String(++request_i) + " from " + mesh_instance.getMeshName() + mesh_instance.getNodeID() + "."); // (void)mesh_instance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else. return status_code; @@ -90,8 +88,9 @@ void setup() { 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 to enable this and 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"); + "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..."); @@ -105,8 +104,7 @@ int32_t time_of_last_scan = -10000; void loop() { if (millis() - time_of_last_scan > 3000 // Give other nodes some time to connect between data transfers. || (WiFi.status() != WL_CONNECTED && millis() - time_of_last_scan > 2000)) { // Scan for networks with two second intervals when not already connected. - char request[60]; - sprintf(request, "Hello world request #%d from %s%s.", request_i, mesh_node.getMeshName().c_str(), mesh_node.getNodeID().c_str()); + String request = "Hello world request #" + String(request_i) + " from " + mesh_node.getMeshName() + mesh_node.getNodeID() + "."; mesh_node.attemptTransmission(request, false); time_of_last_scan = millis(); @@ -118,6 +116,10 @@ void loop() { Serial.println("Transmission failed to mesh AP " + transmission_result.ssid); } else if (transmission_result.transmission_status == TS_CONNECTION_FAILED) { Serial.println("Connection failed to mesh AP " + transmission_result.ssid); + } else if (transmission_result.transmission_status == TS_TRANSMISSION_COMPLETE) { + // No need to do anything, transmission was successful. + } else { + Serial.println("Invalid transmission status for " + transmission_result.ssid + "!"); } } } diff --git a/libraries/ESP8266WiFiMesh/keywords.txt b/libraries/ESP8266WiFiMesh/keywords.txt index 47493500d5..eb425dcb86 100644 --- a/libraries/ESP8266WiFiMesh/keywords.txt +++ b/libraries/ESP8266WiFiMesh/keywords.txt @@ -27,8 +27,15 @@ begin KEYWORD2 activateAP KEYWORD2 deactivateAP KEYWORD2 restartAP KEYWORD2 +getAPController KEYWORD2 +isAPController KEYWORD2 +getWiFiChannel KEYWORD2 +setWiFiChannel KEYWORD2 getMeshName KEYWORD2 +setMeshName KEYWORD2 getNodeID KEYWORD2 +setNodeID KEYWORD2 +setSSID KEYWORD2 getMessage KEYWORD2 setMessage KEYWORD2 attemptTransmission KEYWORD2 @@ -47,3 +54,4 @@ setNetworkFilter KEYWORD2 empty_IP LITERAL1 NETWORK_INFO_DEFAULT_INT LITERAL1 +WIFI_MESH_EMPTY_STRING LITERAL1 diff --git a/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp b/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp index 958ff52980..17504cc120 100644 --- a/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp +++ b/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp @@ -49,7 +49,7 @@ #define SERVER_PORT 4011 // DEPRECATED! -ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, std::function handler) +ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, ESP8266WiFiMesh::compatibilityLayerHandlerType handler) : _server(SERVER_PORT) { _chip_id = chip_id; @@ -65,7 +65,7 @@ ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, std::function * */ // DEPRECATED! -bool ESP8266WiFiMesh::waitForClient(WiFiClient curr_client, int max_wait) +bool ESP8266WiFiMesh::waitForClient(WiFiClient &curr_client, int max_wait) { int wait = max_wait; while(curr_client.connected() && !curr_client.available() && wait--) @@ -88,7 +88,7 @@ bool ESP8266WiFiMesh::waitForClient(WiFiClient curr_client, int max_wait) * */ // DEPRECATED! -bool ESP8266WiFiMesh::exchangeInfo(String message, WiFiClient curr_client) +bool ESP8266WiFiMesh::exchangeInfo(String &message, WiFiClient &curr_client) { curr_client.println( message.c_str() ); @@ -114,7 +114,7 @@ bool ESP8266WiFiMesh::exchangeInfo(String message, WiFiClient curr_client) * */ // DEPRECATED! -void ESP8266WiFiMesh::connectToNode(String target_ssid, String message) +void ESP8266WiFiMesh::connectToNode(const String &target_ssid, String &message) { WiFiClient curr_client; WiFi.begin( target_ssid.c_str() ); diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index adffb48ef4..ec36b6f17f 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "ESP8266WiFiMesh.h" @@ -36,129 +37,78 @@ bool ESP8266WiFiMesh::static_IP_activated = false; IPAddress ESP8266WiFiMesh::static_IP = empty_IP; IPAddress ESP8266WiFiMesh::gateway = IPAddress(192,168,4,1); IPAddress ESP8266WiFiMesh::subnet_mask = IPAddress(255,255,255,0); +ESP8266WiFiMesh *ESP8266WiFiMesh::apController = nullptr; std::vector ESP8266WiFiMesh::connection_queue = {}; std::vector ESP8266WiFiMesh::latest_transmission_outcomes = {}; -ESP8266WiFiMesh::ESP8266WiFiMesh(std::function requestHandler, std::function responseHandler, - std::function networkFilter, String mesh_password, String mesh_name, String node_id, bool verbose_mode, uint8 mesh_wifi_channel, int server_port) +ESP8266WiFiMesh::~ESP8266WiFiMesh() +{ + if(isAPController()) + { + apController = nullptr; + } +} + +ESP8266WiFiMesh::ESP8266WiFiMesh(ESP8266WiFiMesh::requestHandlerType requestHandler, ESP8266WiFiMesh::responseHandlerType responseHandler, + ESP8266WiFiMesh::networkFilterType networkFilter, const String &mesh_password, const String &mesh_name, + const String &node_id, bool verbose_mode, uint8 mesh_wifi_channel, int server_port) : _server(server_port), _lwip_version{0, 0, 0} { + storeLwipVersion(); + updateNetworkNames(mesh_name, (node_id != "" ? node_id : Uint64ToString(ESP.getChipId()))); _requestHandler = requestHandler; _responseHandler = responseHandler; - _mesh_wifi_channel = mesh_wifi_channel; + setWiFiChannel(mesh_wifi_channel); _server_port = server_port; _mesh_password = mesh_password; _verbose_mode = verbose_mode; _networkFilter = networkFilter; - storeLwipVersion(); } -void ESP8266WiFiMesh::verboseModePrint(String string_to_print, bool newline) +void ESP8266WiFiMesh::updateNetworkNames(const String &new_mesh_name, const String &new_node_id) { - if(_verbose_mode) - { - if(newline) - Serial.println(string_to_print); - else - Serial.print(string_to_print); - } -} - -/** - * 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) -{ - String result = ""; - - while(number > 0) - { - result = String((uint32_t)(number % base), base) + result; - number /= base; - } + if(new_mesh_name != "") + _mesh_name = new_mesh_name; + if(new_node_id != "") + _node_id = new_node_id; + + _ssid = _mesh_name + _node_id; - return (result == "" ? "0" : result); + // Apply SSID changes to active AP. + if(isAPController()) + restartAP(); } -/** - * 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(String string, byte base) +void ESP8266WiFiMesh::begin() { - uint64_t result = 0; - - char current_character[1]; - for(uint32_t i = 0; i < string.length(); i++) + //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + if(_handler != NULL) { - result *= base; - current_character[0] = string.charAt(i); - result += strtoul(current_character, NULL, base); + WiFi.mode(WIFI_AP_STA); + WiFi.softAP( _ssid.c_str() ); + _server.begin(); } - - return result; -} - -/** - * Calculate the current lwIP version number and store the numbers in the _lwip_version array. - * lwIP version can be changed in the "Tools" menu of Arduino IDE. - */ -void ESP8266WiFiMesh::storeLwipVersion() -{ - // ESP.getFullVersion() looks something like: - // SDK:2.2.1(cfd48f3)/Core:win-2.5.0-dev/lwIP:2.0.3(STABLE-2_0_3_RELEASE/glue:arduino-2.4.1-10-g0c0d8c2)/BearSSL:94e9704 - String full_version = ESP.getFullVersion(); - - int i = full_version.indexOf("lwIP:") + 5; - char current_char = full_version.charAt(i); - - for(int version_part = 0; version_part < 3; version_part++) + else { - while(!isdigit(current_char)) + //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + WiFi.mode(WIFI_AP_STA); + + #ifdef ENABLE_STATIC_IP_OPTIMIZATION + if(atLeastLwipVersion(lwip_version_203_signature)) { - current_char = full_version.charAt(++i); + verboseModePrint("lwIP version is at least 2.0.3. Static ip optimizations enabled.\n"); } - while(isdigit(current_char)) + else { - _lwip_version[version_part] = 10 * _lwip_version[version_part] + (current_char - '0'); // Left shift and add digit value, in base 10. - current_char = full_version.charAt(++i); + verboseModePrint("lwIP version is less than 2.0.3. Static ip optimizations DISABLED.\n"); } + #endif } } -/** - * Check if the code is running on a version of lwIP that is at least min_lwip_version. - */ -bool ESP8266WiFiMesh::atLeastLwipVersion(const uint32_t min_lwip_version[3]) -{ - for(int version_part = 0; version_part < 3; version_part++) - { - if(_lwip_version[version_part] > min_lwip_version[version_part]) - return true; - else if(_lwip_version[version_part] < min_lwip_version[version_part]) - return false; - } - - return true; -} - -void ESP8266WiFiMesh::updateNetworkNames(String new_mesh_name, String new_node_id) -{ - _mesh_name = new_mesh_name; - _node_id = new_node_id; - _ssid = _mesh_name + _node_id; -} - -void ESP8266WiFiMesh::setStaticIP(IPAddress new_IP) +void ESP8266WiFiMesh::setStaticIP(const IPAddress &new_IP) { // Comment out the line below to remove static IP and use DHCP instead. // DHCP makes WiFi connection happen slower, but there is no need to care about manually giving different IPs to the nodes and less need to worry about used IPs giving "Server unavailable" issues. @@ -184,70 +134,93 @@ void ESP8266WiFiMesh::disableStaticIP() static_IP_activated = false; } -void ESP8266WiFiMesh::begin() +void ESP8266WiFiMesh::activateAP() { - //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// - if(_handler != NULL) - { - WiFi.mode(WIFI_AP_STA); - WiFi.softAP( _ssid.c_str() ); - _server.begin(); - } - else + // 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(), _mesh_password.c_str(), _mesh_wifi_channel ); // Note that a maximum of 5 stations can be connected at a time to each AP + _server.begin(); // Actually calls _server.stop()/_server.close() first. + + apController = this; +} + +void ESP8266WiFiMesh::deactivateAP() +{ + if(isAPController()) { - //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// - WiFi.mode(WIFI_AP_STA); - - #ifdef ENABLE_STATIC_IP_OPTIMIZATION - if(atLeastLwipVersion(lwip_version_203_signature)) - { - verboseModePrint("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"); - } - #endif + _server.stop(); + WiFi.softAPdisconnect(); + + // Since there is no active AP controller now, make the apController variable point to nothing. + apController = nullptr; } } -void ESP8266WiFiMesh::activateAP(String new_mesh_name, String new_node_id) +void ESP8266WiFiMesh::restartAP() { - if(new_mesh_name != "" || new_node_id != "") - updateNetworkNames(new_mesh_name != "" ? new_mesh_name : _mesh_name, new_node_id != "" ? new_node_id : _node_id); - - WiFi.softAP( _ssid.c_str(), _mesh_password.c_str(), _mesh_wifi_channel ); // Note that a maximum of 5 stations can be connected at a time to each AP - _server.begin(); // Actually calls _server.stop()/_server.close() first. + deactivateAP(); + yield(); + activateAP(); + yield(); } -void ESP8266WiFiMesh::deactivateAP(String new_mesh_name, String new_node_id) +ESP8266WiFiMesh * ESP8266WiFiMesh::getAPController() { - _server.stop(); - WiFi.softAPdisconnect(); + return apController; +} - if(new_mesh_name != "" || new_node_id != "") - updateNetworkNames(new_mesh_name != "" ? new_mesh_name : _mesh_name, new_node_id != "" ? new_node_id : _node_id); +bool ESP8266WiFiMesh::isAPController() +{ + return (this == apController); } -void ESP8266WiFiMesh::restartAP(String new_mesh_name, String new_node_id) +uint8 ESP8266WiFiMesh::getWiFiChannel() { - deactivateAP(new_mesh_name, new_node_id); - activateAP(); + return _mesh_wifi_channel; +} + +void ESP8266WiFiMesh::setWiFiChannel(uint8 new_wifi_channel) +{ + assert(1 <= new_wifi_channel && new_wifi_channel <= 13); + + _mesh_wifi_channel = new_wifi_channel; + + // Apply changes to active AP. + if(isAPController()) + restartAP(); } String ESP8266WiFiMesh::getMeshName() {return _mesh_name;} + +void ESP8266WiFiMesh::setMeshName(const String &new_mesh_name) +{ + updateNetworkNames(new_mesh_name); +} + String ESP8266WiFiMesh::getNodeID() {return _node_id;} +void ESP8266WiFiMesh::setNodeID(const String &new_node_id) +{ + updateNetworkNames("", new_node_id); +} + +void ESP8266WiFiMesh::setSSID(const String &new_mesh_name, const String &new_node_id) +{ + updateNetworkNames(new_mesh_name, new_node_id); +} + String ESP8266WiFiMesh::getMessage() {return _message;} -void ESP8266WiFiMesh::setMessage(String new_message) {_message = new_message;} +void ESP8266WiFiMesh::setMessage(const String &new_message) {_message = new_message;} -std::function ESP8266WiFiMesh::getNetworkFilter() {return _networkFilter;} -void ESP8266WiFiMesh::setNetworkFilter(std::function networkFilter) {_networkFilter = networkFilter;} +ESP8266WiFiMesh::networkFilterType ESP8266WiFiMesh::getNetworkFilter() {return _networkFilter;} +void ESP8266WiFiMesh::setNetworkFilter(ESP8266WiFiMesh::networkFilterType networkFilter) {_networkFilter = networkFilter;} /** * Disconnect completely from a network. */ -void ESP8266WiFiMesh::fullStop(WiFiClient curr_client) +void ESP8266WiFiMesh::fullStop(WiFiClient &curr_client) { curr_client.stop(); yield(); @@ -261,7 +234,7 @@ void ESP8266WiFiMesh::fullStop(WiFiClient curr_client) * @returns: True if the client is ready, false otherwise. * */ -bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient curr_client, int max_wait) +bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient &curr_client, int max_wait) { int wait = max_wait; while(curr_client.connected() && !curr_client.available() && wait--) @@ -285,7 +258,7 @@ bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient curr_client, int max_ * @returns: A status code based on the outcome of the exchange. * */ -transmission_status_t ESP8266WiFiMesh::exchangeInfo(WiFiClient curr_client) +transmission_status_t ESP8266WiFiMesh::exchangeInfo(WiFiClient &curr_client) { verboseModePrint("Transmitting"); @@ -309,7 +282,7 @@ transmission_status_t ESP8266WiFiMesh::exchangeInfo(WiFiClient curr_client) curr_client.flush(); /* Pass data to user callback */ - return _responseHandler(response, this); + return _responseHandler(response, *this); } /** @@ -361,7 +334,7 @@ transmission_status_t ESP8266WiFiMesh::attemptDataTransferKernel() return transmission_outcome; } -void ESP8266WiFiMesh::initiateConnectionToAP(String target_ssid, int target_channel, uint8_t *target_bssid) +void ESP8266WiFiMesh::initiateConnectionToAP(const String &target_ssid, int target_channel, uint8_t *target_bssid) { if(target_channel == NETWORK_INFO_DEFAULT_INT) WiFi.begin( target_ssid.c_str(), _mesh_password.c_str() ); // Without giving channel and bssid, connection time is longer. @@ -380,7 +353,7 @@ void ESP8266WiFiMesh::initiateConnectionToAP(String target_ssid, int target_chan * @returns: A status code based on the outcome of the connection and data transfer process. * */ -transmission_status_t ESP8266WiFiMesh::connectToNode(String target_ssid, int target_channel, uint8_t *target_bssid) +transmission_status_t ESP8266WiFiMesh::connectToNode(const String &target_ssid, int target_channel, uint8_t *target_bssid) { if(static_IP_activated && last_ssid != "" && last_ssid != target_ssid) // So we only do this once per connection, in case there is a performance impact. { @@ -439,7 +412,7 @@ transmission_status_t ESP8266WiFiMesh::connectToNode(String target_ssid, int tar return attemptDataTransfer(); } -void ESP8266WiFiMesh::attemptTransmission(String message, bool concluding_disconnect, bool initial_disconnect, bool no_scan, bool scan_all_wifi_channels) +void ESP8266WiFiMesh::attemptTransmission(const String &message, bool concluding_disconnect, bool initial_disconnect, bool no_scan, bool scan_all_wifi_channels) { setMessage(message); @@ -482,7 +455,7 @@ void ESP8266WiFiMesh::attemptTransmission(String message, bool concluding_discon n = WiFi.scanNetworks(); #endif - _networkFilter(n, this); // Update the connection_queue. + _networkFilter(n, *this); // Update the connection_queue. } for(NetworkInfo ¤t_network : connection_queue) @@ -584,7 +557,7 @@ void ESP8266WiFiMesh::acceptRequest() yield(); _client.flush(); - String response = _requestHandler(request, this); + String response = _requestHandler(request, *this); /* Send the response back to the client */ if (_client.connected()) diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 6f7f85bcc1..68a416d7f4 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -31,6 +31,8 @@ #define ENABLE_STATIC_IP_OPTIMIZATION // Requires Arduino core for ESP8266 version 2.4.2 or higher and lwIP2 (lwIP can be changed in "Tools" menu of Arduino IDE). #define ENABLE_WIFI_SCAN_OPTIMIZATION // Requires Arduino core for ESP8266 version 2.4.2 or higher. Scan time should go from about 2100 ms to around 60 ms if channel 1 (standard) is used. +const String WIFI_MESH_EMPTY_STRING = ""; + class ESP8266WiFiMesh { private: @@ -44,25 +46,30 @@ class ESP8266WiFiMesh { WiFiServer _server; uint32_t _lwip_version[3]; static const uint32_t lwip_version_203_signature[3]; - String _message = ""; + String _message = WIFI_MESH_EMPTY_STRING; static String last_ssid; static bool static_IP_activated; static IPAddress static_IP; static IPAddress gateway; static IPAddress subnet_mask; + static ESP8266WiFiMesh *apController; + + typedef std::function requestHandlerType; + typedef std::function responseHandlerType; + typedef std::function networkFilterType; + + requestHandlerType _requestHandler; + responseHandlerType _responseHandler; + networkFilterType _networkFilter; - std::function _requestHandler; - std::function _responseHandler; - std::function _networkFilter; - - void updateNetworkNames(String new_mesh_name, String new_node_id); - void verboseModePrint(String string_to_print, bool newline = true); - void fullStop(WiFiClient curr_client); - void initiateConnectionToAP(String target_ssid, int target_channel = NETWORK_INFO_DEFAULT_INT, uint8_t *target_bssid = NULL); - transmission_status_t connectToNode(String target_ssid, int target_channel = NETWORK_INFO_DEFAULT_INT, uint8_t *target_bssid = NULL); - transmission_status_t exchangeInfo(WiFiClient curr_client); - bool waitForClientTransmission(WiFiClient curr_client, int max_wait); + void updateNetworkNames(const String &new_mesh_name = WIFI_MESH_EMPTY_STRING, const String &new_node_id = WIFI_MESH_EMPTY_STRING); + void verboseModePrint(const String &string_to_print, bool newline = true); + void fullStop(WiFiClient &curr_client); + void initiateConnectionToAP(const String &target_ssid, int target_channel = NETWORK_INFO_DEFAULT_INT, uint8_t *target_bssid = NULL); + transmission_status_t connectToNode(const String &target_ssid, int target_channel = NETWORK_INFO_DEFAULT_INT, uint8_t *target_bssid = NULL); + transmission_status_t exchangeInfo(WiFiClient &curr_client); + bool waitForClientTransmission(WiFiClient &curr_client, int max_wait); transmission_status_t attemptDataTransfer(); transmission_status_t attemptDataTransferKernel(); void storeLwipVersion(); @@ -73,16 +80,18 @@ class ESP8266WiFiMesh { //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + typedef std::function compatibilityLayerHandlerType; + String _ssid_prefix; uint32_t _chip_id; - std::function _handler = NULL; + compatibilityLayerHandlerType _handler = NULL; WiFiClient _client; - void connectToNode(String target_ssid, String message); - bool exchangeInfo(String message, WiFiClient curr_client); - bool waitForClient(WiFiClient curr_client, int max_wait); + void connectToNode(const String &target_ssid, String &message); + bool exchangeInfo(String &message, WiFiClient &curr_client); + bool waitForClient(WiFiClient &curr_client, int max_wait); //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// @@ -100,7 +109,7 @@ class ESP8266WiFiMesh { * is the string received from another node and returns the string to send back. * */ - ESP8266WiFiMesh(uint32_t chip_id, std::function handler); + ESP8266WiFiMesh(uint32_t chip_id, compatibilityLayerHandlerType handler); /** * Scan for other nodes, and exchange the chosen message with any that are found. @@ -112,6 +121,8 @@ class ESP8266WiFiMesh { //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// + ~ESP8266WiFiMesh(); + /** * WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised. * @@ -131,12 +142,13 @@ class ESP8266WiFiMesh { * WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly * make it impossible for other stations to detect the APs whose WiFi channels have changed. * @param server_port The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port. - * If two AP:s on the same ESP8266 are using the same server port, you must call deactivateAP on the active AP before calling activateAP on the inactive AP. + * If two AP:s on the same ESP8266 are using the same server port, they will not be able to have both server instances active at the same time. + * This is managed automatically by the activateAP method. * */ - ESP8266WiFiMesh(std::function requestHandler, std::function responseHandler, - std::function networkFilter, String mesh_password, String mesh_name = "Mesh_Node", String node_id = "", - bool verbose_mode = false, uint8 mesh_wifi_channel = 1, int server_port = 4011); + ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter, + const String &mesh_password, const String &mesh_name = "MeshNode_", const String &node_id = WIFI_MESH_EMPTY_STRING, bool verbose_mode = false, + uint8 mesh_wifi_channel = 1, int server_port = 4011); /** * A vector that contains the WiFi-scan network indicies to connect to. @@ -162,15 +174,82 @@ class ESP8266WiFiMesh { /** * Each AP requires a separate server port. If two AP:s are using the same server port, you must call deactivateAP on the active AP before calling activateAP on the inactive AP. */ - void activateAP(String new_mesh_name = "", String new_node_id = ""); - void deactivateAP(String new_mesh_name = "", String new_node_id = ""); - void restartAP(String new_mesh_name = "", String new_node_id = ""); + void activateAP(); + void deactivateAP(); + void restartAP(); + + /** + * Get the ESP8266WiFiMesh instance currently in control of the ESP8266 AP. + * Note that the result will be nullptr when there is no active AP controller. + * If another instance takes control over the AP after the pointer is created, + * the created pointer will still point to the old AP instance. + * + * @returns A pointer to the ESP8266WiFiMesh instance currently in control of the ESP8266 AP, + * or nullptr if there is no active AP controller. + */ + static ESP8266WiFiMesh * getAPController(); + + /** + * Check if this ESP8266WiFiMesh instance is in control of the ESP8266 AP. + * + * @returns True if this ESP8266WiFiMesh instance is in control of the ESP8266 AP. False otherwise. + */ + 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. + * + * 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. + * In such a case, whenever the station of one ESP8266WiFiMesh instance connects to an AP, it will silently force the + * WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly + * make it impossible for other stations to detect the APs whose WiFi channels have changed. + * + * @param new_wifi_channel The WiFi channel to change to. Valid values are integers from 1 to 13. + * + */ + void setWiFiChannel(uint8 new_wifi_channel); String getMeshName(); + + /** + * 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. + * + * @param new_mesh_name The mesh name to change to. + */ + void setMeshName(const String &new_mesh_name); + String getNodeID(); + + /** + * 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. + * + * @param new_node_id The node id to change to. + */ + void setNodeID(const String &new_node_id); + + /** + * 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. + * + * @param new_mesh_name The mesh name to change to. Will be the SSID prefix. + * @param new_node_id The node id to change to. Will be the SSID suffix. + */ + void setSSID(const String &new_mesh_name, const String &new_node_id); String getMessage(); - void setMessage(String new_message); + + /** + * Set the message that will be sent to other nodes when calling attemptTransmission. + * + * @param new_message The message to send. + */ + void setMessage(const String &new_message); /** * If AP connection already exists, send message only to this AP. @@ -185,7 +264,7 @@ class ESP8266WiFiMesh { * Note that if the ESP8266 has an active AP, that AP will switch WiFi channel to match that of any other AP the ESP8266 connects to. * This can make it impossible for other nodes to detect the AP if they are scanning the wrong WiFi channel. */ - void attemptTransmission(String message, bool concluding_disconnect = true, bool initial_disconnect = false, bool no_scan = false, bool scan_all_wifi_channels = false); + void attemptTransmission(const String &message, bool concluding_disconnect = true, bool initial_disconnect = false, bool no_scan = false, bool scan_all_wifi_channels = false); /** * If any clients are connected, accept their requests and call the requestHandler function for each one. @@ -193,10 +272,10 @@ class ESP8266WiFiMesh { void acceptRequest(); /** - * Set a static IP address for the node and activate use of static IP. + * Set a static IP address for the ESP8266 and activate use of static IP. * The static IP needs to be at the same subnet as the server's gateway. */ - void setStaticIP(IPAddress new_IP); + void setStaticIP(const IPAddress &new_IP); IPAddress getStaticIP(); void disableStaticIP(); @@ -207,10 +286,10 @@ class ESP8266WiFiMesh { static const IPAddress empty_IP; static String Uint64ToString(uint64_t number, byte base = 16); - static uint64_t StringToUint64(String string, byte base = 16); + static uint64_t StringToUint64(const String &string, byte base = 16); - std::function getNetworkFilter(); - void setNetworkFilter(std::function networkFilter); + networkFilterType getNetworkFilter(); + void setNetworkFilter(networkFilterType networkFilter); }; #endif diff --git a/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp b/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp index 8ee187acdf..3b6caae5bd 100644 --- a/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp +++ b/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp @@ -31,7 +31,7 @@ void NetworkInfo::copyBSSID(uint8_t new_bssid[6]) { if(bssid == NULL) { - bssid = bssid_array; + bssid = _bssid_array; } for(int i = 0; i < 6; i++) @@ -55,7 +55,7 @@ NetworkInfo::NetworkInfo(int new_network_index, bool autofill) : network_index(n } } -NetworkInfo::NetworkInfo(String new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index) : +NetworkInfo::NetworkInfo(const String &new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index) : ssid(new_ssid), wifi_channel(new_wifi_channel), network_index(new_network_index) { copyBSSID(new_bssid); diff --git a/libraries/ESP8266WiFiMesh/src/NetworkInfo.h b/libraries/ESP8266WiFiMesh/src/NetworkInfo.h index 93ce84dd78..d8b4dfb66f 100644 --- a/libraries/ESP8266WiFiMesh/src/NetworkInfo.h +++ b/libraries/ESP8266WiFiMesh/src/NetworkInfo.h @@ -34,7 +34,7 @@ class NetworkInfo { private: - uint8_t bssid_array[6] {0}; + uint8_t _bssid_array[6] {0}; public: @@ -51,7 +51,7 @@ class NetworkInfo { /** * Without giving channel and bssid, connection time is longer. */ - NetworkInfo(String new_ssid, int new_wifi_channel = NETWORK_INFO_DEFAULT_INT, uint8_t new_bssid[6] = NULL, int new_network_index = NETWORK_INFO_DEFAULT_INT); + NetworkInfo(const String &new_ssid, int new_wifi_channel = NETWORK_INFO_DEFAULT_INT, uint8_t new_bssid[6] = NULL, int new_network_index = NETWORK_INFO_DEFAULT_INT); NetworkInfo(const NetworkInfo &other); diff --git a/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp b/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp index f1fdf58413..b27e79a0ab 100644 --- a/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp +++ b/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp @@ -29,11 +29,11 @@ TransmissionResult::TransmissionResult(int new_network_index, transmission_statu NetworkInfo(new_network_index, autofill), transmission_status(new_transmission_status) { } -TransmissionResult::TransmissionResult(String new_ssid, int new_wifi_channel, uint8_t new_bssid[6], transmission_status_t new_transmission_status) : +TransmissionResult::TransmissionResult(const String &new_ssid, int new_wifi_channel, uint8_t new_bssid[6], transmission_status_t new_transmission_status) : NetworkInfo(new_ssid, new_wifi_channel, new_bssid), transmission_status(new_transmission_status) { } -TransmissionResult::TransmissionResult(String new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index, transmission_status_t new_transmission_status) : +TransmissionResult::TransmissionResult(const String &new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index, transmission_status_t new_transmission_status) : NetworkInfo(new_ssid, new_wifi_channel, new_bssid, new_network_index), transmission_status(new_transmission_status) { } diff --git a/libraries/ESP8266WiFiMesh/src/TransmissionResult.h b/libraries/ESP8266WiFiMesh/src/TransmissionResult.h index 5a9d7abaed..bc6a652caa 100644 --- a/libraries/ESP8266WiFiMesh/src/TransmissionResult.h +++ b/libraries/ESP8266WiFiMesh/src/TransmissionResult.h @@ -47,9 +47,9 @@ class TransmissionResult : public NetworkInfo { */ TransmissionResult(int new_network_index, transmission_status_t new_transmission_status, bool autofill = true); - TransmissionResult(String new_ssid, int new_wifi_channel, uint8_t new_bssid[6], transmission_status_t new_transmission_status); + TransmissionResult(const String &new_ssid, int new_wifi_channel, uint8_t new_bssid[6], transmission_status_t new_transmission_status); - TransmissionResult(String new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index, transmission_status_t new_transmission_status); + TransmissionResult(const String &new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index, transmission_status_t new_transmission_status); TransmissionResult(const NetworkInfo& origin, transmission_status_t new_transmission_status); }; diff --git a/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp b/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp new file mode 100644 index 0000000000..734290aa63 --- /dev/null +++ b/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp @@ -0,0 +1,127 @@ +/* + * TransmissionResult + * 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 "ESP8266WiFiMesh.h" +#include + +void ESP8266WiFiMesh::verboseModePrint(const String &string_to_print, bool newline) +{ + if(_verbose_mode) + { + if(newline) + Serial.println(string_to_print); + else + Serial.print(string_to_print); + } +} + +/** + * 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 current_character[1]; + for(uint32_t i = 0; i < string.length(); i++) + { + result *= base; + current_character[0] = string.charAt(i); + result += strtoul(current_character, NULL, base); + } + + return result; +} + +/** + * Calculate the current lwIP version number and store the numbers in the _lwip_version array. + * lwIP version can be changed in the "Tools" menu of Arduino IDE. + */ +void ESP8266WiFiMesh::storeLwipVersion() +{ + // ESP.getFullVersion() looks something like: + // SDK:2.2.1(cfd48f3)/Core:win-2.5.0-dev/lwIP:2.0.3(STABLE-2_0_3_RELEASE/glue:arduino-2.4.1-10-g0c0d8c2)/BearSSL:94e9704 + String full_version = ESP.getFullVersion(); + + int i = full_version.indexOf("lwIP:") + 5; + char current_char = full_version.charAt(i); + + for(int version_part = 0; version_part < 3; version_part++) + { + while(!isdigit(current_char)) + { + current_char = full_version.charAt(++i); + } + while(isdigit(current_char)) + { + _lwip_version[version_part] = 10 * _lwip_version[version_part] + (current_char - '0'); // Left shift and add digit value, in base 10. + current_char = full_version.charAt(++i); + } + } +} + +/** + * Check if the code is running on a version of lwIP that is at least min_lwip_version. + */ +bool ESP8266WiFiMesh::atLeastLwipVersion(const uint32_t min_lwip_version[3]) +{ + for(int version_part = 0; version_part < 3; version_part++) + { + if(_lwip_version[version_part] > min_lwip_version[version_part]) + return true; + else if(_lwip_version[version_part] < min_lwip_version[version_part]) + return false; + } + + return true; +} From ed15ab208f53453e53e32c7f0dab6395710c6a79 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 31 Jul 2018 06:15:23 +0200 Subject: [PATCH 15/20] Make the code more stylish. --- libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index 68aa679242..e160774a41 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -88,9 +88,9 @@ void setup() { 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"); + "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..."); From 75a554972a897f15cfd3d52ab50e6357c5c692a0 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 31 Jul 2018 06:31:53 +0200 Subject: [PATCH 16/20] Update README.md with the new ESP8266WiFiMesh constructor documentation. --- libraries/ESP8266WiFiMesh/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/README.md b/libraries/ESP8266WiFiMesh/README.md index 113d029994..7aaf88bd4c 100644 --- a/libraries/ESP8266WiFiMesh/README.md +++ b/libraries/ESP8266WiFiMesh/README.md @@ -37,12 +37,13 @@ For more details, see the included example. The main functions to modify in the * WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly * make it impossible for other stations to detect the APs whose WiFi channels have changed. * @param server_port The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port. -* If two AP:s on the same ESP8266 are using the same server port, you must call deactivateAP on the active AP before calling activateAP on the inactive AP. +* If two AP:s on the same ESP8266 are using the same server port, they will not be able to have both server instances active at the same time. +* This is managed automatically by the activateAP method. * */ -ESP8266WiFiMesh(std::function requestHandler, std::function responseHandler, - std::function networkFilter, String mesh_password, String mesh_name = "Mesh_Node", String node_id = "", - bool verbose_mode = false, uint8 mesh_wifi_channel = 1, int server_port = 4011); +ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter, + const String &mesh_password, const String &mesh_name = "MeshNode_", const String &node_id = WIFI_MESH_EMPTY_STRING, bool verbose_mode = false, + uint8 mesh_wifi_channel = 1, int server_port = 4011); ``` ### Note From a0edf996d32c6601d5385626d06af500a1a69351 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 31 Jul 2018 18:22:06 +0200 Subject: [PATCH 17/20] Make attemptScan method in CompatibilityLayer use reference as argument. --- .../src/CompatibilityLayer.cpp | 28 ++++++++++++++++--- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 11 ++++++-- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp b/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp index 17504cc120..971244a124 100644 --- a/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp +++ b/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp @@ -4,6 +4,7 @@ is passed in both directions, but it is up to the user what the data sent is and how it is dealt with. Copyright (c) 2015 Julian Fell. All rights reserved. + Updated 2018 by Anders Löfgren. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -88,9 +89,9 @@ bool ESP8266WiFiMesh::waitForClient(WiFiClient &curr_client, int max_wait) * */ // DEPRECATED! -bool ESP8266WiFiMesh::exchangeInfo(String &message, WiFiClient &curr_client) +bool ESP8266WiFiMesh::exchangeInfo(const char *message, WiFiClient &curr_client) { - curr_client.println( message.c_str() ); + curr_client.println( message ); if (!waitForClient(curr_client, 1000)) return false; @@ -114,7 +115,7 @@ bool ESP8266WiFiMesh::exchangeInfo(String &message, WiFiClient &curr_client) * */ // DEPRECATED! -void ESP8266WiFiMesh::connectToNode(const String &target_ssid, String &message) +void ESP8266WiFiMesh::connectToNode(const String &target_ssid, const char *message) { WiFiClient curr_client; WiFi.begin( target_ssid.c_str() ); @@ -139,7 +140,7 @@ void ESP8266WiFiMesh::connectToNode(const String &target_ssid, String &message) } // DEPRECATED! -void ESP8266WiFiMesh::attemptScan(String message) +void ESP8266WiFiMesh::attemptScanKernel(const char *message) { /* Scan for APs */ int n = WiFi.scanNetworks(); @@ -159,4 +160,23 @@ void ESP8266WiFiMesh::attemptScan(String message) delay(100); } } +} + +// DEPRECATED! +void ESP8266WiFiMesh::attemptScan(String &message) +{ + attemptScanKernel(message.c_str()); +} + +// DEPRECATED! +void ESP8266WiFiMesh::attemptScan(char *message) +{ + attemptScanKernel(message); +} + +// DEPRECATED! +template +void ESP8266WiFiMesh::attemptScan(char (&message)[Size]) +{ + attemptScanKernel(message); } \ No newline at end of file diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 68a416d7f4..9c73a0241f 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -89,9 +89,10 @@ class ESP8266WiFiMesh { WiFiClient _client; - void connectToNode(const String &target_ssid, String &message); - bool exchangeInfo(String &message, WiFiClient &curr_client); + void connectToNode(const String &target_ssid, const char *message); + bool exchangeInfo(const char *message, WiFiClient &curr_client); bool waitForClient(WiFiClient &curr_client, int max_wait); + void attemptScanKernel(const char *message); //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// @@ -117,7 +118,11 @@ class ESP8266WiFiMesh { * @message The message to send to all other nodes. * */ - void attemptScan(String message); + void attemptScan(String &message); + void attemptScan(char *message); + + template + void attemptScan(char (&message)[Size]); //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// From 40a25e60f593dda249a3793c336b80a27607c5f5 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 31 Jul 2018 18:42:20 +0200 Subject: [PATCH 18/20] Make it possible to use const String as argument to attemptScan. --- libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp | 2 +- libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp b/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp index 971244a124..70e911749e 100644 --- a/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp +++ b/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp @@ -163,7 +163,7 @@ void ESP8266WiFiMesh::attemptScanKernel(const char *message) } // DEPRECATED! -void ESP8266WiFiMesh::attemptScan(String &message) +void ESP8266WiFiMesh::attemptScan(const String &message) { attemptScanKernel(message.c_str()); } diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 9c73a0241f..8bc3070934 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -118,7 +118,7 @@ class ESP8266WiFiMesh { * @message The message to send to all other nodes. * */ - void attemptScan(String &message); + void attemptScan(const String &message); void attemptScan(char *message); template From 0eadbb0a60ace35c6eb5f204278b41c3c0802110 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 31 Jul 2018 22:41:11 +0200 Subject: [PATCH 19/20] - Make code use camelCase instead of snake_case. - Improve documentation. --- libraries/ESP8266WiFiMesh/README.md | 26 +- .../examples/HelloMesh/HelloMesh.ino | 92 +++---- libraries/ESP8266WiFiMesh/keywords.txt | 6 +- .../src/CompatibilityLayer.cpp | 53 ++-- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 260 +++++++++--------- .../ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 127 ++++----- libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp | 38 +-- libraries/ESP8266WiFiMesh/src/NetworkInfo.h | 22 +- .../src/TransmissionResult.cpp | 16 +- .../ESP8266WiFiMesh/src/TransmissionResult.h | 12 +- .../ESP8266WiFiMesh/src/UtilityMethods.cpp | 48 ++-- 11 files changed, 351 insertions(+), 349 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/README.md b/libraries/ESP8266WiFiMesh/README.md index 7aaf88bd4c..5876b0872a 100644 --- a/libraries/ESP8266WiFiMesh/README.md +++ b/libraries/ESP8266WiFiMesh/README.md @@ -12,7 +12,7 @@ Usage The basic operation of a mesh node is as follows: -The `attemptTransmission` method of the ESP8266WiFiMesh instance is called with a message to send to other nodes in the mesh network. If the node is already connected to an AP, the message is sent only to that AP. Otherwise a WiFi scan is performed. The scan results are sent to the `networkFilter` callback function of the ESP8266WiFiMesh instance which adds the AP:s of interest to the `connection_queue` vector. The message is then transmitted to the networks in the `connection_queue`, and the response from each AP is sent to the `responseHandler` callback of the ESP8266WiFiMesh instance. The outcome from each transmission attempt can be found in the `latest_transmission_outcomes` vector. +The `attemptTransmission` method of the ESP8266WiFiMesh instance is called with a message to send to other nodes in the mesh network. If the node is already connected to an AP, the message is sent only to that AP. Otherwise a WiFi scan is performed. The scan results are sent to the `networkFilter` callback function of the ESP8266WiFiMesh instance which adds the AP:s of interest to the `connectionQueue` vector. The message is then transmitted to the networks in the `connectionQueue`, and the response from each AP is sent to the `responseHandler` callback of the ESP8266WiFiMesh instance. The outcome from each transmission attempt can be found in the `latestTransmissionOutcomes` vector. The node receives messages from other nodes by calling the `acceptRequest` method of the ESP8266WiFiMesh instance. These received messages are passed to the `requestHandler` callback of the mesh instance. For each received message the return value of `requestHandler` is sent to the other node as a response to the message. @@ -26,35 +26,37 @@ For more details, see the included example. The main functions to modify in the * @param responseHandler The callback handler for dealing with received responses. Takes a string as an argument which * is the response string received from another node. Returns a transmission status code as a transmission_status_t. * @param networkFilter The callback handler for deciding which WiFi networks to connect to. -* @param mesh_password The WiFi password for the mesh network. -* @param mesh_name The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example network filter function. -* @param node_id The id for this mesh node. Used as suffix for the node SSID. If set to "", the id will default to ESP.getChipId(). -* @param verbose_mode Determines if we should print the events occurring in the library to Serial. Off by default. -* @param mesh_wifi_channel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1. +* @param meshPassword The WiFi password for the mesh network. +* @param meshName The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example network filter function. +* @param nodeID The id for this mesh node. Used as suffix for the node SSID. If set to "", the id will default to ESP.getChipId(). +* @param verboseMode Determines if we should print the events occurring in the library to Serial. Off by default. +* @param meshWiFiChannel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1. * 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. * In such a case, whenever the station of one ESP8266WiFiMesh instance connects to an AP, it will silently force the * WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly * make it impossible for other stations to detect the APs whose WiFi channels have changed. -* @param server_port The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port. -* If two AP:s on the same ESP8266 are using the same server port, they will not be able to have both server instances active at the same time. +* @param serverPort The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port. +* If two AP:s on the same ESP8266 are using the same server port, they will not be able to have both server instances active at the same time. * This is managed automatically by the activateAP method. * */ ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter, - const String &mesh_password, const String &mesh_name = "MeshNode_", const String &node_id = WIFI_MESH_EMPTY_STRING, bool verbose_mode = false, - uint8 mesh_wifi_channel = 1, int server_port = 4011); + const String &meshPassword, const String &meshName = "MeshNode_", const String &nodeID = WIFI_MESH_EMPTY_STRING, bool verboseMode = false, + uint8 meshWiFiChannel = 1, int serverPort = 4011); ``` ### Note * 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. + * 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. If you are using a core version prior to 2.4.2 it is possible to disable the WiFi scan and static IP optimizations by commenting out the `ENABLE_STATIC_IP_OPTIMIZATION` and `ENABLE_WIFI_SCAN_OPTIMIZATION` defines in ESP8266WiFiMesh.h. Press Ctrl+K in the Arduino IDE while an example from the mesh library is opened, to open the library folder (or click "Show Sketch Folder" in the Sketch menu). ESP8266WiFiMesh.h can then be found at ESP8266WiFiMesh/src. Edit the file with any text editor. -* The WiFi scan optimization mentioned above works by making WiFi scans only search through the same WiFi channel as the ESP8266WiFiMesh instance is using. If you would like to scan all WiFi channels instead, set the `scan_all_wifi_channels` argument of the `attemptTransmission` method to `true`. Note that scanning all WiFi channels will slow down scans considerably and make it more likely that existing WiFi connections will break during scans. Also note that if the ESP8266 has an active AP, that AP will switch WiFi channel to match that of any other AP the ESP8266 connects to (compare next bullet point). This can make it impossible for other nodes to detect the AP if they are scanning the wrong WiFi channel. To remedy this, force the AP back on the original channel by using the `restartAP` method of the current AP controller once the ESP8266 has disconnected from the other AP. This would typically be done like so: +* The WiFi scan optimization mentioned above works by making WiFi scans only search through the same WiFi channel as the ESP8266WiFiMesh instance is using. If you would like to scan all WiFi channels instead, set the `scanAllWiFiChannels` argument of the `attemptTransmission` method to `true`. Note that scanning all WiFi channels will slow down scans considerably and make it more likely that existing WiFi connections will break during scans. Also note that if the ESP8266 has an active AP, that AP will switch WiFi channel to match that of any other AP the ESP8266 connects to (compare next bullet point). This can make it impossible for other nodes to detect the AP if they are scanning the wrong WiFi channel. To remedy this, force the AP back on the original channel by using the `restartAP` method of the current AP controller once the ESP8266 has disconnected from the other AP. This would typically be done like so: ``` if(ESP8266WiFiMesh *apController = ESP8266WiFiMesh::getAPController()) // Make sure apController is not nullptr @@ -63,7 +65,7 @@ ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseH * It is possible to have several ESP8266WiFiMesh instances running on every ESP8266 (e.g. to communicate with different mesh networks). However, because the ESP8266 has one WiFi radio only one AP per ESP8266 can be active at a time. Also note that if the ESP8266WiFiMesh instances use different WiFi channels, active APs are forced to use the same WiFi channel as active stations, possibly causing AP disconnections. -* While it is possible to connect to other nodes by only giving their SSID, e.g. `ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo("NodeSSID"));`, it is recommended that AP WiFi channel and AP BSSID are given as well, to minimize connection delay. +* While it is possible to connect to other nodes by only giving their SSID, e.g. `ESP8266WiFiMesh::connectionQueue.push_back(NetworkInfo("NodeSSID"));`, it is recommended that AP WiFi channel and AP BSSID are given as well, to minimize connection delay. * Also, remember to change the default mesh network WiFi password! diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index e160774a41..8c1fd8e983 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -1,51 +1,51 @@ #include #include -String meshName("MeshNode_"); +String exampleMeshName("MeshNode_"); -unsigned int request_i = 0; -unsigned int response_i = 0; +unsigned int requestNumber = 0; +unsigned int responseNumber = 0; -String manageRequest(const String &request, ESP8266WiFiMesh &mesh_instance); -transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &mesh_instance); -void networkFilter(int number_of_networks, ESP8266WiFiMesh &mesh_instance); +String manageRequest(const String &request, ESP8266WiFiMesh &meshInstance); +transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &meshInstance); +void networkFilter(int numberOfNetworks, ESP8266WiFiMesh &meshInstance); /* Create the mesh node object */ -ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(manageRequest, manageResponse, networkFilter, "ChangeThisWiFiPassword_TODO", meshName, "", true); +ESP8266WiFiMesh meshNode = ESP8266WiFiMesh(manageRequest, manageResponse, networkFilter, "ChangeThisWiFiPassword_TODO", exampleMeshName, "", true); /** Callback for when other nodes send you a request @param request The request string received from another node in the mesh - @param mesh_instance The ESP8266WiFiMesh instance that called the function. + @param meshInstance The ESP8266WiFiMesh instance that called the function. @returns The string to send back to the other node */ -String manageRequest(const String &request, ESP8266WiFiMesh &mesh_instance) { +String manageRequest(const String &request, ESP8266WiFiMesh &meshInstance) { /* Print out received message */ Serial.print("Request received: "); Serial.println(request); /* return a string to send back */ - return ("Hello world response #" + String(response_i++) + " from " + mesh_instance.getMeshName() + mesh_instance.getNodeID() + "."); + 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 number_of_networks The number of networks found in the WiFi scan. - @param mesh_instance The ESP8266WiFiMesh instance that called the function. + @param numberOfNetworks The number of networks found in the WiFi scan. + @param meshInstance The ESP8266WiFiMesh instance that called the function. */ -void networkFilter(int number_of_networks, ESP8266WiFiMesh &mesh_instance) { - for (int i = 0; i < number_of_networks; ++i) { - String current_ssid = WiFi.SSID(i); - int mesh_name_index = current_ssid.indexOf(mesh_instance.getMeshName()); +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 mesh_instance.getMeshName() */ - if (mesh_name_index >= 0) { - uint64_t target_node_id = ESP8266WiFiMesh::StringToUint64(current_ssid.substring(mesh_name_index + mesh_instance.getMeshName().length())); + /* Connect to any _suitable_ APs which contain meshInstance.getMeshName() */ + if (meshNameIndex >= 0) { + uint64_t targetNodeID = ESP8266WiFiMesh::StringToUint64(currentSSID.substring(meshNameIndex + meshInstance.getMeshName().length())); - if (target_node_id < ESP8266WiFiMesh::StringToUint64(mesh_instance.getNodeID())) { - ESP8266WiFiMesh::connection_queue.push_back(NetworkInfo(i)); + if (targetNodeID < ESP8266WiFiMesh::StringToUint64(meshInstance.getNodeID())) { + ESP8266WiFiMesh::connectionQueue.push_back(NetworkInfo(i)); } } } @@ -55,23 +55,23 @@ void networkFilter(int number_of_networks, ESP8266WiFiMesh &mesh_instance) { Callback for when you get a response from other nodes @param response The response string received from another node in the mesh - @param mesh_instance The ESP8266WiFiMesh instance that called the function. + @param meshInstance The ESP8266WiFiMesh instance that called the function. @returns The status code resulting from the response, as an int */ -transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &mesh_instance) { - transmission_status_t status_code = TS_TRANSMISSION_COMPLETE; +transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &meshInstance) { + transmission_status_t statusCode = TS_TRANSMISSION_COMPLETE; /* Print out received message */ Serial.print("Request sent: "); - Serial.println(mesh_instance.getMessage()); + Serial.println(meshInstance.getMessage()); Serial.print("Response received: "); Serial.println(response); // Our last request got a response, so time to create a new request. - mesh_instance.setMessage("Hello world request #" + String(++request_i) + " from " + mesh_instance.getMeshName() + mesh_instance.getNodeID() + "."); + meshInstance.setMessage("Hello world request #" + String(++requestNumber) + " from " + meshInstance.getMeshName() + meshInstance.getNodeID() + "."); - // (void)mesh_instance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else. - return status_code; + // (void)meshInstance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else. + return statusCode; } void setup() { @@ -95,37 +95,37 @@ void setup() { Serial.println("Setting up mesh node..."); /* Initialise the mesh node */ - mesh_node.begin(); - mesh_node.activateAP(); // Each AP requires a separate server port. - mesh_node.setStaticIP(IPAddress(192, 168, 4, 22)); // Activate static IP mode to speed up connection times. + meshNode.begin(); + meshNode.activateAP(); // Each AP requires a separate server port. + meshNode.setStaticIP(IPAddress(192, 168, 4, 22)); // Activate static IP mode to speed up connection times. } -int32_t time_of_last_scan = -10000; +int32_t timeOfLastScan = -10000; void loop() { - if (millis() - time_of_last_scan > 3000 // Give other nodes some time to connect between data transfers. - || (WiFi.status() != WL_CONNECTED && millis() - time_of_last_scan > 2000)) { // Scan for networks with two second intervals when not already connected. - String request = "Hello world request #" + String(request_i) + " from " + mesh_node.getMeshName() + mesh_node.getNodeID() + "."; - mesh_node.attemptTransmission(request, false); - time_of_last_scan = millis(); + 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() + "."; + meshNode.attemptTransmission(request, false); + timeOfLastScan = millis(); - if (ESP8266WiFiMesh::latest_transmission_outcomes.empty()) { + if (ESP8266WiFiMesh::latestTransmissionOutcomes.empty()) { Serial.println("No mesh AP found."); } else { - for (TransmissionResult &transmission_result : ESP8266WiFiMesh::latest_transmission_outcomes) { - if (transmission_result.transmission_status == TS_TRANSMISSION_FAILED) { - Serial.println("Transmission failed to mesh AP " + transmission_result.ssid); - } else if (transmission_result.transmission_status == TS_CONNECTION_FAILED) { - Serial.println("Connection failed to mesh AP " + transmission_result.ssid); - } else if (transmission_result.transmission_status == TS_TRANSMISSION_COMPLETE) { + for (TransmissionResult &transmissionResult : ESP8266WiFiMesh::latestTransmissionOutcomes) { + if (transmissionResult.transmissionStatus == TS_TRANSMISSION_FAILED) { + Serial.println("Transmission failed to mesh AP " + transmissionResult.SSID); + } else if (transmissionResult.transmissionStatus == TS_CONNECTION_FAILED) { + Serial.println("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 " + transmission_result.ssid + "!"); + Serial.println("Invalid transmission status for " + transmissionResult.SSID + "!"); } } } Serial.println(); } else { /* Accept any incoming connections */ - mesh_node.acceptRequest(); + meshNode.acceptRequest(); } } diff --git a/libraries/ESP8266WiFiMesh/keywords.txt b/libraries/ESP8266WiFiMesh/keywords.txt index eb425dcb86..b8d659ff35 100644 --- a/libraries/ESP8266WiFiMesh/keywords.txt +++ b/libraries/ESP8266WiFiMesh/keywords.txt @@ -21,8 +21,8 @@ transmission_status_t KEYWORD1 # Methods and Functions (KEYWORD2) ####################################### -connection_queue KEYWORD2 -latest_transmission_outcomes KEYWORD2 +connectionQueue KEYWORD2 +latestTransmissionOutcomes KEYWORD2 begin KEYWORD2 activateAP KEYWORD2 deactivateAP KEYWORD2 @@ -52,6 +52,6 @@ setNetworkFilter KEYWORD2 # Constants (LITERAL1) ####################################### -empty_IP LITERAL1 +emptyIP LITERAL1 NETWORK_INFO_DEFAULT_INT LITERAL1 WIFI_MESH_EMPTY_STRING LITERAL1 diff --git a/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp b/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp index 70e911749e..fd926a9351 100644 --- a/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp +++ b/libraries/ESP8266WiFiMesh/src/CompatibilityLayer.cpp @@ -50,12 +50,12 @@ #define SERVER_PORT 4011 // DEPRECATED! -ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, ESP8266WiFiMesh::compatibilityLayerHandlerType handler) +ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chipID, ESP8266WiFiMesh::compatibilityLayerHandlerType handler) : _server(SERVER_PORT) { - _chip_id = chip_id; - _ssid = String( String( SSID_PREFIX ) + String( _chip_id ) ); - _ssid_prefix = String( SSID_PREFIX ); + _chipID = chipID; + _SSID = String( String( SSID_PREFIX ) + String( _chipID ) ); + _ssidPrefix = String( SSID_PREFIX ); _handler = handler; } @@ -66,14 +66,14 @@ ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, ESP8266WiFiMesh::compatibilit * */ // DEPRECATED! -bool ESP8266WiFiMesh::waitForClient(WiFiClient &curr_client, int max_wait) +bool ESP8266WiFiMesh::waitForClient(WiFiClient &currClient, int maxWait) { - int wait = max_wait; - while(curr_client.connected() && !curr_client.available() && wait--) + int wait = maxWait; + while(currClient.connected() && !currClient.available() && wait--) delay(3); /* Return false if the client isn't ready to communicate */ - if (WiFi.status() == WL_DISCONNECTED || !curr_client.connected()) + if (WiFi.status() == WL_DISCONNECTED || !currClient.connected()) return false; return true; @@ -83,21 +83,20 @@ bool ESP8266WiFiMesh::waitForClient(WiFiClient &curr_client, int max_wait) * Send the supplied message then read back the other node's response * and pass that to the user-supplied handler. * - * @target_ssid The name of the AP the other node has set up. * @message The string to send to the node. * @returns: True if the exchange was a succes, false otherwise. * */ // DEPRECATED! -bool ESP8266WiFiMesh::exchangeInfo(const char *message, WiFiClient &curr_client) +bool ESP8266WiFiMesh::exchangeInfo(const char *message, WiFiClient &currClient) { - curr_client.println( message ); + currClient.println( message ); - if (!waitForClient(curr_client, 1000)) + if (!waitForClient(currClient, 1000)) return false; - String response = curr_client.readStringUntil('\r'); - curr_client.readStringUntil('\n'); + String response = currClient.readStringUntil('\r'); + currClient.readStringUntil('\n'); if (response.length() <= 2) return false; @@ -110,15 +109,15 @@ bool ESP8266WiFiMesh::exchangeInfo(const char *message, WiFiClient &curr_client) /** * Connect to the AP at ssid, send them a message then disconnect. * - * @target_ssid The name of the AP the other node has set up. + * @targetSSID The name of the AP the other node has set up. * @message The string to send to the node. * */ // DEPRECATED! -void ESP8266WiFiMesh::connectToNode(const String &target_ssid, const char *message) +void ESP8266WiFiMesh::connectToNode(const String &targetSSID, const char *message) { - WiFiClient curr_client; - WiFi.begin( target_ssid.c_str() ); + WiFiClient currClient; + WiFi.begin( targetSSID.c_str() ); int wait = 1500; while((WiFi.status() == WL_DISCONNECTED) && wait--) @@ -129,13 +128,13 @@ void ESP8266WiFiMesh::connectToNode(const String &target_ssid, const char *messa return; /* Connect to the node's server */ - if (!curr_client.connect(SERVER_IP_ADDR, SERVER_PORT)) + if (!currClient.connect(SERVER_IP_ADDR, SERVER_PORT)) return; - if (!exchangeInfo(message, curr_client)) + if (!exchangeInfo(message, currClient)) return; - curr_client.stop(); + currClient.stop(); WiFi.disconnect(); } @@ -146,16 +145,16 @@ void ESP8266WiFiMesh::attemptScanKernel(const char *message) int n = WiFi.scanNetworks(); for (int i = 0; i < n; ++i) { - String current_ssid = WiFi.SSID(i); - int index = current_ssid.indexOf( _ssid_prefix ); - uint32_t target_chip_id = (current_ssid.substring(index + _ssid_prefix.length())).toInt(); + String currentSSID = WiFi.SSID(i); + int index = currentSSID.indexOf( _ssidPrefix ); + uint32_t targetChipID = (currentSSID.substring(index + _ssidPrefix.length())).toInt(); - /* Connect to any _suitable_ APs which contain _ssid_prefix */ - if (index >= 0 && (target_chip_id < _chip_id)) { + /* Connect to any _suitable_ APs which contain _ssidPrefix */ + if (index >= 0 && (targetChipID < _chipID)) { WiFi.mode(WIFI_STA); delay(100); - connectToNode(current_ssid, message); + connectToNode(currentSSID, message); WiFi.mode(WIFI_AP_STA); delay(100); } diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index ec36b6f17f..ff0ed6e3ee 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -27,20 +27,20 @@ #define SERVER_IP_ADDR "192.168.4.1" -const IPAddress ESP8266WiFiMesh::empty_IP = IPAddress(); -const uint32_t ESP8266WiFiMesh::lwip_version_203_signature[3] {2,0,3}; +const IPAddress ESP8266WiFiMesh::emptyIP = IPAddress(); +const uint32_t ESP8266WiFiMesh::lwipVersion203Signature[3] {2,0,3}; -String ESP8266WiFiMesh::last_ssid = ""; -bool ESP8266WiFiMesh::static_IP_activated = false; +String ESP8266WiFiMesh::lastSSID = ""; +bool ESP8266WiFiMesh::staticIPActivated = false; // IP needs to be at the same subnet as server gateway (192.168.4 in this case). Station gateway ip must match ip for server. -IPAddress ESP8266WiFiMesh::static_IP = empty_IP; +IPAddress ESP8266WiFiMesh::staticIP = emptyIP; IPAddress ESP8266WiFiMesh::gateway = IPAddress(192,168,4,1); -IPAddress ESP8266WiFiMesh::subnet_mask = IPAddress(255,255,255,0); +IPAddress ESP8266WiFiMesh::subnetMask = IPAddress(255,255,255,0); ESP8266WiFiMesh *ESP8266WiFiMesh::apController = nullptr; -std::vector ESP8266WiFiMesh::connection_queue = {}; -std::vector ESP8266WiFiMesh::latest_transmission_outcomes = {}; +std::vector ESP8266WiFiMesh::connectionQueue = {}; +std::vector ESP8266WiFiMesh::latestTransmissionOutcomes = {}; ESP8266WiFiMesh::~ESP8266WiFiMesh() { @@ -51,30 +51,30 @@ ESP8266WiFiMesh::~ESP8266WiFiMesh() } ESP8266WiFiMesh::ESP8266WiFiMesh(ESP8266WiFiMesh::requestHandlerType requestHandler, ESP8266WiFiMesh::responseHandlerType responseHandler, - ESP8266WiFiMesh::networkFilterType networkFilter, const String &mesh_password, const String &mesh_name, - const String &node_id, bool verbose_mode, uint8 mesh_wifi_channel, int server_port) - : _server(server_port), _lwip_version{0, 0, 0} + ESP8266WiFiMesh::networkFilterType networkFilter, const String &meshPassword, const String &meshName, + const String &nodeID, bool verboseMode, uint8 meshWiFiChannel, int serverPort) + : _server(serverPort), _lwipVersion{0, 0, 0} { storeLwipVersion(); - updateNetworkNames(mesh_name, (node_id != "" ? node_id : Uint64ToString(ESP.getChipId()))); + updateNetworkNames(meshName, (nodeID != "" ? nodeID : Uint64ToString(ESP.getChipId()))); _requestHandler = requestHandler; _responseHandler = responseHandler; - setWiFiChannel(mesh_wifi_channel); - _server_port = server_port; - _mesh_password = mesh_password; - _verbose_mode = verbose_mode; + setWiFiChannel(meshWiFiChannel); + _serverPort = serverPort; + _meshPassword = meshPassword; + _verboseMode = verboseMode; _networkFilter = networkFilter; } -void ESP8266WiFiMesh::updateNetworkNames(const String &new_mesh_name, const String &new_node_id) +void ESP8266WiFiMesh::updateNetworkNames(const String &newMeshName, const String &newNodeID) { - if(new_mesh_name != "") - _mesh_name = new_mesh_name; - if(new_node_id != "") - _node_id = new_node_id; + if(newMeshName != "") + _meshName = newMeshName; + if(newNodeID != "") + _nodeID = newNodeID; - _ssid = _mesh_name + _node_id; + _SSID = _meshName + _nodeID; // Apply SSID changes to active AP. if(isAPController()) @@ -87,7 +87,7 @@ void ESP8266WiFiMesh::begin() if(_handler != NULL) { WiFi.mode(WIFI_AP_STA); - WiFi.softAP( _ssid.c_str() ); + WiFi.softAP( _SSID.c_str() ); _server.begin(); } else @@ -96,7 +96,7 @@ void ESP8266WiFiMesh::begin() WiFi.mode(WIFI_AP_STA); #ifdef ENABLE_STATIC_IP_OPTIMIZATION - if(atLeastLwipVersion(lwip_version_203_signature)) + if(atLeastLwipVersion(lwipVersion203Signature)) { verboseModePrint("lwIP version is at least 2.0.3. Static ip optimizations enabled.\n"); } @@ -108,30 +108,30 @@ void ESP8266WiFiMesh::begin() } } -void ESP8266WiFiMesh::setStaticIP(const IPAddress &new_IP) +void ESP8266WiFiMesh::setStaticIP(const IPAddress &newIP) { // Comment out the line below to remove static IP and use DHCP instead. // DHCP makes WiFi connection happen slower, but there is no need to care about manually giving different IPs to the nodes and less need to worry about used IPs giving "Server unavailable" issues. // Static IP has faster connection times (50 % of DHCP) and will make sending of data to a node that is already transmitting data happen more reliably. - // Note that after WiFi.config(static_IP, gateway, subnet_mask) is used, static IP will always be active, even for new connections, unless WiFi.config(0u,0u,0u); is called. - WiFi.config(new_IP, gateway, subnet_mask); - static_IP_activated = true; - static_IP = new_IP; + // Note that after WiFi.config(staticIP, gateway, subnetMask) is used, static IP will always be active, even for new connections, unless WiFi.config(0u,0u,0u); is called. + WiFi.config(newIP, gateway, subnetMask); + staticIPActivated = true; + staticIP = newIP; } IPAddress ESP8266WiFiMesh::getStaticIP() { - if(static_IP_activated) - return static_IP; + if(staticIPActivated) + return staticIP; - return empty_IP; + return emptyIP; } void ESP8266WiFiMesh::disableStaticIP() { WiFi.config(0u,0u,0u); yield(); - static_IP_activated = false; + staticIPActivated = false; } void ESP8266WiFiMesh::activateAP() @@ -140,7 +140,7 @@ void ESP8266WiFiMesh::activateAP() if(ESP8266WiFiMesh *currentAPController = ESP8266WiFiMesh::getAPController()) currentAPController->deactivateAP(); - WiFi.softAP( _ssid.c_str(), _mesh_password.c_str(), _mesh_wifi_channel ); // 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 ); // Note that a maximum of 5 stations can be connected at a time to each AP _server.begin(); // Actually calls _server.stop()/_server.close() first. apController = this; @@ -178,41 +178,41 @@ bool ESP8266WiFiMesh::isAPController() uint8 ESP8266WiFiMesh::getWiFiChannel() { - return _mesh_wifi_channel; + return _meshWiFiChannel; } -void ESP8266WiFiMesh::setWiFiChannel(uint8 new_wifi_channel) +void ESP8266WiFiMesh::setWiFiChannel(uint8 newWiFiChannel) { - assert(1 <= new_wifi_channel && new_wifi_channel <= 13); + assert(1 <= newWiFiChannel && newWiFiChannel <= 13); - _mesh_wifi_channel = new_wifi_channel; + _meshWiFiChannel = newWiFiChannel; // Apply changes to active AP. if(isAPController()) restartAP(); } -String ESP8266WiFiMesh::getMeshName() {return _mesh_name;} +String ESP8266WiFiMesh::getMeshName() {return _meshName;} -void ESP8266WiFiMesh::setMeshName(const String &new_mesh_name) +void ESP8266WiFiMesh::setMeshName(const String &newMeshName) { - updateNetworkNames(new_mesh_name); + updateNetworkNames(newMeshName); } -String ESP8266WiFiMesh::getNodeID() {return _node_id;} +String ESP8266WiFiMesh::getNodeID() {return _nodeID;} -void ESP8266WiFiMesh::setNodeID(const String &new_node_id) +void ESP8266WiFiMesh::setNodeID(const String &newNodeID) { - updateNetworkNames("", new_node_id); + updateNetworkNames("", newNodeID); } -void ESP8266WiFiMesh::setSSID(const String &new_mesh_name, const String &new_node_id) +void ESP8266WiFiMesh::setSSID(const String &newMeshName, const String &newNodeID) { - updateNetworkNames(new_mesh_name, new_node_id); + updateNetworkNames(newMeshName, newNodeID); } String ESP8266WiFiMesh::getMessage() {return _message;} -void ESP8266WiFiMesh::setMessage(const String &new_message) {_message = new_message;} +void ESP8266WiFiMesh::setMessage(const String &newMessage) {_message = newMessage;} ESP8266WiFiMesh::networkFilterType ESP8266WiFiMesh::getNetworkFilter() {return _networkFilter;} void ESP8266WiFiMesh::setNetworkFilter(ESP8266WiFiMesh::networkFilterType networkFilter) {_networkFilter = networkFilter;} @@ -220,9 +220,9 @@ void ESP8266WiFiMesh::setNetworkFilter(ESP8266WiFiMesh::networkFilterType networ /** * Disconnect completely from a network. */ -void ESP8266WiFiMesh::fullStop(WiFiClient &curr_client) +void ESP8266WiFiMesh::fullStop(WiFiClient &currClient) { - curr_client.stop(); + currClient.stop(); yield(); WiFi.disconnect(); yield(); @@ -234,14 +234,14 @@ void ESP8266WiFiMesh::fullStop(WiFiClient &curr_client) * @returns: True if the client is ready, false otherwise. * */ -bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient &curr_client, int max_wait) +bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient &currClient, int maxWait) { - int wait = max_wait; - while(curr_client.connected() && !curr_client.available() && wait--) + int wait = maxWait; + while(currClient.connected() && !currClient.available() && wait--) delay(3); /* Return false if the client isn't ready to communicate */ - if (WiFi.status() == WL_DISCONNECTED && !curr_client.available()) + if (WiFi.status() == WL_DISCONNECTED && !currClient.available()) { verboseModePrint("Disconnected!"); return false; @@ -254,32 +254,32 @@ bool ESP8266WiFiMesh::waitForClientTransmission(WiFiClient &curr_client, int max * Send the mesh instance's current message then read back the other node's response * and pass that to the user-supplied responseHandler. * - * @param curr_client The client to which the message should be transmitted. + * @param currClient The client to which the message should be transmitted. * @returns: A status code based on the outcome of the exchange. * */ -transmission_status_t ESP8266WiFiMesh::exchangeInfo(WiFiClient &curr_client) +transmission_status_t ESP8266WiFiMesh::exchangeInfo(WiFiClient &currClient) { verboseModePrint("Transmitting"); - curr_client.print(getMessage() + "\r"); + currClient.print(getMessage() + "\r"); yield(); - if (!waitForClientTransmission(curr_client, 1000)) + if (!waitForClientTransmission(currClient, 1000)) { - fullStop(curr_client); + fullStop(currClient); return TS_CONNECTION_FAILED; } - if (!curr_client.available()) + if (!currClient.available()) { verboseModePrint("No response!"); - return TS_TRANSMISSION_FAILED; // WiFi.status() != WL_DISCONNECTED so we do not want to use fullStop(curr_client) here since that would force the node to scan for WiFi networks. + 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. } - String response = curr_client.readStringUntil('\r'); + String response = currClient.readStringUntil('\r'); yield(); - curr_client.flush(); + currClient.flush(); /* Pass data to user callback */ return _responseHandler(response, *this); @@ -297,11 +297,11 @@ transmission_status_t ESP8266WiFiMesh::attemptDataTransfer() // 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). WiFi.mode(WIFI_STA); delay(1); - transmission_status_t transmission_outcome = attemptDataTransferKernel(); + transmission_status_t transmissionOutcome = attemptDataTransferKernel(); WiFi.mode(WIFI_AP_STA); delay(1); - return transmission_outcome; + return transmissionOutcome; } /** @@ -311,54 +311,54 @@ transmission_status_t ESP8266WiFiMesh::attemptDataTransfer() */ transmission_status_t ESP8266WiFiMesh::attemptDataTransferKernel() { - WiFiClient curr_client; + WiFiClient currClient; /* Connect to the node's server */ - if (!curr_client.connect(SERVER_IP_ADDR, _server_port)) + if (!currClient.connect(SERVER_IP_ADDR, _serverPort)) { - fullStop(curr_client); + fullStop(currClient); verboseModePrint("Server unavailable"); return TS_CONNECTION_FAILED; } - transmission_status_t transmission_outcome = exchangeInfo(curr_client); - if (transmission_outcome <= 0) + transmission_status_t transmissionOutcome = exchangeInfo(currClient); + if (transmissionOutcome <= 0) { verboseModePrint("Transmission failed during exchangeInfo."); - return transmission_outcome; + return transmissionOutcome; } - curr_client.stop(); + currClient.stop(); yield(); - return transmission_outcome; + return transmissionOutcome; } -void ESP8266WiFiMesh::initiateConnectionToAP(const String &target_ssid, int target_channel, uint8_t *target_bssid) +void ESP8266WiFiMesh::initiateConnectionToAP(const String &targetSSID, int targetChannel, uint8_t *targetBSSID) { - if(target_channel == NETWORK_INFO_DEFAULT_INT) - WiFi.begin( target_ssid.c_str(), _mesh_password.c_str() ); // Without giving channel and bssid, connection time is longer. - else if(target_bssid == NULL) - WiFi.begin( target_ssid.c_str(), _mesh_password.c_str(), target_channel ); // Without giving channel and bssid, connection time is longer. + if(targetChannel == NETWORK_INFO_DEFAULT_INT) + WiFi.begin( targetSSID.c_str(), _meshPassword.c_str() ); // Without giving channel and BSSID, connection time is longer. + else if(targetBSSID == NULL) + WiFi.begin( targetSSID.c_str(), _meshPassword.c_str(), targetChannel ); // Without giving channel and BSSID, connection time is longer. else - WiFi.begin( target_ssid.c_str(), _mesh_password.c_str(), target_channel, target_bssid ); + WiFi.begin( targetSSID.c_str(), _meshPassword.c_str(), targetChannel, targetBSSID ); } /** - * Connect to the AP at ssid and transmit the mesh instance's current message. + * Connect to the AP at SSID and transmit the mesh instance's current message. * - * @param target_ssid The name of the AP the other node has set up. - * @param target_channel The WiFI channel of the AP the other node has set up. - * @param target_bssid The mac address of the AP the other node has set up. + * @param targetSSID The name of the AP the other node has set up. + * @param targetChannel The WiFI channel of the AP the other node has set up. + * @param targetBSSID The mac address of the AP the other node has set up. * @returns: A status code based on the outcome of the connection and data transfer process. * */ -transmission_status_t ESP8266WiFiMesh::connectToNode(const String &target_ssid, int target_channel, uint8_t *target_bssid) +transmission_status_t ESP8266WiFiMesh::connectToNode(const String &targetSSID, int targetChannel, uint8_t *targetBSSID) { - if(static_IP_activated && last_ssid != "" && last_ssid != target_ssid) // So we only do this once per connection, in case there is a performance impact. + if(staticIPActivated && lastSSID != "" && lastSSID != targetSSID) // So we only do this once per connection, in case there is a performance impact. { #ifdef ENABLE_STATIC_IP_OPTIMIZATION - if(atLeastLwipVersion(lwip_version_203_signature)) + 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. WiFi.mode(WIFI_OFF); @@ -377,30 +377,30 @@ transmission_status_t ESP8266WiFiMesh::connectToNode(const String &target_ssid, verboseModePrint("\nConnecting to a different network. Static IP deactivated to make this possible."); #endif } - last_ssid = target_ssid; + lastSSID = targetSSID; verboseModePrint("Connecting... ", false); - initiateConnectionToAP(target_ssid, target_channel, target_bssid); + initiateConnectionToAP(targetSSID, targetChannel, targetBSSID); - int connection_start_time = millis(); - int attempt_number = 1; + int connectionStartTime = millis(); + int attemptNumber = 1; - int waiting_time = millis() - connection_start_time; - while((WiFi.status() == WL_DISCONNECTED) && waiting_time <= 10000) + int waitingTime = millis() - connectionStartTime; + while((WiFi.status() == WL_DISCONNECTED) && waitingTime <= 10000) { - if(waiting_time > attempt_number * 10000) // 10000 can be lowered if you want to limit the time allowed for each connection attempt. + if(waitingTime > attemptNumber * 10000) // 10000 can be lowered if you want to limit the time allowed for each connection attempt. { verboseModePrint("... ", false); WiFi.disconnect(); yield(); - initiateConnectionToAP(target_ssid, target_channel, target_bssid); - attempt_number++; + initiateConnectionToAP(targetSSID, targetChannel, targetBSSID); + attemptNumber++; } delay(1); - waiting_time = millis() - connection_start_time; + waitingTime = millis() - connectionStartTime; } - verboseModePrint(String(waiting_time)); + verboseModePrint(String(waitingTime)); /* If the connection timed out */ if (WiFi.status() != WL_CONNECTED) @@ -412,102 +412,102 @@ transmission_status_t ESP8266WiFiMesh::connectToNode(const String &target_ssid, return attemptDataTransfer(); } -void ESP8266WiFiMesh::attemptTransmission(const String &message, bool concluding_disconnect, bool initial_disconnect, bool no_scan, bool scan_all_wifi_channels) +void ESP8266WiFiMesh::attemptTransmission(const String &message, bool concludingDisconnect, bool initialDisconnect, bool noScan, bool scanAllWiFiChannels) { setMessage(message); - if(initial_disconnect) + if(initialDisconnect) { WiFi.disconnect(); yield(); } - latest_transmission_outcomes.clear(); + latestTransmissionOutcomes.clear(); if(WiFi.status() == WL_CONNECTED) { - transmission_status_t transmission_result = attemptDataTransfer(); - latest_transmission_outcomes.push_back(TransmissionResult(connection_queue.back(), transmission_result)); + transmission_status_t transmissionResult = attemptDataTransfer(); + latestTransmissionOutcomes.push_back(TransmissionResult(connectionQueue.back(), transmissionResult)); } else { - if(!no_scan) + if(!noScan) { verboseModePrint("Scanning... ", false); /* Scan for APs */ - connection_queue.clear(); + connectionQueue.clear(); - // If Arduino core for ESP8266 version < 2.4.2 scanning will cause the WiFi radio to cycle through all WiFi channels. + // If scanAllWiFiChannels is true or Arduino core for ESP8266 version < 2.4.2 scanning will cause the WiFi radio to cycle through all WiFi channels. // This means existing WiFi connections are likely to break or work poorly if done frequently. int n = 0; #ifdef ENABLE_WIFI_SCAN_OPTIMIZATION - if(scan_all_wifi_channels) + if(scanAllWiFiChannels) { n = WiFi.scanNetworks(); } else { // Scan function argument overview: scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL) - n = WiFi.scanNetworks(false, false, _mesh_wifi_channel); + n = WiFi.scanNetworks(false, false, _meshWiFiChannel); } #else n = WiFi.scanNetworks(); #endif - _networkFilter(n, *this); // Update the connection_queue. + _networkFilter(n, *this); // Update the connectionQueue. } - for(NetworkInfo ¤t_network : connection_queue) + for(NetworkInfo ¤tNetwork : connectionQueue) { WiFi.disconnect(); yield(); - String current_ssid = ""; - int current_wifi_channel = NETWORK_INFO_DEFAULT_INT; - uint8_t *current_bssid = NULL; + String currentSSID = ""; + int currentWiFiChannel = NETWORK_INFO_DEFAULT_INT; + uint8_t *currentBSSID = NULL; - // If an SSID has been assigned, it is prioritized over an assigned network_index since the network_index is more likely to change. - if(current_network.ssid != "") + // If an SSID has been assigned, it is prioritized over an assigned networkIndex since the networkIndex is more likely to change. + if(currentNetwork.SSID != "") { - current_ssid = current_network.ssid; - current_wifi_channel = current_network.wifi_channel; - current_bssid = current_network.bssid; + currentSSID = currentNetwork.SSID; + currentWiFiChannel = currentNetwork.wifiChannel; + currentBSSID = currentNetwork.BSSID; } - else // Use only network_index + else // Use only networkIndex { - current_ssid = WiFi.SSID(current_network.network_index); - current_wifi_channel = WiFi.channel(current_network.network_index); - current_bssid = WiFi.BSSID(current_network.network_index); + currentSSID = WiFi.SSID(currentNetwork.networkIndex); + currentWiFiChannel = WiFi.channel(currentNetwork.networkIndex); + currentBSSID = WiFi.BSSID(currentNetwork.networkIndex); } - if(_verbose_mode) // Avoid string generation if not required + if(_verboseMode) // Avoid string generation if not required { - verboseModePrint("AP acquired: " + current_ssid + ", Ch:" + String(current_wifi_channel) + " ", false); + verboseModePrint("AP acquired: " + currentSSID + ", Ch:" + String(currentWiFiChannel) + " ", false); - if(current_network.network_index != NETWORK_INFO_DEFAULT_INT) + if(currentNetwork.networkIndex != NETWORK_INFO_DEFAULT_INT) { - verboseModePrint("(" + String(WiFi.RSSI(current_network.network_index)) + "dBm) " + - (WiFi.encryptionType(current_network.network_index) == ENC_TYPE_NONE ? "open" : ""), false); + verboseModePrint("(" + String(WiFi.RSSI(currentNetwork.networkIndex)) + "dBm) " + + (WiFi.encryptionType(currentNetwork.networkIndex) == ENC_TYPE_NONE ? "open" : ""), false); } verboseModePrint("... ", false); } - transmission_status_t transmission_result = connectToNode(current_ssid, current_wifi_channel, current_bssid); + transmission_status_t transmissionResult = connectToNode(currentSSID, currentWiFiChannel, currentBSSID); - latest_transmission_outcomes.push_back(TransmissionResult{.origin = current_network, .transmission_status = transmission_result}); + latestTransmissionOutcomes.push_back(TransmissionResult{.origin = currentNetwork, .transmissionStatus = transmissionResult}); } } - if(WiFi.status() == WL_CONNECTED && static_IP != empty_IP && !static_IP_activated) + if(WiFi.status() == WL_CONNECTED && staticIP != emptyIP && !staticIPActivated) { verboseModePrint("Reactivating static IP to allow for faster re-connects."); - setStaticIP(static_IP); + setStaticIP(staticIP); } // If we do not want to be connected at end of transmission, disconnect here so we can re-enable static IP first (above). - if(concluding_disconnect) + if(concludingDisconnect) { WiFi.disconnect(); yield(); diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index 8bc3070934..d1d31d9bf5 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -36,23 +36,23 @@ const String WIFI_MESH_EMPTY_STRING = ""; class ESP8266WiFiMesh { private: - String _ssid; - String _mesh_name; - String _node_id; - int _server_port; - String _mesh_password; - uint8 _mesh_wifi_channel; - bool _verbose_mode; + String _SSID; + String _meshName; + String _nodeID; + int _serverPort; + String _meshPassword; + uint8 _meshWiFiChannel; + bool _verboseMode; WiFiServer _server; - uint32_t _lwip_version[3]; - static const uint32_t lwip_version_203_signature[3]; + uint32_t _lwipVersion[3]; + static const uint32_t lwipVersion203Signature[3]; String _message = WIFI_MESH_EMPTY_STRING; - static String last_ssid; - static bool static_IP_activated; - static IPAddress static_IP; + static String lastSSID; + static bool staticIPActivated; + static IPAddress staticIP; static IPAddress gateway; - static IPAddress subnet_mask; + static IPAddress subnetMask; static ESP8266WiFiMesh *apController; typedef std::function requestHandlerType; @@ -63,17 +63,17 @@ class ESP8266WiFiMesh { responseHandlerType _responseHandler; networkFilterType _networkFilter; - void updateNetworkNames(const String &new_mesh_name = WIFI_MESH_EMPTY_STRING, const String &new_node_id = WIFI_MESH_EMPTY_STRING); - void verboseModePrint(const String &string_to_print, bool newline = true); - void fullStop(WiFiClient &curr_client); - void initiateConnectionToAP(const String &target_ssid, int target_channel = NETWORK_INFO_DEFAULT_INT, uint8_t *target_bssid = NULL); - transmission_status_t connectToNode(const String &target_ssid, int target_channel = NETWORK_INFO_DEFAULT_INT, uint8_t *target_bssid = NULL); - transmission_status_t exchangeInfo(WiFiClient &curr_client); - bool waitForClientTransmission(WiFiClient &curr_client, int max_wait); + void updateNetworkNames(const String &newMeshName = WIFI_MESH_EMPTY_STRING, const String &newNodeID = WIFI_MESH_EMPTY_STRING); + void verboseModePrint(const String &stringToPrint, bool newline = true); + void fullStop(WiFiClient &currClient); + 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); transmission_status_t attemptDataTransfer(); transmission_status_t attemptDataTransferKernel(); void storeLwipVersion(); - bool atLeastLwipVersion(const uint32_t min_lwip_version[3]); + bool atLeastLwipVersion(const uint32_t minLwipVersion[3]); @@ -82,16 +82,16 @@ class ESP8266WiFiMesh { typedef std::function compatibilityLayerHandlerType; - String _ssid_prefix; - uint32_t _chip_id; + String _ssidPrefix; + uint32_t _chipID; compatibilityLayerHandlerType _handler = NULL; WiFiClient _client; - void connectToNode(const String &target_ssid, const char *message); - bool exchangeInfo(const char *message, WiFiClient &curr_client); - bool waitForClient(WiFiClient &curr_client, int max_wait); + void connectToNode(const String &targetSSID, const char *message); + bool exchangeInfo(const char *message, WiFiClient &currClient); + bool waitForClient(WiFiClient &currClient, int maxWait); void attemptScanKernel(const char *message); //////////////////////////// TODO: REMOVE IN 2.5.0//////////////////////////// @@ -105,12 +105,12 @@ class ESP8266WiFiMesh { /** * WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised. * - * @chip_id A unique identifier number for the node. + * @chipID A unique identifier number for the node. * @handler The callback handler for dealing with received messages. Takes a string as an argument which * is the string received from another node and returns the string to send back. * */ - ESP8266WiFiMesh(uint32_t chip_id, compatibilityLayerHandlerType handler); + ESP8266WiFiMesh(uint32_t chipID, compatibilityLayerHandlerType handler); /** * Scan for other nodes, and exchange the chosen message with any that are found. @@ -136,40 +136,40 @@ class ESP8266WiFiMesh { * @param responseHandler The callback handler for dealing with received responses. Takes a string as an argument which * is the response string received from another node. Returns a transmission status code as a transmission_status_t. * @param networkFilter The callback handler for deciding which WiFi networks to connect to. - * @param mesh_password The WiFi password for the mesh network. - * @param mesh_name The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example network filter function. - * @param node_id The id for this mesh node. Used as suffix for the node SSID. If set to "", the id will default to ESP.getChipId(). - * @param verbose_mode Determines if we should print the events occurring in the library to Serial. Off by default. - * @param mesh_wifi_channel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1. + * @param meshPassword The WiFi password for the mesh network. + * @param meshName The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example network filter function. + * @param nodeID The id for this mesh node. Used as suffix for the node SSID. If set to "", the id will default to ESP.getChipId(). + * @param verboseMode Determines if we should print the events occurring in the library to Serial. Off by default. + * @param meshWiFiChannel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1. * 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. * In such a case, whenever the station of one ESP8266WiFiMesh instance connects to an AP, it will silently force the * WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly * make it impossible for other stations to detect the APs whose WiFi channels have changed. - * @param server_port The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port. + * @param serverPort The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port. * If two AP:s on the same ESP8266 are using the same server port, they will not be able to have both server instances active at the same time. * This is managed automatically by the activateAP method. * */ ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter, - const String &mesh_password, const String &mesh_name = "MeshNode_", const String &node_id = WIFI_MESH_EMPTY_STRING, bool verbose_mode = false, - uint8 mesh_wifi_channel = 1, int server_port = 4011); + const String &meshPassword, const String &meshName = "MeshNode_", const String &nodeID = WIFI_MESH_EMPTY_STRING, bool verboseMode = false, + uint8 meshWiFiChannel = 1, int serverPort = 4011); /** - * A vector that contains the WiFi-scan network indicies to connect to. - * The connection_queue vector is cleared before each new scan and filled via the networkFilter callback function once the scan completes. - * WiFi connections will start with connection_queue[0] and then incrementally proceed to higher vector positions. + * A vector that contains the NetworkInfo for each WiFi network to connect to. + * The connectionQueue vector is cleared before each new scan and filled via the networkFilter callback function once the scan completes. + * WiFi connections will start with connectionQueue[0] and then incrementally proceed to higher vector positions. * Note that old network indicies often are invalidated whenever a new WiFi network scan occurs. */ - static std::vector connection_queue; + static std::vector connectionQueue; /** * A vector with the TransmissionResult for each AP to which a transmission was attempted during the latest attemptTransmission call. - * The latest_transmission_outcomes vector is cleared before each new transmission attempt. + * The latestTransmissionOutcomes vector is cleared before each new transmission attempt. * Connection attempts are indexed in the same order they were attempted. * Note that old network indicies often are invalidated whenever a new WiFi network scan occurs. */ - static std::vector latest_transmission_outcomes; + static std::vector latestTransmissionOutcomes; /** * Initialises the node. @@ -177,7 +177,8 @@ class ESP8266WiFiMesh { void begin(); /** - * Each AP requires a separate server port. If two AP:s are using the same server port, you must call deactivateAP on the active AP before calling activateAP on the inactive AP. + * Each AP requires a separate server port. If two AP:s are using the same server port, they will not be able to have both server instances active at the same time. + * This is managed automatically by the activateAP method. */ void activateAP(); void deactivateAP(); @@ -213,10 +214,10 @@ class ESP8266WiFiMesh { * WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly * make it impossible for other stations to detect the APs whose WiFi channels have changed. * - * @param new_wifi_channel The WiFi channel to change to. Valid values are integers from 1 to 13. + * @param newWiFiChannel The WiFi channel to change to. Valid values are integers from 1 to 13. * */ - void setWiFiChannel(uint8 new_wifi_channel); + void setWiFiChannel(uint8 newWiFiChannel); String getMeshName(); @@ -224,9 +225,9 @@ class ESP8266WiFiMesh { * 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. * - * @param new_mesh_name The mesh name to change to. + * @param newMeshName The mesh name to change to. */ - void setMeshName(const String &new_mesh_name); + void setMeshName(const String &newMeshName); String getNodeID(); @@ -234,42 +235,42 @@ class ESP8266WiFiMesh { * 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. * - * @param new_node_id The node id to change to. + * @param newNodeID The node id to change to. */ - void setNodeID(const String &new_node_id); + void setNodeID(const String &newNodeID); /** * 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. * - * @param new_mesh_name The mesh name to change to. Will be the SSID prefix. - * @param new_node_id The node id to change to. Will be the SSID suffix. + * @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 &new_mesh_name, const String &new_node_id); + void setSSID(const String &newMeshName, const String &newNodeID); String getMessage(); /** * Set the message that will be sent to other nodes when calling attemptTransmission. * - * @param new_message The message to send. + * @param newMessage The message to send. */ - void setMessage(const String &new_message); + void setMessage(const String &newMessage); /** - * If AP connection already exists, send message only to this AP. - * Otherwise, scan for other networks, send the scan result to networkFilter and then transmit the message to the networks found in connection_queue. + * If AP connection already exists, and the initialDisconnect argument is set to false, send message only to the already connected AP. + * Otherwise, scan for other networks, send the scan result to networkFilter and then transmit the message to the networks found in connectionQueue. * * @param message The message to send to other nodes. It will be stored in the class instance until replaced via attemptTransmission or setMessage. - * @param concluding_disconnect Disconnect from AP once transmission is complete. - * @param initial_disconnect Disconnect from any currently connected AP before attempting transmission. - * @param no_scan Do not scan for new networks and do not call networkFilter function. Will only use the data already in connection_queue for the transmission. - * @param scan_all_wifi_channels Scan all WiFi channels during a WiFi scan, instead of just the channel the ESP8266WiFiMesh instance is using. + * @param concludingDisconnect Disconnect from AP once transmission is complete. + * @param initialDisconnect Disconnect from any currently connected AP before attempting transmission. + * @param noScan Do not scan for new networks and do not call networkFilter function. Will only use the data already in connectionQueue for the transmission. + * @param scanAllWiFiChannels Scan all WiFi channels during a WiFi scan, instead of just the channel the ESP8266WiFiMesh instance is using. * Scanning all WiFi channels takes about 2100 ms, compared to just 60 ms if only channel 1 (standard) is scanned. * Note that if the ESP8266 has an active AP, that AP will switch WiFi channel to match that of any other AP the ESP8266 connects to. * This can make it impossible for other nodes to detect the AP if they are scanning the wrong WiFi channel. */ - void attemptTransmission(const String &message, bool concluding_disconnect = true, bool initial_disconnect = false, bool no_scan = false, bool scan_all_wifi_channels = false); + void attemptTransmission(const String &message, bool concludingDisconnect = true, bool initialDisconnect = false, bool noScan = false, bool scanAllWiFiChannels = false); /** * If any clients are connected, accept their requests and call the requestHandler function for each one. @@ -280,7 +281,7 @@ class ESP8266WiFiMesh { * Set a static IP address for the ESP8266 and activate use of static IP. * The static IP needs to be at the same subnet as the server's gateway. */ - void setStaticIP(const IPAddress &new_IP); + void setStaticIP(const IPAddress &newIP); IPAddress getStaticIP(); void disableStaticIP(); @@ -288,7 +289,7 @@ class ESP8266WiFiMesh { /** * An empty IPAddress. Used as default when no IP is set. */ - static const IPAddress empty_IP; + static const IPAddress emptyIP; static String Uint64ToString(uint64_t number, byte base = 16); static uint64_t StringToUint64(const String &string, byte base = 16); diff --git a/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp b/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp index 3b6caae5bd..10300dd7bf 100644 --- a/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp +++ b/libraries/ESP8266WiFiMesh/src/NetworkInfo.cpp @@ -25,53 +25,53 @@ #include "NetworkInfo.h" -void NetworkInfo::copyBSSID(uint8_t new_bssid[6]) +void NetworkInfo::copyBSSID(uint8_t newBSSID[6]) { - if(new_bssid != NULL) + if(newBSSID != NULL) { - if(bssid == NULL) + if(BSSID == NULL) { - bssid = _bssid_array; + BSSID = _bssidArray; } for(int i = 0; i < 6; i++) { - bssid[i] = new_bssid[i]; + BSSID[i] = newBSSID[i]; } } else { - bssid = NULL; + BSSID = NULL; } } -NetworkInfo::NetworkInfo(int new_network_index, bool autofill) : network_index(new_network_index) +NetworkInfo::NetworkInfo(int newNetworkIndex, bool autofill) : networkIndex(newNetworkIndex) { if(autofill) { - ssid = WiFi.SSID(new_network_index); - wifi_channel = WiFi.channel(new_network_index); - copyBSSID(WiFi.BSSID(new_network_index)); + SSID = WiFi.SSID(newNetworkIndex); + wifiChannel = WiFi.channel(newNetworkIndex); + copyBSSID(WiFi.BSSID(newNetworkIndex)); } } -NetworkInfo::NetworkInfo(const String &new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index) : - ssid(new_ssid), wifi_channel(new_wifi_channel), network_index(new_network_index) +NetworkInfo::NetworkInfo(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], int newNetworkIndex) : + SSID(newSSID), wifiChannel(newWiFiChannel), networkIndex(newNetworkIndex) { - copyBSSID(new_bssid); + copyBSSID(newBSSID); } -NetworkInfo::NetworkInfo(const NetworkInfo &other) : ssid(other.ssid), wifi_channel(other.wifi_channel), network_index(other.network_index) +NetworkInfo::NetworkInfo(const NetworkInfo &other) : SSID(other.SSID), wifiChannel(other.wifiChannel), networkIndex(other.networkIndex) { - copyBSSID(other.bssid); + copyBSSID(other.BSSID); } NetworkInfo & NetworkInfo::operator=(const NetworkInfo &other) { - ssid = other.ssid; - wifi_channel = other.wifi_channel; - copyBSSID(other.bssid); - network_index = other.network_index; + SSID = other.SSID; + wifiChannel = other.wifiChannel; + copyBSSID(other.BSSID); + networkIndex = other.networkIndex; return *this; } diff --git a/libraries/ESP8266WiFiMesh/src/NetworkInfo.h b/libraries/ESP8266WiFiMesh/src/NetworkInfo.h index d8b4dfb66f..82fcd90c04 100644 --- a/libraries/ESP8266WiFiMesh/src/NetworkInfo.h +++ b/libraries/ESP8266WiFiMesh/src/NetworkInfo.h @@ -34,24 +34,24 @@ class NetworkInfo { private: - uint8_t _bssid_array[6] {0}; + uint8_t _bssidArray[6] {0}; public: - String ssid = ""; - int wifi_channel = NETWORK_INFO_DEFAULT_INT; - uint8_t *bssid = NULL; - int network_index = NETWORK_INFO_DEFAULT_INT; + String SSID = ""; + int wifiChannel = NETWORK_INFO_DEFAULT_INT; + uint8_t *BSSID = NULL; + int networkIndex = NETWORK_INFO_DEFAULT_INT; /** - * @param autofill Automatically fill in the rest of the network info using _network_index and the WiFi scan results. + * @param autofill Automatically fill in the rest of the network info using newNetworkIndex and the WiFi scan results. */ - NetworkInfo(int new_network_index, bool autofill = true); + NetworkInfo(int newNetworkIndex, bool autofill = true); /** - * Without giving channel and bssid, connection time is longer. + * Without giving channel and BSSID, connection time is longer. */ - NetworkInfo(const String &new_ssid, int new_wifi_channel = NETWORK_INFO_DEFAULT_INT, uint8_t new_bssid[6] = NULL, int new_network_index = NETWORK_INFO_DEFAULT_INT); + NetworkInfo(const String &newSSID, int newWiFiChannel = NETWORK_INFO_DEFAULT_INT, uint8_t newBSSID[6] = NULL, int newNetworkIndex = NETWORK_INFO_DEFAULT_INT); NetworkInfo(const NetworkInfo &other); @@ -60,10 +60,10 @@ class NetworkInfo { // No need for explicit destructor with current class design /** - * Copy new_bssid into bssid. + * Copy newBSSID into BSSID. * Prefer this method for changing NetworkInfo BSSID, unless you actually want to change the BSSID pointer. */ - void copyBSSID(uint8_t new_bssid[6]); + void copyBSSID(uint8_t newBSSID[6]); }; #endif diff --git a/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp b/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp index b27e79a0ab..81f9312461 100644 --- a/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp +++ b/libraries/ESP8266WiFiMesh/src/TransmissionResult.cpp @@ -25,18 +25,18 @@ #include "TransmissionResult.h" -TransmissionResult::TransmissionResult(int new_network_index, transmission_status_t new_transmission_status, bool autofill) : - NetworkInfo(new_network_index, autofill), transmission_status(new_transmission_status) +TransmissionResult::TransmissionResult(int newNetworkIndex, transmission_status_t newTransmissionStatus, bool autofill) : + NetworkInfo(newNetworkIndex, autofill), transmissionStatus(newTransmissionStatus) { } -TransmissionResult::TransmissionResult(const String &new_ssid, int new_wifi_channel, uint8_t new_bssid[6], transmission_status_t new_transmission_status) : - NetworkInfo(new_ssid, new_wifi_channel, new_bssid), transmission_status(new_transmission_status) +TransmissionResult::TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], transmission_status_t newTransmissionStatus) : + NetworkInfo(newSSID, newWiFiChannel, newBSSID), transmissionStatus(newTransmissionStatus) { } -TransmissionResult::TransmissionResult(const String &new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index, transmission_status_t new_transmission_status) : - NetworkInfo(new_ssid, new_wifi_channel, new_bssid, new_network_index), transmission_status(new_transmission_status) +TransmissionResult::TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], int newNetworkIndex, transmission_status_t newTransmissionStatus) : + NetworkInfo(newSSID, newWiFiChannel, newBSSID, newNetworkIndex), transmissionStatus(newTransmissionStatus) { } -TransmissionResult::TransmissionResult(const NetworkInfo& origin, transmission_status_t new_transmission_status) : - NetworkInfo(origin), transmission_status(new_transmission_status) +TransmissionResult::TransmissionResult(const NetworkInfo& origin, transmission_status_t newTransmissionStatus) : + NetworkInfo(origin), transmissionStatus(newTransmissionStatus) { } diff --git a/libraries/ESP8266WiFiMesh/src/TransmissionResult.h b/libraries/ESP8266WiFiMesh/src/TransmissionResult.h index bc6a652caa..8cc4cc020b 100644 --- a/libraries/ESP8266WiFiMesh/src/TransmissionResult.h +++ b/libraries/ESP8266WiFiMesh/src/TransmissionResult.h @@ -40,18 +40,18 @@ class TransmissionResult : public NetworkInfo { public: - transmission_status_t transmission_status; + transmission_status_t transmissionStatus; /** - * @param autofill Automatically fill in the rest of the network info using _network_index and the WiFi scan results. + * @param autofill Automatically fill in the rest of the network info using newNetworkIndex and the WiFi scan results. */ - TransmissionResult(int new_network_index, transmission_status_t new_transmission_status, bool autofill = true); + TransmissionResult(int newNetworkIndex, transmission_status_t newTransmissionStatus, bool autofill = true); - TransmissionResult(const String &new_ssid, int new_wifi_channel, uint8_t new_bssid[6], transmission_status_t new_transmission_status); + TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], transmission_status_t newTransmissionStatus); - TransmissionResult(const String &new_ssid, int new_wifi_channel, uint8_t new_bssid[6], int new_network_index, transmission_status_t new_transmission_status); + TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], int newNetworkIndex, transmission_status_t newTransmissionStatus); - TransmissionResult(const NetworkInfo& origin, transmission_status_t new_transmission_status); + TransmissionResult(const NetworkInfo& origin, transmission_status_t newTransmissionStatus); }; #endif diff --git a/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp b/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp index 734290aa63..6f6cf31c73 100644 --- a/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp +++ b/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp @@ -26,19 +26,19 @@ #include "ESP8266WiFiMesh.h" #include -void ESP8266WiFiMesh::verboseModePrint(const String &string_to_print, bool newline) +void ESP8266WiFiMesh::verboseModePrint(const String &stringToPrint, bool newline) { - if(_verbose_mode) + if(_verboseMode) { if(newline) - Serial.println(string_to_print); + Serial.println(stringToPrint); else - Serial.print(string_to_print); + Serial.print(stringToPrint); } } /** - * Note that using a base higher than 16 increases likelihood of randomly generating ssid strings containing controversial words. + * 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. @@ -60,7 +60,7 @@ String ESP8266WiFiMesh::Uint64ToString(uint64_t number, byte base) } /** - * Note that using a base higher than 16 increases likelihood of randomly generating ssid strings containing controversial words. + * 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. @@ -72,54 +72,54 @@ uint64_t ESP8266WiFiMesh::StringToUint64(const String &string, byte base) uint64_t result = 0; - char current_character[1]; + char currentCharacter[1]; for(uint32_t i = 0; i < string.length(); i++) { result *= base; - current_character[0] = string.charAt(i); - result += strtoul(current_character, NULL, 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 _lwip_version array. + * 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. */ void ESP8266WiFiMesh::storeLwipVersion() { // ESP.getFullVersion() looks something like: // SDK:2.2.1(cfd48f3)/Core:win-2.5.0-dev/lwIP:2.0.3(STABLE-2_0_3_RELEASE/glue:arduino-2.4.1-10-g0c0d8c2)/BearSSL:94e9704 - String full_version = ESP.getFullVersion(); + String fullVersion = ESP.getFullVersion(); - int i = full_version.indexOf("lwIP:") + 5; - char current_char = full_version.charAt(i); + int i = fullVersion.indexOf("lwIP:") + 5; + char currentChar = fullVersion.charAt(i); - for(int version_part = 0; version_part < 3; version_part++) + for(int versionPart = 0; versionPart < 3; versionPart++) { - while(!isdigit(current_char)) + while(!isdigit(currentChar)) { - current_char = full_version.charAt(++i); + currentChar = fullVersion.charAt(++i); } - while(isdigit(current_char)) + while(isdigit(currentChar)) { - _lwip_version[version_part] = 10 * _lwip_version[version_part] + (current_char - '0'); // Left shift and add digit value, in base 10. - current_char = full_version.charAt(++i); + _lwipVersion[versionPart] = 10 * _lwipVersion[versionPart] + (currentChar - '0'); // Left shift and add digit value, in base 10. + currentChar = fullVersion.charAt(++i); } } } /** - * Check if the code is running on a version of lwIP that is at least min_lwip_version. + * Check if the code is running on a version of lwIP that is at least minLwipVersion. */ -bool ESP8266WiFiMesh::atLeastLwipVersion(const uint32_t min_lwip_version[3]) +bool ESP8266WiFiMesh::atLeastLwipVersion(const uint32_t minLwipVersion[3]) { - for(int version_part = 0; version_part < 3; version_part++) + for(int versionPart = 0; versionPart < 3; versionPart++) { - if(_lwip_version[version_part] > min_lwip_version[version_part]) + if(_lwipVersion[versionPart] > minLwipVersion[versionPart]) return true; - else if(_lwip_version[version_part] < min_lwip_version[version_part]) + else if(_lwipVersion[versionPart] < minLwipVersion[versionPart]) return false; } From b6fc4bb637b61245d6c20cb468827f443ecc9263 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 31 Jul 2018 22:46:35 +0200 Subject: [PATCH 20/20] Rename Uint64ToString to uint64ToString and StringToUint64 to stringToUint64, since they are methods. --- libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino | 4 ++-- libraries/ESP8266WiFiMesh/keywords.txt | 4 ++-- libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp | 2 +- libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h | 4 ++-- libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index 8c1fd8e983..f5347743ab 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -42,9 +42,9 @@ void networkFilter(int numberOfNetworks, ESP8266WiFiMesh &meshInstance) { /* Connect to any _suitable_ APs which contain meshInstance.getMeshName() */ if (meshNameIndex >= 0) { - uint64_t targetNodeID = ESP8266WiFiMesh::StringToUint64(currentSSID.substring(meshNameIndex + meshInstance.getMeshName().length())); + uint64_t targetNodeID = ESP8266WiFiMesh::stringToUint64(currentSSID.substring(meshNameIndex + meshInstance.getMeshName().length())); - if (targetNodeID < ESP8266WiFiMesh::StringToUint64(meshInstance.getNodeID())) { + if (targetNodeID < ESP8266WiFiMesh::stringToUint64(meshInstance.getNodeID())) { ESP8266WiFiMesh::connectionQueue.push_back(NetworkInfo(i)); } } diff --git a/libraries/ESP8266WiFiMesh/keywords.txt b/libraries/ESP8266WiFiMesh/keywords.txt index b8d659ff35..fdb0caf08e 100644 --- a/libraries/ESP8266WiFiMesh/keywords.txt +++ b/libraries/ESP8266WiFiMesh/keywords.txt @@ -43,8 +43,8 @@ acceptRequest KEYWORD2 setStaticIP KEYWORD2 getStaticIP KEYWORD2 disableStaticIP->KEYWORD2 -Uint64ToString KEYWORD2 -StringToUint64 KEYWORD2 +uint64ToString KEYWORD2 +stringToUint64 KEYWORD2 getNetworkFilter KEYWORD2 setNetworkFilter KEYWORD2 diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp index ff0ed6e3ee..b617be1f00 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -57,7 +57,7 @@ ESP8266WiFiMesh::ESP8266WiFiMesh(ESP8266WiFiMesh::requestHandlerType requestHand { storeLwipVersion(); - updateNetworkNames(meshName, (nodeID != "" ? nodeID : Uint64ToString(ESP.getChipId()))); + updateNetworkNames(meshName, (nodeID != "" ? nodeID : uint64ToString(ESP.getChipId()))); _requestHandler = requestHandler; _responseHandler = responseHandler; setWiFiChannel(meshWiFiChannel); diff --git a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h index d1d31d9bf5..0cbd4407b6 100644 --- a/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h +++ b/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -291,8 +291,8 @@ class ESP8266WiFiMesh { */ static const IPAddress emptyIP; - static String Uint64ToString(uint64_t number, byte base = 16); - static uint64_t StringToUint64(const String &string, byte base = 16); + static String uint64ToString(uint64_t number, byte base = 16); + static uint64_t stringToUint64(const String &string, byte base = 16); networkFilterType getNetworkFilter(); void setNetworkFilter(networkFilterType networkFilter); diff --git a/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp b/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp index 6f6cf31c73..ecc36ca72f 100644 --- a/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp +++ b/libraries/ESP8266WiFiMesh/src/UtilityMethods.cpp @@ -44,7 +44,7 @@ void ESP8266WiFiMesh::verboseModePrint(const String &stringToPrint, bool newline * @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) +String ESP8266WiFiMesh::uint64ToString(uint64_t number, byte base) { assert(2 <= base && base <= 36); @@ -66,7 +66,7 @@ String ESP8266WiFiMesh::Uint64ToString(uint64_t number, byte 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) +uint64_t ESP8266WiFiMesh::stringToUint64(const String &string, byte base) { assert(2 <= base && base <= 36);