mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-27 14:42:18 +03:00
283 lines
9.7 KiB
C++
283 lines
9.7 KiB
C++
|
|
#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;
|
|||
|
|
}
|
|||
|
|
}
|