So you're a Noob? Post your questions here until you graduate! Don't be shy.

User avatar
By QuickFix
#70550 Ah in AP mode...

Of course in software "Everything" (within limits) should be possible, but I don't know of any plug 'n pay solutions at the moment, but in theory it shouldn't be too difficult, I suppose.
Maybe some other members here?
User avatar
By Lando_TT
#91605 Hey, I have a solution that works pretty well for me, as it only acts as a range extender. Basically on initial boot it wipes the EEPROM (Only the needed addresses, because I know we have limited writes to the EEPROM) and sets a default SSID and Password for both the Station and AP (you can configure it in the program before you upload). Afterwards it simply reads the SSID and Password from the set addresses in the EEPROM and uses that. I can just connect to the AP and visit it's local IP and change the SSID and Password of either the Station or AP there.

A copy of my code is below. I am very new to C programming, so my code may be a little obfuscated and any improvements suggested will be much appreciated.

Edit: Made some improvements to my code. Added a pic of the configuration page.

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>
#include <EEPROM.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

//Additional Functions
void firstboot(void) {
  Serial.println("Wiping EEPROM Addresses < 193...");
  for (int i = 0; i < 193; i++) {
    EEPROM.write(i, 0);
  }
  Serial.println("Setting up WiFi and AP...");
  String stassid = "Digicel_WiFi_M4cK";
  for (int i = 0; i < stassid.length(); i++) {
    EEPROM.write(i, stassid[i]);
    Serial.println("Wrote: " + stassid[i]);
  }
  String stapsk = "B3hY6t4Y";
  for (int i = 0; i < stapsk.length(); i++) {
    EEPROM.write(32 + i, stapsk[i]);
    Serial.println("Wrote: " + stapsk[i]);
  }
  String apssid = "My Hotspot";
  for (int i = 0; i < apssid.length(); i++) {
    EEPROM.write(96 + i, apssid[i]);
    Serial.println("Wrote: " + apssid[i]);
  }
  String appsk = "1234567890";
  for (int i = 0; i < appsk.length(); i++) {
    EEPROM.write(128 + i, appsk[i]);
    Serial.println("Wrote: " + appsk[i]);
  }
  EEPROM.commit();
  delay(500);
  ESP.reset();
}

String netcreds (int x, int y) {
  // STASSID at Address 0-31 (32 characters max)
  // STAPSK at Address 32-95 (63 characters max)
  // APSSID at Address 96-127
  // APPSK at Address 128-191
  String cred = "";
  for (int i = x; i < y; i++) {
    cred += char(EEPROM.read(i));
  }
  return cred;
}

bool testwifi() {
  int count = 0;
  while (count < 20) {
    if (WiFi.status() == WL_CONNECTED) {
      Serial.printf("WiFi Connected! \nSTA: %s (dns: %s / %s)\n",
                    WiFi.localIP().toString().c_str(),
                    WiFi.dnsIP(0).toString().c_str(),
                    WiFi.dnsIP(1).toString().c_str());

      // give DNS servers to AP side
      dhcpSoftAP.dhcps_set_dns(0, WiFi.dnsIP(0));
      dhcpSoftAP.dhcps_set_dns(1, WiFi.dnsIP(1));
      return true;
    }
    Serial.print(".");
    delay(1000);
    count++;
  }
  Serial.println("\nCan't connect to WiFi, connect to AP and configure...");
  return false;
}

// Server Stuff
ESP8266WebServer server(80);
String content;

