Загрузка данных
#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
#include <ArduinoOTA.h>
// ---- Данные домашней сети (используются только при первом запуске,
// дальше берутся из NVS) ----
#define HOME_SSID "LegendaryBoka"
#define HOME_PASSWORD "ВАШ_ПАРОЛЬ"
#define TELNET_PORT 23 // порт, который указываете в Termius
Preferences preferences;
WebServer server(80);
String ssid = "";
String password = "";
String deviceName = "esp32-ota"; // имя устройства, под которым оно будет видно в Arduino IDE как сетевой порт
// ---------- Телнет-мост: дублирует Serial-вывод по Wi-Fi ----------
// Используйте dbg.print/println/printf вместо Serial.print/println/printf —
// тогда текст будет виден и в мониторе порта (USB), и в Termius (по Wi-Fi).
class TelnetSerial : public Print {
public:
TelnetSerial() : server(TELNET_PORT) {}
void begin() {
server.begin();
server.setNoDelay(true);
}
// Вызывайте в loop(): принимает нового клиента и отклоняет "лишних"
void handle() {
if (server.hasClient()) {
if (!client || !client.connected()) {
if (client) client.stop();
client = server.available();
client.println("=== Подключено к ESP32 (телнет-монитор) ===");
} else {
WiFiClient reject = server.available();
reject.stop(); // одновременно поддерживается только один клиент
}
}
// Символы, введённые в Termius, тоже пробрасываем в Serial —
// удобно, если ваш скетч читает команды из Serial.read()
while (client && client.connected() && client.available()) {
Serial.write(client.read());
}
}
size_t write(uint8_t c) override {
Serial.write(c);
if (client && client.connected()) {
client.write(c);
}
return 1;
}
using Print::write;
private:
WiFiServer server;
WiFiClient client;
};
TelnetSerial dbg;
// ---------- Работа с NVS (энергонезависимая память) ----------
void loadCredentials() {
preferences.begin("wifi-config", true); // true = только чтение
ssid = preferences.getString("ssid", "");
password = preferences.getString("password", "");
deviceName = preferences.getString("devname", "esp32-ota");
preferences.end();
// Если это первый запуск и в NVS ещё ничего не сохранено —
// используем встроенные данные домашней сети и сохраняем их в NVS.
if (ssid.length() == 0) {
ssid = HOME_SSID;
password = HOME_PASSWORD;
saveCredentialsInternal(ssid, password);
}
}
void saveCredentialsInternal(const String &newSsid, const String &newPassword) {
preferences.begin("wifi-config", false); // false = чтение и запись
preferences.putString("ssid", newSsid);
preferences.putString("password", newPassword);
preferences.end();
}
void clearCredentials() {
preferences.begin("wifi-config", false);
preferences.clear();
preferences.end();
}
// ---------- Подключение к Wi-Fi ----------
void connectToWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid.c_str(), password.c_str());
dbg.print("Подключение к сети \"");
dbg.print(ssid);
dbg.print("\"");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
dbg.print(".");
}
dbg.println();
}
// ---------- Настройка OTA ----------
void setupOTA() {
ArduinoOTA.setHostname(deviceName.c_str());
// Раскомментируйте и задайте пароль, если хотите защитить OTA:
// ArduinoOTA.setPassword("your_ota_password");
ArduinoOTA.onStart([]() {
String type = (ArduinoOTA.getCommand() == U_FLASH) ? "sketch" : "filesystem";
dbg.println("Начало OTA обновления: " + type);
});
ArduinoOTA.onEnd([]() {
dbg.println("\nOTA обновление завершено");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
dbg.printf("Прогресс: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
dbg.printf("Ошибка [%u]: ", error);
if (error == OTA_AUTH_ERROR) dbg.println("ошибка авторизации");
else if (error == OTA_BEGIN_ERROR) dbg.println("ошибка начала записи");
else if (error == OTA_CONNECT_ERROR) dbg.println("ошибка подключения");
else if (error == OTA_RECEIVE_ERROR) dbg.println("ошибка приёма данных");
else if (error == OTA_END_ERROR) dbg.println("ошибка завершения записи");
});
ArduinoOTA.begin();
dbg.println("OTA готово, устройство доступно для заливки по сети");
}
void setup() {
Serial.begin(115200);
delay(500);
loadCredentials();
connectToWiFi();
dbg.println("Wi-Fi подключён!");
dbg.print("IP адрес: ");
dbg.println(WiFi.localIP());
setupOTA();
dbg.begin();
Serial.print("Телнет-монитор доступен на ");
Serial.print(WiFi.localIP());
Serial.print(":");
Serial.println(TELNET_PORT);
// Страница для сброса сохранённых настроек Wi-Fi (на случай, если
// в будущем понадобится сменить сеть):
// http://<IP-адрес>/reset
server.on("/reset", []() {
clearCredentials();
server.send(200, "text/plain", "Настройки Wi-Fi сброшены. Перезагрузка...");
delay(1000);
ESP.restart();
});
server.begin();
}
void loop() {
ArduinoOTA.handle();
server.handleClient();
dbg.handle();
// ---- сюда добавляйте основной код вашего проекта, используя
// dbg.print(...) / dbg.println(...) вместо Serial.print/println ----
}