Web page in access point ESP8266

Buongiorno o buonasera a tutti, ho un clone del wemos D1 mini (AZ-delivery per la precisione) e vorrei creare un access point con una pagina web locale per controllare il tempo di permanenza di un pin a livello alto con un form dove andrò a scrivere (tramite un device ad esempio smartphone) il tempo in secondi che andrà a sostituire l'argomento nel delay. Ho già testato la rete, e mi si connette benissimo via wifi, immetto l'indirizzo ip locale e mi apre la pagina con una semplice scritta "You are connected". Qualcuno può consigliarmi una guida su come personalizzare la pagina web? Mi ha dato un problema durante la compilazione poichè avevo scritto una riga in html che partiva con "<p" invece di "<h1" non posso dare colore al testo, ne creare bottoni, ne centrare il testo in mezzo alla pagina.
Grazie a tutti.

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

#ifndef APSSID
#define APSSID "Mio esp8266"
#define APPSK  "12345678"
#endif

/* Set these to your desired credentials. */
const char *ssid = APSSID;
const char *password = APPSK;

ESP8266WebServer server(80);

/* Just a little test message.  Go to http://192.168.4.1 in a web browser
   connected to this access point to see it.
*/
void handleRoot() {
  server.send(200, "text/html", "<h1>You are connected</h1>");
  /* Vorrei inserire una pagina web qui dentro personalizzata per poter controllare il tempo di permanenza in HIGH di 3 pin indipendenti
}

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println();
  Serial.print("Configuring access point...");
  /* You can remove the password parameter if you want the AP to be open. */
  WiFi.softAP(ssid, password);

  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
  server.on("/", handleRoot);
  server.begin();
  Serial.println("HTTP server started");
}

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

Visto che sei all'inizio del tuo progetto, se vuoi partire bene e lasciarti la possibilità di modificare facilmente e/o aggiungere funzionalità alla tua pagina web senza dover ogni volta ricompilare il firmware, ti consiglio di abbandonare il pessimo approccio con la String infinita compilata a runtime.

Tra gli esempi per l'ESP8266 installati nell'IDE troverai FSBrowser.ino che ti illustra come far girare un webserver prendendo tutto il necessario (HTML, CSS, Javascript) dalla memoria flash dell'ESP (la cartella data nel folder dello sketch).
L'esempio include anche un web editor che ti consente di modificare il codice della pagina direttamente dal browser.
Per fare l'upload nella memoria flash dell'esp ti consiglio di usare questo plugin esp8266/arduino-esp8266fs-plugin: Arduino plugin for uploading files to ESP8266 file system (github.com)

(prima fai l'upload del firmware come al solito e dopo l'upload del contenuto del folder data)

Ho installato il plugin .jar, ma se lo sketch lo carico attraverso la compilazione classica dell'IDE di arduino, cosa devo caricare sulla memoria flash dell'esp8266? É la prima volta che uso il wemos d1 mini e vorrei migliori delucidazioni, grazie mille.

Nel momento in cui hai installato correttamente il plugin come da istruzioni,
ti ritrovi questa voce nel menu strumenti.

image

Quando la selezioni (chiudi il monitor seriale se è aperto), verrà eseguito l'upload di tutti i file presenti nella cartella data (situata allo stesso livello dello sketch), nella memoria flash dell'ESP.

N.B.
Il plugin in questione funziona con filesystem di tipo SPIFFS (ricordati di modificare lo sketch).
In realtà SPIFFS è deprecato, ma nell'ultima release del core Arduino per ESP8266 hanno fatto qualche casino e manca l'eseguibile per usare LittleFS (almeno su Window).
Se vedi nell'immagine, io ho più di qualche plugin installato.

