Serwisy partnerskie:
Close icon
Serwisy partnerskie

Automatyka domowa z wykorzystaniem płytki NodeMCU (ESP8266)

Article Image
Elmax
Automatyka domowa odnosi się do zdolności Twojego domu do podejmowania własnych decyzji w zależności od warunków otoczenia i daje Ci możliwość sterowania nim z odległej lokalizacji. W jednym z naszych poprzednich projektów na temat modułu Wi-Fi ESP8266, sprawdziliśmy jak NodeMCU lub jakakolwiek inna płytka oparta na ESP8266 może być użyta do zbudowania serwera internetowego, poprzez który wszystkie GPIO płytki mogą być kontrolowane przez Wi-Fi. W tym projekcie zamierzamy wykorzystać ten web serwer i sterować za jego pomocą urządzeniami domowymi.
Uwaga! Ważne jest, aby pamiętać, że podłączenie urządzeń do przekaźnika wymaga interakcji z napięciami sieci 230 V, które mogą być niebezpieczne. Upewnij się, że masz doświadczenie w interakcji z instalacją 230 V i rób to w bezpieczny sposób.
Light icon

Sercem dzisiejszego projektu jest płytka z Wi-Fi, której nie trzeba przedstawiać; oparta na ESP8266 płytka deweloperska NodeMCU. Jest to platforma open source do tworzenia systemów wbudowanych opartych na Wi-Fi i jest oparta na popularnym module Wi-Fi ESP8266, z firmware NodeMCU opartym na Lua. NodeMCU narodził się z chęci przezwyciężenia ograniczeń związanych z pierwszymi wersjami modułu ESP8266, który nie był kompatybilny z breadboardami, był trudny do zasilania i jeszcze trudniejszy do  programowania. Płytka NodeMCU jest łatwa w użyciu, tania, co szybko przyciągnęło ją do serc konstruktorów i dziś jest jedną z najpopularniejszych płytek.

W tym projekcie dodamy 2-kanałowy moduł przekaźnika do płytki ESP8266. Istota projektu polega na sterowaniu GPIO NodeMCU z poziomu strony internetowej na dowolnym urządzeniu podłączonym do tej samej sieci co płytka. Stan GPIO steruje cewkami przekaźników, co powoduje, że przekaźnik przełącza się pomiędzy stanem normalnie otwartym (NO) i normalnie zamkniętym (NC) w zależności od stanu GPIO, tym samym efektywnie włączając lub wyłączając podłączone urządzenie.

Jeśli nie masz dostępu do modułu przekaźnikowego, możesz użyć 2× jednokanałowych modułów przekaźnikowych lub pojedynczych przekaźników z obsługującymi je układami tranzystorowymi.

Schemat

Schemat dla tego projektu jest dość prosty. Podłącz elementy tak jak pokazano na poniższym schemacie.

Schemat połączeń płytki przekaźników z modułem Wi-Fi

Aby ułatwić śledzenie połączeń, poniżej znajduje się mapa pinów połączeń pomiędzy NodeMCU a modułem przekaźnika.

NodeMCU - moduł przekaźnika
VCC
3,3V
GND
GND
D1
D1
D2
D2
D3
D3
D4
D4

Jeśli używasz zwykłych przekaźników bez układu podtrzymującego moduł, podłącz przekaźniki do NodeMCU jak pokazano poniżej. Upewnij się, że cewki przekaźnika mają napięcie znamionowe 5 V lub zmień zasilanie 5 V, aby dopasować je do znamionowego napięcia cewki Twojego przekaźnika.

Schemat elektryczny zbudowanego układu

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

Kod

Jednym z najłatwiejszych sposobów programowania NodeMCU jest użycie 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 tego projektu. Postępuj zgodnie ze szczegółowym przewodnikiem "Getting Started with the NodeMCU", aby dowiedzieć się, jak skonfigurować Arduino IDE do programowania płytek opartych na ESP8266.

