ESP - WeMos






Здравствуйте.


В статье описана работа с платой ESP D1 mini (она же WeMos D1 mini, она же LOLIN D1 mini) и файловой системой SPIFFS.


Вначале о разновидностях плат…

непременно ознакомьтесь
WeMos D1 (не mini)



Эта плата существует в двух ревизиях — WeMos D1 R1 и WeMos D1 R2. Различия заключаются в распиновке…

R1




R2






WeMos D1 mini

Может быть в таком исполнении…




А может быть в таком…


Есть ли на плате надпись «WeMos» или нету, не имеет значения, чипы везде стоят одни и те же.


По сути это одинаковые девайсы, разница лишь в том, что в первом варианте чип и spi-flash находятся под железкой на отдельной платке, а во втором всё распаяно на основной плате. Чип может быть esp8266 или esp8285, об этом ниже.


spi-flash она же внешняя флешь-память, это вот такая «козявочка»…






WeMos D1 mini Lite



Отличается от предыдущих отсутствием внешней spi-flash, и расположением всех компонентов на одной стороне. Установлен чип esp8285 (см.ниже).




WeMos D1 mini Pro



Как и у предыдущей платы все компоненты расположены на одной стороне, а так же есть spi-flash, керамическая антенна • Rainsun и разъём для внешней антенны.



Ещё есть вот такая D1 mini Pro (LOLIN)



У неё 16М spi-flash и интерфейс для зарядки аккумулятора.



Чипы esp8266 и esp8285

У чипа esp8266 отсутствует flash-память, поэтому применяется внешняя spi-flash (флешь-память работающая по SPI). Часть этой памяти используется для хранения прошивки, в IDE Arduino это обозначается так…



… а оставшуюся часть пользователь может использовать под свои нужды, например, хранить там файлы, которые отдаёт веб-сервер (.html, .css, .js и т.д).


Чип esp8285 отличается от предыдущего только тем, что у него есть встроенная флешь-память (1М). На платах с этим чипом spi-flash (если она есть) полностью отдана пользователю (если конечно я правильно всё понимаю).




Описание будет сделано на примере платы D1 mini (как на самой первой картинке), а среда разработки — IDE Arduino 1.8.5.


Первым делом нужно установить ядро. В IDE Arduino переходим в Файл ⇨ Настройки и добавляем ссылку для менеджера плат…


http://arduino.esp8266.com/stable/package_esp8266com_index.json


Внимание! На картинке ниже указана не актуальная ссылка. И та, что выше, тоже может быть не актуальная, сходите сюда — github.com/esp8266/Arduino и посмотрите Latest release.




Жмём ОК и открываем менеджер плат…



Устанавливаем пакет esp8266 by ESP8266 Community



После установки нужно перезапустить среду.


Если у Вас такая же плата как у меня, тогда выберите LOLIN(WEMOS) D1 R2 & mini



Flash Size — размер памяти на spi-флешки, который мы выделяем под пользовательские данные (в данном случае выделяем 3 мегабайта). Это то, о чём написано под спойлером в разделе «Чипы esp8266 и esp8285».

Debug port — в какой порт выводить отладочную инфу.

Debug Level — какую отладочную инфу выводить. Чтоб поглядеть что там пишется, нужно выбрать что-нибудь, загрузить скетч, открыть «Монитор порта» и нажать кнопочку Reset на плате...


В данном случае выбрано Debug port — Serial и Debug Level — CORE.

lwIP Variant — что-то связанное с размером полезного блока данных TCP-пакета (но могу и ошибаться).

VTables — смотреть здесь.

CPU Frequency — лучше оставить 80МГц, 160 может работать не стабильно.

Upload Speed — можно поставить максимальную, но у меня лучше всего загружалось на 115200.

Erase Flash

Only Sketch — удаляется только прежний скетч.

Sketch + WiFi Setting — удаляется прежний скетч и настройки WiFi. Если ранее был залит скетч какого-нибудь сервера, а потом залить скетч не связанный с WiFi, например Blink, то настройки WiFi от предыдущего скетча останутся.

All Flash Contents — удаляются данные на spi-флешке (см. ниже).


На первое время установите всё как на картинке.



Пришло время загрузить традиционный Blink


void setup() 
{
  pinMode(LED_BUILTIN, OUTPUT);  
}

void loop() 
{
  digitalWrite(LED_BUILTIN, LOW); 
  delay(1000);                      
  digitalWrite(LED_BUILTIN, HIGH);  
  delay(1000);                      
}