Ricapitolando, le operazioni da fare per eseguire con successo l'esempio sono:

  1. Modifica SSID e password (poi ovviamente lo imposterai per farlo andare come Access Point
  2. Programmi il wemos come al solito
  3. Esegui una prima volta lo sketch (il firmware provvederà a formattare il filesystem)
  4. Con il plugin carichi il contenuto della cartella data

A questo punto se ti colleghi all'indirizzo File manager (fsbrowser.local) apri l'editor per modificare il contenuto dei file appena caricati.

Ho modificato i parametri per avviare un access point, ma la rete non la vedo nell'elenco wifi, sbaglio qualcosa?

////////////////////////////////

// Select the FileSystem by uncommenting one of the lines below

//#define USE_SPIFFS
#define USE_LITTLEFS
//#define USE_SDFS

// Uncomment the following line to embed a version of the web page in the code
// (program code will be larger, but no file will have to be written to the filesystem).
// Note: the source file "extras/index_htm.h" must have been generated by "extras/reduce_index.sh"

//#define INCLUDE_FALLBACK_INDEX_HTM

////////////////////////////////

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <SPI.h>

#ifdef INCLUDE_FALLBACK_INDEX_HTM
#include "extras/index_htm.h"
#endif

#if defined USE_SPIFFS
#include <FS.h>
const char* fsName = "SPIFFS";
FS* fileSystem = &SPIFFS;
SPIFFSConfig fileSystemConfig = SPIFFSConfig();
#elif defined USE_LITTLEFS
#include <LittleFS.h>
const char* fsName = "LittleFS";
FS* fileSystem = &LittleFS;
LittleFSConfig fileSystemConfig = LittleFSConfig();
#elif defined USE_SDFS
#include <SDFS.h>
const char* fsName = "SDFS";
FS* fileSystem = &SDFS;
SDFSConfig fileSystemConfig = SDFSConfig();
// fileSystemConfig.setCSPin(chipSelectPin);
#else
#error Please select a filesystem first by uncommenting one of the "#define USE_xxx" lines at the beginning of the sketch.
#endif


#define DBG_OUTPUT_PORT Serial

#ifndef APSSID
#define APSSID "Eccomi"
#define APPSK  "12345678"
#endif

const char* ssid = APSSID;
const char* password = APPSK;
const char* host = "fsbrowser";

ESP8266WebServer server(80);

static bool fsOK;
String unsupportedFiles = String();

File uploadFile;

static const char TEXT_PLAIN[] PROGMEM = "text/plain";
static const char FS_INIT_ERROR[] PROGMEM = "FS INIT ERROR";
static const char FILE_NOT_FOUND[] PROGMEM = "FileNotFound";

////////////////////////////////
// Utils to return HTTP codes, and determine content-type

void replyOK() {
  server.send(200, FPSTR(TEXT_PLAIN), "");
}

void replyOKWithMsg(String msg) {
  server.send(200, FPSTR(TEXT_PLAIN), msg);
}

void replyNotFound(String msg) {
  server.send(404, FPSTR(TEXT_PLAIN), msg);
}

void replyBadRequest(String msg) {
  DBG_OUTPUT_PORT.println(msg);
  server.send(400, FPSTR(TEXT_PLAIN), msg + "\r\n");
}

void replyServerError(String msg) {
  DBG_OUTPUT_PORT.println(msg);
  server.send(500, FPSTR(TEXT_PLAIN), msg + "\r\n");
}

#ifdef USE_SPIFFS
/*
   Checks filename for character combinations that are not supported by FSBrowser (alhtough valid on SPIFFS).
   Returns an empty String if supported, or detail of error(s) if unsupported
*/
String checkForUnsupportedPath(String filename) {
  String error = String();
  if (!filename.startsWith("/")) {
    error += F("!NO_LEADING_SLASH! ");
  }
  if (filename.indexOf("//") != -1) {
    error += F("!DOUBLE_SLASH! ");
  }
  if (filename.endsWith("/")) {
    error += F("!TRAILING_SLASH! ");
  }
  return error;
}
#endif


////////////////////////////////
// Request handlers

/*
   Return the FS type, status and size info
*/
void handleStatus() {
  DBG_OUTPUT_PORT.println("handleStatus");
  FSInfo fs_info;
  String json;
  json.reserve(128);

  json = "{\"type\":\"";
  json += fsName;
  json += "\", \"isOk\":";
  if (fsOK) {
    fileSystem->info(fs_info);
    json += F("\"true\", \"totalBytes\":\"");
    json += fs_info.totalBytes;
    json += F("\", \"usedBytes\":\"");
    json += fs_info.usedBytes;
    json += "\"";
  } else {
    json += "\"false\"";
  }
  json += F(",\"unsupportedFiles\":\"");
  json += unsupportedFiles;
  json += "\"}";

  server.send(200, "application/json", json);
}


/*
   Return the list of files in the directory specified by the "dir" query string parameter.
   Also demonstrates the use of chuncked responses.
*/
void handleFileList() {
  if (!fsOK) {
    return replyServerError(FPSTR(FS_INIT_ERROR));
  }

  if (!server.hasArg("dir")) {
    return replyBadRequest(F("DIR ARG MISSING"));
  }

  String path = server.arg("dir");
  if (path != "/" && !fileSystem->exists(path)) {
    return replyBadRequest("BAD PATH");
  }

  DBG_OUTPUT_PORT.println(String("handleFileList: ") + path);
  Dir dir = fileSystem->openDir(path);
  path.clear();

  // use HTTP/1.1 Chunked response to avoid building a huge temporary string
  if (!server.chunkedResponseModeStart(200, "text/json")) {
    server.send(505, F("text/html"), F("HTTP1.1 required"));
    return;
  }

  // use the same string for every line
  String output;
  output.reserve(64);
  while (dir.next()) {
#ifdef USE_SPIFFS
    String error = checkForUnsupportedPath(dir.fileName());
    if (error.length() > 0) {
      DBG_OUTPUT_PORT.println(String("Ignoring ") + error + dir.fileName());
      continue;
    }
#endif
    if (output.length()) {
      // send string from previous iteration
      // as an HTTP chunk
      server.sendContent(output);
      output = ',';
    } else {
      output = '[';
    }

    output += "{\"type\":\"";
    if (dir.isDirectory()) {
      output += "dir";
    } else {
      output += F("file\",\"size\":\"");
      output += dir.fileSize();
    }

    output += F("\",\"name\":\"");
    // Always return names without leading "/"
    if (dir.fileName()[0] == '/') {
      output += &(dir.fileName()[1]);
    } else {
      output += dir.fileName();
    }

    output += "\"}";
  }

  // send last string
  output += "]";
  server.sendContent(output);
  server.chunkedResponseFinalize();
}


/*
   Read the given file from the filesystem and stream it back to the client
*/
bool handleFileRead(String path) {
  DBG_OUTPUT_PORT.println(String("handleFileRead: ") + path);
  if (!fsOK) {
    replyServerError(FPSTR(FS_INIT_ERROR));
    return true;
  }

  if (path.endsWith("/")) {
    path += "index.htm";
  }

  String contentType;
  if (server.hasArg("download")) {
    contentType = F("application/octet-stream");
  } else {
    contentType = mime::getContentType(path);
  }

  if (!fileSystem->exists(path)) {
    // File not found, try gzip version
    path = path + ".gz";
  }
  if (fileSystem->exists(path)) {
    File file = fileSystem->open(path, "r");
    if (server.streamFile(file, contentType) != file.size()) {
      DBG_OUTPUT_PORT.println("Sent less data than expected!");
    }
    file.close();
    return true;
  }

  return false;
}


/*
   As some FS (e.g. LittleFS) delete the parent folder when the last child has been removed,
   return the path of the closest parent still existing
*/
String lastExistingParent(String path) {
  while (!path.isEmpty() && !fileSystem->exists(path)) {
    if (path.lastIndexOf('/') > 0) {
      path = path.substring(0, path.lastIndexOf('/'));
    } else {
      path = String();  // No slash => the top folder does not exist
    }
  }
  DBG_OUTPUT_PORT.println(String("Last existing parent: ") + path);
  return path;
}

/*
   Handle the creation/rename of a new file
   Operation      | req.responseText
   ---------------+--------------------------------------------------------------
   Create file    | parent of created file
   Create folder  | parent of created folder
   Rename file    | parent of source file
   Move file      | parent of source file, or remaining ancestor
   Rename folder  | parent of source folder
   Move folder    | parent of source folder, or remaining ancestor
*/
void handleFileCreate() {
  if (!fsOK) {
    return replyServerError(FPSTR(FS_INIT_ERROR));
  }

  String path = server.arg("path");
  if (path.isEmpty()) {
    return replyBadRequest(F("PATH ARG MISSING"));
  }

#ifdef USE_SPIFFS
  if (checkForUnsupportedPath(path).length() > 0) {
    return replyServerError(F("INVALID FILENAME"));
  }
#endif

  if (path == "/") {
    return replyBadRequest("BAD PATH");
  }
  if (fileSystem->exists(path)) {
    return replyBadRequest(F("PATH FILE EXISTS"));
  }

  String src = server.arg("src");
  if (src.isEmpty()) {
    // No source specified: creation
    DBG_OUTPUT_PORT.println(String("handleFileCreate: ") + path);
    if (path.endsWith("/")) {
      // Create a folder
      path.remove(path.length() - 1);
      if (!fileSystem->mkdir(path)) {
        return replyServerError(F("MKDIR FAILED"));
      }
    } else {
      // Create a file
      File file = fileSystem->open(path, "w");
      if (file) {
        file.write((const char *)0);
        file.close();
      } else {
        return replyServerError(F("CREATE FAILED"));
      }
    }
    if (path.lastIndexOf('/') > -1) {
      path = path.substring(0, path.lastIndexOf('/'));
    }
    replyOKWithMsg(path);
  } else {
    // Source specified: rename
    if (src == "/") {
      return replyBadRequest("BAD SRC");
    }
    if (!fileSystem->exists(src)) {
      return replyBadRequest(F("SRC FILE NOT FOUND"));
    }

    DBG_OUTPUT_PORT.println(String("handleFileCreate: ") + path + " from " + src);

    if (path.endsWith("/")) {
      path.remove(path.length() - 1);
    }
    if (src.endsWith("/")) {
      src.remove(src.length() - 1);
    }
    if (!fileSystem->rename(src, path)) {
      return replyServerError(F("RENAME FAILED"));
    }
    replyOKWithMsg(lastExistingParent(src));
  }
}


/*
   Delete the file or folder designed by the given path.
   If it's a file, delete it.
   If it's a folder, delete all nested contents first then the folder itself

   IMPORTANT NOTE: using recursion is generally not recommended on embedded devices and can lead to crashes (stack overflow errors).
   This use is just for demonstration purpose, and FSBrowser might crash in case of deeply nested filesystems.
   Please don't do this on a production system.
*/
void deleteRecursive(String path) {
  File file = fileSystem->open(path, "r");
  bool isDir = file.isDirectory();
  file.close();

  // If it's a plain file, delete it
  if (!isDir) {
    fileSystem->remove(path);
    return;
  }

  // Otherwise delete its contents first
  Dir dir = fileSystem->openDir(path);

  while (dir.next()) {
    deleteRecursive(path + '/' + dir.fileName());
  }

  // Then delete the folder itself
  fileSystem->rmdir(path);
}


/*
   Handle a file deletion request
   Operation      | req.responseText
   ---------------+--------------------------------------------------------------
   Delete file    | parent of deleted file, or remaining ancestor
   Delete folder  | parent of deleted folder, or remaining ancestor
*/
void handleFileDelete() {
  if (!fsOK) {
    return replyServerError(FPSTR(FS_INIT_ERROR));
  }

  String path = server.arg(0);
  if (path.isEmpty() || path == "/") {
    return replyBadRequest("BAD PATH");
  }

  DBG_OUTPUT_PORT.println(String("handleFileDelete: ") + path);
  if (!fileSystem->exists(path)) {
    return replyNotFound(FPSTR(FILE_NOT_FOUND));
  }
  deleteRecursive(path);

  replyOKWithMsg(lastExistingParent(path));
}

/*
   Handle a file upload request
*/
void handleFileUpload() {
  if (!fsOK) {
    return replyServerError(FPSTR(FS_INIT_ERROR));
  }
  if (server.uri() != "/edit") {
    return;
  }
  HTTPUpload& upload = server.upload();
  if (upload.status == UPLOAD_FILE_START) {
    String filename = upload.filename;
    // Make sure paths always start with "/"
    if (!filename.startsWith("/")) {
      filename = "/" + filename;
    }
    DBG_OUTPUT_PORT.println(String("handleFileUpload Name: ") + filename);
    uploadFile = fileSystem->open(filename, "w");
    if (!uploadFile) {
      return replyServerError(F("CREATE FAILED"));
    }
    DBG_OUTPUT_PORT.println(String("Upload: START, filename: ") + filename);
  } else if (upload.status == UPLOAD_FILE_WRITE) {
    if (uploadFile) {
      size_t bytesWritten = uploadFile.write(upload.buf, upload.currentSize);
      if (bytesWritten != upload.currentSize) {
        return replyServerError(F("WRITE FAILED"));
      }
    }
    DBG_OUTPUT_PORT.println(String("Upload: WRITE, Bytes: ") + upload.currentSize);
  } else if (upload.status == UPLOAD_FILE_END) {
    if (uploadFile) {
      uploadFile.close();
    }
    DBG_OUTPUT_PORT.println(String("Upload: END, Size: ") + upload.totalSize);
  }
}


/*
   The "Not Found" handler catches all URI not explicitely declared in code
   First try to find and return the requested file from the filesystem,
   and if it fails, return a 404 page with debug information
*/
void handleNotFound() {
  if (!fsOK) {
    return replyServerError(FPSTR(FS_INIT_ERROR));
  }

  String uri = ESP8266WebServer::urlDecode(server.uri()); // required to read paths with blanks

  if (handleFileRead(uri)) {
    return;
  }

  // Dump debug data
  String message;
  message.reserve(100);
  message = F("Error: File not found\n\nURI: ");
  message += uri;
  message += F("\nMethod: ");
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += F("\nArguments: ");
  message += server.args();
  message += '\n';
  for (uint8_t i = 0; i < server.args(); i++) {
    message += F(" NAME:");
    message += server.argName(i);
    message += F("\n VALUE:");
    message += server.arg(i);
    message += '\n';
  }
  message += "path=";
  message += server.arg("path");
  message += '\n';
  DBG_OUTPUT_PORT.print(message);

  return replyNotFound(message);
}

/*
   This specific handler returns the index.htm (or a gzipped version) from the /edit folder.
   If the file is not present but the flag INCLUDE_FALLBACK_INDEX_HTM has been set, falls back to the version
   embedded in the program code.
   Otherwise, fails with a 404 page with debug information
*/
void handleGetEdit() {
  if (handleFileRead(F("/edit/index.htm"))) {
    return;
  }

#ifdef INCLUDE_FALLBACK_INDEX_HTM
  server.sendHeader(F("Content-Encoding"), "gzip");
  server.send(200, "text/html", index_htm_gz, index_htm_gz_len);
#else
  replyNotFound(FPSTR(FILE_NOT_FOUND));
#endif

}

void setup(void) {
  ////////////////////////////////
  // SERIAL INIT
  DBG_OUTPUT_PORT.begin(115200);
  DBG_OUTPUT_PORT.setDebugOutput(true);
  DBG_OUTPUT_PORT.print('\n');

  ////////////////////////////////
  // FILESYSTEM INIT

  fileSystemConfig.setAutoFormat(false);
  fileSystem->setConfig(fileSystemConfig);
  fsOK = fileSystem->begin();
  DBG_OUTPUT_PORT.println(fsOK ? F("Filesystem initialized.") : F("Filesystem init failed!"));

#ifdef USE_SPIFFS
  // Debug: dump on console contents of filessytem with no filter and check filenames validity
  Dir dir = fileSystem->openDir("");
  DBG_OUTPUT_PORT.println(F("List of files at root of filesystem:"));
  while (dir.next()) {
    String error = checkForUnsupportedPath(dir.fileName());
    String fileInfo = dir.fileName() + (dir.isDirectory() ? " [DIR]" : String(" (") + dir.fileSize() + "b)");
    DBG_OUTPUT_PORT.println(error + fileInfo);
    if (error.length() > 0) {
      unsupportedFiles += error + fileInfo + '\n';
    }
  }
  DBG_OUTPUT_PORT.println();

  // Keep the "unsupportedFiles" variable to show it, but clean it up
  unsupportedFiles.replace("\n", "<br/>");
  unsupportedFiles = unsupportedFiles.substring(0, unsupportedFiles.length() - 5);
#endif

  ////////////////////////////////
  // WI-FI INIT
  DBG_OUTPUT_PORT.printf("Connecting to %s\n", ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    DBG_OUTPUT_PORT.print(".");
  }
  DBG_OUTPUT_PORT.println("");
  DBG_OUTPUT_PORT.print(F("Connected! IP address: "));
  DBG_OUTPUT_PORT.println(WiFi.localIP());

  ////////////////////////////////
  // MDNS INIT
  if (MDNS.begin(host)) {
    MDNS.addService("http", "tcp", 80);
    DBG_OUTPUT_PORT.print(F("Open http://"));
    DBG_OUTPUT_PORT.print(host);
    DBG_OUTPUT_PORT.println(F(".local/edit to open the FileSystem Browser"));
  }

  ////////////////////////////////
  // WEB SERVER INIT

  // Filesystem status
  server.on("/status", HTTP_GET, handleStatus);

  // List directory
  server.on("/list", HTTP_GET, handleFileList);

  // Load editor
  server.on("/edit", HTTP_GET, handleGetEdit);

  // Create file
  server.on("/edit",  HTTP_PUT, handleFileCreate);

  // Delete file
  server.on("/edit",  HTTP_DELETE, handleFileDelete);

  // Upload file
  // - first callback is called after the request has ended with all parsed arguments
  // - second callback handles file upload at that location
  server.on("/edit",  HTTP_POST, replyOK, handleFileUpload);

  // Default handler for all URIs not defined above
  // Use it to read files from filesystem
  server.onNotFound(handleNotFound);

  // Start server
  server.begin();
  DBG_OUTPUT_PORT.println("HTTP server started");
}


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

No non lo hai fatto.

L'istruzione che devi mettere nel setup() è questa (come nel primo esempio che hai postato):
WiFi.softAP(ssid, password);

mentre tu hai lasciato

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

Se ti risulta più chiaro e di facile comprensione, tutte le funzioni "di servizio" per il webserver le puoi spostare in una seconda tab che poi includi nello sketch principale.
Io di solito faccio cosi per non farmi distrarre da funzioni già presenti negli esempi e che sò funzionare per certo (e alle quali quindi non devo dedicare la mia attenzione).
Per semplificare ulteriormente, una volta che hai deciso quale filesystem usare, tutto il codice e gli #include necessari per lasciare la "scelta" all'utente, puoi eliminare.

Ah, un'altra cosa.
Attenzione che quando fai salva con nome partendo dagli esempi inclusi, Arduino IDE non salva tutto il contenuto della cartella, ma solo i file e la cartella data (almeno quella).

In questo caso specifico ad esempio, non ti fa la copia della cartella "extras" in cui c'è il sorgente del web editor quindi dovrai fare copia e incolla dalla cartella dell'esempio a quella di destinazione che decidi tu se vuoi usarlo.

Sto cercando di aprire il link di fsbrowser, sono riuscito ad avviare l'access point ed a connettermi ad esso, ma mi dice pagina web non trovata, devo usare qualche ip?

Se usi l'access point il MDNS client chiaramente non funziona e quindi non sei in grado di risolvere l'hostname http://fsbrowser.local

Devi usare l'indirizzamento diretto come ad esempio (dipende dalla tua configurazione ovviamente).

http://192.168.4.1/edit

ho visto le informazioni dell'access point e l'indirizzo ip locale è 192.168.4.2, quindi cerco 192.168.4.2/edit, ma non riesco ad aprire l'editor.
Ah, comunque ho caricato solo il contenuto della cartella data salvata in automatico dal salva con nome di arduino ide

 if (MDNS.begin(host)) {
    MDNS.addService("http", "tcp", 80);
    DBG_OUTPUT_PORT.print(F("Open http://"));
    DBG_OUTPUT_PORT.print(host);
    DBG_OUTPUT_PORT.println(F(".local/edit to open the FileSystem Browser"));
  }

Che intendi? Il plugin carica solo data come è giusto che sia.

Sei sicuro dell'indirizzo? Quello a me sa tanto di indirizzo del tuo PC e non dell'ESP, controlla nel serial monitor quel che dice.
Sono pronto a scommettere che l'indirizzo dell'ESP è 192.168.4.1 :face_with_raised_eyebrow:

Allora ho appena provato, il fatto che tu sia "offline" con il web editor complica un po' il lavoro preparatorio.

Nulla di che non scoraggiarti, bisogna solo includere anche il file che lui va a reperire online e che in Access Point ovviamente non può fare.

Scarica questo file Javascript e copialo nella cartella /edit/ace.js all'interno del tuo sketch.
Apri il file /edit/index.htm e sostituisci il link esterno https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.9/ace.js con quello locale in memoria flash ace.js.
Dopodiché esegui nuovamente l'upload di data con il plugin.

A questo punto l'editor può funzionare anche offline (ho appena provato ovviamente :sunglasses:)

Nel senso che non ho caricato la cartella extras.
Ho provato con 192.168.4.2/edit, fsbrowser.local/edit, 192.168.4.1/edit, ma nulla.
Il monitor seriale dice questo:

bcn 0
del if1
usl
add if1
dhcp server start:(ip:192.168.4.1,mask:255.255.255.0,gw:192.168.4.1)
bcn 100
....add 1
aid 1
station: ce:d1:0f:60:43:76 join, AID = 1
........................................................................................

A quanto pare l'indirizzo è quello che hai detto tu, ma non va, mi dice che la pagina web non esiste

Probabilmente sono stato poco chiaro.
L'esempio parte dall'assunto che tu usi l'ESP in station mode, mentre invece vuoi usarlo in access point mode.

Dal log che hai postato presumo che tu sei rimasto fermo qui:

 // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    DBG_OUTPUT_PORT.print(".");
  }

