-->
Page 1 of 3

WiFi Range Extender - Arduino IDE

PostPosted: Mon Jun 14, 2021 5:44 am
by Lando_TT
This is some code I recently wrote for the ESP8266. It is based off of the example which can be found on GitHub.

As you know, most of the examples for using the ESP simply hard-codes the SSID and PSK to the device, but I carry it around with me so this is inconvenient. I am very new to C++ programming so any tips will be appreciated.

EDIT 1: Previously my code would unnecessarily stored the credentials twice (thanks to the user below for pointing that out). I've updated my code so that you can now temporarily change the credentials until a reboot (It's useful if you mainly use it at home and carry it around often).

EDIT 2: Fixed a problem with my code, where specifying WiFi.mode(WIFI_AP) would allow devices to connec to the AP but not get an IP Address from DHCP.

EDIT 3: Removed the WiFi.setAutoReconnect() stuff as the WiFi library automatically tries reconnect when signal is lost. ALSO added some led indications so you can know when it's connecting or loses signal (solid for connecting, blinking for lost signal and trying to reconnect)

EDIT 4: Re-written from scratch. Fixed DHCP (again) as well as improved UI and added the ability to select SSID from list instead of having to manually enter.

V1.0.0
Image

V1.0.1
Image
Image

Code: Select all// NAPT example released to public domain

#if LWIP_FEATURES && !LWIP_IPV6

#define HAVE_NETDUMP 0

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <lwip/napt.h>
#include <lwip/dns.h>
#include <LwipDhcpServer.h>

#define NAPT 1000
#define NAPT_PORT 10

#if HAVE_NETDUMP

#include <NetDump.h>

void dump(int netif_idx, const char* data, size_t len, int out, int success) {
  (void)success;
  Serial.print(out ? F("out ") : F(" in "));
  Serial.printf("%d ", netif_idx);

  // optional filter example: if (netDump_is_ARP(data))
  {
    netDump(Serial, data, len);
    //netDumpHex(Serial, data, len);
  }
}
#endif

// MY FUNCTIONS
void testwifi() {
  Serial.printf("\nTesting connection with '%s'\n", WiFi.SSID().c_str());
  int count = 0;
  digitalWrite(2,LOW);
  while (count < 20) {
    WiFi.mode(WIFI_STA);
    if (WiFi.status() == WL_CONNECTED) {
      Serial.printf("\nWiFi Connected! \nSTA: %s (dns: %s / %s)\n\n",
                    WiFi.localIP().toString().c_str(),
                    WiFi.dnsIP(0).toString().c_str(),
                    WiFi.dnsIP(1).toString().c_str());
      WiFi.mode(WIFI_AP_STA);
      WiFi.softAPConfig(  // Set IP Address, Gateway and Subnet
        IPAddress(192, 168, 4, 1),
        IPAddress(192, 168, 4, 1),
        IPAddress(255, 255, 255, 0));
      // dhcpSoftAP.dhcps_set_dns(0, WiFi.dnsIP(0));
      // dhcpSoftAP.dhcps_set_dns(1, WiFi.dnsIP(1));
      WiFi.softAPDhcpServer().setDns(WiFi.dnsIP(0));
      WiFi.softAP(WiFi.softAPSSID(), WiFi.softAPPSK());
      return;
    }
    else {
      Serial.print(".");
      delay(1000);
      count++;
    }
  }
  Serial.printf("\nCan't connect to WiFi, connect to AP '%s' and configure...\n\n", WiFi.softAPSSID());
}

