Окончательный скетч для умной розетки на esp8266

Окончательный скетч для умной розетки на esp8266


Скетч для ESP8266, предназначенный для управления релейным модулем через HTTP-сервер с возможностью первоначальной настройки устройства через собственную Wi-Fi-точку доступа и веб-интерфейс.

При запуске ESP8266 загружает из EEPROM сохранённые параметры: название устройства, SSID и пароль Wi-Fi, URL сервера и GPIO реле. По умолчанию реле подключено к GPIO5 (D1). Для реле используется инвертированная логика управления: низкий уровень (LOW) соответствует выключенному состоянию, высокий (HIGH) — включенному.

После подключения к Wi-Fi контроллер обращается к указанному HTTP-серверу и получает команду управления. Проверка выполняется каждые 2 секунды. Ответ:

Текущее состояние реле хранится в переменной relayState, поэтому повторное получение той же команды не приводит к лишнему переключению выхода. Кроме периодических запросов, состояние реле проверяется сразу после успешного подключения к Wi-Fi.

Если Wi-Fi не настроен или подключение к сохранённой сети не удалось, ESP8266 запускает собственную точку доступа ESP8266-Relay-Control. Через встроенный веб-сервер пользователь может настроить:

Настройки сохраняются в EEPROM и используются после перезагрузки устройства. При изменении GPIO скетч повторно инициализирует новый вывод и устанавливает его в безопасное выключенное состояние.

Таким образом, скетч представляет собой готовую основу для Wi-Fi-реле, управляемого удалённым сервером: ESP8266 самостоятельно подключается к сети, периодически получает состояние устройства по HTTP и переключает физический выход релейного модуля.

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

// Настройки по умолчанию
const char* AP_SSID = "ESP8266-Relay-Control";
const unsigned long CHECK_INTERVAL = 2000;
String SERVER_URL = "http://192.168.1.207/get_handler.php?id=pap1";
int RELAY_PIN = 5;  // GPIO5 (D1) для управления реле
String PAGE_TITLE = "ESP8266 Relay Controller";

// Глобальные переменные
ESP8266WebServer server(80);
String wifi_ssid = "";
String wifi_password = "";
unsigned long last_check_time = 0;
bool relayState = false;

// HTML страница для настройки
const char* config_page = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
  <title>%PAGE_TITLE%</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    body { font-family: Arial; margin: 20px; }
    form { max-width: 300px; }
    .form-group { margin-bottom: 15px; }
    label { display: block; margin-bottom: 5px; }
    input[type="text"], input[type="password"], input[type="url"], input[type="number"] { 
      width: 100%; padding: 8px; box-sizing: border-box; }
    input[type="submit"] { padding: 10px 20px; background: #4CAF50; color: white; border: none; }
  </style>
</head>
<body>
  <h1>%PAGE_TITLE%</h1>
  <form action="/save" method="POST">
    <div class="form-group">
      <label>Page Title:</label>
      <input type="text" name="page_title" value="%PAGE_TITLE%">
    </div>
    <div class="form-group">
      <label>Wi-Fi SSID:</label>
      <input type="text" name="ssid" value="%SSID%">
    </div>
    <div class="form-group">
      <label>Wi-Fi Password:</label>
      <input type="password" name="password" value="%PASSWORD%">
    </div>
    <div class="form-group">
      <label>Server URL:</label>
      <input type="url" name="server_url" value="%SERVER_URL%">
    </div>
    <div class="form-group">
      <label>Relay Pin (GPIO):</label>
      <input type="number" name="relay_pin" value="%RELAY_PIN%">
    </div>
    <input type="submit" value="Save Settings">
  </form>
</body>
</html>
)rawliteral";

void setup() {
  Serial.begin(115200);
  
  EEPROM.begin(512);
  loadSettings();
  
  // Инициализация пина реле с инвертированным управлением
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW); // Выключено по умолчанию (инвертировано)
  Serial.printf("Relay initialized on GPIO%d (inverted logic)\n", RELAY_PIN);
  
  WiFi.mode(WIFI_STA);
  connectToWiFi();
  
  setupWebServer();
}

void loop() {
  server.handleClient();
  
  if (WiFi.status() == WL_CONNECTED && millis() - last_check_time >= CHECK_INTERVAL) {
    last_check_time = millis();
    checkServer();
  }
}