Если не прошилось, тогда есть несколько вариантов — нажать Reset или отключить/включить плату или поменять скорость или закрыть «Монитор порта» (если открыт). Что-то из этого должно помочь. У меня время от времени вываливается ошибка.


LED_BUILTIN — это пин D4 он же пин 2.






В программе, Serial — это TXD0 и RXD0 (пины 1 и 3), могут переназначаться на TXD2 и RXD2 (пины 15 и 13).

Для переназначения нужно после функции Serial.begin() вызвать Serial.swap().

Serial1 — это TXD1(пин 2), только отправка.

Оба UART'а аппаратные.



Теперь можно протестировать работу в сети…


Web Server


#include <ESP8266WiFi.h>

const char* ssid = "istarik"; // имя вашей wifi точки доступа
const char* password = "S2fs5ds123GTs"; // пароль wifi
int val = 0;

WiFiServer server(80); // порт сервера 

void setup() 
{
  Serial.begin(115200);
  Serial.print("Connecting to ");
  Serial.println(ssid);

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

  while (WiFi.status() != WL_CONNECTED) // подключение к точке
  {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("WiFi connected");
  server.begin(); // запуск сервера
  Serial.println("Server started");
  Serial.println(WiFi.localIP());
}

void loop() 
{
  WiFiClient client = server.available();
  if (!client) // ждёт подключения клиента, пока клиент не подключится дальше этой функции дело не пойдёт
  {
    return;
  }

  Serial.println("new client");
  while (!client.available()) // после подключения клиента ожидает данные
  {
    delay(1);
  }

  String req = client.readStringUntil('\r'); // читает первую строку заголовка
  Serial.println(req); // печатает первую строку заголовка
  client.flush(); // очищает приёмный буфер

  val++;
  
  /* отправка ответа клиенту */
  client.println("HTTP/1.1 200 OK"); 
  client.println("Content-Type: text/html; charset=utf-8");
  client.println("Refresh: 5");  // refresh the page automatically every 5 sec
  client.println("Connection: close");
  client.println();
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.print("Счётчик ");
  client.print(val);
  client.println("<br />");
  client.println("</html>");
  
  delay(1);
  Serial.println("Client disonnected");
}

Укажите свою точку доступа и пароль.


В «Монитор порта» будет выеден адрес, присвоенный модулю…



Откройте страничку в браузере и увидите счётчик обновляющийся каждые пять секунд.



Web Client

Будем подключаться к google.com...


#include <ESP8266WiFi.h>

const char* ssid = "istarik"; // имя вашей wifi точки доступа
const char* password = "S2fs5ds123GTs"; // пароль wifi
const char* host = "google.com";
const int httpPort = 80;


void setup() 
{
  Serial.begin(115200);
  delay(10);
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) // подключение к точке
  {
    delay(500);
    Serial.print(".");
  }

  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
}

void loop() 
{
  delay(5000);
  Serial.print("Connecting to ");
  Serial.println(host);
  WiFiClient client;
  if(!client.connect(host, httpPort)) // подключаемся к серверу
  {
    Serial.println("connection failed");
    return;
  }

  // запрос к серверу
  client.print(String("GET / ") + "HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n");
  
  unsigned long timeout = millis();
  
  while(client.available() == 0) // ждёт ответ от сервера
  {
    if(millis() - timeout > 5000) // если нет ответа в течении 5 сек, то разрывает соединение
    {
      Serial.println("Client Timeout");
      client.stop();
      return;
    }
  }

  while(client.available()) // читает построчно ответ от сервера
  {
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }

  Serial.println();
  Serial.println("closing connection");
}

Укажите свою точку доступа и пароль.


В «Монитор порта» будет выводиться ответ от google…



Запрос перенаправляется на https.



ESP как точка доступа

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

const char *ssid = "ESPap";
const char *password = "12345678";

ESP8266WebServer server(80);
// Go to http://192.168.4.1 in a web browser

void handleRoot() 
{
  server.send(200, "text/html", "<h1>You are connected</h1>");
}

void setup() 
{
  delay(1000);
  Serial.begin(115200);
  Serial.println();
  Serial.print("Configuring access point...");
  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();
}


Тут в общем-то и пояснять нечего, после загрузки скетча подключитесь к точке ESPap, введите пароль 12345678 и откройте в браузере адрес 192.168.4.1


В Примерах вы найдёте примеры всех возможных сетевых взаимодействий.



SPIFFS

SPIFFS (Serial Peripheral Interface Flash File System) — это файловая система на spi-флешке. Выражаясь простым языком, это «жёсткий диск», на котором можно хранить любые файлы.