Kod dla tego projektu jest zmodyfikowaną wersją kodu z artykułu "NodeMCU ESP8266 WebServer". Kod bazuje na bibliotece ESP8266Wi-Fi.h, która pozwala na łatwe wykorzystanie funkcjonalności Wi-Fi płytki. Zawiera ona wszystko co jest nam potrzebne do stworzenia lub dołączenia do punktu dostępowego Wi-Fi, a także stworzenia serwera i klienta, które są istotne dla tego projektu. Biblioteka jest dołączona do plików płytki NodeMCU dla Arduino, więc nie ma potrzeby instalowania jej po zainstalowaniu plików płytki.

Kod do tego projektu pozwoli nam na zdalne sterowanie urządzeniami podłączonymi do GPIO (poprzez przekaźniki) płytki NodeMCU.

Na początek dołączamy bibliotekę, którą wykorzystamy w projekcie, czyli w tym przypadku jest to biblioteka ESP8266Wi-Fi.h.

#include <ESP8266WiFi.h>

Następnie dodajemy dane uwierzytelniające punktu dostępowego Wi-Fi, do którego będzie podłączone NodeMCU. 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ł i tworzymy zmienną do przechowywania żądań.

// Add wifi access point credentiaals
const char* ssid     = "xxxxx";
const char* password = "xxxx";

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

Następnie deklarujemy piny Nodemcu, do których podłączone są piny przekaźników i tworzymy zmienne przechowujące stan każdego przekaźnika.

// Declare the pins to which the appliances are connected via relays
int app1 = D1; //appliance 1
int app2 = D2; //appliance 2`
//you can add more more appliances below.

String app1state = "off";// state of appliance1
String app2state = "off";// state of appliance2

Następna jest funkcja 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ą przekaźniki jako wyjściowe. Następnie ustawiamy piny "LOW", aby zapewnić, że system startuje w stanie OFF.

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(app1, OUTPUT);
  pinMode(app2, OUTPUT);
  digitalWrite(app1, LOW);
  digitalWrite(app2, LOW);

Następnie łączymy się z punktem dostępowym używając poświadczeń podanych jako argumenty do funkcji Wi-Fi.begin() i używamy funkcji Wi-Fi.status() do sprawdzenia czy połączenie się powiodło. System będzie próbował tak długo, aż połączenie się powiedzie.

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

Jeżeli połączenie jest udane, na monitorze szeregowym jest drukowany tekst, aby to wskazać, wraz z adresem IP NodeMCU. Ten adres IP staje się adresem internetowym serwera i powinien być wpisany w dowolnej przeglądarce internetowej w tej samej sieci co serwer, abyśmy mogli uzyskać do niego dostęp.

// 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 browse
}

Następnie uruchamiamy serwer za pomocą funkcji server.begin().

server.begin();
}

Następnie piszemy funkcję void loop(). To właśnie tutaj 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). Gdy klient jest dostępny i połączony, odczytujemy jego żądanie i wysyłamy nagłówek jako odpowiedź.

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();

Następnie żądanie klienta jest sprawdzane, czy wskazuje ono na naciśnięcie przycisku na stronie internetowej. Jeżeli tak, to stan GPIO jest zmieniany odpowiednio do żądania. Jeśli żądanie wskazuje na "ON", pin jest ustawiany na HIGH, a zmienna stanu jest odpowiednio aktualizowana.

// turns the GPIOs on and off
           if (header.indexOf("GET /app1/on") >= 0) {
             Serial.println("App 1 on");
             app1state = "on";
             digitalWrite(app1, HIGH);
           } else if (header.indexOf("GET /app1/off") >= 0) {
             Serial.println("App 1 off");
             app1state = "off";
             digitalWrite(app1, LOW);
           } else if (header.indexOf("GET /app2/on") >= 0) {
             Serial.println("App 2 on");
             app2state = "on";
             digitalWrite(app2, HIGH);
           } else if (header.indexOf("GET /app2/off") >= 0) {
             Serial.println("App 2 off");
             app2state = "off";
             digitalWrite(app2, 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.

Zaczynamy od wskazania, że kilka następnych tekstów, które mają zostać wydrukowane, to linie HTML, zgodnie z deklaracją doctype.

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\">");
client.println("<link rel=\"icon\" href=\"data:,\">");

Następnie, niektóre kawałki CSS są wysyłane do klienta, aby nadać stronie internetowej przyjazny wygląd. 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 wysyłany jest nagłówek strony, po którym następują przyciski, a przyciski są ustawione tak, aby wyświetlały aktualny stan urządzeń. Będą one pokazywały OFF, jeśli aktualny stan to ON i odwrotnie.

client.println("<body><h1>ESP8266 Web Server</h1>");
            
            // Display current state, and ON/OFF buttons for GPIO 5  
            client.println("<p>app1 - State " + app1state + "</p>");
            // If Appliance 1 is off, it displays the ON button       
            if (app1state == "off") {
              client.println("<p><a href=\"/app1/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/app1/off\"><button class=\"button button2\">OFF</button></a></p>");
            } 
               
            // Display current state, and ON/OFF buttons for GPIO 4  
            client.println("<p>app2 - State " + app2state + "</p>");
            // If Appliance 2 is off, it displays the ON button       
            if (app2state == "off") {
              client.println("<p><a href=\"/app2/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/app2/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
        }
      }
    }

