Serwisy partnerskie:
Close icon
Serwisy partnerskie

NodeMCU ESP8266 WebServer

Od Wemos D1 mini do NodeMCU, płytki oparte na ESP8266 są zdecydowanie najpopularniejszą platformą do budowania projektów opartych na Wi-Fi, ze względu na ich niski koszt i ogólną łatwość użycia. W tym projekcie będziemy kontynuować naszą eksplorację najpopularniejszej z płytek opartych na ESP8266, płytki rozwojowej NodeMCU i zbadamy, jak zbudować serwer WWW przy jej użyciu. Poprzez serwer WWW będziemy mogli kontrolować wszystko, co jest podłączone do pinów GPIO płytki. Nie będziemy się ograniczać tylko do sterowania diodami LED, ale rozszerzając ten projekt możesz zbudować pełnowartościowy system automatyki domowej lub jakikolwiek inny projekt, który wymaga zdalnego sterowania lub uzyskiwania danych z GPIO płytki NodeMCU.
Article Image

Płytka rozwojowa NodeMCU jest platformą open source do tworzenia urządzeń wbudowanych opartych na Wi-Fi. Jest ona oparta na module Wi-Fi ESP8266 i uruchamia firmware NodeMCU oparty na Lua. NodeMCU narodził się z chęci przezwyciężenia wszystkich wąskich gardeł związanych z pierwszymi wersjami modułu ESP8266, który nie był kompatybilny z breadboardami, trudny do zasilania i jeszcze trudniejszy do zaprogramowania. Jego łatwość użycia i niska cena, szybko przyciągnęły go do serca twórców i dziś jest to jedna z najpopularniejszych płytek.

Pod koniec tego projektu-kursu dowiesz się, jak używać NodeMCU jako serwera WWW oraz jak kontrolować piny GPIO płytki NodeMCU/ESP8266 z poziomu strony internetowej.

Wykaz elementów
Ilość
Symbol
Nazwa/opis/gdzie kupić

Schemat

Schemat tego projektu jest dość prosty. Jak wspomniano wcześniej, będziemy przełączać diody LED, aby zademonstrować, co można osiągnąć za pomocą serwera WWW NodeMCU. Podczas gdy diody LED są tutaj używane, możesz zdecydować się na użycie bardziej użytecznych komponentów, takich jak przekaźnik, który może być użyty do sterowania urządzeniami w Twoim domu.

Podłącz komponenty tak jak pokazano na poniższym schemacie.

Schemat połączeń elementów z płytką rozwojową NodeMcu

Dodatnie nóżki zielonej i czerwonej diody LED są podłączone do pinów cyfrowych 1 i 2 NodeMCU (odpowiednio), podczas gdy ich ujemne nóżki są podłączone do masy przez rezystor 220 omów, aby ograniczyć wartość prądu płynącego przez diody LED.

Mając gotowy schemat, możemy teraz przejść do kodu projektu.

Kod

Jednym z najprostszych sposobów zaprogramowania NodeMCU jest Arduino IDE. Wymaga to jednak skonfigurowania Arduino IDE poprzez zainstalowanie pliku obsługi płytki dla NodeMCU. Jeśli używasz Arduino IDE do zaprogramowania NodeMCU po raz pierwszy, musisz to zrobić zanim przejdziesz do dalszej części instrukcji. Skorzystaj z tego szczegółowego przewodnika, aby dowiedzieć się, jak skonfigurować Arduino do programowania płytek opartych na ESP8266.

Mając to już za sobą, możemy teraz przejść do kodu. Główną siłą napędową tego projektu jest biblioteka ESP8266WiFi. Biblioteka ta zawiera przydatne  funkcje do implementacji działań i projektów opartych o Wi-Fi na NodeMCU. Zawiera ona wszystko czego potrzebujemy do stworzenia punktu dostępowego Wi-Fi lub połączenia się z istniejącym punktem dostępowym, a także stworzenia serwera i klienta, które są ważne dla tego projektu. Biblioteki są dołączone do plików płytki NodeMCU dla Arduino, więc nie ma potrzeby instalowania ich po zainstalowaniu plików płytki.

Jak wspomniałem wyżej, naszym celem jest stworzenie serwera WWW, poprzez który będzie można sterować GPIO jednostki NodeMCU. Serwer WWW powinien być dostępny przez przeglądarkę na dowolnym urządzeniu w tej samej sieci co NodeMCU.

Kod tego projektu jest zmodyfikowaną wersją kodu Rui Santosa (podziękowania dla niego). Jest on trochę skomplikowany i może być trudny do zrozumienia dla osób bez znajomości HTML, ale postaram się go jak najlepiej rozłożyć na czynniki pierwsze.

Na początek, jak zwykle, dołączamy bibliotekę, która będzie używana w kodzie, w tym przypadku jest to biblioteka ESP8266WiFi.

#include <ESP8266WiFi.h>

