From 12ef79c558dcfa7663e767401d3907c5f79e0cdc Mon Sep 17 00:00:00 2001 From: Dmitry Borisenko <49808844+DmitryBorisenko33@users.noreply.github.com> Date: Thu, 8 Sep 2022 00:27:38 +0200 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D0=BD=D1=8B=20=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data_svelte/settings.json | 2 +- include/Const.h | 2 +- include/NTP.h | 1 + include/classes/IoTItem.h | 1 + myProfile.json | 2 +- src/Main.cpp | 14 +- src/NTP.cpp | 8 + src/classes/IoTItem.cpp | 8 +- src/modules/virtual/Logging/Loging.cpp | 332 +++++++++++++++---------- src/utils/FileUtils.cpp | 9 +- 10 files changed, 240 insertions(+), 139 deletions(-) diff --git a/data_svelte/settings.json b/data_svelte/settings.json index e22aa0a8..78a7212d 100644 --- a/data_svelte/settings.json +++ b/data_svelte/settings.json @@ -3,7 +3,7 @@ "name": "IoTmanagerVer4", "apssid": "IoTmanager", "appass": "", - "routerssid": "rise", + "routerssid": "rise2", "routerpass": "hostel3333", "timezone": 1, "ntp": "pool.ntp.org", diff --git a/include/Const.h b/include/Const.h index 97961bff..55d0b2e7 100644 --- a/include/Const.h +++ b/include/Const.h @@ -1,7 +1,7 @@ #pragma once //Версия прошивки -#define FIRMWARE_VERSION 415 +#define FIRMWARE_VERSION 416 #ifdef esp8266_4mb #define FIRMWARE_NAME "esp8266_4mb" diff --git a/include/NTP.h b/include/NTP.h index 7bf1f1f2..815a9b17 100644 --- a/include/NTP.h +++ b/include/NTP.h @@ -12,3 +12,4 @@ extern const String getTimeLocal_hhmm(); extern const String getTimeLocal_hhmmss(); extern const String getDateTimeDotFormated(); extern unsigned long strDateToUnix(String date); +const String getDateTimeDotFormatedFromUnix(unsigned long unixTime); diff --git a/include/classes/IoTItem.h b/include/classes/IoTItem.h index cb8d7279..76709c69 100644 --- a/include/classes/IoTItem.h +++ b/include/classes/IoTItem.h @@ -25,6 +25,7 @@ class IoTItem { String getSubtype(); virtual void sendChart(bool mqtt); + virtual void cleanData(); String getID(); virtual String getValue(); diff --git a/myProfile.json b/myProfile.json index 28cb48c2..255072e5 100644 --- a/myProfile.json +++ b/myProfile.json @@ -4,7 +4,7 @@ "name": "IoTmanagerVer4", "apssid": "IoTmanager", "appass": "", - "routerssid": "rise", + "routerssid": "rise2", "routerpass": "hostel3333", "timezone": 1, "ntp": "pool.ntp.org", diff --git a/src/Main.cpp b/src/Main.cpp index 102995e1..7b0a69a8 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -62,7 +62,7 @@ void setup() { //запуск работы udp asyncUdpInit(); - + //подготавливаем сценарии iotScen.loadScenario("/scenario.txt"); @@ -123,7 +123,7 @@ void loop() { #endif #ifdef STANDARD_WEB_SERVER - //обработка web сервера + //обработка web сервера 1 HTTP.handleClient(); #endif @@ -135,6 +135,11 @@ void loop() { //обновление mqtt mqttLoop(); +#ifdef STANDARD_WEB_SERVER + //обработка web сервера 2 + // HTTP.handleClient(); +#endif + // передаем управление каждому элементу конфигурации для выполнения своих функций for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { (*it)->loop(); @@ -149,6 +154,11 @@ void loop() { handleEvent(); +#ifdef STANDARD_WEB_SERVER + //обработка web сервера 3 + // HTTP.handleClient(); +#endif + // сохраняем значения IoTItems в файл каждую секунду, если были изменения (установлены маркеры на сохранение) // currentMillis = millis(); // if (currentMillis - prevMillis >= 1000) { diff --git a/src/NTP.cpp b/src/NTP.cpp index bd1d53fe..9281d2b2 100644 --- a/src/NTP.cpp +++ b/src/NTP.cpp @@ -137,3 +137,11 @@ unsigned long strDateToUnix(String date) { } return (day * secsInOneDay) + (numberOfDaysInPastMonths * secsInOneDay) + (totalNormalYears * daysInOneYear * secsInOneDay) + (numberOfLeepYears * daysInLeepYear * secsInOneDay); } + +const String getDateTimeDotFormatedFromUnix(unsigned long unixTime) { + Time_t time; + breakEpochToTime(unixTime, time); + char buf[32]; + 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); +} diff --git a/src/classes/IoTItem.cpp b/src/classes/IoTItem.cpp index 2a54741e..d60a35e0 100644 --- a/src/classes/IoTItem.cpp +++ b/src/classes/IoTItem.cpp @@ -33,7 +33,8 @@ IoTItem::IoTItem(String parameters) { _map2 = selectFromMarkerToMarker(map, ",", 1).toInt(); _map3 = selectFromMarkerToMarker(map, ",", 2).toInt(); _map4 = selectFromMarkerToMarker(map, ",", 3).toInt(); - } else _map1 = _map2 = _map3 = _map4 = 0; + } else + _map1 = _map2 = _map3 = _map4 = 0; } //луп выполняющий переодическое дерганье @@ -65,7 +66,8 @@ String IoTItem::getValue() { return value.valS = buf; } else return (String)value.valD; - } else return value.valS; + } else + return value.valS; } //установить @@ -128,6 +130,8 @@ String IoTItem::getSubtype() { void IoTItem::sendChart(bool mqtt) {} +void IoTItem::cleanData() {} + String IoTItem::getID() { return _id; }; diff --git a/src/modules/virtual/Logging/Loging.cpp b/src/modules/virtual/Logging/Loging.cpp index 9fb05bc6..727f1fe0 100644 --- a/src/modules/virtual/Logging/Loging.cpp +++ b/src/modules/virtual/Logging/Loging.cpp @@ -6,6 +6,8 @@ class Loging : public IoTItem { private: String logid; String id; + String filesList = ""; + int points; int keepdays; @@ -56,13 +58,13 @@ class Loging : public IoTItem { //прочитаем путь к файлу последнего сохранения String filePath = readDataDB(id); - // Serial.println("filePath " + filePath); - //если данные о файле отсутствуют, создадим новый if (filePath == "failed" || filePath == "") { SerialPrint("E", F("Loging"), "'" + id + "' file path not found"); createNewFileWithData(logData); return; + } else { + // SerialPrint("i", F("Loging"), "'" + id + "' file path found " + filePath); } //считаем количество строк @@ -80,7 +82,7 @@ class Loging : public IoTItem { } void createNewFileWithData(String &logData) { - String path = "/lg/" + id + "-" + String(unixTimeShort) + ".txt"; //создадим путь + String path = "/lg/" + id + "/" + String(unixTimeShort) + ".txt"; //создадим путь вида /lg/id/133256622333.txt addFileLn(path, logData); //запишем файл и данные в него saveDataDB(id, path); //запишем путь к файлу в базу данных SerialPrint("i", F("Loging"), "'" + id + "' file created http://" + WiFi.localIP().toString() + path); @@ -91,146 +93,216 @@ class Loging : public IoTItem { SerialPrint("i", F("Loging"), "'" + id + "' loging in file http://" + WiFi.localIP().toString() + path); } - void sendChart(bool mqtt) { - //отправка графика может происходить только если время синхронизированно - if (!isTimeSynch) { - SerialPrint("E", F("Loging"), "'" + id + "' Сant send chart - time not synchronized"); - return; - } - SerialPrint("i", F("Loging"), "'" + id + "'----------------------------"); - String reqUnixTimeStr = "27.08.2022"; //нужно получить эту дату из окна ввода под графиком. - unsigned long reqUnixTime = strDateToUnix(reqUnixTimeStr); - - int i = 0; #if defined(ESP8266) - String directory = "lg"; + void getFilesList8266() { + filesList = ""; + String directory = "lg/" + id; auto dir = FileFS.openDir(directory); while (dir.next()) { String fname = dir.fileName(); + if (fname != "") filesList += directory + "/" + fname + ";"; + } + } +#endif + +#if defined(ESP32) + void getFilesList32() { + filesList = ""; + String directory = "/lg/" + id; + File root = FileFS.open(directory); + directory = String(); + if (root.isDirectory()) { + File file = root.openNextFile(); + while (file) { + String fname = file.name(); + fname = selectToMarkerLast(fname, "/"); + file = root.openNextFile(); + if (fname != "") filesList += directory + "/" + fname + ";"; + } + } + } +#endif + + void getFilesList() { +#if defined(ESP8266) + getFilesList8266(); #endif #if defined(ESP32) - String directory = "/lg"; - File root = FileFS.open(directory); - directory = String(); - if (root.isDirectory()) { - File file = root.openNextFile(); - while (file) { - String fname = file.name(); - fname = selectToMarkerLast(fname, "/"); - file = root.openNextFile(); -#endif - String idInFileName = selectToMarker(fname, "-"); - unsigned long fileUnixTime = deleteBeforeDelimiter(deleteToMarkerLast(fname, "."), "-").toInt() + START_DATETIME; - if (isItemExist(id)) { - //если id в имени файла совпадает с id данного экземпляра, пусть каждый экземпляр класса шлет только свое - if (idInFileName == id) { - //выбираем только те файлы которые входят в выбранные пользователем сутки - // if (fileUnixTime > reqUnixTime && fileUnixTime < reqUnixTime + 86400) { - SerialPrint("i", F("Loging"), "'" + id + "' matching file found '" + fname + "'"); - //выгрузка по частям, по одному файлу - createJson("/lg/" + fname, i, mqtt); - //} - //удаление старых файлов - if ((fileUnixTime + (points * interval)) < (unixTime - (keepdays * 86400))) { - SerialPrint("i", F("Loging"), "'" + id + "' file '" + fname + "' too old, deleted"); - removeFile(directory + "/" + fname); - } - } - } else { - SerialPrint("i", F("Loging"), "'" + id + "' file '" + fname + "' not used, deleted"); - removeFile(directory + "/" + fname); - } - } -#if defined(ESP32) - } + getFilesList32(); #endif + } - SerialPrint("i", F("Loging"), "'" + id + "'--------------'" + String(i) + "'--------------"); - } + void sendChart(bool mqtt) { + getFilesList(); + int f = 0; - void createJson(String file, int &i, bool mqtt) { - File configFile = FileFS.open(file, "r"); - if (!configFile) { - SerialPrint("E", F("Loging"), "'" + id + "' open file error"); - return; - } - configFile.seek(0, SeekSet); - String buf = "{}"; - String oneSingleJson; - String unix_time; - String value; - unsigned int psn; - unsigned int sz = configFile.size(); - do { - i++; - psn = configFile.position(); - String line = configFile.readStringUntil('\n'); - unix_time = selectToMarker(line, " "); - jsonWriteInt(buf, "x", unix_time.toInt() + START_DATETIME); - value = deleteBeforeDelimiter(line, " "); - jsonWriteFloat(buf, "y1", value.toFloat()); - if (unix_time != "" || value != "") { - oneSingleJson += buf + ","; - } - } while (psn < sz); + while (filesList.length()) { + String buf = selectToMarker(filesList, ";"); - configFile.close(); + f++; + int i = 0; + createJson(buf, i, mqtt); + unsigned long fileUnixTime = selectToMarkerLast(deleteToMarkerLast(buf, "."), "/").toInt() + START_DATETIME; + SerialPrint("i", F("Loging"), String(f) + ") path: " + buf + ", lines №: " + String(i) + ", creation time: " + getDateTimeDotFormatedFromUnix(fileUnixTime)); - String topic = mqttRootDevice + "/" + id; - oneSingleJson = "{\"maxCount\":" + String(calculateMaxCount()) + ",\"topic\":\"" + topic + "\",\"status\":[" + oneSingleJson + "]}"; - oneSingleJson.replace("},]}", "}]}"); - - publishJson(oneSingleJson, mqtt); - } - - void publishJson(String & oneSingleJson, bool mqtt) { - if (mqtt) { - publishChart(id, oneSingleJson); - } else { - publishStatusWsJson(oneSingleJson); - } - } - - //примерный подсчет максимального количества точек - int calculateMaxCount() { - return 86400 / interval; - } - }; - - void *getAPI_Loging(String subtype, String param) { - if (subtype == F("Loging")) { - return new Loging(param); - } else { - return nullptr; + filesList = deleteBeforeDelimiter(filesList, ";"); } } - //то что не пригодилось но пригодится потом может быть - // void createOneSingleJson(String &oneSingleJson, String file, int &maxCount, int &i) { - // File configFile = FileFS.open(file, "r"); - // if (!configFile) { - // return; - // } - // configFile.seek(0, SeekSet); - // String buf = "{}"; - // String unix_time; - // String value; - // unsigned int psn; - // unsigned int sz = configFile.size(); - // do { - // maxCount++; - // i++; - // psn = configFile.position(); - // String line = configFile.readStringUntil('\n'); - // unix_time = selectToMarker(line, " "); - // jsonWriteInt(buf, "x", unix_time.toInt() + START_DATETIME); - // value = deleteBeforeDelimiter(line, " "); - // jsonWriteFloat(buf, "y1", value.toFloat()); - // if (unix_time != "" || value != "") { - // oneSingleJson += buf + ","; - // } + void cleanData() { + getFilesList(); + int i = 0; + while (filesList.length()) { + String buf = selectToMarker(filesList, ";"); + + i++; + removeFile(buf); + SerialPrint("i", "Files", String(i) + ") " + buf + " => deleted"); + + filesList = deleteBeforeDelimiter(filesList, ";"); + } + } + + // void sendChart2(bool mqtt) { + // //отправка графика может происходить только если время синхронизированно + // if (!isTimeSynch) { + // SerialPrint("E", F("Loging"), "'" + id + "' Сant send chart - time not synchronized"); + // return; + // } + // SerialPrint("i", F("Loging"), "'" + id + "'----------------------------"); + // String reqUnixTimeStr = "27.08.2022"; //нужно получить эту дату из окна ввода под графиком. + // unsigned long reqUnixTime = strDateToUnix(reqUnixTimeStr); // - // } while (psn < sz); + // int i = 0; + //#if defined(ESP8266) + // String directory = "lg"; + // auto dir = FileFS.openDir(directory); + // while (dir.next()) { + // String fname = dir.fileName(); + //#endif + //#if defined(ESP32) + // String directory = "/lg"; + // File root = FileFS.open(directory); + // directory = String(); + // if (root.isDirectory()) { + // File file = root.openNextFile(); + // while (file) { + // String fname = file.name(); + // fname = selectToMarkerLast(fname, "/"); + // file = root.openNextFile(); + //#endif + // String idInFileName = selectToMarker(fname, "-"); + // unsigned long fileUnixTime = deleteBeforeDelimiter(deleteToMarkerLast(fname, "."), "-").toInt() + START_DATETIME; + // if (isItemExist(id)) { + // //если id в имени файла совпадает с id данного экземпляра, пусть каждый экземпляр класса шлет только свое + // if (idInFileName == id) { + // //выбираем только те файлы которые входят в выбранные пользователем сутки + // // if (fileUnixTime > reqUnixTime && fileUnixTime < reqUnixTime + 86400) { + // SerialPrint("i", F("Loging"), "'" + id + "' matching file found '" + fname + "'"); + // //выгрузка по частям, по одному файлу + // createJson("/lg/" + fname, i, mqtt); + // //} + // //удаление старых файлов + // if ((fileUnixTime + (points * interval)) < (unixTime - (keepdays * 86400))) { + // SerialPrint("i", F("Loging"), "'" + id + "' file '" + fname + "' too old, deleted"); + // removeFile(directory + "/" + fname); + // } + // } + // } else { + // SerialPrint("i", F("Loging"), "'" + id + "' file '" + fname + "' not used, deleted"); + // removeFile(directory + "/" + fname); + // } + // } + //#if defined(ESP32) + // } + //#endif // - // configFile.close(); - // } + // SerialPrint("i", F("Loging"), "'" + id + "'--------------'" + String(i) + "'--------------"); + // } + + void createJson(String file, int &i, bool mqtt) { + File configFile = FileFS.open(file, "r"); + if (!configFile) { + SerialPrint("E", F("Loging"), "'" + id + "' open file error"); + return; + } + configFile.seek(0, SeekSet); + String buf = "{}"; + String oneSingleJson; + String unix_time; + String value; + unsigned int psn; + unsigned int sz = configFile.size(); + do { + i++; + psn = configFile.position(); + String line = configFile.readStringUntil('\n'); + unix_time = selectToMarker(line, " "); + jsonWriteInt(buf, "x", unix_time.toInt() + START_DATETIME); + value = deleteBeforeDelimiter(line, " "); + jsonWriteFloat(buf, "y1", value.toFloat()); + if (unix_time != "" || value != "") { + oneSingleJson += buf + ","; + } + } while (psn < sz); + + configFile.close(); + + String topic = mqttRootDevice + "/" + id; + oneSingleJson = "{\"maxCount\":" + String(calculateMaxCount()) + ",\"topic\":\"" + topic + "\",\"status\":[" + oneSingleJson + "]}"; + oneSingleJson.replace("},]}", "}]}"); + + publishJson(oneSingleJson, mqtt); + } + + void publishJson(String &oneSingleJson, bool mqtt) { + if (mqtt) { + publishChart(id, oneSingleJson); + } else { + publishStatusWsJson(oneSingleJson); + } + } + + //примерный подсчет максимального количества точек + int calculateMaxCount() { + return 86400 / interval; + } +}; + +void *getAPI_Loging(String subtype, String param) { + if (subtype == F("Loging")) { + return new Loging(param); + } else { + return nullptr; + } +} + +//то что не пригодилось но пригодится потом может быть +// void createOneSingleJson(String &oneSingleJson, String file, int &maxCount, int &i) { +// File configFile = FileFS.open(file, "r"); +// if (!configFile) { +// return; +// } +// configFile.seek(0, SeekSet); +// String buf = "{}"; +// String unix_time; +// String value; +// unsigned int psn; +// unsigned int sz = configFile.size(); +// do { +// maxCount++; +// i++; +// psn = configFile.position(); +// String line = configFile.readStringUntil('\n'); +// unix_time = selectToMarker(line, " "); +// jsonWriteInt(buf, "x", unix_time.toInt() + START_DATETIME); +// value = deleteBeforeDelimiter(line, " "); +// jsonWriteFloat(buf, "y1", value.toFloat()); +// if (unix_time != "" || value != "") { +// oneSingleJson += buf + ","; +// } +// +// } while (psn < sz); +// +// configFile.close(); +// } diff --git a/src/utils/FileUtils.cpp b/src/utils/FileUtils.cpp index 48515a53..343b1c3c 100644 --- a/src/utils/FileUtils.cpp +++ b/src/utils/FileUtils.cpp @@ -183,7 +183,7 @@ void removeFile(const String& filename) { String path = filepath(filename); if (FileFS.exists(path)) { if (!FileFS.remove(path)) { - SerialPrint("I", "Files", "remove " + path); + // SerialPrint("i", "Files", "remove " + path); } } else { SerialPrint("E", "Files", "not exist " + path); @@ -232,8 +232,13 @@ String readDataDB(String id) { } void cleanLogs() { - cleanDirectory("lg"); cleanDirectory("db"); + //очистка данных всех экземпляров графиков + for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { + if ((*it)->getSubtype() == "Loging") { + (*it)->cleanData(); + } + } } //счетчик количества записей на флешь за сеанс