Files
IoTManager/src/Main.cpp
2025-03-27 22:19:36 +03:00

392 lines
14 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 "Main.h"
#include <time.h>
#include "classes/IoTDB.h"
#include "utils/Statistic.h"
#include "classes/IoTBench.h"
#ifndef LIBRETINY
#include <Wire.h>
#endif
#include "DebugTrace.h"
#if defined(ESP32)
#include <esp_task_wdt.h>
#endif
#if defined(esp32s2_4mb) || defined(esp32s3_16mb)
#include <USB.h>
#endif
IoTScenario iotScen; // объект управления сценарием
String volStrForSave = "";
// unsigned long currentMillis; // это сдесь лишнее
// unsigned long prevMillis;
void elementsLoop() {
// передаем управление каждому элементу конфигурации для выполнения своих функций
for (std::list<IoTItem *>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) {
if (benchTaskItem) benchTaskItem->preTaskFunction((*it)->getID());
(*it)->loop();
if (benchTaskItem) benchTaskItem->postTaskFunction((*it)->getID());
// if ((*it)->iAmDead) {
if (!((*it)->iAmLocal) && (*it)->getIntFromNet() == -1) {
delete *it;
IoTItems.erase(it);
break;
}
}
handleOrder();
handleEvent();
}
#define SETUPBASE_ERRORMARKER 0
#define SETUPCONF_ERRORMARKER 1
#define SETUPSCEN_ERRORMARKER 2
#define SETUPINET_ERRORMARKER 3
#define SETUPLAST_ERRORMARKER 4
#define TICKER_ERRORMARKER 5
#define HTTP_ERRORMARKER 6
#define SOCKETS_ERRORMARKER 7
#define MQTT_ERRORMARKER 8
#define MODULES_ERRORMARKER 9
#define COUNTER_ERRORMARKER 4 // количество шагов счетчика
#define STEPPER_ERRORMARKER 100000 // размер шага счетчика интервала доверия выполнения блока кода мкс
#if defined(esp32_4mb) || defined(esp32_4mb3f) || defined(esp32_16mb) || defined(esp32cam_4mb)
static int IRAM_ATTR initErrorMarkerId = 0; // ИД маркера
static int IRAM_ATTR errorMarkerId = 0;
static int IRAM_ATTR errorMarkerCounter = 0;
hw_timer_t *My_timer = NULL;
void IRAM_ATTR onTimer() {
if (errorMarkerCounter >= 0) {
if (errorMarkerCounter >= COUNTER_ERRORMARKER) {
errorMarkerId = initErrorMarkerId;
errorMarkerCounter = -1;
} else
errorMarkerCounter++;
}
}
#endif
void initErrorMarker(int id) {
#if defined(esp32_4mb) || defined(esp32_4mb3f) || defined(esp32_16mb) || defined(esp32cam_4mb)
initErrorMarkerId = id;
errorMarkerCounter = 0;
#endif
}
void stopErrorMarker(int id) {
#if defined(esp32_4mb) || defined(esp32_4mb3f) || defined(esp32_16mb) || defined(esp32cam_4mb)
errorMarkerCounter = -1;
if (errorMarkerId)
SerialPrint("I", "WARNING!", "A lazy (freezing loop more than " + (String)(COUNTER_ERRORMARKER * STEPPER_ERRORMARKER / 1000) + " ms) section has been found! With ID=" + (String)errorMarkerId);
errorMarkerId = 0;
initErrorMarkerId = 0;
#endif
}
void setup() {
#if defined(esp32s2_4mb) || defined(esp32s3_16mb)
USB.begin();
#endif
#if defined(esp32_4mb) || defined(esp32_4mb3f) || defined(esp32_16mb) || defined(esp32cam_4mb)
My_timer = timerBegin(0, 80, true);
timerAttachInterrupt(My_timer, &onTimer, true);
timerAlarmWrite(My_timer, STEPPER_ERRORMARKER, true);
timerAlarmEnable(My_timer);
// timerAlarmDisable(My_timer);
initErrorMarker(SETUPBASE_ERRORMARKER);
#endif
Serial.begin(115200);
Serial.flush();
//----------- Отладка EXCEPTION (функции с заглушками для отключения) ---------
#if defined(RESTART_DEBUG_INFO)
//Привязка коллбэк функции для вызова при перезагрузке
esp_register_shutdown_handler(debugUpdate);
#endif // RESTART_DEBUG_INFO
// Печать или оправка отладочной информации
printDebugTrace();
startWatchDog();
Serial.println();
Serial.println(F("--------------started----------------"));
// создание экземпляров классов
// myNotAsyncActions = new NotAsync(do_LAST);
// инициализация файловой системы
fileSystemInit();
Serial.println(F("------------------------"));
Serial.println("FIRMWARE NAME " + String(FIRMWARE_NAME));
Serial.println("FIRMWARE VERSION " + String(FIRMWARE_VERSION));
Serial.println("WEB VERSION " + getWebVersion());
const String buildTime = String(BUILD_DAY) + "." + String(BUILD_MONTH) + "." + String(BUILD_YEAR) + " " + String(BUILD_HOUR) + ":" + String(BUILD_MIN) + ":" + String(BUILD_SEC);
Serial.println("BUILD TIME " + buildTime);
jsonWriteStr_(errorsHeapJson, F("bt"), buildTime);
Serial.println(F("------------------------"));
// получение chip id
setChipId();
verifyFirmware();
// синхронизация глобальных переменных с flash
globalVarsSync();
stopErrorMarker(SETUPBASE_ERRORMARKER);
initErrorMarker(SETUPCONF_ERRORMARKER);
// настраиваем i2c шину
int i2c, pinSCL, pinSDA, i2cFreq;
jsonRead(settingsFlashJson, "pinSCL", pinSCL, false);
jsonRead(settingsFlashJson, "pinSDA", pinSDA, false);
jsonRead(settingsFlashJson, "i2cFreq", i2cFreq, false);
jsonRead(settingsFlashJson, "i2c", i2c, false);
//jsonWriteStr_(ssidListHeapJson, "0", "Scaning...");
if (i2c != 0) {
#ifdef ESP32
Wire.end();
Wire.begin(pinSDA, pinSCL, (uint32_t)i2cFreq);
#elif defined(ESP8266)
Wire.begin(pinSDA, pinSCL);
Wire.setClock(i2cFreq);
#endif
SerialPrint("i", "i2c", F("i2c pins overriding done"));
}
#if defined(RESTART_DEBUG_INFO)
esp_reset_reason_t esp_reason = esp_reset_reason();
if (esp_reason == ESP_RST_UNKNOWN || esp_reason == ESP_RST_POWERON)
bootloop_panic_count = 0;
/* else if (bootloop_panic_count == 3 || bootloop_panic_count == 0 ) bootloop_panic_count = 1;
else if (bootloop_panic_count == 2) bootloop_panic_count = 3;
else if (bootloop_panic_count == 1) bootloop_panic_count = 2;
else bootloop_panic_count = 0; */
Serial.println("bootloop_panic_count " + String(bootloop_panic_count));
if (bootloop_panic_count >3 )
{
//resetSettingsFlashByPanic();
bootloop_panic_count = 0;
}
if (bootloop_panic_count >= 3)
{
resetSettingsFlashByPanic();
bootloop_panic_count = -1;
}
if (bootloop_panic_count == -1)
{
SerialPrint("E", "CORE", F("CONFIG and SCENARIO reset !!!"));
bootloop_panic_count = 0;
ESP.restart();
}
#endif // RESTART_DEBUG_INFO
// настраиваем микроконтроллер
configure("/config.json");
stopErrorMarker(SETUPCONF_ERRORMARKER);
initErrorMarker(SETUPSCEN_ERRORMARKER);
// подготавливаем сценарии
iotScen.loadScenario("/scenario.txt");
// создаем событие завершения инициализации основных моментов для возможности выполнения блока кода при загрузке
createItemFromNet("onInit", "1", 1);
// elementsLoop(); //Для работы MQTT Брокера перенес ниже, иначе брокер падает если вызван до routerConnect();
stopErrorMarker(SETUPSCEN_ERRORMARKER);
initErrorMarker(SETUPINET_ERRORMARKER);
// подключаемся к роутеру
#ifndef WIFI_ASYNC
routerConnect();
#else
WiFiUtilsItit();
#endif
// инициализация асинхронного веб сервера и веб сокетов
#ifdef ASYNC_WEB_SERVER
asyncWebServerInit();
#endif
#ifdef ASYNC_WEB_SOCKETS
asyncWebSocketsInit();
#endif
// инициализация стандартного веб сервера и веб сокетов
#ifdef STANDARD_WEB_SERVER
standWebServerInit();
#endif
#ifdef STANDARD_WEB_SOCKETS
standWebSocketsInit();
#endif
stopErrorMarker(SETUPINET_ERRORMARKER);
bool postMsgTelegram;
if (!jsonRead(settingsFlashJson, "debugTraceMsgTlgrm", postMsgTelegram, false)) postMsgTelegram = 1;
sendDebugTraceAndFreeMemory(postMsgTelegram);
initErrorMarker(SETUPLAST_ERRORMARKER);
elementsLoop();
// NTP
ntpInit();
// инициализация задач переодического выполнения
periodicTasksInit();
#if !defined(WIFI_ASYNC)
// Перенесли после получения IP, так как теперь работа WiFi асинхронная
// запуск работы udp
addThisDeviceToList();
#ifdef UDP_ENABLED
udpListningInit();
udpBroadcastInit();
#endif
#endif
// создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке
createItemFromNet("onStart", "1", 1);
stInit();
// настраиваем секундные обслуживания системы
ts.add(
TIMES, 1000, [&](void *) {
// сброс WDT
#if defined(ESP32)
//SerialPrint("i", "Task", "reset wdt");
#if !defined(esp32c6_4mb) && !defined(esp32c6_8mb) //TODO esp32-c6 переписать esp_task_wdt_init
esp_task_wdt_reset();
#endif
#endif
// сохраняем значения IoTItems в файл каждую секунду, если были изменения (установлены маркеры на сохранение)
if (needSaveValues) {
syncValuesFlashJson();
needSaveValues = false;
}
// проверяем все элементы на тухлость
for (std::list<IoTItem *>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) {
(*it)->checkIntFromNet();
// Serial.printf("[ITEM] size: %d, id: %s, int: %d, intnet: %d\n", sizeof(**it), (*it)->getID(), (*it)->getInterval(), (*it)->getIntFromNet());
}
},
nullptr, true);
// ловим пинги от WS (5сек) и дисконнектим если их нет (20сек)
ts.add(
PiWS, 6000, [&](void*) {
if (isNetworkActive()) {
for (size_t i = 0; i < WEBSOCKETS_CLIENT_MAX; i++)
{
if (ws_clients[i] == 0) {
disconnectWSClient(i);
ws_clients[i]=-1;
}
if (ws_clients[i] > 0) {
ws_clients[i]=0;
}
}
}
},
nullptr, true);
// test
//Serial.println("-------test start--------");
//Serial.println("--------test end---------");
stopErrorMarker(SETUPLAST_ERRORMARKER);
#if defined(RESTART_DEBUG_INFO)
bootloop_panic_count = 0;
#endif // RESTART_DEBUG_INFO
}
void loop() {
#if defined(WIFI_ASYNC)
static bool udpFirstFlag = true;
// Перенесли после получения IP, так как теперь работа WiFi асинхронная
if (isNetworkActive() && udpFirstFlag) {
udpFirstFlag = false;
// запуск работы udp
addThisDeviceToList();
#ifdef UDP_ENABLED
udpListningInit();
udpBroadcastInit();
#endif
}
#endif
#ifdef LOOP_DEBUG
unsigned long st = millis();
#endif
if (benchLoadItem) benchLoadItem->preLoadFunction();
if (benchTaskItem) benchTaskItem->preTaskFunction("TickerScheduler");
initErrorMarker(TICKER_ERRORMARKER);
ts.update();
stopErrorMarker(TICKER_ERRORMARKER);
if (benchTaskItem) benchTaskItem->postTaskFunction("TickerScheduler");
if (benchTaskItem) benchTaskItem->preTaskFunction("webServer");
#ifdef STANDARD_WEB_SERVER
initErrorMarker(HTTP_ERRORMARKER);
HTTP.handleClient();
stopErrorMarker(HTTP_ERRORMARKER);
#endif
if (benchTaskItem) benchTaskItem->postTaskFunction("webServer");
if (benchTaskItem) benchTaskItem->preTaskFunction("webSocket");
#ifdef STANDARD_WEB_SOCKETS
initErrorMarker(SOCKETS_ERRORMARKER);
standWebSocket.loop();
stopErrorMarker(SOCKETS_ERRORMARKER);
#endif
if (benchTaskItem) benchTaskItem->postTaskFunction("webSocket");
if (benchTaskItem) benchTaskItem->preTaskFunction("mqtt");
initErrorMarker(MQTT_ERRORMARKER);
mqttLoop();
stopErrorMarker(MQTT_ERRORMARKER);
if (benchTaskItem) benchTaskItem->postTaskFunction("mqtt");
initErrorMarker(MODULES_ERRORMARKER);
elementsLoop();
stopErrorMarker(MODULES_ERRORMARKER);
if (benchLoadItem) benchLoadItem->postLoadFunction();
// #ifdef LOOP_DEBUG
// loopPeriod = millis() - st;
// if (loopPeriod > 2) Serial.println(loopPeriod);
// #endif
}
// отправка json
// #ifdef QUEUE_FROM_STR
// if (sendJsonFiles) sendJsonFiles->loop();
// #endif
// if(millis()%2000==0){
// //watch->settimeUnix(time(&iotTimeNow));
// Serial.println(watch->gettime("d-m-Y, H:i:s, M"));
// delay(1);
// }
// File dir = FileFS.open("/", "r");
// String out;
// printDirectory(dir, out);
// Serial.println(out);
//=======проверка очереди из структур=================
// myDB = new IoTDB;
// QueueItems myItem;
// myItem.myword = "word1";
// myDB->push(myItem);
// myItem.myword = "word2";
// myDB->push(myItem);
// myItem.myword = "word3";
// myDB->push(myItem);
// Serial.println(myDB->front().myword);
// Serial.println(myDB->front().myword);
// Serial.println(myDB->front().myword);
// Serial.println(FileList("lg"));