Następnie dodajemy dane uwierzytelniające punktu dostępowego Wi-Fi, do którego NodeMCU będzie podłączony. Upewnij się, że nazwa użytkownika i hasło znajdują się pomiędzy cudzysłowami. Określamy również port, przez który system będzie się komunikował oraz tworzymy zmienną do przechowywania żądań.

const char* ssid     = "WIFI_SSID";
const char* password = "WIFI_PASSWORD";

WiFiServer server(80);// Set port to 80


String header; // This storees the HTTP request

Następnie deklarujemy piny Nodemcu, do których będą podłączone czerwona i zielona dioda LED oraz tworzymy zmienne, które będą przechowywały stan diod LED.

int greenled = D1;
int redled = D2; 

String greenstate = "off";// state of green LED
String redstate = "off";// state of red LED

Mając to już za sobą, przechodzimy do funkcji void setup().

Zaczynamy od zainicjalizowania monitora szeregowego (ponieważ będzie on później używany do debugowania) i ustawienia pinModes pinów, do których podłączone są diody LED jako wyjściowe. Następnie ustawiamy piny "LOW", aby zapewnić, że układ startuje w stanie neutralnym.

void setup() {
  Serial.begin(115200);
 // Set the pinmode of the pins to which the LEDs are connected and turn them low to prevent flunctuations
  pinMode(greenled, OUTPUT);
  pinMode(redled, OUTPUT);
  digitalWrite(greenled, LOW);
  digitalWrite(redled, LOW);

Następnie łączymy się z punktem dostępowym używając danych uwierzytelniających jako argumentów do funkcji WiFi.begin() i używamy funkcji WiFi.status() do sprawdzenia czy połączenie się powiodło.

WiFi.begin(ssid, password);
Serial.print("Connecting to ");
Serial.println(ssid);
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}

Jeżeli połączenie się powiedzie, na monitorze szeregowym zostanie wyświetlony tekst informujący o tym fakcie, a także adres IP serwera sieciowego. Ten adres IP staje się adresem internetowym serwera i to właśnie on będzie wpisywany w każdej przeglądarce internetowej w tej samej sieci, aby uzyskać dostęp do serwera.

Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());// this will display the Ip address of the Pi which should be entered into your browser

Po wykonaniu tych czynności uruchamiamy serwer za pomocą funkcji server.begin() i przechodzimy do funkcji void loop( ).

server.begin();

Funkcja void loop() jest miejscem, w którym wykonywana jest większość pracy. Zaczynamy od użycia funkcji server.available() do nasłuchiwania połączeń przychodzących od klientów (przeglądarek internetowych). Kiedy klient jest dostępny i połączony, odczytujemy żądanie klienta i wysyłamy nagłówek jako odpowiedź.

WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

Następnie sprawdzamy, czy żądanie klienta wskazuje na naciśnięcie przycisku na stronie internetowej, aby włączyć/wyłączyć któryś z pinów, zaczynając od zielonej diody. Jeśli żądanie wskazuje na "on", pin jest ustawiany w stan wysoki, a zmienna stanu jest odpowiednio aktualizowana i vice versa.

// turns the GPIOs on and off
           if (header.indexOf("GET /green/on") >= 0) {
             Serial.println("green on");
             greenstate = "on";
             digitalWrite(greenled, HIGH);
           } else if (header.indexOf("GET /green/off") >= 0) {
             Serial.println("green off");
             greenstate = "off";
             digitalWrite(greenled, LOW);
           } else if (header.indexOf("GET /red/on") >= 0) {
             Serial.println("red on");
             redstate = "on";
             digitalWrite(redled, HIGH);
           } else if (header.indexOf("GET /red/off") >= 0) {
             Serial.println("red off");
             redstate = "off";
             digitalWrite(redled, LOW);
           }

Następnie tworzymy stronę internetową, która będzie wyświetlana i aktualizowana przez NodeMCU w miarę interakcji z użytkownikiem. Kluczową funkcją do tego jest funkcja Client.println(), która służy do wysyłania skryptów HTML linia po linii do klienta (przeglądarki).

Zaczynamy od użycia "doctype", aby wskazać, że następne kilka tekstów, które mają zostać wydrukowane, to linie HTML.

client.println("<!DOCTYPE html><html>");

Następnie dodajemy poniższe linie, aby strona była responsywna niezależnie od używanej przeglądarki

client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");

Wrzucamy również kilka fragmentów CSS do klienta, aby strona była przyjazna dla użytkownika. Możesz to edytować, aby dodać swój własny kolor, styl czcionki itp.

client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color: #77878A;}</style></head>");

Następnie nagłówek strony jest wysyłany wraz z przyciskami, które są ustawione na wyświetlanie włączone lub wyłączone w zależności od aktualnego stanu diody LED. Będą one wyświetlane wyłączone, jeśli aktualny stan to ON i na odwrót.