void setup() {
  Serial.begin(230400);
  EEPROM.begin(512);
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(1000);
  Serial.println("Setting Radio Type to N");
  WiFi.setPhyMode(WIFI_PHY_MODE_11N);
  Serial.printf("\n\nNAPT Range extender\n");
  Serial.printf("Heap on start: %d\n", ESP.getFreeHeap());

  if (EEPROM.read(192) != 0) {
    Serial.println("It seems that this is a fresh device... configuring");
    delay(2000);
    firstboot();
  }

#if HAVE_NETDUMP
  phy_capture = dump;
#endif

  // first, connect to STA so we can get a proper local DNS server
  char *STASSID = strdup(netcreds(0, 32).c_str());
  char *STAPSK = strdup(netcreds(32, 96).c_str());
  WiFi.mode(WIFI_STA);
  Serial.printf("Attempting to connect to '%s' using password '%s'\n", STASSID, STAPSK);
  WiFi.begin(STASSID, STAPSK);
  testwifi();

  WiFi.softAPConfig(  // enable AP, with android-compatible google domain
    IPAddress(192, 168, 4, 1),
    IPAddress(192, 168, 4, 1),
    IPAddress(255, 255, 255, 0));

  char *APSSID = strdup(netcreds(96, 128).c_str());
  char *APPSK = strdup(netcreds(128, 192).c_str());
  WiFi.softAP(APSSID, APPSK);
  Serial.printf("AP: %s\n", WiFi.softAPIP().toString().c_str());

  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("WiFi Network '%s' with Password '%s' is now setup.", APSSID, APPSK);
    }
  }
  Serial.printf("\nHeap after napt init: %d\n", ESP.getFreeHeap());
  if (ret != ERR_OK) {
    Serial.printf("NAPT initialization failed\n");
  }

  // Server Config
  server.begin();
 
  server.on("/", []() {
    char *STASSID = strdup(netcreds(0, 32).c_str());
    char *APSSID = strdup(netcreds(96, 128).c_str());
    char *APPSK = strdup(netcreds(128, 192).c_str());
    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</h2>";
    content += "<form method='get' action='stasettings'>";
    content += "<label>SSID:</label><br><input name='stassid' placeholder='";
    content += STASSID;
    content += "' length=32><br>";
    content += "<label>Password:</label><br><input type='password' placeholder='********' name='stapsk' length=63><br><small>Must be at least 8 characters or blank!</small><br>";
    content += "<br><input type='submit'>";
    content += "</form>";
    content += "<h1>Wireless Access Point Settings</h2>";
    content += "<form method='get' action='apsettings'>";
    content += "<label>SSID:</label><br><input name='apssid' placeholder='";
    content += APSSID;
    content += "' length=32><br>";
    content += "<label>Password:</label><br><input type='password' placeholder='";
    content += APPSK;
    content += "' name='appsk' length=63><br><small>Must be at least 8 characters or blank!</small><br>";
    content += "<br><input type='submit'>";
    content += "</form>";
    content += "<h1>Miscellaneous</h1>";
    content += "<form method='get' action='reboot'><input type='submit' value='Reboot'></form>";
    content += "<form method='get' action='reset'><input type='submit' value='Factory Reset'></form>";
    content += "<br><small>*Factory Reset changes the STA and AP settings to initial values set before code upload</small>";
    server.send(200, "text/html", content);
  });

  server.onNotFound([]() {
    server.send(404, "text/plain", "How the heck did you get here?");
  });

  server.on("/stasettings", []() {
    String stassid = server.arg("stassid");
    String stapsk = server.arg("stapsk");
    if (stassid.length() > 0) {
      Serial.println("Clearing EEPROM Addresses");
      for (int i = 0; i < 96; i++) {
        EEPROM.write(i, 0);
      }
      Serial.printf("New STA SSID: ");
      Serial.println(stassid);
      Serial.printf("New STA PASS: ");
      Serial.println(stapsk);

      Serial.println("Writing new credentials");
      for (int i = 0; i < stassid.length(); ++i) {
        EEPROM.write(i, stassid[i]);
        Serial.print("Wrote: ");
        Serial.println(stassid[i]);
      }
      for (int i = 0; i < stapsk.length(); ++i) {
        EEPROM.write(32 + i, stapsk[i]);
        Serial.print("Wrote: ");
        Serial.println(stapsk[i]);
      }

      EEPROM.commit();
      server.send(200, "text/plain", "Done! Rebooting...");
      delay(5000);
      ESP.reset();
    }
    else {
      server.send(404);
    }
  });

  server.on("/apsettings", []() {
    String apssid = server.arg("apssid");
    String appsk = server.arg("appsk");
    if (apssid.length() > 0) {
      Serial.println("Clearing EEPROM Addresses");
      for (int i = 96; i < 192; i++) {
        EEPROM.write(i, 0);
      }
      Serial.printf("New AP SSID: ");
      Serial.println(apssid);
      Serial.printf("New AP PASS: ");
      Serial.println(appsk);

      Serial.println("Writing new credentials");
      for (int i = 0; i < apssid.length(); ++i) {
        EEPROM.write(96 + i, apssid[i]);
        Serial.print("Wrote: ");
        Serial.println(apssid[i]);
      }
      for (int i = 0; i < appsk.length(); ++i) {
        EEPROM.write(128 + i, appsk[i]);
        Serial.print("Wrote: ");
        Serial.println(appsk[i]);
      }

      EEPROM.commit();
      server.send(200, "text/plain", "Done! Rebooting...");
      delay(5000);
      ESP.reset();
    }
    else {
      server.send(404);
    }
  });

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

  server.on("/reset", []() {
    server.send(200, "text/plain", "Resetting to default...");
    EEPROM.write(192, 1);
    EEPROM.commit();
    delay(5000);
    ESP.reset();
  });
}

#else

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

#endif

void loop() {
  server.handleClient();
  if (WiFi.status() != WL_CONNECTED) {
    digitalWrite(2, LOW);
    delay(1000);
    digitalWrite(2, HIGH);
    delay(1000);
  }
  else {
    digitalWrite(2, HIGH);
  }
}