Che può funzionare solo in station mode. Devi sistemaere il setup() sostituento TUTTE le istruzioni usate per lo station mode con quelle necessarie per andare in access point mode.

Prendi i due esempi e mettili a confronto, ma essenzialmente nel setup devi inserire solo queste righe

 ////////////////////////////////
  // WI-FI INIT
  WiFi.softAP(ssid, password);

  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);

Il blocco del MDNS (e il relativo #include) puoi anche rimuoverlo visto che tanto non lo userai

////////////////////////////////
  // MDNS INIT

In relazione alla sostituzione del file js da esterno a locale, sto provvedendo a sostituire il link, devo impostare la directory da C:/ e così via?

No, semplicemente ace.js

La riga dovrà essere cosi

<script src="ace.js" type="text/javascript" charset="utf-8"></script>

Ti ringrazio per la tua infinita pazienza :worried:, ho fatto un copia e incolla del file js in un blocco note e salvato in formato .js, cambiata la stringa del link in ace.js, rifatto il compila e carica in più lo storage dei file data nella memoria flash. Mi da nuovamente l'errore. Come posso fare?

Questo è l'esempio che sto testando proprio su un Wemos D1-mini (quindi deve per forza di cose andare anche per te).

Considerando che si tratta in pratica soltanto dell'esempio incluso nell'IDE configurato e semplificato per il tuo caso e sul quale poi dovrai aggiungere tutto quello che ti serve, in teoria non stiamo infrangendo il regolamento (leggasi pappa pronta :rofl: :rofl: :rofl:)

FSBrowser.zip (186.2 KB)

1 Like

ecco, io webserver.h e la cartella extras non ce li ho