client.println("<body><h1>ESP8266 Web Server</h1>");

// Display current state, and ON/OFF buttons for GPIO 5  
client.println("<p>green - State " + greenstate + "</p>");
// If the green LED is off, it displays the ON button       
if (greenstate == "off") {
  client.println("<p><a href=\"/green/on\"><button class=\"button\">ON</button></a></p>");
} else {
  client.println("<p><a href=\"/green/off\"><button class=\"button button2\">OFF</button></a></p>");
} 
   
// Display current state, and ON/OFF buttons for GPIO 4  
client.println("<p>red - State " + redstate + "</p>");
// If the red LED is off, it displays the ON button       
if (redstate == "off") {
  client.println("<p><a href=\"/red/on\"><button class=\"button\">ON</button></a></p>");
} else {
  client.println("<p><a href=\"/red/off\"><button class=\"button button2\">OFF</button></a></p>");
}
client.println("</body></html>");

Następnie zamykamy połączenie i pętla przechodzi od nowa.

// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");

Kompletny kod projektu znajduje się poniżej, a także jest dostępny do pobrania w sekcji download na końcu tutoriala.

#include <ESP8266WiFi.h>

// Add wifi access point credentiaals
const char* ssid     = "WIFI_SSID";
const char* password = "WIFI_PASSWORD";

WiFiServer server(80);// Set port to 80


String header; // This storees the HTTP request

// Declare the pins to which the LEDs are connected 
int greenled = D1;
int redled = D2; 

String greenstate = "off";// state of green LED
String redstate = "off";// state of red LED


void setup() {
  Serial.begin(115200);
 // Set the pinmode of the pins to which the LEDs are connected and turn them low to prevent flunctuations
  pinMode(greenled, OUTPUT);
  pinMode(redled, OUTPUT);
  digitalWrite(greenled, LOW);
  digitalWrite(redled, LOW);
  //connect to access point
  WiFi.begin(ssid, password);
  Serial.print("Connecting to ");
  Serial.println(ssid);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());// this will display the Ip address of the Pi which should be entered into your browser
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
            
            // turns the GPIOs on and off
            if (header.indexOf("GET /green/on") >= 0) {
              Serial.println("green on");
              greenstate = "on";
              digitalWrite(greenled, HIGH);
            } else if (header.indexOf("GET /green/off") >= 0) {
              Serial.println("green off");
              greenstate = "off";
              digitalWrite(greenled, LOW);
            } else if (header.indexOf("GET /red/on") >= 0) {
              Serial.println("red on");
              redstate = "on";
              digitalWrite(redled, HIGH);
            } else if (header.indexOf("GET /red/off") >= 0) {
              Serial.println("red off");
              redstate = "off";
              digitalWrite(redled, LOW);
            }
       
            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the on/off buttons 
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #77878A;}</style></head>");
            
            // Web Page Heading
            client.println("<body><h1>ESP8266 Web Server</h1>");
            
            // Display current state, and ON/OFF buttons for GPIO 5  
            client.println("<p>green - State " + greenstate + "</p>");
            // If the green LED is off, it displays the ON button       
            if (greenstate == "off") {
              client.println("<p><a href=\"/green/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/green/off\"><button class=\"button button2\">OFF</button></a></p>");
            } 
               
            // Display current state, and ON/OFF buttons for GPIO 4  
            client.println("<p>red - State " + redstate + "</p>");
            // If the red LED is off, it displays the ON button       
            if (redstate == "off") {
              client.println("<p><a href=\"/red/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/red/off\"><button class=\"button button2\">OFF</button></a></p>");
            }
            client.println("</body></html>");
            
            // The HTTP response ends with another blank line
            client.println();
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Demo

Wgraj kod do swojego NodeMCU. Upewnij się, że wszystko jest podłączone zgodnie z opisem w sekcji schematy. Po załadowaniu kodu, otwórz monitor szeregowy, powinieneś zobaczyć adres IP swojego serwera WWW, jak pokazano poniżej.

Adres IP

Skopiuj adres IP i wklej go w przeglądarce internetowej na urządzeniu podłączonym do tej samej sieci co NodeMCU. Powinieneś zobaczyć stronę internetową i mieć możliwość przełączania diod LED poprzez klikanie na przyciski.

Demonstracja: Klikaj przyciski aby zmieniać stany diod LED

Jak wspomniano powyżej, ten tutorial może służyć jako budulec dla złożonych serwerów internetowych i rozwiązań IoT. Co zbudujesz?

Do pobrania
Download icon Kompletny kod webserwera

Artykuł NODEMCU ESP8266 WEBSERVER TUTORIAL opracowano w wersji polskiej na podstawie współpracy z portalem www.electronics-lab.com.

Tematyka materiału: NodeMCU, ESP8266-12E
AUTOR
Źródło
www.electronics-lab.com
Udostępnij
UK Logo