// SERVER
ESP8266WebServer server(80);
void handleRoot() {
  String content;
  content = "<!DOCTYPE html><html lang='en'><meta name='viewport' content='width=device-width, initial-scale=1.0'>";
  content += "<head><title>ESP8266 Configuration Page</title></head>";
  content += "<body>";
  content += "<h1>Wireless Station Settings</h1>";
  content += "<form action='/applysta' method='post'>";
  content += "<label for='ssid-select'>SSID:</label><br>";
  content += "<select name='stassid' id='ssid-select'>";
  String ssid;
  int32_t rssi;
  uint8_t encryptionType;
  uint8_t *bssid;
  int32_t channel;
  bool hidden;
  int scanResult;
 
  Serial.println(F("Starting WiFi scan..."));
 
  scanResult = WiFi.scanNetworks(/*async=*/false, /*hidden=*/true);

  if (scanResult == 0) {
    Serial.println(F("No networks found"));
  }
  else if (scanResult > 0) {
    Serial.printf(PSTR("%d networks found:\n"), scanResult);
 
    // Print unsorted scan results
    for (int8_t i = 0; i < scanResult; i++) {
      WiFi.getNetworkInfo(i, ssid, encryptionType, rssi, bssid, channel, hidden);
      if (ssid == WiFi.SSID() && WiFi.status() == WL_CONNECTED) {
        content += "<option value='" + ssid + "' selected>" +  rssi + "dB | " + ssid + "</option>";
      }
      else {
        content += "<option value='" + ssid + "'>" + rssi + "dB | " + ssid + "</option>";
      }
    }
  }
  else {
    Serial.printf(PSTR("WiFi scan error %d"), scanResult);
  }
  content += "</select><br>";
  content += "<label for='stapsk'>Password:</label><br><input type='password' id='stapsk' name='stapsk' placeholder='********' minlength='8' maxlength='63'><br>";
  content += "<input type='radio' id='perm' name='stasetting' value='true'>";
  content += "<label for='perm'>Save Permanently</label>";
  content += "<input checked type='radio' id='temp' name='stasetting' value='false'>";
  content += "<label for='temp'>Save Until Reboot</label><br><br>";
  content += "<input type='submit' value='Apply'><br>";
  content += "</form>";
  content += "<h1>Access Point Settings</h1>";
  content += "<form action='/applyap' method='post'>";
  content += "<label for='apssid'>SSID:</label><br><input type='text' id='apssid' name='apssid' minlength='2' maxlength='32' value='" + WiFi.softAPSSID() + "'><br>";
  content += "<label for='stapsk'>Password:</label><br><input type='text' id='appsk' name='appsk' minlength='8' maxlength='63' value='" + WiFi.softAPPSK() + "'><br>";
  content += "<input type='radio' id='perm' name='apsetting' value='true'>";
  content += "<label for='perm'>Save Permanently</label>";
  content += "<input checked type='radio' id='temp' name='apsetting' value='false'>";
  content += "<label for='temp'>Save Until Reboot</label><br><br>";
  content += "<input type='submit' value='Apply'><br>";
  content += "</form>";
  content += "<h1>Miscellaneous</h1><br>";
  content += "<form><input type='submit' value='Reboot' formaction='/reboot'></form>";
  content += "</body>";
  content += "</html>";
  server.send(200, "text/html", content);
}
String content;
void serverconfig() {
  server.begin();
  server.on("/", handleRoot);
  server.onNotFound([]() {
    server.send(404, "text/plain", "How the heck did you get here? I'd go back if I were you.");
  });

  server.on("/applysta", []() {
    String stassid = server.arg("stassid");
    String stapsk = server.arg("stapsk");
    server.send(200, "text/plain", "Settings Recieved. You can go back and wait for reconnection.");
    delay(5000);
    (server.arg("stasetting") == "true") ? WiFi.persistent(true) : WiFi.persistent(false);
    Serial.printf("\n\nAttempting to connect to '%s' using password '%s' \n", stassid.c_str(), stapsk.c_str());
    WiFi.begin(stassid, stapsk);
    testwifi();
  });

  server.on("/applyap", []() {
    String apssid = server.arg("apssid");
    String appsk = server.arg("appsk");
    server.send(200, "text/plain", "Settings Recieved. You can go back and wait for reconnection.");
    delay(5000);
    (server.arg("apsetting") == "true") ? WiFi.persistent(true) : WiFi.persistent(false);
    Serial.printf("Creating AP '%s' with password '%s' \n", apssid.c_str(), appsk.c_str());
    WiFi.softAP(apssid, appsk);
  });

  server.on("/reboot", []() {
    server.send(200, "text/plain", "Rebooting now...");
    delay(2000);
    ESP.reset();
  });
}

void setup() {
  Serial.begin(115200);
  pinMode(2, OUTPUT);
  delay(1000);
  Serial.printf("\n\nNAPT Range extender\n");
  Serial.printf("Heap on start: %d\n", ESP.getFreeHeap());

#if HAVE_NETDUMP
  phy_capture = dump;
#endif

  WiFi.setPhyMode(WIFI_PHY_MODE_11N); // Set radio type to N
  WiFi.mode(WIFI_AP_STA);
  WiFi.persistent(false);
 
  if (WiFi.SSID() != NULL) {
    WiFi.begin(); // Use stored credentials to connect to network
    testwifi();
  }
  else {
    WiFi.softAPConfig(  // Set IP Address, Gateway and Subnet
      IPAddress(192, 168, 4, 1),
      IPAddress(192, 168, 4, 1),
      IPAddress(255, 255, 255, 0));
    WiFi.softAP(WiFi.softAPSSID(), WiFi.softAPPSK()); // Create AP with stored credentials
  }

  Serial.printf("Heap before: %d\n", ESP.getFreeHeap());
  err_t ret = ip_napt_init(NAPT, NAPT_PORT);
  Serial.printf("ip_napt_init(%d,%d): ret=%d (OK=%d)\n", NAPT, NAPT_PORT, (int)ret, (int)ERR_OK);
  if (ret == ERR_OK) {
    ret = ip_napt_enable_no(SOFTAP_IF, 1);
    Serial.printf("ip_napt_enable_no(SOFTAP_IF): ret=%d (OK=%d)\n", (int)ret, (int)ERR_OK);
    if (ret == ERR_OK) {
      Serial.printf("\nWiFi Network '%s' with Password '%s' and IP '%s' is now setup\n", WiFi.softAPSSID().c_str(), WiFi.softAPPSK().c_str(), WiFi.softAPIP().toString().c_str());
    }
  }
  Serial.printf("Heap after napt init: %d\n", ESP.getFreeHeap());
  if (ret != ERR_OK) {
    Serial.printf("NAPT initialization failed\n");
  }

  serverconfig();
}

#else

void setup() {
  Serial.begin(115200);
  Serial.printf("\n\nNAPT not supported in this configuration\n");
}

#endif

void loop() {
  server.handleClient();
}

Re: WiFi Range Extender - Arduino IDE

PostPosted: Wed Jun 16, 2021 12:17 am
by JurajA
the WiFiManager library and other similar libraries can be used for WiFi provisioning.

the esp8266 remembers the last WiFi credentials and the SoftAP settings by itself. you don't have to store it.
I have a very simple example which demonstrates storing of the STA credentials.
https://github.com/jandrassy/lab/blob/m ... tionAP.ino

Re: WiFi Range Extender - Arduino IDE

PostPosted: Fri Jun 18, 2021 6:06 pm
by Lando_TT
JurajA wrote:the esp8266 remembers the last WiFi credentials and the SoftAP settings by itself. you don't have to store it.


Oh, thanks for letting me know that. I'll update my code so that it doesn't unnecessarily store the credentials twice.

Re: WiFi Range Extender - Arduino IDE

PostPosted: Fri Feb 18, 2022 1:37 pm
by YurkshireLad
This is interesting, thanks. I tried Lando_TT's code, but it wouldn't save the extender's password, so the WiFi access point is wide open. Did I forget to do something?