Далее будут встречаться слова «SPIFFS» и «флешка», всё это относится к внешней флешь-памяти.

Работать с файлами на флешке можно из своей программы так же как это делается на обычном компьютере, можно читать из файлов, записывать в них, создавать, удалять и переименовывать. Помимо этого можно загружать на флешку любые файлы с компьютера через IDE Arduino.


Загрузите скетч демонстрирующий работу с SPIFFS


/* SPIFFS.ino author stD */

#include "FS.h"

FSInfo fs_info;
Dir dir;
File f;
String str;

void setup(void) 
{
  Serial.begin(115200);
  SPIFFS.begin(); // инициализация флешки
}

void loop(void) 
{
  if(Serial.available()) 
  {
    switch(Serial.read())
    {
      case '1': // форматирование SPIFFS
       Serial.println();
       Serial.println("1. Please wait 30 secs for SPIFFS to be formatted...");
       SPIFFS.format();
       Serial.println("SPIFFS formatted OK");
       Serial.println("----------------");
      break;
      
      case '2': // SPIFFS инфа
       SPIFFS.info(fs_info);
       Serial.println();
       Serial.println("2. SPIFFS INFO...");
       Serial.print("totalBytes=");
       Serial.println(fs_info.totalBytes); // размер SPIFFS
       Serial.println("----------------");

       Serial.print("usedBytes=");
       Serial.println(fs_info.usedBytes); // количество байт, используемых файлами
       Serial.println("----------------");

       Serial.print("blockSize=");
       Serial.println(fs_info.blockSize); // размер блока SPIFFS
       Serial.println("----------------");

       Serial.print("pageSize=");
       Serial.println(fs_info.pageSize); // размер логической страницы SPIFFS
       Serial.println("----------------");

       Serial.print("maxPathLength=");
       Serial.println(fs_info.maxPathLength); // макс. длина файлового имени (включая один байт для завершающего нуля)
       Serial.println("----------------");
      break;

      case '3': // создание файла или открытие существующего для записи
       Serial.println();
       Serial.println("3. Creat/open file...");
       f = SPIFFS.open("/myfile.txt", "w");
       if(!f) 
       {
         Serial.println("NOT сreat/open file :(");  // создать/открыть файл не удалось
       }
       else
       {
         Serial.println("OK сreat/open file :)");  // файл создан/открыт

         f.print("one = "); // запись строк
         f.println(1);

         f.print("two = ");
         f.println('2');

         f.print("three = ");
         f.println("3 = three");

         f.write('B'); // запись байта (символ B)
         f.write('\n'); // запись байта (перенос строки)
         f.write(0xff); // запись байта (255 в HEX-формате)

         Serial.println("Write to file");
         
         f.close(); // закрыли файл
         Serial.println("Close file");
       }
       
       Serial.println("----------------");
      break;

      case '4': // просмотр содержимого SPIFFS
       Serial.println();
       Serial.println("4. View content...");
       dir = SPIFFS.openDir("/");
       while(dir.next()) 
       {
         Serial.println(dir.fileName());
         f = dir.openFile("r"); 
         Serial.print("Size file=");
         Serial.println(f.size()); // размер файла в байтах
       }
       
       Serial.println("----------------");
      break;

      case '5': // чтение файла
       Serial.println();
       Serial.println("5. Read...");

       if(SPIFFS.exists("/blabla.txt")) // проверка есть ли файл
       {
         Serial.println("File exists");
         f = SPIFFS.open("/blabla.txt", "r");
         if(f) // проверка открылся ли файл
         {
           Serial.println("File open");
           if(f.size()) // если файл не пустой, тогда читаем
           {     
             while(f.available())
             {
               str += char(f.read()); // чтение посимвольно
             }
           
             Serial.println("Content...");
             Serial.println();
             Serial.println(str);
           }
           else Serial.println("File empty");
           
           f.close(); // закрыли файл
         }
         else Serial.println("File not open");
       }  
       else Serial.println("NOT file");

       Serial.println("----------------");
      break;
    }


    for (byte i = 0; i < 3; i++)
    {
      Serial.read();
      delay(1);
    }
  }
}


Откройте «монитор порта» и последовательно отправляйте цифры…

1 — отформатирует SPIFFS.
2 — покажет инфу о SPIFFS.
3 — создаст файл myfile.txt и запишет в него несколько строк.
4 — покажет что есть на SPIFFS.
5 — покажет содержимое файла myfile.txt.

Все действия прокомментированы в коде.




Подробнее о SPIFFS почитайте здесь. Заодно ознакомитесь со структурой FSInfo fs_info.