void connectToWiFi() {
  if (wifi_ssid.length() == 0) {
    startAPMode();
    return;
  }

  Serial.printf("Connecting to %s\n", wifi_ssid.c_str());
  WiFi.begin(wifi_ssid.c_str(), wifi_password.c_str());

  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.printf("\nConnected! IP: %s\n", WiFi.localIP().toString().c_str());
    // После подключения сразу проверим состояние сервера
    checkServer();
  } else {
    Serial.println("\nFailed to connect. Starting AP mode...");
    startAPMode();
  }
}

void startAPMode() {
  WiFi.mode(WIFI_AP);
  WiFi.softAP(AP_SSID);
  Serial.printf("AP Mode. SSID: %s, IP: %s\n", AP_SSID, WiFi.softAPIP().toString().c_str());
}

void setupWebServer() {
  server.on("/", HTTP_GET, handleRoot);
  server.on("/save", HTTP_POST, handleSave);
  server.begin();
  Serial.println("HTTP server started");
}

void handleRoot() {
  String page = config_page;
  page.replace("%PAGE_TITLE%", PAGE_TITLE);
  page.replace("%SSID%", wifi_ssid);
  page.replace("%PASSWORD%", wifi_password);
  page.replace("%SERVER_URL%", SERVER_URL);
  page.replace("%RELAY_PIN%", String(RELAY_PIN));
  server.send(200, "text/html", page);
}

void handleSave() {
  if (server.hasArg("page_title") && server.hasArg("ssid") && server.hasArg("password") && 
      server.hasArg("server_url") && server.hasArg("relay_pin")) {
    PAGE_TITLE = server.arg("page_title");
    wifi_ssid = server.arg("ssid");
    wifi_password = server.arg("password");
    SERVER_URL = server.arg("server_url");
    RELAY_PIN = server.arg("relay_pin").toInt();
    
    saveSettings();
    
    // Реинициализация пина реле с инвертированным управлением
    pinMode(RELAY_PIN, OUTPUT);
    digitalWrite(RELAY_PIN, LOW); // Безопасное состояние при переконфигурации
    
    server.sendHeader("Location", "/");
    server.send(303);
    
    // Перезагрузка для применения новых настроек
    ESP.restart();
  } else {
    server.send(400, "text/plain", "Missing parameters");
  }
}

void checkServer() {
  WiFiClient client;
  HTTPClient http;
  
  Serial.printf("Requesting URL: %s\n", SERVER_URL.c_str());
  
  if (http.begin(client, SERVER_URL)) {
    int httpCode = http.GET();
    
    if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();
      payload.trim();
      Serial.printf("Server response: %s\n", payload.c_str());
      
      // Инвертированная логика управления реле
      if (payload == "1" && !relayState) {
        digitalWrite(RELAY_PIN, HIGH);  // Включить реле (инвертировано)
        relayState = true;
        Serial.println("Relay ON (HIGH)");
      } else if (payload == "0" && relayState) {
        digitalWrite(RELAY_PIN, LOW);   // Выключить реле (инвертировано)
        relayState = false;
        Serial.println("Relay OFF (LOW)");
      }
    } else {
      Serial.printf("HTTP error: %s\n", http.errorToString(httpCode).c_str());
    }
    
    http.end();
  } else {
    Serial.println("Failed to connect to server");
  }
}

// Функции EEPROM
void loadSettings() {
  wifi_ssid = readEEPROM(0);
  wifi_password = readEEPROM(64);
  SERVER_URL = readEEPROM(128);
  RELAY_PIN = readEEPROM(192).toInt();
  PAGE_TITLE = readEEPROM(256);
  
  if (PAGE_TITLE.length() == 0) PAGE_TITLE = "ESP8266 Relay Controller";
  if (RELAY_PIN < 0 || RELAY_PIN > 16) RELAY_PIN = 5; // Проверка корректности пина
}

void saveSettings() {
  writeEEPROM(0, wifi_ssid);
  writeEEPROM(64, wifi_password);
  writeEEPROM(128, SERVER_URL);
  writeEEPROM(192, String(RELAY_PIN));
  writeEEPROM(256, PAGE_TITLE);
  EEPROM.commit();
}

String readEEPROM(int offset) {
  String value;
  for (int i = offset; i < offset + 64; ++i) {
    char c = EEPROM.read(i);
    if (c == 0) break;
    value += c;
  }
  return value;
}

void writeEEPROM(int offset, String value) {
  for (int i = 0; i < value.length(); ++i) {
    EEPROM.write(offset + i, value[i]);
  }
  EEPROM.write(offset + value.length(), 0);
}
Комментариев пока нет.

Оставить комментарий