Files
IoTManager/src/modules/virtual/Loging2/Loging2.cpp
2025-03-28 22:47:10 +03:00

496 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "Global.h"
#include "classes/IoTItem.h"
#include "ESPConfiguration.h"
#include "NTP.h"
void *getAPI_Date2(String params);
class Loging2 : public IoTItem
{
private:
String logid1;
String logid2;
String id;
String tmpValue;
String filesList = "";
int _publishType = -2;
int _wsNum = -1;
int points;
// int keepdays;
IoTItem *dateIoTItem;
String prevDate = "";
bool firstTimeInit = true;
// long interval;
public:
Loging2(String parameters) : IoTItem(parameters)
{
jsonRead(parameters, F("logid1"), logid1);
jsonRead(parameters, F("logid2"), logid2);
jsonRead(parameters, F("id"), id);
jsonRead(parameters, F("points"), points);
if (points > 300)
{
points = 300;
SerialPrint("E", F("Loging2"), "'" + id + "' user set more points than allowed, value reset to 300");
}
long interval;
jsonRead(parameters, F("int"), interval); // в минутах
setInterval(interval * 60);
// jsonRead(parameters, F("keepdays"), keepdays, false);
// создадим экземпляр класса даты
dateIoTItem = (IoTItem *)getAPI_Date2("{\"id\": \"" + id + "-date\",\"int\":\"20\",\"subtype\":\"date\"}");
IoTItems.push_back(dateIoTItem);
SerialPrint("I", F("Loging2"), "created date instance " + id);
}
void doByInterval()
{
// если объект логгирования не был создан
if (!isItemExist(logid1))
{
SerialPrint("E", F("Loging2"), "'" + id + "' loging object not exist, return");
return;
}
String value = getItemValue(logid1);
// если значение логгирования пустое
if (value == "")
{
SerialPrint("E", F("Loging2"), "'" + id + "' loging value is empty, return");
return;
}
String value2 = getItemValue(logid2);
// если значение логгирования пустое
if (value == "")
{
SerialPrint("E", F("Loging2"), "'" + id + "' loging value is empty, return");
return;
}
// если время не было получено из интернета
if (!isTimeSynch)
{
SerialPrint("E", F("Loging2"), "'" + id + "' Сant loging - time not synchronized, return");
return;
}
regEvent(value, F("Loging2"));
String logData2;
jsonWriteInt(logData2, "x", unixTime, false);
jsonWriteFloat(logData2, "y1", value.toFloat(), false);
jsonWriteFloat(logData2, "y2", value2.toFloat(), false);
// прочитаем путь к файлу последнего сохранения
String filePath = readDataDB(id);
// если данные о файле отсутствуют, создадим новый
if (filePath == "failed" || filePath == "")
{
SerialPrint("E", F("Loging2"), "'" + id + "' file path not found, start create new file");
createNewFileWithData(logData2);
return;
}
else
{
// если файл все же есть но был создан не сегодня, то создаем сегодняшний
if (getTodayDateDotFormated() != getDateDotFormatedFromUnix(getFileUnixLocalTime(filePath)))
{
SerialPrint("E", F("Loging2"), "'" + id + "' file too old, start create new file");
createNewFileWithData(logData2);
return;
}
}
// считаем количество строк и определяем размер файла
size_t size = 0;
int lines = countJsonObj(filePath, size);
SerialPrint("i", F("Loging2"), "'" + id + "' " + "lines = " + String(lines) + ", size = " + String(size));
// если количество строк до заданной величины и дата не менялась
if (lines <= points && !hasDayChanged())
{
// просто добавим в существующий файл новые данные
addNewDataToExistingFile(filePath, logData2);
// если больше или поменялась дата то создадим следующий файл
}
else
{
createNewFileWithData(logData2);
}
// запускаем процедуру удаления старых файлов если память переполняется
deleteLastFile();
}
/*
void SetDoByInterval(String valse)
{
String value = valse;
// если значение логгирования пустое
if (value == "")
{
SerialPrint("E", F("Loging2Event"), "'" + id + "' loging value is empty, return");
return;
}
// если время не было получено из интернета
if (!isTimeSynch)
{
SerialPrint("E", F("Loging2Event"), "'" + id + "' Сant loging - time not synchronized, return");
return;
}
regEvent(value, F("Loging2Event"));
String logData2;
jsonWriteInt(logData2, "x", unixTime, false);
jsonWriteFloat(logData2, "y1", value.toFloat(), false);
jsonWriteFloat(logData2, "y2", value.toFloat(), false);
// прочитаем путь к файлу последнего сохранения
String filePath = readDataDB(id);
// если данные о файле отсутствуют, создадим новый
if (filePath == "failed" || filePath == "")
{
SerialPrint("E", F("Loging2Event"), "'" + id + "' file path not found, start create new file");
createNewFileWithData(logData2);
return;
}
else
{
// если файл все же есть но был создан не сегодня, то создаем сегодняшний
if (getTodayDateDotFormated() != getDateDotFormatedFromUnix(getFileUnixLocalTime(filePath)))
{
SerialPrint("E", F("Loging2Event"), "'" + id + "' file too old, start create new file");
createNewFileWithData(logData2);
return;
}
}
// считаем количество строк и определяем размер файла
size_t size = 0;
int lines = countJsonObj(filePath, size);
SerialPrint("i", F("Loging2Event"), "'" + id + "' " + "lines = " + String(lines) + ", size = " + String(size));
// если количество строк до заданной величины и дата не менялась
if (lines <= points && !hasDayChanged())
{
// просто добавим в существующий файл новые данные
addNewDataToExistingFile(filePath, logData2);
// если больше или поменялась дата то создадим следующий файл
}
else
{
createNewFileWithData(logData2);
}
// запускаем процедуру удаления старых файлов если память переполняется
deleteLastFile();
}
*/
void createNewFileWithData(String &logData)
{
logData = logData + ",";
String path = "/lg2/" + id + "/" + String(unixTimeShort) + ".txt"; // создадим путь вида /lg/id/133256622333.txt
// создадим пустой файл
if (writeEmptyFile(path) != "success")
{
SerialPrint("E", F("Loging2"), "'" + id + "' file writing error, return");
return;
}
// запишем в него данные
if (addFile(path, logData) != "success")
{
SerialPrint("E", F("Loging2"), "'" + id + "' data writing error, return");
return;
}
// запишем путь к нему в базу данных
if (saveDataDB(id, path) != "success")
{
SerialPrint("E", F("Loging2"), "'" + id + "' db file writing error, return");
return;
}
SerialPrint("i", F("Loging2"), "'" + id + "' file created http://" + WiFi.localIP().toString() + path);
}
void addNewDataToExistingFile(String &path, String &logData)
{
logData = logData + ",";
if (addFile(path, logData) != "success")
{
SerialPrint("i", F("Loging2"), "'" + id + "' file writing error, return");
return;
};
SerialPrint("i", F("Loging2"), "'" + id + "' loging in file http://" + WiFi.localIP().toString() + path);
}
// данная функция уже перенесена в ядро и будет удалена в последствии
bool hasDayChanged()
{
bool changed = false;
String currentDate = getTodayDateDotFormated();
if (!firstTimeInit)
{
if (prevDate != currentDate)
{
changed = true;
SerialPrint("i", F("NTP"), F("Change day event"));
#if defined(ESP8266)
FileFS.gc();
#endif
#if defined(ESP32)
#endif
}
}
firstTimeInit = false;
prevDate = currentDate;
return changed;
}
void publishValue()
{
String dir = "/lg2/" + id;
filesList = getFilesList(dir);
SerialPrint("i", F("Loging2"), "file list: " + filesList);
int f = 0;
bool noData = true;
while (filesList.length())
{
String path = selectToMarker(filesList, ";");
path = "/lg2/" + id + path;
f++;
unsigned long fileUnixTimeLocal = getFileUnixLocalTime(path);
unsigned long reqUnixTime = strDateToUnix(getItemValue(id + "-date"));
if (fileUnixTimeLocal > reqUnixTime && fileUnixTimeLocal < reqUnixTime + 86400)
{
noData = false;
String json = getAdditionalJson();
if (_publishType == TO_MQTT)
{
publishChartFileToMqtt(path, id, calculateMaxCount());
}
else if (_publishType == TO_WS)
{
sendFileToWsByFrames(path, "charta", json, _wsNum, WEB_SOCKETS_FRAME_SIZE);
}
else if (_publishType == TO_MQTT_WS)
{
sendFileToWsByFrames(path, "charta", json, _wsNum, WEB_SOCKETS_FRAME_SIZE);
publishChartFileToMqtt(path, id, calculateMaxCount());
}
SerialPrint("i", F("Loging2"), String(f) + ") " + path + ", " + getDateTimeDotFormatedFromUnix(fileUnixTimeLocal) + ", sent");
}
else
{
SerialPrint("i", F("Loging2"), String(f) + ") " + path + ", " + getDateTimeDotFormatedFromUnix(fileUnixTimeLocal) + ", skipped");
}
filesList = deleteBeforeDelimiter(filesList, ";");
}
// если данных нет отправляем пустой грфик
if (noData)
{
clearValue();
}
}
String getAdditionalJson()
{
String topic = mqttRootDevice + "/" + id;
String json = "{\"maxCount\":" + String(calculateMaxCount()) + ",\"topic\":\"" + topic + "\"}";
return json;
}
void publishChartToWsSinglePoint(String value)
{
String topic = mqttRootDevice + "/" + id;
String value2 = getItemValue(logid2);
String json = "{\"maxCount\":" + String(calculateMaxCount()) + ",\"topic\":\"" + topic + "\",\"status\":[{\"x\":" + String(unixTime) + ",\"y1\":" + value + ",\"y2\":" + value2 + "}]}";
sendStringToWs("chartb", json, -1);
}
void clearValue()
{
String topic = mqttRootDevice + "/" + id;
String json = "{\"maxCount\":0,\"topic\":\"" + topic + "\",\"status\":[]}";
sendStringToWs("chartb", json, -1);
}
void clearHistory()
{
String dir = "/lg2/" + id;
cleanDirectory(dir);
}
void deleteLastFile()
{
IoTFSInfo tmp = getFSInfo();
SerialPrint("i", "Loging2", String(tmp.freePer) + " % free flash remaining");
if (tmp.freePer <= 20.00)
{
String dir = "/lg/" + id;
filesList = getFilesList(dir);
int i = 0;
while (filesList.length())
{
String path = selectToMarker(filesList, ";");
path = dir + path;
i++;
if (i == 1)
{
removeFile(path);
SerialPrint("!", "Loging2", String(i) + ") " + path + " => oldest files been deleted");
return;
}
filesList = deleteBeforeDelimiter(filesList, ";");
}
}
}
void setPublishDestination(int publishType, int wsNum)
{
_publishType = publishType;
_wsNum = wsNum;
}
String getValue()
{
return "";
}
/*
void loop() {
if (enableDoByInt) {
currentMillis = millis();
difference = currentMillis - prevMillis;
if (difference >= interval) {
prevMillis = millis();
if (interval != 0) {
this->doByInterval();
}
}
}
}
*/
void regEvent(const String &value, const String &consoleInfo, bool error = false, bool genEvent = true)
{
String userDate = getItemValue(id + "-date");
String currentDate = getTodayDateDotFormated();
// отправляем в график данные только когда выбран сегодняшний день
if (userDate == currentDate)
{
// generateEvent(_id, value);
// publishStatusMqtt(_id, value);
publishChartToWsSinglePoint(value);
// SerialPrint("i", "Sensor " + consoleInfo, "'" + _id + "' data: " + value + "'");
}
}
// просто максимальное количество точек
int calculateMaxCount()
{
return 86400;
}
// путь вида: /lg/log/1231231.txt
unsigned long getFileUnixLocalTime(String path)
{
return gmtTimeToLocal(selectToMarkerLast(deleteToMarkerLast(path, "."), "/").toInt() + START_DATETIME);
}
/*
void setValue(const IoTValue &Value, bool genEvent = true)
{
value = Value;
this->SetDoByInterval(String(value.valD));
SerialPrint("i", "Loging2", "setValue:" + String(value.valD));
regEvent(value.valS, "Loging2", false, genEvent);
}
*/
};
void *getAPI_Loging2(String subtype, String param)
{
if (subtype == F("Loging2"))
{
return new Loging2(param);
}
else
{
return nullptr;
}
}
class Date : public IoTItem
{
private:
bool firstTime = true;
public:
String id;
Date(String parameters) : IoTItem(parameters)
{
jsonRead(parameters, F("id"), id);
value.isDecimal = false;
}
void setValue(const String &valStr, bool genEvent = true)
{
value.valS = valStr;
setValue(value, genEvent);
}
void setValue(const IoTValue &Value, bool genEvent = true)
{
value = Value;
regEvent(value.valS, "", false, genEvent);
// отправка данных при изменении даты
for (std::list<IoTItem *>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it)
{
if ((*it)->getSubtype() == "Loging2")
{
if ((*it)->getID() == selectToMarker(id, "-"))
{
(*it)->setPublishDestination(TO_MQTT_WS, -1);
(*it)->publishValue();
}
}
}
}
void setTodayDate()
{
setValue(getTodayDateDotFormated());
SerialPrint("E", F("Loging2"), "today date set " + getTodayDateDotFormated());
}
void doByInterval()
{
if (isTimeSynch)
{
if (firstTime)
{
setTodayDate();
firstTime = false;
}
}
}
};
void *getAPI_Date2(String param)
{
return new Date(param);
}