#include #include #include #include #include #include // Список сетей, к которым разрешено подключаться: const char *allowedNetworks[] = {"link", "M2000", "MikroTik-2"}; // Соответствующие пароли: const char *networkPasswords[] = {"dkfgf#*12091997", "99887766", "dkfgf#*12091997"}; const uint8_t networkCount = 3; // Количество сетей в списке const char *server_url = "http://89.110.92.137:8000/upload"; const uint32_t utcOffsetInSeconds = 10800; // +3часа const uint32_t utcPeriodMseconds = 259200000; // 3сутки-259200000 // 1сутки-86400000; WiFiUDP ntpUDP; const char *timeSite = "ntp3.vniiftri.ru"; // "pool.ntp.org" NTPClient timeClient(ntpUDP, timeSite, utcOffsetInSeconds, utcPeriodMseconds); const uint16_t LOG_INTERVAL = 1000; // логируем раз в минуту (60000 мс) const uint8_t PIN_LED = 1; const uint8_t PIN_LED_MINUS = 3; const uint8_t PIN_VCC = 4; const uint8_t PIN_BUTTON = 9; const uint16_t BLINK_IN = 500; const uint16_t NUMBER_OF_ENTRIES = 1000; // кол-во записей в файле String chipId = "VCC_log"; uint32_t lastLogTime = 0; const uint8_t countConnect = 20; const uint16_t countPause = 500; float voltage = 0; float voltageOld = 0; float difference = 0.1; uint32_t now = 0; bool flagButton = false; bool flagSendData = true; //=========================================== // Форматирование SPIFS: void formatSPIFFS() { Serial.println("Начинаю форматирование SPIFFS..."); if (SPIFFS.format()) { Serial.println("Форматирование успешно завершено."); } else { Serial.println("Ошибка форматирования!"); } } // ======== ОТПРАВКА ФАЙЛОВ НА СЕРВЕР ======= bool sendFileToServer(String fileName) { HTTPClient http; WiFiClient client; // Открываем файл для чтения File file = SPIFFS.open("/" + fileName, FILE_READ); if (!file) { Serial.println("Не могу открыть файл"); return false; } // Читаем файл в строку (для небольших файлов) String fileContent = file.readString(); file.close(); // Настраиваем HTTP запрос http.begin(client, server_url); http.addHeader("Content-Type", "text/csv"); http.addHeader("X-Device-ID", chipId); http.addHeader("X-File-Name", fileName); // Отправляем POST запрос int httpCode = http.POST(fileContent); bool success = (httpCode == 200 || httpCode == 201); http.end(); return success; } void createCSVIfNeeded(String name) { // String fileName = name; if (!SPIFFS.exists("/" + name + ".csv")) { File file = SPIFFS.open("/" + name + ".csv", FILE_WRITE); if (file) { // String timeTemp = ""; // if (timeClient.getHours() < 10) // timeTemp += "0"; // timeTemp += timeClient.getHours(); // if (timeClient.getMinutes() < 10) // timeTemp += "0"; // timeTemp += timeClient.getMinutes(); // if (timeClient.getSeconds() < 10) // timeTemp += "0"; // timeTemp += timeClient.getSeconds(); // Serial.print(timeTemp); // Serial.print(" - "); // Serial.println(voltage); // file.print(timeTemp); // file.print(","); file.println("ЛОГГЕР :"); //, temperature); // ,%.1f,%d current, temperature, state); // voltageOld = voltage; file.close(); Serial.println("Создан новый CSV файл с заголовком"); } else { Serial.println("Ошибка создания CSV файла"); } } } //=========================================== void sendAllLogsToServer() { File root = SPIFFS.open("/"); if (!root) { Serial.println("Не удалось открыть корневую директорию"); return; } File file = root.openNextFile(); while (file) { String fileName = file.name(); // Пропускаем директории if (file.isDirectory()) { file = root.openNextFile(); continue; } // Отправляем только CSV файлы if (fileName.endsWith(".csv")) // && !fileName.startsWith("sent_")) { Serial.printf("Отправка %s... ", fileName.c_str()); if (sendFileToServer(fileName)) { Serial.println("Успешно !"); SPIFFS.remove("/" + fileName); voltageOld = 0; } else { Serial.println("Ошибка !"); createCSVIfNeeded(chipId); } } file = root.openNextFile(); } root.close(); } // ======== ПРОВЕРКА И ОТПРАВКА ДАННЫХ ====== bool connectToWiFi() { digitalWrite(PIN_LED, HIGH); WiFi.mode(WIFI_STA); // Явно устанавливаем режим станции delay(100); Serial.println("Начинаем сканирование WiFi:"); int n = WiFi.scanNetworks(); Serial.println("Сканирование завершено."); if (n == 0) { Serial.println("Сетей не найдено."); } else { Serial.print("Найдено сетей: "); Serial.println(n); } for (uint8_t i = 0; i < networkCount; ++i) { for (uint8_t k = 0; k < n; ++k) { String foundSSID = WiFi.SSID(k); if (foundSSID.equals(allowedNetworks[i])) { WiFi.begin(allowedNetworks[i], networkPasswords[i]); Serial.print("Подключение к WiFi:\n"); int attempts = 0; while (WiFi.status() != WL_CONNECTED && attempts < 20) { Serial.print(n); Serial.print(">"); attempts++; delay(500); } if (WiFi.status() == WL_CONNECTED) { Serial.println("\nWi-Fi подключен!"); Serial.print("IP адрес: "); Serial.println(WiFi.localIP()); Serial.print("RSSI: "); Serial.print(WiFi.RSSI()); Serial.println(" dBm"); digitalWrite(PIN_LED, LOW); return true; } else { Serial.println("\nОшибка подключения к Wi-Fi"); } } } } for (uint8_t i = 0; i < 30; ++i) { digitalWrite(PIN_LED, !digitalRead(PIN_LED)); delay(100); } digitalWrite(PIN_LED, LOW); return false; } //=========================================== // Проверить доступность интернета через ping: #include bool checkInternetConnection() { // Проверяем доступность Google DNS: bool success = Ping.ping("8.8.8.8", 3); // Или проверка по доменному имени: // bool success = Ping.ping("google.com", 3); if (success) { Serial.println("Интернет доступен!"); return true; } else { Serial.println("Нет доступа в интернет!"); return false; } return success; } //=========================================== void checkAndSendData() { Serial.println("Проверка наличия Wi-Fi сети..."); // Пробуем подключиться к Wi-Fi if (connectToWiFi()) { if (checkInternetConnection()) { // Отправляем все накопленные файлы sendAllLogsToServer(); } // Отключаем Wi-Fi для экономии энергии WiFi.disconnect(true); WiFi.mode(WIFI_OFF); Serial.println("Wi-Fi отключен для экономии энергии"); } else { Serial.println("Пропускаем отправку данных - нет подключения к Wi-Fi"); WiFi.disconnect(true); } } // ======== ЛОГГИРОВАНИЕ ДАННЫХ ============= void logBatteryData() { static uint32_t countData = 0; static uint8_t number_of_measurements = 100; uint32_t raw = 0; for (uint8_t i = 0; i < number_of_measurements; ++i) { raw += analogRead(PIN_VCC); } voltage = (raw / number_of_measurements) * 4884 / 1000000.0; // // Получаем время в секундах / 10 от старта // unsigned long uptime = millis() / 1000; // Открываем файл для добавления File file = SPIFFS.open("/" + chipId + ".csv", FILE_APPEND); if (!file) { Serial.println("Ошибка открытия файла для записи"); return; } // Записываем строку в CSV если разница больше или равна difference: if (abs(voltage - voltageOld) >= difference) { String timeTemp = ""; if (timeClient.getHours() < 10) timeTemp += "0"; timeTemp += timeClient.getHours(); if (timeClient.getMinutes() < 10) timeTemp += "0"; timeTemp += timeClient.getMinutes(); if (timeClient.getSeconds() < 10) timeTemp += "0"; timeTemp += timeClient.getSeconds(); Serial.print(timeTemp); Serial.print(" - "); Serial.println(voltage); file.print(timeTemp); file.print(","); file.println(voltage); //, temperature); // ,%.1f,%d current, temperature, state); file.close(); voltageOld = voltage; if (countData >= NUMBER_OF_ENTRIES - 1) { countData = 0; checkAndSendData(); } else { countData++; } } } //=========================================== void timeSinhro() { connectToWiFi(); timeClient.begin(); if (!timeClient.update()) Serial.println("Время обновить не удалось !"); Serial.println(timeClient.getFormattedTime()); flagButton = true; } // ================== SETUP ================= void setup() { Serial.begin(115200); Serial.println("\n\n=== Запуск устройства ==="); pinMode(PIN_LED, OUTPUT); pinMode(PIN_LED_MINUS, OUTPUT); digitalWrite(PIN_LED, HIGH); digitalWrite(PIN_LED_MINUS, LOW); // Получаем уникальный ID чипа для имени файла // uint64_t mac = ESP.getEfuseMac(); // chipId = String((uint16_t)(mac >> 32), HEX) + String((uint32_t)mac, HEX); // Serial.println("ChipID: " + chipId); // Монтируем SPIFFS if (!SPIFFS.begin(true)) { Serial.println("SPIFFS Mount Failed - пробуем форматировать"); formatSPIFFS(); if (!SPIFFS.begin(true)) { Serial.println("Критическая ошибка SPIFFS!"); return; } } // Создаем заголовок CSV, если файл новый createCSVIfNeeded(chipId); Serial.println("Логгер запущен"); Serial.println("=================\n"); while (1) { if (millis() - lastLogTime >= BLINK_IN) { digitalWrite(PIN_LED, !digitalRead(PIN_LED)); lastLogTime = millis(); } if (!digitalRead(PIN_BUTTON)) { delay(50); if (!digitalRead(PIN_BUTTON)) { digitalWrite(PIN_LED, HIGH); timeSinhro(); break; } } } digitalWrite(PIN_LED, LOW); lastLogTime = millis(); } // ================== LOOP ================== void loop() { unsigned long now = millis(); // 1. Логируем данные по расписанию if (now - lastLogTime >= LOG_INTERVAL) { lastLogTime = now; logBatteryData(); } // 2. Проверяем нажатие кнопки, подключаемся к Wi-Fi, отправляем данные if (!digitalRead(PIN_BUTTON)) { delay(50); if (!digitalRead(PIN_BUTTON)) { (!flagButton) ? timeSinhro() : checkAndSendData(); WiFi.disconnect(true); WiFi.mode(WIFI_OFF); } } static uint8_t hourOld = 0; uint8_t hour = timeClient.getHours(); if (hour != hourOld) flagSendData = true; if (hour >= 10 && hour <= 20 && flagSendData) { checkAndSendData(); flagSendData = false; } delay(10); }