Następnie zamykamy połączenie i przepływ wraca na górę.

 client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Kompletny kod projektu dostępny jest poniżej, a także załączony w dziale download.

#include <ESP8266WiFi.h>

// Add wifi access point credentiaals
const char* ssid     = "xxxx";
const char* password = "xxxxx";

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


String header; // This storees the HTTP request

// Declare the pins to which the appliances are connected via relays
int app1 = D1; //appliance 1
int app2 = D2; //appliance 2`
//you can add more more appliances below.

String app1state = "off";// state of appliance1
String app2state = "off";// state of appliance2


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(app1, OUTPUT);
  pinMode(app2, OUTPUT);
  digitalWrite(app1, LOW);
  digitalWrite(app2, 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 /app1/on") >= 0) {
              Serial.println("App 1 on");
              app1state = "on";
              digitalWrite(app1, HIGH);
            } else if (header.indexOf("GET /app1/off") >= 0) {
              Serial.println("App 1 off");
              app1state = "off";
              digitalWrite(app1, LOW);
            } else if (header.indexOf("GET /app2/on") >= 0) {
              Serial.println("App 2 on");
              app2state = "on";
              digitalWrite(app2, HIGH);
            } else if (header.indexOf("GET /app2/off") >= 0) {
              Serial.println("App 2 off");
              app2state = "off";
              digitalWrite(app2, 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>app1 - State " + app1state + "</p>");
            // If Appliance 1 is off, it displays the ON button       
            if (app1state == "off") {
              client.println("<p><a href=\"/app1/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/app1/off\"><button class=\"button button2\">OFF</button></a></p>");
            } 
               
            // Display current state, and ON/OFF buttons for GPIO 4  
            client.println("<p>app2 - State " + app2state + "</p>");
            // If Appliance 2 is off, it displays the ON button       
            if (app2state == "off") {
              client.println("<p><a href=\"/app2/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/app2/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 NodeMCU. Upewnij się, że wszystko jest podłączone zgodnie z opisem w sekcji schematy. Po załadowaniu kodu powinieneś zobaczyć adres IP swojego serwera WWW wyświetlony na monitorze szeregowym, jak pokazano poniżej.

Wyjście terminala szeregowego

Skopiuj adres IP i wklej go w przeglądarce internetowej na dowolnym urządzeniu (Mobile lub PC) podłączonym do tej samej sieci co NodeMCU. Powinieneś zobaczyć stronę internetową i mieć możliwość przełączania podłączonych urządzeń poprzez klikanie przycisków.

Interfejs serwera WWW

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

Do pobrania
Download icon Kod webserwera

Artykuł Home automation using NODEMCU /ESP8266/ board opracowano w wersji polskiej na podstawie współpracy z portalem www.electronics-lab.com.

Firma:
AUTOR
Źródło
www.electronics-lab.com
Udostępnij
Zobacz wszystkie quizy
Quiz weekendowy
Edukacja
1/10 Jak działa rezystor LDR?
UK Logo
Elektronika dla Wszystkich
Zapisując się na nasz newsletter możesz otrzymać GRATIS
najnowsze e-wydanie magazynu "Elektronika dla Wszystkich"