راه اندازی ماژول رله یک کاناله با قابلیت کنترل WiFi :
ماژول های رله معمولا شامل چند رله ( بسته به تعداد کانال ) و مدار بافر برای راه اندازی و کنترل رله ها از طریق منطق های 5 ولت و 3.3 ولت هستند . این ماژول ها قیمت ارزانی دارند و می توان از آن ها در پروژه های عملی و صنعتی استفاده کرد . ماژول های رله متنوعی در بازار وجود دارند که هر کدام مناسب کاربرد خاصی هستند . یکی از مدل های این ماژول های ، ماژول های موسوم به رله WiFi هستند. در این مدل ها از یک ماژول ESP8266 01 استفاده شده است که امکان راه اندازی ماژول از طریق WiFi را فراهم می سازد . به طور معمول این ماژول ها فاقد برنامه می باشند و باید کاربر ESP8266 موجود بر روی ماژول را برنامه ریزی کند . در تصاویر زیر مدل های مختلف این ماژول ها نشان داده شده است :
در این آموزش ما از مدل تک کاناله استفاد می کنیم . راه اندازی مدل تک کاناله متفاوت از دیگر مدل ها است . در سری های بعدی آموزش راه اندازی مدل های دیگر نیز قرار داده خواهد شد .
نکته : ماژول رله تک کانال بر خلاف مدل های دیگر دارای تغذیه 5 ولت است . اتصال تغذیه های بیشتر از 5 ولت به ماژول آسیب می رساند .
در مدل تک کاناله GPIO0 ماژول ESP8266 به بافر راه انداز رله متصل است . پس با کنترل GPIO0 می توان رله برد را روشن و خاموش کرد . در مدل های دیگر ESP8266 از طریق ارتباط UART فرمان های خاموش و روشن شدن رله ها به یک میکروکنترل ارسال می شود و میکرکنترل وظیفه خاموش و روشن کردن رله ها را بر عهده دارد .
کد های پروژه :
در اینجا ما از وب سرور محلی برای راه اندازی استفاده خواهیم کرد . همچنین در این پروژه ماژول از طریق یک شبکه Local کنترل می گردد . در واقع ماژول ESP8266 و ابزار کاربر (گوشی یا لبتاب ) به یک مودم متصل هستند. برای راه اندازی از طریق اینترنت و از راه دور ساختار برنامه تقریبا به همان شکل است . در آموزش های بعدی نحوه کنترل ماژول های ESP8266 از طریق اینترنت قرار داده خواهد شد . کنترل ماژول های ESP8266 از طریق اینترنت کار ساده است ، حتی بدون استفاده از IP استاتیک می توانید این ماژول ها را از هر نقطه که به اینترنت دسترسی دارید کنترل کنید .
#include <ESP8266WiFi.h> // Replace with your network credentials const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // Set web server port number to 80 WiFiServer server(80); // Variable to store the HTTP request String header; // Auxiliar variables to store the current output state String output5State = "off"; // Assign output variables to GPIO pins const int output5 = 0; // Current time unsigned long currentTime = millis(); // Previous time unsigned long previousTime = 0; // Define timeout time in milliseconds (example: 2000ms = 2s) const long timeoutTime = 2000; void setup() { Serial.begin(115200); // Initialize the output variables as outputs pinMode(output5, OUTPUT); // Set outputs to LOW digitalWrite(output5, LOW); // Connect to Wi-Fi network with SSID and password Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); 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()); server.begin(); } void loop(){ WiFiClient client = server.available(); // Listen for incoming clients if (client) { // If a new client connects, Serial.println("New Client."); // print a message out in the serial port String currentLine = ""; // make a String to hold incoming data from the client currentTime = millis(); previousTime = currentTime; while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected currentTime = millis(); 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 /5/on") >= 0) { Serial.println("GPIO 5 on"); output5State = "on"; digitalWrite(output5, HIGH); } else if (header.indexOf("GET /5/off") >= 0) { Serial.println("GPIO 5 off"); output5State = "off"; digitalWrite(output5, 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>GPIO 5 - State " + output5State + "</p>"); // If the output5State is off, it displays the ON button if (output5State=="off") { client.println("<p><a href=\"/0/on\"><button class=\"button\">ON</button></a></p>"); } else { client.println("<p><a href=\"/0/off\"><button class=\"button button2\">OFF</button></a></p>"); } // Display current state, and ON/OFF buttons for GPIO 4 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(""); } }
نکته : در آموزش های مربوط به ماژول های ESP8266 و ESP32 در اینترنت معمولا کد های پروژه قرار داده شده اند و راجب جزئیات دستور ها اطلاعاتی وجود ندارد یا توضیحات مختصری دارند . در این جا سعی ما بر این است با تشریح کد ها ، توابع و متد ها شما هر چه بیشتر با ساختار برنامه های این ماژول ها آشنایی پیدا کنید . این کار توانایی بسیار بیشتری از کپی کردن و دستکاری کردن کد ها به شما می دهد .
شرح کد های پروژه :
بهتر است برای درک بهتر ساختار این پروژه ،راجب به پرتکل HTTP و ساختار وب استایل ها مطالعه کنید .
ابتدا هدر فایل زیر به پروژه اضافه شده است . از این کتابخانه جهت پیکر بندی های مربوط به ارتباط WiFi استفاده می شود . ESP8266WiFi یک کتابخانه رایگان و منبع باز جهت راه اندازی و پیکر بندی ارتباط WiFi در ماژول های ESP8266 است . این کتابخانه تقریبا هر آنچه را برای پیکربندی WiFi و همچنین ارتباط های بر پایه TCP/IP لازم است را دارد . می توانید از لینک زیر آن را دانلود کیند . همچنین کلیه توضیحات و شرح توابع ، متد ها ، کلاس های این کتابخانه در لینک زیر قرار داده شده است :
https://github.com/ekstrand/ESP8266wifi
#include <ESP8266WiFi.h>
در خط های بعدی دو آرایه کاراکتری استاتیک تعریف شده اند . از این دو آرایه برای تعریف اکسس پوینت و رمز وایفای استفاده می شود . می توان مستقما نام وایفای و رمز آن را در توابع وارد کنید اما با تعریف آرایه در ابتدای برنامه ، علاوه بر خوانایی برنامه ، ایجاد تغییرات در اسم و رمز وافای راحت تر است . در این قسمت نام و رمز وایفای خود را وارد کنید تا پس از روشن شدن ماژول ، ESP8266 به آن متصل شود :
const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD";
در خط بعدی با استفاده از کلاس WiFiServer یک شی سرور ساخته می شود با این کار می توان یک وب سرور ساخت . در این جا یک وب سرور بر روی پورت 80 ساخته شده است ( پورت 80 مربوط به HTTP می باشد ) :
WiFiServer server(80);
سپس در تابع setup پیکر بندی های اولیه انجام می شود . این فرایند شامل تعریف GPIO0 به عنوان خروجی ، پیکربندی ارتباط وایفای و انتظار برای اتصال به وایفای است همچین در پایان با دستور Server.begin ماژول در مد سرور قرار میگیرد :
void setup() { Serial.begin(115200); // Initialize the output variables as outputs pinMode(output5, OUTPUT); // Set outputs to LOW digitalWrite(output5, LOW); // Connect to Wi-Fi network with SSID and password Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); 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()); server.begin(); }
سپس در تابع loop با استفاده از دستورات زیر ، شی از کلاس WiFiClient ساخته می شود که می توان پاسخ های کاربر متصل به سرور را در داخل آن قرار داد (رشته های ارسالی ، اتصال و یا عدم اتصال کاریر ) . در خط زیر مقدار (server.availabe) در client قرار داده می شود در واقع با اتصال کاربر یا client به سرور ، مقدار برگشتی این تابع یک خواهد شد . از این موضوع برای تشخیص اتصال کاربر استفاده می شود :
WiFiClient client = server.available();
سپس با استفاده از شی client ساخته شده در بالا ، کاراکتر های مختلف را به کاربر فرستاد می شوند. در این پروژه از پورت 80 استفاده شده است . پورت 80 پورت پیشفرض پرتکل http می باشد . با استفاده از هر نرم افزار وایفای ترمینالی می توانید به ماژول متصل شوید و با قرار دادن پورت بر روی 80 دیتای ارسالی از ماژول را دریافت کنید . اما چون پورت 80 پیش فرض http است ، پس با اتصال به IP ماژول ، مرورگر شما با دریافت هر دیتایی ، آن را یک ارتباط http تلقی می کند . پس به راحتی می توانید یک درخواست http ارسال کنید و پس از آن کاراکتر های html را به سمت client بفرستید که در این حالت مرورگر شما کد ها را اجرا و نمایش خواهد داد (بر خلاف اتصال در وایفای ترمینال که تنها کاراکتر ها را نشان خواهد دارد و کد های html را اجرا نمی کند ) . در دستور زیر ابتدا شرط اتصال client بررسی می شود . پس از اتصال کلاینت متن هایی جهت نمایش وضعیت ارتباط در serial monitor چاپ می شود و پس از آن کاراکتر های دریافتی از سمت client در یک رشته قرار می گیرد . در انتهای پیغام های کلاینت به سرور یک کارات “\n” وجود دارد که می توان از آن برای تشخیص پایان پیغام client استفاده کرد و پس از آن کاراکتر ها و دستورات لازم را به client ارسال کرد . خط آخر در دستورات زیر همان شرط رسیدن به آخر پیغام است و با درست بوردن این شرط فرایند ارسال کد های html و درخواست های http مهیا می شود :
if (client) { // If a new client connects, Serial.println("New Client."); // print a message out in the serial port String currentLine = ""; // make a String to hold incoming data from the client currentTime = millis(); previousTime = currentTime; while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected currentTime = millis(); 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') {
با رسیدن به کاراکتر پایانی (‘n\’) فرایند ارسال درخواست های http و ارسال دیتا های دیگر فراهم می شود . با استفاده از متد print برای شی client می توان هر متن را به سمت سخت افزار کاربر فرستاد (می توان یک درخواست http ارسال و پس از آن فایل html را فرستاد ) .
کلیه این فرایند ها را می توانید در نرم افزار هایی همچون Postman مشاهده کنید .
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();
در ادامه برنامه با استفاده از دستورات شرطی ، مقادیر ارسالی با استفاده از متد GET توسط کاربر به سرور ، مورد بررسی قرار می گیرد و بر اساس آن ها خروجی GPIO0 فعال و یا غیر فعال می گردد . در استایل تعریف شده ، ما کلیدی را تعریف می کنیم که با هر بار فشردن آن یک رشته خاص را با استفاده از متد GET به سرورو می فرستد .
if (header.indexOf("GET /5/on") >= 0) { Serial.println("GPIO 5 on"); output5State = "on"; digitalWrite(output5, LOW); } else if (header.indexOf("GET /5/off") >= 0) { Serial.println("GPIO 5 off"); output5State = "off"; digitalWrite(output5, HIGH); } else if (header.indexOf("GET /4/on") >= 0) { Serial.println("GPIO 4 on"); output4State = "on"; digitalWrite(output4, HIGH); } else if (header.indexOf("GET /4/off") >= 0) { Serial.println("GPIO 4 off"); output4State = "off"; digitalWrite(output4, LOW); }
و در پایان کد های HTML ارسال می شوند . می توانید از روش های مختلفی برای استفاده از فایل های HTML در ماژول های ESPressif استفاده کنید . ساده ترین راه پرینت خط به خط کد های HTML است ، کاری که در اینجا صورت گرفته ، اما این روش مشکلاتی از جمله حجم بالای کد های نوشته شده و همچنین رعایت قواعد مربوط به رشته ها در C را به همراه دارد . یکی از بهترین روش ها استفاده از قابلیت SPIFFs است . در مقالات قبلی راجب به این قابلیت توضیح داده شده است .
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: #774500A;}</style></head>"); // Web Page Heading client.println("<body><h1>Relay WiFi Module</h1>"); // Display current state, and ON/OFF buttons for GPIO 5 client.println("<p>Relay 1" + output5State + "</p>"); // If the output5State is off, it displays the ON button if (output5State=="off") { client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>"); } else { client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>"); } // Display current state, and ON/OFF buttons for GPIO 4 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(""); } }
با آپلود برنامه بر روی ماژول (ابتدا لازم است نام و رمز وایفای خود را در برنامه تعریف کنید ) با روشن شدن برد ، ماژول به وایفای شما متصل می شود .
سپس با وارد کردن IP ماژول در مروگر خود ، صفحه کنترل برای شما باز خواهد شد . IP ماژول را می توانید در تنظیمات مودوم خود ببینید یا اگر از هات اسپارت گوشی استفاده می کنید می تواند از تنظیمات هات اسپات IP را مشاهده کنید .
بسیار عالی و با تشکر☺
سلام .عرض ادب.
ممنون از آموزش خوبتون
آیا ممکنه نام و رمز وایفای رواز طریق به اپلیکیشن که می نویسیم …برای ماژول آپلود کرد و عملا بدون پروگرام برنامه اینکار صورت بگیره ؟
ممنون از شما