Теперь нужно добавить в IDE возможность загрузки файлов на флешку с компьютера. Для этого нужно скачать пакет ESP8266FS как это описано тут — github.com/esp8266/arduino-esp8266fs-plugin в разделе Installation.

После перезапуска IDE появится пункт ESP8266 Sketch Data Upload





Чтобы загрузить файлы, нужно сделать следующее: откройте папку со скетчем (можно через меню IDE Скетч ⇨ Показать папку скетча) и создайте там папку data



SPIFFS.ino это скетч, который вы только что загрузили.

Папка data обязательна, в неё нужно будет складывать файлы, которые Вы хотите залить на флешку. Внутри data можно создавать подпапки.

Теперь скопируйте или создайте в папке data какой-нибудь файл, например blabla.txt, закройте «монитор порта» (обязательно закройте) и нажмите ESP8266 Sketch Data Upload. При успешном завершении процесса, взору предстанет такая картинка…



Если вылезут ошибки, тогда Reset вам в помощь.


Теперь откройте «монитор порта» и отправьте цифру 4




Вот и наш файлик — blabla.txt. Обратите внимание, что после загрузки затёрся созданный ранее файл.

При обращении к файлам на флешке, указывать папку data не нужно.



Ну и в довершение сделаем сервер, который будет отдавать файлы расположенные на флешке.


Содайте в папке data два файла…

index.html

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
  <title>ESP</title>
  <link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
  <div class="mypanel">
    <div class="mytext">ESP Server</div>
  </div> 
</body>
</html>


style.css

.mypanel {
position: absolute;
top: 0px;
left: 0px;
width: 100%; 
height: 50px; 
background:#3b4045;
border-bottom: 1px solid #e71341;
}

.mytext {
position: absolute;
top: 11px;
left: 100px;
font-size: 24px;
color: #babdb2; 
}


Загрузите их в плату, а следом прошейте этот…

скетч
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <FS.h>

const char* ssid = "istarik"; // имя вашей wifi точки доступа
const char* password = "Ss32f16ys"; // пароль wifi

ESP8266WebServer server(80);

String getContentType(String filename) 
{
  if (filename.endsWith(".htm")) 
  {
    return "text/html";
  } 
  else if (filename.endsWith(".html")) 
  {
    return "text/html";
  } 
  else if (filename.endsWith(".css")) 
  {
    return "text/css";
  } 
  else if (filename.endsWith(".js")) 
  {
    return "application/javascript";
  } 
  else if (filename.endsWith(".png")) 
  {
    return "image/png";
  } 
  else if (filename.endsWith(".gif")) 
  {
    return "image/gif";
  } 
  else if (filename.endsWith(".jpg")) 
  {
    return "image/jpeg";
  } 
  else if (filename.endsWith(".ico")) 
  {
    return "image/x-icon";
  } 
  else if (filename.endsWith(".xml")) 
  {
    return "text/xml";
  } 
  else if (filename.endsWith(".pdf")) 
  {
    return "application/x-pdf";
  } 
  else if (filename.endsWith(".zip")) 
  {
    return "application/x-zip";
  } 
  else if (filename.endsWith(".gz")) 
  {
    return "application/x-gzip";
  }
  
  return "text/plain";
}

bool handleFileRead(String path) 
{
  Serial.println("handleFileRead: " + path);
  
  if(path.endsWith("/")) 
  {
    path += "index.html";
  }
  
  String contentType = getContentType(path);
  String pathWithGz = path + ".gz";
  
  if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) 
  {
    if(SPIFFS.exists(pathWithGz)) 
    {
      path += ".gz";
    }
    
    File file = SPIFFS.open(path, "r");
    server.streamFile(file, contentType);
    file.close();
    return true;
  }
  
  return false;
}

void setup(void) 
{
  Serial.begin(115200);
  SPIFFS.begin();
  Serial.printf("Connecting to %s\n", ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.print("Connected! IP address: ");
  Serial.println(WiFi.localIP());

  server.onNotFound([]() 
  {
    if(!handleFileRead(server.uri())) 
    {
      server.send(404, "text/plain", "FileNotFound");
    }
  });

  server.begin();
  Serial.println("HTTP server started");
}


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



Открывайте в браузере и смотрите что получилось.

Можно добавить любые файлы, .js, .png и т.д.


На этом всё.


Всем спасибо


  • 0
  • 31576
Поддержать автора


Telegram-чат istarik

Задать вопрос по статье
Telegram-канал istarik

Известит Вас о новых публикациях






Комментарии (1)

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.