diff --git a/data_svelte/items.json b/data_svelte/items.json index e107c0ea..f78855e6 100644 --- a/data_svelte/items.json +++ b/data_svelte/items.json @@ -455,18 +455,16 @@ "num": 34 }, { - "name": "35. PWM ESP32", + "name": "35. PWM ESP8266", "type": "Writing", - "subtype": "Pwm32", + "subtype": "Pwm8266", "id": "pwm", "widget": "range", "page": "Кнопки", "descr": "PWM", "int": 0, - "pin": 2, + "pin": 15, "freq": 5000, - "ledChannel": 2, - "PWM_resolution": 10, "val": 0, "apin": -1, "num": 35 diff --git a/include/Const.h b/include/Const.h index 32f2c239..77dfd39c 100644 --- a/include/Const.h +++ b/include/Const.h @@ -1,7 +1,7 @@ #pragma once //Версия прошивки -#define FIRMWARE_VERSION 421 +#define FIRMWARE_VERSION 422 #ifdef esp8266_4mb #define FIRMWARE_NAME "esp8266_4mb" diff --git a/include/EspFileSystem.h b/include/EspFileSystem.h index 4723b754..fbae8a7b 100644 --- a/include/EspFileSystem.h +++ b/include/EspFileSystem.h @@ -5,6 +5,7 @@ #include #define FileFS LittleFS #define FS_NAME "LittleFS_32" +#define CONFIG_LITTLEFS_SPIFFS_COMPAT 1 #else #include extern FS* filesystem; @@ -21,6 +22,9 @@ using littlefs_impl::LittleFSConfig; extern FS* filesystem; #define FileFS LittleFS #define FS_NAME "LittleFS_8266" +#define FILE_READ "r" +#define FILE_WRITE "w" +#define FILE_APPEND "a" #else extern FS* filesystem; #define FileFS SPIFFS diff --git a/include/NTP.h b/include/NTP.h index 9f32ae6b..d1bcc1f6 100644 --- a/include/NTP.h +++ b/include/NTP.h @@ -13,5 +13,6 @@ extern const String getTimeLocal_hhmmss(); extern const String getDateTimeDotFormated(); extern const String getDateDotFormated(); extern unsigned long strDateToUnix(String date); -const String getDateTimeDotFormatedFromUnix(unsigned long unixTime); +extern const String getDateTimeDotFormatedFromUnix(unsigned long unixTime); extern unsigned long gmtTimeToLocal(unsigned long gmtTimestamp); +extern const String getDateDotFormatedFromUnix(unsigned long unixTime); diff --git a/include/utils/FileUtils.h b/include/utils/FileUtils.h index d1a20f0e..1f021bce 100644 --- a/include/utils/FileUtils.h +++ b/include/utils/FileUtils.h @@ -6,6 +6,7 @@ extern void writeFileUint8tByFrames(const String& filename, uint8_t*& big_buf, s extern void writeFileUint8tByByte(const String& filename, uint8_t*& payload, size_t length, size_t headerLenth); extern File seekFile(const String& filename, size_t position = 0); extern const String writeFile(const String& filename, const String& str); +const String writeEmptyFile(const String& filename); extern const String addFileLn(const String& filename, const String& str); extern const String readFile(const String& filename, size_t max_size); extern const String filepath(const String& filename); @@ -15,7 +16,7 @@ void removeFile(const String& filename); void removeDirectory(const String& dir); void cleanDirectory(String path); void cleanLogs(); -void saveDataDB(String id, String data); +String saveDataDB(String id, String data); String readDataDB(String id); extern void onFlashWrite(); diff --git a/myProfile.json b/myProfile.json index 5b57857e..b807c1e6 100644 --- a/myProfile.json +++ b/myProfile.json @@ -21,7 +21,7 @@ }, "projectProp": { "platformio": { - "default_envs": "esp32_4mb", + "default_envs": "esp8266_4mb", "data_dir": "data_svelte" } }, diff --git a/platformio.ini b/platformio.ini index 72b9330b..ef5b920a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -41,7 +41,7 @@ build_src_filter = ${env:esp32_4mb_fromitems.build_src_filter} [platformio] -default_envs = esp32_4mb +default_envs = esp8266_4mb data_dir = data_svelte [common_env_data] diff --git a/src/NTP.cpp b/src/NTP.cpp index dfeca01c..fd0016c2 100644 --- a/src/NTP.cpp +++ b/src/NTP.cpp @@ -156,3 +156,11 @@ const String getDateTimeDotFormatedFromUnix(unsigned long unixTime) { sprintf(buf, "%02d.%02d.%02d %02d:%02d:%02d", time.day_of_month, time.month, time.year, time.hour, time.minute, time.second); return String(buf); } + +const String getDateDotFormatedFromUnix(unsigned long unixTime) { + Time_t time; + breakEpochToTime(unixTime, time); + char buf[32]; + sprintf(buf, "%02d.%02d.%d", time.day_of_month, time.month, time.year + 2000); + return String(buf); +} diff --git a/src/modules/API.cpp b/src/modules/API.cpp index b2f9af1f..9ee02105 100644 --- a/src/modules/API.cpp +++ b/src/modules/API.cpp @@ -22,7 +22,7 @@ void* getAPI_ButtonOut(String subtype, String params); void* getAPI_IoTServo(String subtype, String params); void* getAPI_Mcp23017(String subtype, String params); void* getAPI_Mp3(String subtype, String params); -void* getAPI_Pwm32(String subtype, String params); +void* getAPI_Pwm8266(String subtype, String params); void* getAPI_TelegramLT(String subtype, String params); void* getAPI_Lcd2004(String subtype, String params); @@ -50,7 +50,7 @@ if ((tmpAPI = getAPI_ButtonOut(subtype, params)) != nullptr) return tmpAPI; if ((tmpAPI = getAPI_IoTServo(subtype, params)) != nullptr) return tmpAPI; if ((tmpAPI = getAPI_Mcp23017(subtype, params)) != nullptr) return tmpAPI; if ((tmpAPI = getAPI_Mp3(subtype, params)) != nullptr) return tmpAPI; -if ((tmpAPI = getAPI_Pwm32(subtype, params)) != nullptr) return tmpAPI; +if ((tmpAPI = getAPI_Pwm8266(subtype, params)) != nullptr) return tmpAPI; if ((tmpAPI = getAPI_TelegramLT(subtype, params)) != nullptr) return tmpAPI; if ((tmpAPI = getAPI_Lcd2004(subtype, params)) != nullptr) return tmpAPI; return nullptr; diff --git a/src/modules/virtual/Logging/Loging.cpp b/src/modules/virtual/Logging/Loging.cpp index 880750ac..8d4668a4 100644 --- a/src/modules/virtual/Logging/Loging.cpp +++ b/src/modules/virtual/Logging/Loging.cpp @@ -44,22 +44,23 @@ class Loging : public IoTItem { } void doByInterval() { + SerialPrint("E", F("Loging"), "----------------------start loging cycle----------------------------"); //если объект логгирования не был создан if (!isItemExist(logid)) { - SerialPrint("E", F("Loging"), "'" + id + "' loging object not exist"); + SerialPrint("E", F("Loging"), "'" + id + "' loging object not exist, return"); return; } String value = getItemValue(logid); //если значение логгирования пустое if (value == "") { - SerialPrint("E", F("Loging"), "'" + id + "' loging value is empty"); + SerialPrint("E", F("Loging"), "'" + id + "' loging value is empty, return"); return; } //если время не было получено из интернета if (!isTimeSynch) { - SerialPrint("E", F("Loging"), "'" + id + "' Сant loging - time not synchronized"); + SerialPrint("E", F("Loging"), "'" + id + "' Сant loging - time not synchronized, return"); return; } @@ -72,9 +73,16 @@ class Loging : public IoTItem { //если данные о файле отсутствуют, создадим новый if (filePath == "failed" || filePath == "") { - SerialPrint("E", F("Loging"), "'" + id + "' file path not found"); + SerialPrint("E", F("Loging"), "'" + id + "' file path not found, start create new file"); createNewFileWithData(logData); return; + } else { + //если файл все же есть но был создан не сегодня, то создаем сегодняшний + if (getDateDotFormated() != getDateDotFormatedFromUnix(getFileUnixLocalTime(filePath))) { + SerialPrint("E", F("Loging"), "'" + id + "' file too old, start create new file"); + createNewFileWithData(logData); + return; + } } //считаем количество строк @@ -91,17 +99,34 @@ class Loging : public IoTItem { } //запускаем процедуру удаления старых файлов если память переполняется deleteLastFile(); + SerialPrint("E", F("Loging"), "----------------------compl loging cycle----------------------------"); } void createNewFileWithData(String &logData) { String path = "/lg/" + id + "/" + String(unixTimeShort) + ".txt"; //создадим путь вида /lg/id/133256622333.txt - addFileLn(path, logData); //запишем файл и данные в него - saveDataDB(id, path); //запишем путь к файлу в базу данных + //создадим пустой файл + if (writeEmptyFile(path) != "sucсess") { + SerialPrint("E", F("Loging"), "'" + id + "' file writing error, return"); + return; + } + //запишем в него данные + if (addFileLn(path, logData) != "sucсess") { + SerialPrint("E", F("Loging"), "'" + id + "' data writing error, return"); + return; + } + //запишем путь к нему в базу данных + if (saveDataDB(id, path) != "sucсess") { + SerialPrint("E", F("Loging"), "'" + id + "' db file writing error, return"); + return; + } SerialPrint("i", F("Loging"), "'" + id + "' file created http://" + WiFi.localIP().toString() + path); } void addNewDataToExistingFile(String &path, String &logData) { - addFileLn(path, logData); + if (addFileLn(path, logData) != "sucсess") { + SerialPrint("i", F("Loging"), "'" + id + "' file writing error, return"); + return; + }; SerialPrint("i", F("Loging"), "'" + id + "' loging in file http://" + WiFi.localIP().toString() + path); } @@ -120,8 +145,13 @@ class Loging : public IoTItem { } void sendChart() { - String dir = "lg/" + id; + SerialPrint("E", F("Loging"), "----------------------start send chart----------------------------"); + + String dir = "/lg/" + id; filesList = getFilesList(dir); + + SerialPrint("i", F("Loging"), "file list: " + filesList); + int f = 0; bool noData = true; @@ -129,16 +159,20 @@ class Loging : public IoTItem { while (filesList.length()) { String buf = selectToMarker(filesList, ";"); + buf = "/lg/" + id + buf; + f++; int i = 0; - unsigned long fileUnixTimeGMT = selectToMarkerLast(deleteToMarkerLast(buf, "."), "/").toInt() + START_DATETIME; - unsigned long fileUnixTimeLocal = gmtTimeToLocal(fileUnixTimeGMT); + unsigned long fileUnixTimeLocal = getFileUnixLocalTime(buf); unsigned long reqUnixTime = strDateToUnix(getItemValue(id + "-date")); if (fileUnixTimeLocal > reqUnixTime && fileUnixTimeLocal < reqUnixTime + 86400) { noData = false; - createJson(buf, i); + if (!createJson(buf, i)) { + SerialPrint("E", F("Loging"), buf + " file reading error, json not created, return"); + return; + } SerialPrint("i", F("Loging"), String(f) + ") " + buf + ", " + String(i) + ", " + getDateTimeDotFormatedFromUnix(fileUnixTimeLocal) + ", sent"); } else { SerialPrint("i", F("Loging"), String(f) + ") " + buf + ", nil, " + getDateTimeDotFormatedFromUnix(fileUnixTimeLocal) + ", skipped"); @@ -150,6 +184,7 @@ class Loging : public IoTItem { if (noData) { cleanChart(); } + SerialPrint("E", F("Loging"), "----------------------compl send chart----------------------------"); } void cleanChart() { @@ -159,30 +194,22 @@ class Loging : public IoTItem { } void cleanData() { - String dir = "lg/" + id; - filesList = getFilesList(dir); - int i = 0; - while (filesList.length()) { - String buf = selectToMarker(filesList, ";"); - - i++; - removeFile(buf); - SerialPrint("i", "Files", String(i) + ") " + buf + " => deleted"); - - filesList = deleteBeforeDelimiter(filesList, ";"); - } + String dir = "/lg/" + id; + cleanDirectory(dir); } void deleteLastFile() { IoTFSInfo tmp = getFSInfo(); SerialPrint("i", "Loging", String(tmp.freePer) + " % free flash remaining"); - if (tmp.freePer <= 10.00) { - String dir = "lg/" + id; + if (tmp.freePer <= 20.00) { + String dir = "/lg/" + id; filesList = getFilesList(dir); int i = 0; while (filesList.length()) { String buf = selectToMarker(filesList, ";"); + buf = dir + buf; + i++; if (i == 1) { removeFile(buf); @@ -195,11 +222,10 @@ class Loging : public IoTItem { } } - void createJson(String file, int &i) { - File configFile = FileFS.open(file, "r"); + bool createJson(String file, int &i) { + File configFile = FileFS.open(file, FILE_READ); if (!configFile) { - SerialPrint("E", F("Loging"), "'" + id + "' open file error"); - return; + return false; } configFile.seek(0, SeekSet); String buf = "{}"; @@ -228,6 +254,7 @@ class Loging : public IoTItem { oneSingleJson.replace("},]}", "}]}"); publishJson(oneSingleJson); + return true; } // publishType 1 - в mqtt, 2 - в ws, 3 - mqtt и ws @@ -292,6 +319,11 @@ class Loging : public IoTItem { int calculateMaxCount() { return 86400; } + + //путь вида: /lg/log/1231231.txt + unsigned long getFileUnixLocalTime(String path) { + return gmtTimeToLocal(selectToMarkerLast(deleteToMarkerLast(path, "."), "/").toInt() + START_DATETIME); + } }; void *getAPI_Loging(String subtype, String param) { diff --git a/src/utils/FileUtils.cpp b/src/utils/FileUtils.cpp index ecb6b01d..8b351c33 100644 --- a/src/utils/FileUtils.cpp +++ b/src/utils/FileUtils.cpp @@ -3,7 +3,7 @@ //данная функция записывает файл из буфера страницами указанного размера void writeFileUint8tByFrames(const String& filename, uint8_t*& big_buf, size_t length, size_t headerLenth, size_t frameSize) { String path = filepath(filename); - auto file = FileFS.open(path, "w"); + auto file = FileFS.open(path, FILE_WRITE); if (!file) { Serial.println(F("failed write file uint8tByFrames")); return; @@ -24,42 +24,9 @@ void writeFileUint8tByFrames(const String& filename, uint8_t*& big_buf, size_t l onFlashWrite(); } -// void writeStrValueToJsonFile(const String& filename, String key, String value) { -// String tmp = readFile(filename, 4096); -// if (!jsonWriteStr_(tmp, key, value)) { -// Serial.println(F("failed write json value to file")); -// } -// writeFile(filename, tmp); -// } - -//данная функция читает из файла страницами указанного размера -// void readFileUint8tByFrames(const String& filename, size_t frameSize) { -// String path = filepath(filename); -// auto file = FileFS.open(path, "r"); -// if (!file) { -// Serial.println(F("failed read file Uint8tByFrames")); -// return; -// } -// size_t length = file.size(); -// size_t read{0}; -// while (length > read) { -// size_t size = length - read; -// if (size > frameSize) size = frameSize; -// uint8_t p[size]; -// size_t res = file.read(p, size); -// // -// if (size != res) { -// break; -// } -// read += res; -// yield(); -// } -// file.close(); -//} - void writeFileUint8tByByte(const String& filename, uint8_t*& payload, size_t length, size_t headerLenth) { String path = filepath(filename); - auto file = FileFS.open(path, "w"); + auto file = FileFS.open(path, FILE_WRITE); if (!file) { Serial.println(F("failed write file uint8tByByte")); return; @@ -81,7 +48,7 @@ void writeFileUint8tByByte(const String& filename, uint8_t*& payload, size_t len File seekFile(const String& filename, size_t position) { String path = filepath(filename); - auto file = FileFS.open(path, "r"); + auto file = FileFS.open(path, FILE_READ); if (!file) { SerialPrint(F("E"), F("FS"), F("seek file error")); } @@ -91,7 +58,12 @@ File seekFile(const String& filename, size_t position) { const String writeFile(const String& filename, const String& str) { String path = filepath(filename); - auto file = FileFS.open(path, "w"); +#ifdef ESP32 + auto file = FileFS.open(path, FILE_WRITE, true); +#endif +#ifdef ESP8266 + auto file = FileFS.open(path, FILE_WRITE); +#endif if (!file) { return "failed"; } @@ -101,9 +73,25 @@ const String writeFile(const String& filename, const String& str) { onFlashWrite(); } +const String writeEmptyFile(const String& filename) { + String path = filepath(filename); +#ifdef ESP32 + auto file = FileFS.open(path, FILE_WRITE, true); +#endif +#ifdef ESP8266 + auto file = FileFS.open(path, FILE_WRITE); +#endif + if (!file) { + return "failed"; + } + file.close(); + return "sucсess"; + onFlashWrite(); +} + const String addFileLn(const String& filename, const String& str) { String path = filepath(filename); - auto file = FileFS.open(path, "a"); + auto file = FileFS.open(path, FILE_APPEND); if (!file) { return "failed"; } @@ -115,7 +103,7 @@ const String addFileLn(const String& filename, const String& str) { const String readFile(const String& filename, size_t max_size) { String path = filepath(filename); - auto file = FileFS.open(path, "r"); + auto file = FileFS.open(path, FILE_READ); if (!file) { return "failed"; } @@ -144,8 +132,8 @@ bool cutFile(const String& src, const String& dst) { if (FileFS.exists(dstPath)) { FileFS.remove(dstPath); } - auto srcFile = FileFS.open(srcPath, "r"); - auto dstFile = FileFS.open(dstPath, "w"); + auto srcFile = FileFS.open(srcPath, FILE_READ); + auto dstFile = FileFS.open(dstPath, FILE_WRITE); uint8_t buf[512]; while (srcFile.available()) { size_t len = srcFile.read(buf, 512); @@ -162,7 +150,7 @@ bool cutFile(const String& src, const String& dst) { size_t countLines(const String filename) { size_t cnt = -1; String path = filepath(filename); - auto file = FileFS.open(path, "r"); + auto file = FileFS.open(path, FILE_READ); if (!file) { return cnt; } @@ -202,24 +190,9 @@ void removeDirectory(const String& dir) { } } -//очищаем директорию с файлами -void cleanDirectory(String path) { - String filesList = getFilesList(path); - int i = 0; - while (filesList.length()) { - String buf = selectToMarker(filesList, ";"); - - i++; - removeFile(buf); - SerialPrint("i", "Files", String(i) + ") " + buf + " => deleted"); - - filesList = deleteBeforeDelimiter(filesList, ";"); - } -} - -void saveDataDB(String id, String data) { +String saveDataDB(String id, String data) { String path = "/db/" + id + ".txt"; - writeFile(path, data); + return writeFile(path, data); } String readDataDB(String id) { @@ -229,7 +202,7 @@ String readDataDB(String id) { void cleanLogs() { SerialPrint("i", "Files", "cleanLogs"); - cleanDirectory("db"); + cleanDirectory("/db"); //очистка данных всех экземпляров графиков for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { if ((*it)->getSubtype() == "Loging") { @@ -238,6 +211,22 @@ void cleanLogs() { } } +//очищаем директорию с файлами +void cleanDirectory(String path) { + String filesList = getFilesList(path); + int i = 0; + while (filesList.length()) { + String buf = selectToMarker(filesList, ";"); + buf = path + buf; + SerialPrint("i", "", buf); + i++; + removeFile(buf); + SerialPrint("i", "Files", String(i) + ") " + buf + " => deleted"); + + filesList = deleteBeforeDelimiter(filesList, ";"); + } +} + //счетчик количества записей на флешь за сеанс void onFlashWrite() { flashWriteNumber++; @@ -260,14 +249,15 @@ String getFilesList8266(String& directory) { #if defined(ESP32) String getFilesList32(String& directory) { String filesList = ""; - directory = "/" + directory; File root = FileFS.open(directory); - directory = String(); + // if (!root) { + // return ""; + // } if (root.isDirectory()) { File file = root.openNextFile(); while (file) { String fname = file.name(); - if (fname != "") filesList += fname + ";"; + if (fname != "") filesList += "/" + fname + ";"; file = root.openNextFile(); } }