diff --git a/.vscode/settings.json b/.vscode/settings.json index 89f6be4b..61cd5f78 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,7 @@ "vector": "cpp", "string_view": "cpp", "initializer_list": "cpp", - "ranges": "cpp" + "ranges": "cpp", + "thread": "cpp" } } \ No newline at end of file diff --git a/data_svelte/build/bundle.css.gz b/data_svelte/build/bundle.css.gz index c361c2f9..bf923a99 100644 Binary files a/data_svelte/build/bundle.css.gz and b/data_svelte/build/bundle.css.gz differ diff --git a/data_svelte/build/bundle.js.gz b/data_svelte/build/bundle.js.gz index 06ffd07e..52ed0f77 100644 Binary files a/data_svelte/build/bundle.js.gz and b/data_svelte/build/bundle.js.gz differ diff --git a/data_svelte/index.html b/data_svelte/index.html index b036526e..f9d231aa 100644 --- a/data_svelte/index.html +++ b/data_svelte/index.html @@ -4,12 +4,12 @@ - IoT Manager 4.3.4 + IoT Manager 4.3.5 - + - + diff --git a/data_svelte/items.json b/data_svelte/items.json index 01d93319..dfc47a9c 100644 --- a/data_svelte/items.json +++ b/data_svelte/items.json @@ -7,7 +7,7 @@ "header": "Виртуальные элементы" }, { - "name": "1. Логирование в график", + "name": "1. График", "type": "Writing", "subtype": "Loging", "id": "log", @@ -20,7 +20,20 @@ "points": 300 }, { - "name": "2. Таймер", + "name": "2. График дневного расхода", + "type": "Writing", + "subtype": "LogingDaily", + "id": "log", + "widget": "chart3", + "page": "Графики", + "descr": "Температура", + "num": 2, + "int": 1, + "logid": "t", + "points": 365 + }, + { + "name": "3. Таймер", "type": "Writing", "subtype": "Timer", "id": "timer", @@ -32,10 +45,10 @@ "ticker": 1, "repeat": 1, "needSave": 0, - "num": 2 + "num": 3 }, { - "name": "3. Окно ввода числа (переменная)", + "name": "4. Окно ввода числа (переменная)", "type": "Reading", "subtype": "Variable", "id": "value", @@ -44,10 +57,10 @@ "descr": "Введите число", "int": "0", "val": "0.0", - "num": 3 + "num": 4 }, { - "name": "4. Окно ввода времени", + "name": "5. Окно ввода времени", "type": "Reading", "subtype": "Variable", "id": "time", @@ -56,10 +69,10 @@ "descr": "Введите время", "int": "0", "val": "02:00", - "num": 4 + "num": 5 }, { - "name": "5. Окно ввода даты", + "name": "6. Окно ввода даты", "type": "Reading", "subtype": "Variable", "id": "time", @@ -68,10 +81,10 @@ "descr": "Введите дату", "int": "0", "val": "24.05.2022", - "num": 5 + "num": 6 }, { - "name": "6. Окно ввода текста", + "name": "7. Окно ввода текста", "type": "Reading", "subtype": "Variable", "id": "txt", @@ -80,10 +93,10 @@ "descr": "Введите текст", "int": "0", "val": "текст", - "num": 6 + "num": 7 }, { - "name": "7. Виртуальная кнопка", + "name": "8. Виртуальная кнопка", "type": "Reading", "subtype": "VButton", "id": "vbtn", @@ -92,13 +105,13 @@ "descr": "Кнопка", "int": "0", "val": "0", - "num": 7 + "num": 8 }, { "header": "Сенсоры" }, { - "name": "8. Acs712 Ток", + "name": "9. Acs712 Ток", "type": "Reading", "subtype": "Acs712", "id": "amp", @@ -108,10 +121,10 @@ "round": 3, "pin": 39, "int": 5, - "num": 8 + "num": 9 }, { - "name": "9. AHT20 Температура", + "name": "10. AHT20 Температура", "type": "Reading", "subtype": "Aht20t", "id": "Temp20", @@ -121,10 +134,10 @@ "int": 15, "addr": "0x38", "round": 1, - "num": 9 + "num": 10 }, { - "name": "10. AHT20 Влажность", + "name": "11. AHT20 Влажность", "type": "Reading", "subtype": "Aht20h", "id": "Hum20", @@ -134,10 +147,10 @@ "int": 15, "addr": "0x38", "round": 1, - "num": 10 + "num": 11 }, { - "name": "11. Аналоговый сенсор", + "name": "12. Аналоговый сенсор", "type": "Reading", "subtype": "AnalogAdc", "id": "t", @@ -151,10 +164,10 @@ "pin": 0, "int": 15, "avgSteps": 1, - "num": 11 + "num": 12 }, { - "name": "12. BME280 Температура", + "name": "13. BME280 Температура", "type": "Reading", "subtype": "Bme280t", "id": "tmp3", @@ -164,10 +177,10 @@ "int": 15, "addr": "0x77", "round": 1, - "num": 12 + "num": 13 }, { - "name": "13. BME280 Давление", + "name": "14. BME280 Давление", "type": "Reading", "subtype": "Bme280p", "id": "Press3", @@ -177,10 +190,10 @@ "int": 15, "addr": "0x77", "round": 1, - "num": 13 + "num": 14 }, { - "name": "14. BME280 Влажность", + "name": "15. BME280 Влажность", "type": "Reading", "subtype": "Bme280h", "id": "Hum3", @@ -190,10 +203,10 @@ "int": 15, "addr": "0x77", "round": 1, - "num": 14 + "num": 15 }, { - "name": "15. BMP280 Температура", + "name": "16. BMP280 Температура", "type": "Reading", "subtype": "Bmp280t", "id": "tmp3", @@ -203,10 +216,10 @@ "int": 15, "addr": "0x77", "round": 1, - "num": 15 + "num": 16 }, { - "name": "16. BMP280 Давление", + "name": "17. BMP280 Давление", "type": "Reading", "subtype": "Bmp280p", "id": "Press3", @@ -216,10 +229,10 @@ "int": 15, "addr": "0x77", "round": 1, - "num": 16 + "num": 17 }, { - "name": "17. DHT11 Температура", + "name": "18. DHT11 Температура", "type": "Reading", "subtype": "Dht1122t", "id": "tmp3", @@ -229,10 +242,10 @@ "int": 15, "pin": 0, "senstype": "dht11", - "num": 17 + "num": 18 }, { - "name": "18. DHT11 Влажность", + "name": "19. DHT11 Влажность", "type": "Reading", "subtype": "Dht1122h", "id": "Hum3", @@ -242,10 +255,10 @@ "int": 15, "pin": 0, "senstype": "dht11", - "num": 18 + "num": 19 }, { - "name": "19. DS18B20 Температура", + "name": "20. DS18B20 Температура", "type": "Reading", "subtype": "Ds18b20", "id": "dstmp", @@ -257,10 +270,10 @@ "index": 0, "addr": "", "round": 1, - "num": 19 + "num": 20 }, { - "name": "20. GY21 Температура", + "name": "21. GY21 Температура", "type": "Reading", "subtype": "GY21t", "id": "tmp4", @@ -269,10 +282,10 @@ "descr": "Температура", "round": 1, "int": 15, - "num": 20 + "num": 21 }, { - "name": "21. GY21 Влажность", + "name": "22. GY21 Влажность", "type": "Reading", "subtype": "GY21h", "id": "Hum4", @@ -281,10 +294,10 @@ "descr": "Влажность", "round": 1, "int": 15, - "num": 21 + "num": 22 }, { - "name": "22. HDC1080 Температура", + "name": "23. HDC1080 Температура", "type": "Reading", "subtype": "Hdc1080t", "id": "Temp1080", @@ -294,10 +307,10 @@ "int": 15, "addr": "0x40", "round": 1, - "num": 22 + "num": 23 }, { - "name": "23. HDC1080 Влажность", + "name": "24. HDC1080 Влажность", "type": "Reading", "subtype": "Hdc1080h", "id": "Hum1080", @@ -307,10 +320,10 @@ "int": 15, "addr": "0x40", "round": 1, - "num": 23 + "num": 24 }, { - "name": "24. MAX6675 Температура", + "name": "25. MAX6675 Температура", "type": "Reading", "subtype": "Max6675t", "id": "maxtmp", @@ -321,10 +334,10 @@ "DO": 12, "CS": 13, "CLK": 14, - "num": 24 + "num": 25 }, { - "name": "25. PZEM 004t Напряжение", + "name": "26. PZEM 004t Напряжение", "type": "Reading", "subtype": "Pzem004v", "id": "v", @@ -333,10 +346,10 @@ "descr": "Напряжение", "int": 15, "addr": "0xF8", - "num": 25 + "num": 26 }, { - "name": "26. PZEM 004t Сила тока", + "name": "27. PZEM 004t Сила тока", "type": "Reading", "subtype": "Pzem004a", "id": "a", @@ -345,10 +358,10 @@ "descr": "Сила тока", "int": 15, "addr": "0xF8", - "num": 26 + "num": 27 }, { - "name": "27. PZEM 004t Мощность", + "name": "28. PZEM 004t Мощность", "type": "Reading", "subtype": "Pzem004w", "id": "w", @@ -357,10 +370,10 @@ "descr": "Мощность", "int": 15, "addr": "0xF8", - "num": 27 + "num": 28 }, { - "name": "28. PZEM 004t Энергия", + "name": "29. PZEM 004t Энергия", "type": "Reading", "subtype": "Pzem004wh", "id": "wh", @@ -369,10 +382,10 @@ "descr": "Энергия", "int": 15, "addr": "0xF8", - "num": 28 + "num": 29 }, { - "name": "29. PZEM 004t Частота", + "name": "30. PZEM 004t Частота", "type": "Reading", "subtype": "Pzem004hz", "id": "hz", @@ -381,11 +394,11 @@ "descr": "Частота", "int": 15, "addr": "0xF8", - "num": 29 + "num": 30 }, { - "name": "30. Сканер кнопок 433 MHz", - "num": 30, + "name": "31. Сканер кнопок 433 MHz", + "num": 31, "type": "Reading", "subtype": "RCswitch", "id": "rsw", @@ -394,7 +407,7 @@ "pinTx": 12 }, { - "name": "31. Sht20 Температура", + "name": "32. Sht20 Температура", "type": "Reading", "subtype": "Sht20t", "id": "tmp2", @@ -403,10 +416,10 @@ "descr": "Температура", "int": 15, "round": 1, - "num": 31 + "num": 32 }, { - "name": "32. Sht20 Влажность", + "name": "33. Sht20 Влажность", "type": "Reading", "subtype": "Sht20h", "id": "Hum2", @@ -415,10 +428,10 @@ "descr": "Влажность", "int": 15, "round": 1, - "num": 32 + "num": 33 }, { - "name": "33. Sht30 Температура", + "name": "34. Sht30 Температура", "type": "Reading", "subtype": "Sht30t", "id": "tmp30", @@ -427,10 +440,10 @@ "descr": "SHT30 Температура", "int": 15, "round": 1, - "num": 33 + "num": 34 }, { - "name": "34. Sht30 Влажность", + "name": "35. Sht30 Влажность", "type": "Reading", "subtype": "Sht30h", "id": "Hum30", @@ -439,11 +452,11 @@ "descr": "SHT30 Влажность", "int": 15, "round": 1, - "num": 34 + "num": 35 }, { - "name": "35. HC-SR04 Ультразвуковой дальномер", - "num": 35, + "name": "36. HC-SR04 Ультразвуковой дальномер", + "num": 36, "type": "Reading", "subtype": "Sonar", "id": "sonar", @@ -455,7 +468,7 @@ "int": 5 }, { - "name": "36. UART", + "name": "37. UART", "type": "Reading", "subtype": "UART", "page": "", @@ -465,13 +478,13 @@ "tx": 12, "rx": 13, "speed": 9600, - "num": 36 + "num": 37 }, { "header": "Исполнительные устройства" }, { - "name": "37. Кнопка подключенная к пину", + "name": "38. Кнопка подключенная к пину", "type": "Writing", "subtype": "ButtonIn", "id": "btn", @@ -484,10 +497,10 @@ "pinMode": "INPUT", "debounceDelay": 50, "fixState": 0, - "num": 37 + "num": 38 }, { - "name": "38. Управление пином", + "name": "39. Управление пином", "type": "Writing", "subtype": "ButtonOut", "id": "btn", @@ -497,10 +510,10 @@ "int": 0, "inv": 0, "pin": 2, - "num": 38 + "num": 39 }, { - "name": "39. Сервопривод", + "name": "40. Сервопривод", "type": "Writing", "subtype": "IoTServo", "id": "servo", @@ -511,10 +524,10 @@ "pin": 12, "apin": -1, "amap": "0, 4096, 0, 180", - "num": 39 + "num": 40 }, { - "name": "40. Расширитель портов Mcp23017", + "name": "41. Расширитель портов Mcp23017", "type": "Reading", "subtype": "Mcp23017", "id": "Mcp", @@ -524,10 +537,10 @@ "int": "0", "addr": "0x20", "index": 1, - "num": 40 + "num": 41 }, { - "name": "41. MP3 плеер", + "name": "42. MP3 плеер", "type": "Reading", "subtype": "Mp3", "id": "mp3", @@ -537,10 +550,10 @@ "int": 1, "pins": "14,12", "volume": 20, - "num": 41 + "num": 42 }, { - "name": "42. PWM ESP8266", + "name": "43. PWM ESP8266", "type": "Writing", "subtype": "Pwm8266", "id": "pwm", @@ -552,10 +565,10 @@ "freq": 5000, "val": 0, "apin": -1, - "num": 42 + "num": 43 }, { - "name": "43. Телеграм-Лайт", + "name": "44. Телеграм-Лайт", "type": "Writing", "subtype": "TelegramLT", "id": "tg", @@ -564,13 +577,13 @@ "descr": "", "token": "", "chatID": "", - "num": 43 + "num": 44 }, { "header": "Экраны" }, { - "name": "44. LCD экран 2004", + "name": "45. LCD экран 2004", "type": "Reading", "subtype": "Lcd2004", "id": "Lcd", @@ -582,10 +595,10 @@ "size": "20,4", "coord": "0,0", "id2show": "id датчика", - "num": 44 + "num": 45 }, { - "name": "45. LCD экран 1602", + "name": "46. LCD экран 1602", "type": "Reading", "subtype": "Lcd2004", "id": "Lcd", @@ -597,6 +610,6 @@ "size": "16,2", "coord": "0,0", "id2show": "id датчика", - "num": 45 + "num": 46 } ] \ No newline at end of file diff --git a/data_svelte/widgets.json b/data_svelte/widgets.json index b4cf75cd..cab0dbe2 100644 --- a/data_svelte/widgets.json +++ b/data_svelte/widgets.json @@ -47,7 +47,7 @@ "name": "anydataWth", "label": "Энергия", "widget": "anydata", - "after": "Wt/Hr", + "after": "kWt/Hr", "icon": "speedometer" }, { @@ -103,34 +103,27 @@ }, { "name": "chart1", - "label": "График1", + "label": "График без точек", "widget": "chart", "dateFormat": "HH:mm", - "maxCount": 255, + "maxCount": 86400, "pointRadius": 0 }, { "name": "chart2", - "label": "График2", + "label": "График с точками", "widget": "chart", - "maxCount": 255, + "maxCount": 86400, "dateFormat": "HH:mm" }, { "name": "chart3", - "label": "График3", + "label": "График Дневной", "widget": "chart", "dateFormat": "DD.MM.YYYY", - "maxCount": 255, + "maxCount": 86400, "type": "bar" }, - { - "name": "chart4", - "label": "График4", - "widget": "chart", - "maxCount": 255, - "dateFormat": "DD.MM.YYYY" - }, { "name": "fillgauge", "label": "Бочка", diff --git a/include/Const.h b/include/Const.h index a164f11a..6e328d7d 100644 --- a/include/Const.h +++ b/include/Const.h @@ -1,7 +1,7 @@ #pragma once //Версия прошивки -#define FIRMWARE_VERSION 426 +#define FIRMWARE_VERSION 427 #ifdef esp8266_4mb #define FIRMWARE_NAME "esp8266_4mb" diff --git a/myProfile.json b/myProfile.json index 80009947..5a5f56cd 100644 --- a/myProfile.json +++ b/myProfile.json @@ -28,7 +28,11 @@ "modules": { "Виртуальные элементы": [ { - "path": "src\\modules\\virtual\\Logging", + "path": "src\\modules\\virtual\\Loging", + "active": true + }, + { + "path": "src\\modules\\virtual\\LogingDaily", "active": true }, { diff --git a/platformio.ini b/platformio.ini index 44b4403e..49db09ca 100644 --- a/platformio.ini +++ b/platformio.ini @@ -71,7 +71,8 @@ lib_deps = dfrobot/DFRobotDFPlayerMini @ ^1.0.5 marcoschwartz/LiquidCrystal_I2C@^1.1.4 build_src_filter = - + + + + + + + + diff --git a/src/MqttClient.cpp b/src/MqttClient.cpp index 52902620..8d9bfa88 100644 --- a/src/MqttClient.cpp +++ b/src/MqttClient.cpp @@ -134,9 +134,10 @@ void mqttCallback(char* topic, uint8_t* payload, size_t length) { publishWidgets(); publishState(); + //обращение к логированию из ядра //отправка данных графиков for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { - if ((*it)->getSubtype() == "Loging") { + if ((*it)->getSubtype() == "Loging" || "LogingDaily") { (*it)->setPublishDestination(TO_MQTT); (*it)->publishValue(); } diff --git a/src/WsServer.cpp b/src/WsServer.cpp index 256f0a8b..80f09870 100644 --- a/src/WsServer.cpp +++ b/src/WsServer.cpp @@ -73,13 +73,14 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) //отвечаем на запрос графиков if (headerStr == "/charts|") { + //обращение к логированию из ядра //отправка данных графиков только в выбранный сокет for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { //сбрасываем даты графиков // if ((*it)->getID().endsWith("-date")) { // (*it)->setTodayDate(); //} - if ((*it)->getSubtype() == "Loging") { + if ((*it)->getSubtype() == "Loging" || "LogingDaily") { (*it)->setPublishDestination(TO_WS, num); (*it)->publishValue(); } diff --git a/src/modules/API.cpp b/src/modules/API.cpp index 98f4489d..467f8588 100644 --- a/src/modules/API.cpp +++ b/src/modules/API.cpp @@ -1,6 +1,7 @@ #include "ESPConfiguration.h" void* getAPI_Loging(String subtype, String params); +void* getAPI_LogingDaily(String subtype, String params); void* getAPI_Timer(String subtype, String params); void* getAPI_Variable(String subtype, String params); void* getAPI_VButton(String subtype, String params); @@ -32,6 +33,7 @@ void* getAPI_Lcd2004(String subtype, String params); void* getAPI(String subtype, String params) { void* tmpAPI; if ((tmpAPI = getAPI_Loging(subtype, params)) != nullptr) return tmpAPI; +if ((tmpAPI = getAPI_LogingDaily(subtype, params)) != nullptr) return tmpAPI; if ((tmpAPI = getAPI_Timer(subtype, params)) != nullptr) return tmpAPI; if ((tmpAPI = getAPI_Variable(subtype, params)) != nullptr) return tmpAPI; if ((tmpAPI = getAPI_VButton(subtype, params)) != nullptr) return tmpAPI; diff --git a/src/modules/virtual/Logging/Loging.cpp b/src/modules/virtual/Loging/Loging.cpp similarity index 100% rename from src/modules/virtual/Logging/Loging.cpp rename to src/modules/virtual/Loging/Loging.cpp diff --git a/src/modules/virtual/Logging/modinfo.json b/src/modules/virtual/Loging/modinfo.json similarity index 79% rename from src/modules/virtual/Logging/modinfo.json rename to src/modules/virtual/Loging/modinfo.json index 42f2e768..354fb517 100644 --- a/src/modules/virtual/Logging/modinfo.json +++ b/src/modules/virtual/Loging/modinfo.json @@ -2,7 +2,7 @@ "menuSection": "Виртуальные элементы", "configItem": [ { - "name": "Логирование в график", + "name": "График", "type": "Writing", "subtype": "Loging", "id": "log", @@ -24,7 +24,7 @@ "moduleVersion": "3.0", "usedRam": 15, "title": "Логирование в график", - "moduleDesc": "Расширение позволяющее логировать любую величину в график. Графики доступны в мобильном приложении и в веб интерфейсе. Данные графиков хранятся в встроенной памяти esp. В окне ввода даты нужно выбрать день, историю которого вы хотите посмотреть. Старые файлы будут удаляться автоматически после того как объем оставшейся flesh памяти устройства будет менее 20 процентов", + "moduleDesc": "Расширение позволяющее логировать любую величину в график. Графики доступны в мобильном приложении и в веб интерфейсе. Данные графиков хранятся в встроенной памяти esp. В окне ввода даты можно выбирать день, историю которого вы хотите посмотреть. Старые файлы будут удаляться автоматически после того как объем оставшейся flesh памяти устройства будет менее 20 процентов", "propInfo": { "int": "Интервал логирования в мнутах, рекомендуется для esp8266 использоать интервал не менее 5-ти минут", "logid": "ID величины которую будем логировать", diff --git a/src/modules/virtual/LogingDaily/LogingDaily.cpp b/src/modules/virtual/LogingDaily/LogingDaily.cpp new file mode 100644 index 00000000..62e82e0d --- /dev/null +++ b/src/modules/virtual/LogingDaily/LogingDaily.cpp @@ -0,0 +1,282 @@ +#include "Global.h" +#include "classes/IoTItem.h" +#include "ESPConfiguration.h" +#include "NTP.h" + +class LogingDaily : public IoTItem { + private: + String logid; + String id; + String filesList = ""; + + int _publishType = -2; + int _wsNum = -1; + + int points; + + IoTItem *dateIoTItem; + + String prevDate = ""; + bool firstTimeDate = true; + + unsigned long interval; + + public: + LogingDaily(String parameters) : IoTItem(parameters) { + jsonRead(parameters, F("logid"), logid); + jsonRead(parameters, F("id"), id); + jsonRead(parameters, F("points"), points); + + if (points > 365) { + points = 365; + SerialPrint("E", F("LogingDaily"), "'" + id + "' user set more points than allowed, value reset to 365"); + } + jsonRead(parameters, F("int"), interval); + interval = interval * 1000 * 60; //приводим к милисекундам + } + + void doByInterval() { + if (hasDayChanged()) { + execute(); + } + } + + void execute() { + //если объект логгирования не был создан + if (!isItemExist(logid)) { + SerialPrint("E", F("LogingDaily"), "'" + id + "' LogingDaily object not exist, return"); + return; + } + + String value = getItemValue(logid); + + //если значение логгирования пустое + if (value == "") { + SerialPrint("E", F("LogingDaily"), "'" + id + "' LogingDaily value is empty, return"); + return; + } + + //если время не было получено из интернета + if (!isTimeSynch) { + SerialPrint("E", F("LogingDaily"), "'" + id + "' Сant LogingDaily - time not synchronized, return"); + return; + } + + String logData; + + float currentValue = value.toFloat(); + //прочитаем предудущее значение + float prevValue = readDataDB(id + "-v").toFloat(); + //сохраним в базу данных текущее значение, понадобится в следующие сутки + saveDataDB(id + "-v", value); + + float difference = currentValue - prevValue; + + jsonWriteInt(logData, "x", unixTime); + jsonWriteFloat(logData, "y1", difference); + + //прочитаем путь к файлу последнего сохранения + String filePath = readDataDB(id); + + //если данные о файле отсутствуют, создадим новый + if (filePath == "failed" || filePath == "") { + SerialPrint("E", F("LogingDaily"), "'" + id + "' file path not found, start create new file"); + createNewFileWithData(logData); + return; + } + + //считаем количество строк и определяем размер файла + size_t size = 0; + int lines = countJsonObj(filePath, size); + SerialPrint("i", F("LogingDaily"), "'" + id + "' " + "lines = " + String(lines) + ", size = " + String(size)); + + //если количество строк до заданной величины и дата не менялась + if (lines <= points && !hasDayChanged()) { + //просто добавим в существующий файл новые данные + addNewDataToExistingFile(filePath, logData); + //если больше или поменялась дата то создадим следующий файл + } else { + createNewFileWithData(logData); + } + } + + void createNewFileWithData(String &logData) { + logData = logData + ","; + + String path = "/lgd/" + id + "/" + id + ".txt"; //создадим путь вида /lgd/id/id.txt + //создадим пустой файл + if (writeEmptyFile(path) != "sucсess") { + SerialPrint("E", F("LogingDaily"), "'" + id + "' file writing error, return"); + return; + } + + //запишем в него данные + if (addFile(path, logData) != "sucсess") { + SerialPrint("E", F("LogingDaily"), "'" + id + "' data writing error, return"); + return; + } + //запишем путь к нему в базу данных + if (saveDataDB(id, path) != "sucсess") { + SerialPrint("E", F("LogingDaily"), "'" + id + "' db file writing error, return"); + return; + } + SerialPrint("i", F("LogingDaily"), "'" + id + "' file created http://" + WiFi.localIP().toString() + path); + } + + void addNewDataToExistingFile(String &path, String &logData) { + logData = logData + ","; + if (addFile(path, logData) != "sucсess") { + SerialPrint("i", F("LogingDaily"), "'" + id + "' file writing error, return"); + return; + }; + SerialPrint("i", F("LogingDaily"), "'" + id + "' LogingDaily in file http://" + WiFi.localIP().toString() + path); + } + + bool hasDayChanged() { + bool changed = false; + String currentDate = getTodayDateDotFormated(); + if (!firstTimeDate) { + if (prevDate != currentDate) { + changed = true; + SerialPrint("i", F("NTP"), "Change day event"); +#if defined(ESP8266) + FileFS.gc(); +#endif +#if defined(ESP32) +#endif + } + } + firstTimeDate = false; + prevDate = currentDate; + return changed; + } + + void publishValue() { + String dir = "/lgd/" + id; + filesList = getFilesList(dir); + + SerialPrint("i", F("LogingDaily"), "file list: " + filesList); + + int f = 0; + + while (filesList.length()) { + String path = selectToMarker(filesList, ";"); + + path = "/lgd/" + id + path; + + f++; + + if (_publishType == TO_MQTT) { + publishChartFileToMqtt(path); + } else if (_publishType == TO_WS) { + publishChartToWs(path, _wsNum, 1000); + } else if (_publishType == TO_MQTT_WS) { + publishChartFileToMqtt(path); + publishChartToWs(path, _wsNum, 1000); + } + SerialPrint("i", F("LogingDaily"), String(f) + ") " + path + ", sent"); + + filesList = deleteBeforeDelimiter(filesList, ";"); + } + } + + void clearHistory() { + String dir = "/lgd/" + id; + cleanDirectory(dir); + } + + bool publishChartFileToMqtt(String path) { + File configFile = FileFS.open(path, FILE_READ); + if (!configFile) { + SerialPrint("E", F("LogingDaily"), path + " file reading error, json not created, return"); + return false; + } + String oneSingleJson = configFile.readString(); + configFile.close(); + String topic = mqttRootDevice + "/" + id; + oneSingleJson = "{\"maxCount\":" + String(calculateMaxCount()) + ",\"topic\":\"" + topic + "\",\"status\":[" + oneSingleJson + "]}"; + oneSingleJson.replace("},]}", "}]}"); + SerialPrint("i", "LogingDaily", "json size: " + String(oneSingleJson.length())); + publishChartMqtt(id, oneSingleJson); + return true; + } + + //особая функция отправки графиков в веб + void publishChartToWs(String filename, int num, size_t frameSize) { + String json; + jsonWriteStr(json, "topic", mqttRootDevice + "/" + id); + jsonWriteInt(json, "maxCount", calculateMaxCount()); + + String st = "/st/chart.json|"; + if (num == -1) { + standWebSocket.broadcastTXT(st); + } else { + standWebSocket.sendTXT(num, st); + } + String path = filepath(filename); + auto file = FileFS.open(path, "r"); + if (!file) { + SerialPrint(F("E"), F("FS"), F("reed file error")); + return; + } + size_t fileSize = file.size(); + SerialPrint(F("i"), F("FS"), "Send file '" + String(filename) + "', file size: " + String(fileSize)); + uint8_t payload[frameSize]; + int countRead = file.read(payload, sizeof(payload)); + while (countRead > 0) { + if (num == -1) { + standWebSocket.broadcastBIN(payload, countRead); + } else { + standWebSocket.sendBIN(num, payload, countRead); + } + countRead = file.read(payload, sizeof(payload)); + } + file.close(); + String end = "/end/chart.json|" + json; + if (num == -1) { + standWebSocket.broadcastTXT(end); + } else { + standWebSocket.sendTXT(num, end); + } + } + + void publishChartToWsSinglePoint(String value) { + String topic = mqttRootDevice + "/" + id; + String json = "{\"maxCount\":" + String(calculateMaxCount()) + ",\"topic\":\"" + topic + "\",\"status\":[{\"x\":" + String(unixTime) + ",\"y1\":" + value + "}]}"; + String pk = "/string/chart.json|" + json; + standWebSocket.broadcastTXT(pk); + } + + void setPublishDestination(int publishType, int wsNum = -1) { + _publishType = publishType; + _wsNum = wsNum; + } + + String getValue() { + return ""; + } + + void loop() { + if (enableDoByInt) { + currentMillis = millis(); + difference = currentMillis - prevMillis; + if (difference >= interval) { + prevMillis = millis(); + this->doByInterval(); + } + } + } + + //просто максимальное количество точек + int calculateMaxCount() { + return 86400; + } +}; + +void *getAPI_LogingDaily(String subtype, String param) { + if (subtype == F("LogingDaily")) { + return new LogingDaily(param); + } else { + return nullptr; + } +} diff --git a/src/modules/virtual/LogingDaily/modinfo.json b/src/modules/virtual/LogingDaily/modinfo.json new file mode 100644 index 00000000..ed6fe3c3 --- /dev/null +++ b/src/modules/virtual/LogingDaily/modinfo.json @@ -0,0 +1,39 @@ +{ + "menuSection": "Виртуальные элементы", + "configItem": [ + { + "name": "График дневного расхода", + "type": "Writing", + "subtype": "LogingDaily", + "id": "log", + "widget": "chart3", + "page": "Графики", + "descr": "Температура", + "num": 1, + "int": 1, + "logid": "t", + "points": 365 + } + ], + "about": { + "authorName": "Dmitry Borisenko", + "authorContact": "https://t.me/Dmitry_Borisenko", + "authorGit": "https://github.com/DmitryBorisenko33", + "specialThanks": "@itsid1 @Valiuhaaa Serg", + "moduleName": "LogingDaily", + "moduleVersion": "3.0", + "usedRam": 15, + "title": "График дневного расхода", + "moduleDesc": "Расширение позволяющее логировать накопительные величины и видеть их дневное изменение. Графики доступны в мобильном приложении и в веб интерфейсе. Данные графиков хранятся в встроенной памяти esp", + "propInfo": { + "int": "Интервал логирования в мнутах, частота проверки смены суток в минутах. Не рекомендуется менять", + "logid": "ID накопительной величины которую будем логировать", + "points": "Максимальное количество точек" + } + }, + "defActive": true, + "devices": { + "esp32_4mb": [], + "esp8266_4mb": [] + } +} \ No newline at end of file diff --git a/src/utils/FileUtils.cpp b/src/utils/FileUtils.cpp index f9698874..f7f33332 100644 --- a/src/utils/FileUtils.cpp +++ b/src/utils/FileUtils.cpp @@ -214,9 +214,10 @@ String readDataDB(String id) { void cleanLogs() { SerialPrint("i", "Files", "cleanLogs"); cleanDirectory("/db"); + //обращение к логированию из ядра //очистка данных всех экземпляров графиков for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { - if ((*it)->getSubtype() == "Loging") { + if ((*it)->getSubtype() == "Loging" || "LogingDaily") { (*it)->clearHistory(); } }