Merge branch 'ver4dev' into ver4dev

This commit is contained in:
Mit4el
2025-07-25 00:05:43 +03:00
committed by GitHub
27 changed files with 1607 additions and 91 deletions

View File

@@ -201,6 +201,7 @@ for section, modules in profJson['modules'].items():
configItemsJson['num'] = itemsCount configItemsJson['num'] = itemsCount
configItemsJson['name'] = str(itemsCount) + ". " + configItemsJson['name'] configItemsJson['name'] = str(itemsCount) + ". " + configItemsJson['name']
itemsCount = itemsCount + 1 itemsCount = itemsCount + 1
configItemsJson['moduleName'] = moduleJson['about']['moduleName']
itemsJson.append(configItemsJson) itemsJson.append(configItemsJson)
else: # В первую очередь ищем по имени deviceName, чтобы для данной платы можно было уточнить либы. Если не нашли плату по имени в usedLibs пробуем найти её по типу deviceType else: # В первую очередь ищем по имени deviceName, чтобы для данной платы можно было уточнить либы. Если не нашли плату по имени в usedLibs пробуем найти её по типу deviceType
if deviceType in moduleJson['usedLibs']: # проверяем поддерживает ли модуль текущее устройство if deviceType in moduleJson['usedLibs']: # проверяем поддерживает ли модуль текущее устройство
@@ -210,9 +211,10 @@ for section, modules in profJson['modules'].items():
allLibs = allLibs + "\n" + libPath allLibs = allLibs + "\n" + libPath
for configItemsJson in moduleJson['configItem']: for configItemsJson in moduleJson['configItem']:
configItemsJson['num'] = itemsCount configItemsJson['num'] = itemsCount
configItemsJson['name'] = str(itemsCount) + ". " + configItemsJson['name'] configItemsJson['name'] = str(itemsCount) + ". " + configItemsJson['name']
itemsCount = itemsCount + 1 itemsCount = itemsCount + 1
itemsJson.append(configItemsJson) itemsJson.append(configItemsJson)
configItemsJson['moduleName'] = moduleJson['about']['moduleName']
with open("data_svelte/items.json", "w", encoding='utf-8') as write_file: with open("data_svelte/items.json", "w", encoding='utf-8') as write_file:
json.dump(itemsJson, write_file, ensure_ascii=False, indent=4, sort_keys=False) json.dump(itemsJson, write_file, ensure_ascii=False, indent=4, sort_keys=False)

Binary file not shown.

Binary file not shown.

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" /> <meta name="viewport" content="width=device-width,initial-scale=1" />
<title>IoT Manager 4.5.5</title> <title>IoT Manager 4.6.2</title>
<link rel="icon" type="image/png" href="/favicon.ico" /> <link rel="icon" type="image/png" href="/favicon.ico" />
<link rel="stylesheet" href="/build/bundle.css?4550" /> <link rel="stylesheet" href="/build/bundle.css?4550" />

Binary file not shown.

Binary file not shown.

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" /> <meta name="viewport" content="width=device-width,initial-scale=1" />
<title>IoT Manager 4.5.5</title> <title>IoT Manager 4.6.2</title>
<link rel="icon" type="image/png" href="/favicon.ico" /> <link rel="icon" type="image/png" href="/favicon.ico" />
<link rel="stylesheet" href="/build/bundle.css?4550" /> <link rel="stylesheet" href="/build/bundle.css?4550" />

View File

@@ -177,6 +177,39 @@
"maxCount": 86400, "maxCount": 86400,
"type": "bar" "type": "bar"
}, },
{
"name": "chart4",
"label": "График Часовой",
"widget": "chart",
"dateFormat": "HH:mm",
"maxCount": 3600,
"type": "bar"
},
{
"name": "chart5",
"label": "График двойной",
"widget": "chart",
"series": [
"Температура, С",
"Влажность, %"
],
"dateFormat": "HH:mm",
"maxCount": 86400,
"pointRadius": 0
},
{
"name": "chart6",
"label": "График тройной",
"widget": "chart",
"series": [
"Температура, С",
"Влажность, %",
"Давление, кПа"
],
"dateFormat": "HH:mm",
"maxCount": 86400,
"pointRadius": 0
},
{ {
"name": "fillgauge", "name": "fillgauge",
"label": "Бочка", "label": "Бочка",
@@ -321,10 +354,6 @@
"widget": "anydata", "widget": "anydata",
"after": "°", "after": "°",
"icon": "speedometer" "icon": "speedometer"
},
{
"name": "nil",
"label": "Без виджета"
}, },
{ {
"name": "anydataBar", "name": "anydataBar",
@@ -332,5 +361,9 @@
"widget": "anydata", "widget": "anydata",
"after": "Kg/cm²", "after": "Kg/cm²",
"icon": "speedometer" "icon": "speedometer"
},
{
"name": "nil",
"label": "Без виджета"
} }
] ]

View File

@@ -2,7 +2,8 @@
#include "BuildTime.h" #include "BuildTime.h"
// Версия прошивки // Версия прошивки
#define FIRMWARE_VERSION 460
#define FIRMWARE_VERSION 462
#ifdef esp8266_1mb_ota #ifdef esp8266_1mb_ota
#define FIRMWARE_NAME "esp8266_1mb_ota" #define FIRMWARE_NAME "esp8266_1mb_ota"
@@ -68,6 +69,9 @@
#define FIRMWARE_NAME "esp32c6_8mb" #define FIRMWARE_NAME "esp32c6_8mb"
#endif #endif
#ifdef esp32_wifirep
#define FIRMWARE_NAME "esp32_wifirep"
#endif
// Размер буфера json // Размер буфера json
#define JSON_BUFFER_SIZE 4096 // держим 2 кб не меняем #define JSON_BUFFER_SIZE 4096 // держим 2 кб не меняем
@@ -108,7 +112,7 @@ WEB_SOCKETS_FRAME_SIZE создан для того что бы не загру
//#define WIFI_ASYNC //#define WIFI_ASYNC
#endif #endif
#ifdef ESP32 #if defined(ESP32) && !defined(esp32_wifirep)
#define WIFI_ASYNC #define WIFI_ASYNC
#endif #endif

View File

@@ -10,6 +10,7 @@
#include <list> #include <list>
#ifdef LIBRETINY #ifdef LIBRETINY
#include <Update.h>
#include <vector> #include <vector>
#include <typedef.h> #include <typedef.h>
#ifdef STANDARD_WEB_SERVER #ifdef STANDARD_WEB_SERVER

View File

@@ -10,6 +10,8 @@ extern void handleFileUpload();
extern void handleFileDelete(); extern void handleFileDelete();
extern void handleFileCreate(); extern void handleFileCreate();
extern void handleLocalOTA(); extern void handleLocalOTA();
extern void handleUpdateOTA();
extern void handleCors();
extern void handleLocalOTA_Handler(); extern void handleLocalOTA_Handler();
extern void handleFileList(); extern void handleFileList();
//void printDirectory(File dir, String& out); //void printDirectory(File dir, String& out);

View File

@@ -2,6 +2,9 @@
#include "Global.h" #include "Global.h"
#include "MqttClient.h" #include "MqttClient.h"
void addPortMap(String TCP_UDP, String maddr, u16_t mport, String daddr, u16_t dport);
boolean isNetworkActive(); boolean isNetworkActive();
uint8_t getNumAPClients(); uint8_t getNumAPClients();
bool startAPMode(); bool startAPMode();

View File

@@ -3,6 +3,12 @@
"name": "IoTmanagerVer4", "name": "IoTmanagerVer4",
"apssid": "IoTmanager", "apssid": "IoTmanager",
"appass": "", "appass": "",
"wifirep_apchanel": 7,
"wifirep_apip": "192.168.4.1",
"wifirep_staip": "192.168.1.160",
"wifirep_netmask": "255.255.255.0",
"wifirep_gateway": "192.168.4.1",
"wifirep_dns": "192.168.4.1",
"routerssid": "iot", "routerssid": "iot",
"routerpass": "hostel3333", "routerpass": "hostel3333",
"timezone": 2, "timezone": 2,
@@ -27,7 +33,7 @@
"projectProp": { "projectProp": {
"platformio": { "platformio": {
"default_envs": "esp32_4mb3f", "default_envs": "esp32_4mb3f",
"comments_default_envs": "choose from: esp8266_4mb, esp32_4mb, esp32_4mb3f, esp8266_16mb, esp32_16mb, esp32cam_4mb, esp32s2_4mb, esp32s3_16mb, esp32c3m_4mb, esp8266_1mb, esp8266_1mb_ota, esp8266_2mb, esp8266_2mb_ota, esp8285_1mb, esp8285_1mb_ota, esp32c6_4mb, esp32c6_8mb, bk7231n", "comments_default_envs": "choose from: esp8266_4mb, esp32_4mb, esp32_4mb3f, esp8266_16mb, esp32_16mb, esp32cam_4mb, esp32s2_4mb, esp32s3_16mb, esp32c3m_4mb, esp8266_1mb, esp8266_1mb_ota, esp8266_2mb, esp8266_2mb_ota, esp8285_1mb, esp8285_1mb_ota, esp32c6_4mb, esp32c6_8mb, bk7231n, esp32_wifirep",
"envs": [ "envs": [
{ {
"name": "esp8266_4mb", "name": "esp8266_4mb",
@@ -55,6 +61,14 @@
"partitions": "0x8000", "partitions": "0x8000",
"littlefs": "0x310000" "littlefs": "0x310000"
}, },
{
"name": "esp32_wifirep",
"boot_app0": "0xe000",
"bootloader_qio_80m": "0x1000",
"firmware": "0x10000",
"partitions": "0x8000",
"littlefs": "0x310000"
},
{ {
"name": "esp32cam_4mb", "name": "esp32cam_4mb",
"boot_app0": "0xe000", "boot_app0": "0xe000",
@@ -170,6 +184,14 @@
"path": "src/modules/virtual/Loging", "path": "src/modules/virtual/Loging",
"active": true "active": true
}, },
{
"path": "src/modules/virtual/Loging2",
"active": false
},
{
"path": "src/modules/virtual/Loging3",
"active": false
},
{ {
"path": "src/modules/virtual/LogingDaily", "path": "src/modules/virtual/LogingDaily",
"active": true "active": true
@@ -428,7 +450,7 @@
}, },
{ {
"path": "src/modules/exec/Buzzer", "path": "src/modules/exec/Buzzer",
"active": true "active": false
}, },
{ {
"path": "src/modules/exec/EctoControlAdapter", "path": "src/modules/exec/EctoControlAdapter",
@@ -506,6 +528,10 @@
"path": "src/modules/exec/SysExt", "path": "src/modules/exec/SysExt",
"active": false "active": false
}, },
{
"path": "src/modules/exec/Tca9555",
"active": false
},
{ {
"path": "src/modules/exec/Telegram", "path": "src/modules/exec/Telegram",
"active": false "active": false

View File

@@ -375,6 +375,30 @@ build_src_filter =
+<modules/*.cpp> +<modules/*.cpp>
${env:esp32_16mb_fromitems.build_src_filter} ${env:esp32_16mb_fromitems.build_src_filter}
[env:esp32_wifirep]
lib_deps =
${common_env_data.lib_deps_external}
${env:esp32_wifirep_fromitems.lib_deps}
lib_ignore = LT_WebSockets
build_flags =
-Desp32_wifirep="esp32_wifirep"
-Wl,--wrap=esp_panic_handler
framework = arduino
board = esp32dev
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.3/platform-espressif32-2.0.5.3.zip
monitor_filters = esp32_exception_decoder
upload_speed = 921600
monitor_speed = 115200
debug_tool = esp-prog
board_build.partitions = tools/partitions_custom.csv
board_build.filesystem = littlefs
build_src_filter =
+<*.cpp>
+<classes/*.cpp>
+<utils/*.cpp>
+<modules/*.cpp>
${env:esp32_wifirep_fromitems.build_src_filter}
[env:esp32c6_4mb] [env:esp32c6_4mb]
extra_scripts = pre:tools/patch32c6.py extra_scripts = pre:tools/patch32c6.py
lib_deps = lib_deps =
@@ -894,6 +918,47 @@ build_src_filter =
+<modules/virtual/VariableColor> +<modules/virtual/VariableColor>
+<modules/virtual/VButton> +<modules/virtual/VButton>
[env:esp32_wifirep_fromitems]
lib_deps =
https://github.com/enjoyneering/AHTxx.git
adafruit/Adafruit BME280 Library
adafruit/Adafruit BMP280 Library
beegee-tokyo/DHT sensor library for ESPx
https://github.com/milesburton/Arduino-Temperature-Control-Library
plerup/EspSoftwareSerial
gyverlibs/EncButton @ ^2.0
build_src_filter =
+<modules/virtual/Cron>
+<modules/virtual/Loging>
+<modules/virtual/LogingDaily>
+<modules/virtual/LogingHourly>
+<modules/virtual/Math>
+<modules/virtual/owmWeather>
+<modules/virtual/Ping>
+<modules/virtual/Timer>
+<modules/virtual/UpdateServer>
+<modules/virtual/Variable>
+<modules/virtual/VButton>
+<modules/sensors/AhtXX>
+<modules/sensors/AnalogAdc>
+<modules/sensors/Bme280>
+<modules/sensors/Bmp280>
+<modules/sensors/Dht1122>
+<modules/sensors/Ds18b20>
+<modules/sensors/Impulse>
+<modules/sensors/Ntc>
+<modules/sensors/RTC>
+<modules/sensors/UART>
+<modules/exec/AnalogBtn>
+<modules/exec/ButtonIn>
+<modules/exec/ButtonOut>
+<modules/exec/Buzzer>
+<modules/exec/Enconder>
+<modules/exec/Multitouch>
+<modules/exec/Pwm32>
+<modules/exec/TelegramLT>
+<modules/exec/Thermostat>
[env:esp32c6_4mb_fromitems] [env:esp32c6_4mb_fromitems]
lib_deps = lib_deps =
https://github.com/enjoyneering/AHTxx.git https://github.com/enjoyneering/AHTxx.git

View File

@@ -224,9 +224,9 @@ void setup() {
stopErrorMarker(SETUPINET_ERRORMARKER); stopErrorMarker(SETUPINET_ERRORMARKER);
bool postMsgTelegram; // bool postMsgTelegram;
if (!jsonRead(settingsFlashJson, "debugTraceMsgTlgrm", postMsgTelegram, false)) postMsgTelegram = 1; // if (!jsonRead(settingsFlashJson, "debugTraceMsgTlgrm", postMsgTelegram, false)) postMsgTelegram = 1;
sendDebugTraceAndFreeMemory(postMsgTelegram); // sendDebugTraceAndFreeMemory(postMsgTelegram);
initErrorMarker(SETUPLAST_ERRORMARKER); initErrorMarker(SETUPLAST_ERRORMARKER);
@@ -276,9 +276,9 @@ void setup() {
}, },
nullptr, true); nullptr, true);
// ловим пинги от WS (5сек) и дисконнектим если их нет (20сек) // ловим пинги от WS (2сек) и дисконнектим если их нет 3 раза 3сек*2прохода = 6сек
ts.add( ts.add(
PiWS, 6000, [&](void*) { PiWS, 3000, [&](void*) {
if (isNetworkActive()) { if (isNetworkActive()) {
for (size_t i = 0; i < WEBSOCKETS_CLIENT_MAX; i++) for (size_t i = 0; i < WEBSOCKETS_CLIENT_MAX; i++)
{ {

View File

@@ -64,6 +64,10 @@ void synchTime() {
if (sntp_enabled()) { if (sntp_enabled()) {
sntp_stop(); sntp_stop();
} }
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, jsonReadStr(settingsFlashJson, F("ntp")).c_str());
sntp_setservername(1, "pool.ntp.org");
sntp_setservername(2, "ru.pool.ntp.org");
sntp_init(); sntp_init();
#else #else

View File

@@ -9,6 +9,12 @@ static const char FS_INIT_ERROR[] PROGMEM = "FS INIT ERROR";
static const char FILE_NOT_FOUND[] PROGMEM = "FileNotFound"; static const char FILE_NOT_FOUND[] PROGMEM = "FileNotFound";
// static bool fsOK; // static bool fsOK;
// const char* fsName = "LittleFS"; // const char* fsName = "LittleFS";
// Типы обновлений
enum UpdateType {
FIRMWARE,
FILESYSTEM
};
void standWebServerInit() { void standWebServerInit() {
// Кэшировать файлы для быстрой работы // Кэшировать файлы для быстрой работы
@@ -88,11 +94,18 @@ void standWebServerInit() {
// - first callback is called after the request has ended with all parsed arguments // - first callback is called after the request has ended with all parsed arguments
// - second callback handles file upload at that location // - second callback handles file upload at that location
HTTP.on("/edit", HTTP_POST, replyOK, handleFileUpload); HTTP.on("/edit", HTTP_POST, replyOK, handleFileUpload);
// отображение страницы с полем ввода для сервера обновления
HTTP.on("/localota", HTTP_GET, handleLocalOTA); HTTP.on("/localota", HTTP_GET, handleLocalOTA);
// непосредственно ОТА обновление со стороннего сервера
HTTP.on("/localota_handler", HTTP_GET, handleLocalOTA_Handler); HTTP.on("/localota_handler", HTTP_GET, handleLocalOTA_Handler);
// Обработка обновления от WS drag&drop
HTTP.on("/update", HTTP_POST, []() {
HTTP.send(200); // Для CORS
}, handleUpdateOTA);
HTTP.on("/update", HTTP_OPTIONS, handleCors);
// Default handler for all URIs not defined above // Default handler for all URIs not defined above
// Use it to read files from filesystem // Use it to read files from filesystem
HTTP.onNotFound(handleNotFound); HTTP.onNotFound(handleNotFound);
@@ -164,6 +177,66 @@ void handleLocalOTA() {
String page = "<form action='/localota' method='POST'><label for='server'>Server Address:</label><input type='text' name='server' value='http://192.168.1.2:5500'><input type='submit' value='Update'></form>"; String page = "<form action='/localota' method='POST'><label for='server'>Server Address:</label><input type='text' name='server' value='http://192.168.1.2:5500'><input type='submit' value='Update'></form>";
HTTP.send(200, "text/html", page);} HTTP.send(200, "text/html", page);}
void handleCors() {
HTTP.sendHeader("Access-Control-Allow-Origin", "*");
HTTP.send(200);
}
void handleUpdateOTA() {
UpdateType typeOTAfile = FIRMWARE;
HTTPUpload& upload = HTTP.upload();
if (upload.filename != "firmware.bin" && upload.filename != "littlefs.bin")
{
SerialPrint("E", F("OTA"), "Неверное имя файла: " + upload.filename);
return;
}
if (upload.filename == "firmware.bin")
{
typeOTAfile = FIRMWARE;
} else if (upload.filename == "littlefs.bin")
{
typeOTAfile = FILESYSTEM;
}
#ifdef ESP8266
size_t size = upload.totalSize;
int updatePartition = (typeOTAfile == FIRMWARE)? U_FLASH : U_FS; //U_FS
//#endif
#else //ESP32
size_t size = UPDATE_SIZE_UNKNOWN;
int updatePartition = (typeOTAfile == FIRMWARE)? U_FLASH : U_SPIFFS; //U_FS
#endif
if (upload.status == UPLOAD_FILE_START) {
//Serial.print("Начало загрузки: ");
//Serial.println(upload.filename);
SerialPrint("i", F("OTA"), "Начало загрузки файла: " + upload.filename);
if (!Update.begin(size, updatePartition)) { // UPDATE_SIZE_UNKNOWN 0xFFFFFFFF
Update.end();
SerialPrint("E", F("OTA"), "Ошибка: Недостаточно памяти");
HTTP.send(500, "text/plain", "Ошибка: Недостаточно памяти");
return;
}
}
else if (upload.status == UPLOAD_FILE_WRITE) {
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.end();
SerialPrint("E", F("OTA"), "Ошибка записи данных");
HTTP.send(500, "text/plain", "Ошибка записи данных");
return;
}
}
else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { // true - перезагрузка после обновления
SerialPrint("i", F("OTA"), "Обновление завершено");
HTTP.send(200, "text/plain", "Обновление успешно");
ESP.restart();
} else {
Update.end();
SerialPrint("E", F("OTA"), "Ошибка завершения обновления");
HTTP.send(500, "text/plain", "Ошибка завершения обновления");
}
}
}
void handleLocalOTA_Handler() { void handleLocalOTA_Handler() {
String serverValue = HTTP.arg("server"); String serverValue = HTTP.arg("server");
upgrade_firmware(3,serverValue); upgrade_firmware(3,serverValue);

View File

@@ -59,9 +59,9 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
//----------------------------------------------------------------------// //----------------------------------------------------------------------//
// Страница веб интерфейса dashboard // Страница веб интерфейса dashboard
//----------------------------------------------------------------------// //----------------------------------------------------------------------//
if (headerStr == "p|") { if (headerStr == "/pi|") {
standWebSocket.sendTXT(num, "p|"); standWebSocket.sendTXT(num, "/po|");
//Serial.printf("Ping client: %u\n", num); Serial.printf("Ping client: %u\n", num);
ws_clients[num]=1; ws_clients[num]=1;
} }
// публикация всех виджетов // публикация всех виджетов
@@ -233,6 +233,50 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
sendStringToWs("settin", settingsFlashJson, num); sendStringToWs("settin", settingsFlashJson, num);
} }
if (headerStr == "/localt|") {
String timeStr = String((char*)payload + 8);
//Serial.println("Время с фронта: /localt|" + timeStr);
// Обрезаем дробную часть, если есть
int dotIndex = timeStr.indexOf('.');
if (dotIndex != -1) {
timeStr = timeStr.substring(0, dotIndex);
}
// Парсим UNIX-время в секундах
time_t unixTime = (time_t)timeStr.toInt();
// Создаём структуру timeval
timeval tv;
tv.tv_sec = unixTime; // Секунды эпохи
tv.tv_usec = 0; // Микросекунды
// Устанавливаем время
if (settimeofday(&tv, NULL) == 0) {
//Serial.printf("Время установлено: %ld\n", unixTime);
#ifdef LIBRETINY
SerialPrint("i", F("Time"), "Время установлено из браузера: ");
#else
SerialPrint("i", F("Time"), "Время установлено из браузера: " + String(unixTime));
#endif
} else {
#ifdef LIBRETINY
//Serial.printf("Ошибка установки времени: %ld\n", unixTime);
SerialPrint("i", F("=>WS"), "Ошибка установки времени: ");
#else
SerialPrint("i", F("=>WS"), "Ошибка установки времени: " + String(unixTime));
#endif
}
// timeval tv2{0, 0};
// timezone tz = timezone{0, 0};
// time_t epoch = 0;
// if (gettimeofday(&tv2, &tz) != -1) {
// epoch = tv2.tv_sec;
// }
// unixTime = epoch;
// SerialPrint("I", F("NTP"), "TIME " + String(unixTime));
}
//----------------------------------------------------------------------// //----------------------------------------------------------------------//
// Страница веб интерфейса dev // Страница веб интерфейса dev
//----------------------------------------------------------------------// //----------------------------------------------------------------------//

View File

@@ -2,6 +2,7 @@
#include "classes/IoTItem.h" #include "classes/IoTItem.h"
#include "classes/IoTScenario.h" #include "classes/IoTScenario.h"
#include "utils/FileUtils.h" #include "utils/FileUtils.h"
#include "utils/WiFiUtils.h"
#include "NTP.h" #include "NTP.h"
@@ -358,7 +359,8 @@ enum SysOp {
sysop_getUptime, sysop_getUptime,
sysop_mqttIsConnect, sysop_mqttIsConnect,
sysop_wifiIsConnect, sysop_wifiIsConnect,
sysop_setInterval sysop_setInterval,
sysop_addPortMap
}; };
IoTValue sysExecute(SysOp command, std::vector<IoTValue> &param) { IoTValue sysExecute(SysOp command, std::vector<IoTValue> &param) {
@@ -470,6 +472,11 @@ IoTValue sysExecute(SysOp command, std::vector<IoTValue> &param) {
} }
break; break;
case sysop_addPortMap:
if (param.size() == 5) {
addPortMap(param[0].valS, param[1].valS, param[2].valD, param[3].valS, param[4].valD);
}
break;
} }
return value; return value;
@@ -530,6 +537,8 @@ class SysCallExprAST : public ExprAST {
operation = sysop_wifiIsConnect; operation = sysop_wifiIsConnect;
else if (Callee == F("setInterval")) else if (Callee == F("setInterval"))
operation = sysop_setInterval; operation = sysop_setInterval;
else if (Callee == F("addPortMap"))
operation = sysop_addPortMap;
else else
operation = sysop_notfound; operation = sysop_notfound;
} }

View File

@@ -8,7 +8,6 @@
// #include "Stream.h" // #include "Stream.h"
#include <vector> #include <vector>
// class ModbusUart; // class ModbusUart;
Stream *_modbusUART = nullptr; Stream *_modbusUART = nullptr;
@@ -21,7 +20,6 @@ uint8_t _DIR_PIN = 0;
#define MODBUS_TX_PIN 19 // Tx pin #define MODBUS_TX_PIN 19 // Tx pin
#define MODBUS_SERIAL_BAUD 9600 // Baud rate for esp32 and max485 communication #define MODBUS_SERIAL_BAUD 9600 // Baud rate for esp32 and max485 communication
void modbusPreTransmission() void modbusPreTransmission()
{ {
// delay(500); // delay(500);
@@ -52,7 +50,7 @@ private:
int protocol = SERIAL_8N1; int protocol = SERIAL_8N1;
uint8_t _addr = 0xF0; // Адрес слейва от 1 до 247 uint8_t _addr = 0xF0; // Адрес слейва от 1 до 247
uint8_t _type = 0x14; // Тип устройства: 0x14 адаптер OpenTherm (вторая версия); 0x11 адаптер OpenTherm (первая версия, снята с производства) uint8_t _type = 0x14; // Тип устройства: 0x14 адаптер OpenTherm (вторая версия); 0x11 адаптер OpenTherm (первая версия, снята с производства)
bool _debugLevel; // Дебаг uint8_t _debugLevel; // Дебаг
ModbusMaster node; ModbusMaster node;
uint8_t _debug; uint8_t _debug;
@@ -136,36 +134,39 @@ public:
{ {
SerialPrint("E", "EctoControlAdapter", "Не подходящее устройство, type: " + String(type, HEX)); SerialPrint("E", "EctoControlAdapter", "Не подходящее устройство, type: " + String(type, HEX));
} }
getModelVersion();
getBoilerInfo();
getBoilerStatus();
} }
else if (_addr == 0) else if (_addr == 0)
{ // если адреса нет, то шлем широковещательный запрос адреса { // если адреса нет, то шлем широковещательный запрос адреса
uint8_t addr = node.readAddresEctoControl(); uint8_t addr = node.readAddresEctoControl();
SerialPrint("I", "EctoControlAdapter", "readAddresEctoControl, addr: " + String(addr, HEX) + " - Enter to configuration"); SerialPrint("I", "EctoControlAdapter", "readAddresEctoControl, addr: " + String(addr, HEX) + " - Enter to configuration");
} }
getModelVersion();
getBoilerInfo();
getBoilerStatus();
} }
void doByInterval() void doByInterval()
{ {
// readBoilerInfo(); if (_addr > 0)
getBoilerStatus(); {
// readBoilerInfo();
getBoilerStatus();
getCodeError(); getCodeError();
getCodeErrorExt(); getCodeErrorExt();
if (info.adapterType == 0) if (info.adapterType == 0)
getFlagErrorOT(); getFlagErrorOT();
// getFlowRate(); // getFlowRate();
// getMaxSetCH(); // getMaxSetCH();
// getMaxSetDHW(); // getMaxSetDHW();
// getMinSetCH(); // getMinSetCH();
// getMinSetDHW(); // getMinSetDHW();
getModLevel(); getModLevel();
getPressure(); getPressure();
getTempCH(); getTempCH();
getTempDHW(); getTempDHW();
getTempOutside(); getTempOutside();
}
} }
void loop() void loop()
@@ -176,10 +177,6 @@ public:
IoTValue execute(String command, std::vector<IoTValue> &param) IoTValue execute(String command, std::vector<IoTValue> &param)
{ {
if (command == "getModelVersion")
{
getModelVersion();
}
if (command == "getModelVersion") if (command == "getModelVersion")
{ {
getModelVersion(); getModelVersion();
@@ -324,13 +321,12 @@ public:
tlgrmItem->sendTelegramMsg(false, msg); tlgrmItem->sendTelegramMsg(false, msg);
} }
~EctoControlAdapter() { ~EctoControlAdapter(){};
};
bool writeFunctionModBus(const uint16_t &reg, uint16_t &data) bool writeFunctionModBus(const uint16_t &reg, uint16_t &data)
{ {
// set word 0 of TX buffer to least-significant word of counter (bits 15..0) // set word 0 of TX buffer to least-significant word of counter (bits 15..0)
//node.setTransmitBuffer(1, lowWord(data)); // node.setTransmitBuffer(1, lowWord(data));
// set word 1 of TX buffer to most-significant word of counter (bits 31..16) // set word 1 of TX buffer to most-significant word of counter (bits 31..16)
node.setTransmitBuffer(0, data); node.setTransmitBuffer(0, data);
// slave: write TX buffer to (2) 16-bit registers starting at register 0 // slave: write TX buffer to (2) 16-bit registers starting at register 0
@@ -348,6 +344,7 @@ public:
bool readFunctionModBus(const uint16_t &reg, uint16_t &reading) bool readFunctionModBus(const uint16_t &reg, uint16_t &reading)
{ {
if (_addr == 0) return false;
// float retValue = 0; // float retValue = 0;
if (_modbusUART) if (_modbusUART)
{ {

View File

@@ -1,6 +1,9 @@
#include "ModbusEC.h" #include "ModbusEC.h"
#define COUNT_BIT_AVAIL 5
#define COUNT_BIT_AVAIL_46F 4
ModbusMaster::ModbusMaster(void) ModbusMaster::ModbusMaster(void)
{ {
_idle = 0; _idle = 0;
@@ -256,8 +259,8 @@ uint8_t ModbusMaster::readHoldingRegisters(uint16_t u16ReadAddress,
/** /**
Modbus function 0x06 Write Single Register. Modbus function 0x06 Write Single Register.
This function code is used to write a single holding register in a This function code is used to write a single holding register in a
remote device. The request specifies the address of the register to be remote device. The request specifies the address of the register to be
written. Registers are addressed starting at zero. written. Registers are addressed starting at zero.
@param u16WriteAddress address of the holding register (0x0000..0xFFFF) @param u16WriteAddress address of the holding register (0x0000..0xFFFF)
@@ -266,7 +269,7 @@ written. Registers are addressed starting at zero.
@ingroup register @ingroup register
*/ */
uint8_t ModbusMaster::writeSingleRegister(uint16_t u16WriteAddress, uint8_t ModbusMaster::writeSingleRegister(uint16_t u16WriteAddress,
uint16_t u16WriteValue) uint16_t u16WriteValue)
{ {
_u16WriteAddress = u16WriteAddress; _u16WriteAddress = u16WriteAddress;
_u16WriteQty = 0; _u16WriteQty = 0;
@@ -274,7 +277,6 @@ uint8_t ModbusMaster::writeSingleRegister(uint16_t u16WriteAddress,
return ModbusMasterTransaction(ku8MBWriteSingleRegister); return ModbusMasterTransaction(ku8MBWriteSingleRegister);
} }
/** /**
Modbus function 0x10 Write Multiple Registers. Modbus function 0x10 Write Multiple Registers.
@@ -308,7 +310,8 @@ uint8_t ModbusMaster::readAddresEctoControl()
{ {
_u16ReadAddress = 0x00; _u16ReadAddress = 0x00;
_u16ReadQty = 1; _u16ReadQty = 1;
return ModbusMasterTransaction(ku8MBProgRead46); ModbusMasterTransaction(ku8MBProgRead46);
return getResponseBuffer(0x00);
} }
uint8_t ModbusMaster::writeAddresEctoControl(uint8_t addr) uint8_t ModbusMaster::writeAddresEctoControl(uint8_t addr)
{ {
@@ -393,8 +396,17 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
{ {
u16CRC = crc16_update(u16CRC, u8ModbusADU[i]); u16CRC = crc16_update(u16CRC, u8ModbusADU[i]);
} }
// if (u8MBFunction == ku8MBProgRead46 || u8MBFunction == ku8MBProgWrite47)
// {
// u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC);
// u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC);
// }
// else
// {
u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC); u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC);
u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC); u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC);
// }
u8ModbusADU[u8ModbusADUSize] = 0; u8ModbusADU[u8ModbusADUSize] = 0;
// flush receive buffer before transmitting request // flush receive buffer before transmitting request
@@ -427,7 +439,9 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
#if __MODBUSMASTER_DEBUG__ #if __MODBUSMASTER_DEBUG__
digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true); digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true);
#endif #endif
u8ModbusADU[u8ModbusADUSize++] = _serial->read(); uint8_t req = _serial->read();
u8ModbusADU[u8ModbusADUSize++] = req;
Serial.print(req, HEX);
u8BytesLeft--; u8BytesLeft--;
#if __MODBUSMASTER_DEBUG__ #if __MODBUSMASTER_DEBUG__
digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, false); digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, false);
@@ -448,26 +462,34 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
} }
// evaluate slave ID, function code once enough bytes have been read // evaluate slave ID, function code once enough bytes have been read
if (u8ModbusADUSize == 5) uint8_t count;
if (u8MBFunction == ku8MBProgRead46 || u8MBFunction == ku8MBProgWrite47)
count = COUNT_BIT_AVAIL_46F;
else
count = COUNT_BIT_AVAIL;
if (u8ModbusADUSize == count)
{ {
// verify response is for correct Modbus slave if (u8MBFunction != ku8MBProgRead46 && u8MBFunction != ku8MBProgWrite47)
if (u8ModbusADU[0] != _u8MBSlave)
{ {
// Serial.print(u8ModbusADU[0], HEX); // verify response is for correct Modbus slave
// Serial.print(" != "); if (u8ModbusADU[0] != _u8MBSlave)
// Serial.println(_u8MBSlave, HEX); {
// Serial.print(u8ModbusADU[0], HEX);
u8MBStatus = ku8MBInvalidSlaveID; // Serial.print(" != ");
break; // Serial.println(_u8MBSlave, HEX);
}
// verify response is for correct Modbus function code (mask exception bit 7) u8MBStatus = ku8MBInvalidSlaveID;
if ((u8ModbusADU[1] & 0x7F) != u8MBFunction) break;
{ }
u8MBStatus = ku8MBInvalidFunction;
break;
}
// verify response is for correct Modbus function code (mask exception bit 7)
if ((u8ModbusADU[1] & 0x7F) != u8MBFunction)
{
u8MBStatus = ku8MBInvalidFunction;
break;
}
}
// check whether Modbus exception occurred; return Modbus Exception Code // check whether Modbus exception occurred; return Modbus Exception Code
if (bitRead(u8ModbusADU[1], 7)) if (bitRead(u8ModbusADU[1], 7))
{ {
@@ -485,6 +507,16 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
case ku8MBWriteMultipleRegisters: case ku8MBWriteMultipleRegisters:
u8BytesLeft = 3; u8BytesLeft = 3;
break; break;
case ku8MBProgRead46:
u8BytesLeft = 1;
break;
case ku8MBProgWrite47:
u8BytesLeft = 1;
break;
default:
} }
} }
if ((millis() - u32StartTime) > ku16MBResponseTimeout) if ((millis() - u32StartTime) > ku16MBResponseTimeout)
@@ -493,24 +525,26 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
} }
} }
// verify response is large enough to inspect further if (u8MBFunction != ku8MBProgRead46 && u8MBFunction != ku8MBProgWrite47)
if (!u8MBStatus && u8ModbusADUSize >= 5)
{ {
// calculate CRC // verify response is large enough to inspect further
u16CRC = 0xFFFF; if (!u8MBStatus && u8ModbusADUSize >= COUNT_BIT_AVAIL)
for (i = 0; i < (u8ModbusADUSize - 2); i++)
{ {
u16CRC = crc16_update(u16CRC, u8ModbusADU[i]); // calculate CRC
} u16CRC = 0xFFFF;
for (i = 0; i < (u8ModbusADUSize - 2); i++)
{
u16CRC = crc16_update(u16CRC, u8ModbusADU[i]);
}
// verify CRC // verify CRC
if (!u8MBStatus && (lowByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 2] || if (!u8MBStatus && (lowByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 2] ||
highByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 1])) highByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 1]))
{ {
u8MBStatus = ku8MBInvalidCRC; u8MBStatus = ku8MBInvalidCRC;
}
} }
} }
// disassemble ADU into words // disassemble ADU into words
if (!u8MBStatus) if (!u8MBStatus)
{ {
@@ -530,6 +564,12 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
} }
break; break;
case ku8MBProgRead46: case ku8MBProgRead46:
Serial.print("ku8MBProgRead46");
for (i = 0; i < (u8ModbusADUSize); i++)
{
Serial.println(u8ModbusADU[i], HEX);
}
_u16ResponseBuffer[0] = (uint16_t)u8ModbusADU[2]; _u16ResponseBuffer[0] = (uint16_t)u8ModbusADU[2];
_u8ResponseBufferLength = 1; _u8ResponseBufferLength = 1;
break; break;

View File

@@ -0,0 +1,495 @@
#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);
}

View File

@@ -0,0 +1,48 @@
{
"menuSection": "virtual_elments",
"configItem": [
{
"global": 0,
"name": "Двойной график",
"type": "Writing",
"subtype": "Loging2",
"id": "log2",
"widget": "chart5",
"page": "Графики",
"descr": "Датчик",
"num": 1,
"int": 5,
"logid1": "t",
"logid2": "h",
"points": 300,
"series1": "Температура, С",
"series2": "Влажность, %"
}
],
"about": {
"authorName": "Serghei Crasnicov",
"authorContact": "https://t.me/Serghei63",
"authorGit": "https://github.com/Serghei63",
"specialThanks": "@itsid1 @Valiuhaaa Serg",
"moduleName": "Loging2",
"moduleVersion": "0.0",
"usedRam": {
"esp32_4mb": 15,
"esp8266_4mb": 15
},
"title": "Логирование в график",
"moduleDesc": "Расширение позволяющее логировать любую величину в график. Графики доступны в мобильном приложении и в веб интерфейсе. Данные графиков хранятся в встроенной памяти esp. В окне ввода даты можно выбирать день, историю которого вы хотите посмотреть. Старые файлы будут удаляться автоматически после того как объем оставшейся flesh памяти устройства будет менее 20 процентов",
"propInfo": {
"int": "Интервал логирования в мнутах, рекомендуется для esp8266 использоать интервал не менее 5-ти минут",
"logid1": "ID 1 величины которую будем логировать (температура)",
"logid2": "ID 2 величины которую будем логировать (влажность)",
"points": "Максимальное количество точек в одном файле, может быть не более 300. Не рекомендуется менять этот параметр"
}
},
"defActive": false,
"usedLibs": {
"esp32*": [],
"esp82*": []
}
}

View File

@@ -0,0 +1,498 @@
#include "Global.h"
#include "classes/IoTItem.h"
#include "ESPConfiguration.h"
#include "NTP.h"
void *getAPI_Date3(String params);
class Loging3 : public IoTItem
{
private:
String logid1;
String logid2;
String logid3;
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:
Loging3(String parameters) : IoTItem(parameters)
{
jsonRead(parameters, F("logid1"), logid1);
jsonRead(parameters, F("logid2"), logid2);
jsonRead(parameters, F("logid3"), logid3);
jsonRead(parameters, F("id"), id);
jsonRead(parameters, F("points"), points);
if (points > 300)
{
points = 300;
SerialPrint("E", F("Loging3"), "'" + 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_Date3("{\"id\": \"" + id + "-date\",\"int\":\"20\",\"subtype\":\"date\"}");
IoTItems.push_back(dateIoTItem);
SerialPrint("I", F("Loging3"), "created date instance " + id);
}
void doByInterval()
{
// если объект логгирования не был создан
if (!isItemExist(logid1))
{
SerialPrint("E", F("Loging3"), "'" + id + "' loging object not exist, return");
return;
}
String value = getItemValue(logid1);
// если значение логгирования пустое
if (value == "")
{
SerialPrint("E", F("Loging3"), "'" + id + "' loging value is empty, return");
return;
}
String value2 = getItemValue(logid2);
// если значение логгирования пустое
if (value == "")
{
SerialPrint("E", F("Loging3"), "'" + id + "' loging value is empty, return");
return;
}
String value3 = getItemValue(logid3);
// если значение логгирования пустое
if (value == "")
{
SerialPrint("E", F("Loging3"), "'" + id + "' loging value is empty, return");
return;
}
// если время не было получено из интернета
if (!isTimeSynch)
{
SerialPrint("E", F("Loging"), "'" + id + "' Сant loging - time not synchronized, return");
return;
}
regEvent(value, F("Loging3"));
// String logData2;
String logData3;
jsonWriteInt(logData3, "x", unixTime, false);
jsonWriteFloat(logData3, "y1", value.toFloat(), false);
jsonWriteFloat(logData3, "y2", value2.toFloat(), false);
jsonWriteFloat(logData3, "y3", value3.toFloat(), false);
// прочитаем путь к файлу последнего сохранения
String filePath = readDataDB(id);
// если данные о файле отсутствуют, создадим новый
if (filePath == "failed" || filePath == "")
{
SerialPrint("E", F("Loging3"), "'" + id + "' file path not found, start create new file");
createNewFileWithData(logData3);
return;
}
else
{
// если файл все же есть но был создан не сегодня, то создаем сегодняшний
if (getTodayDateDotFormated() != getDateDotFormatedFromUnix(getFileUnixLocalTime(filePath)))
{
SerialPrint("E", F("Loging3"), "'" + id + "' file too old, start create new file");
createNewFileWithData(logData3);
return;
}
}
// считаем количество строк и определяем размер файла
size_t size = 0;
int lines = countJsonObj(filePath, size);
SerialPrint("i", F("Loging3"), "'" + id + "' " + "lines = " + String(lines) + ", size = " + String(size));
// если количество строк до заданной величины и дата не менялась
if (lines <= points && !hasDayChanged())
{
// просто добавим в существующий файл новые данные
addNewDataToExistingFile(filePath, logData3);
// если больше или поменялась дата то создадим следующий файл
}
else
{
createNewFileWithData(logData3);
}
// запускаем процедуру удаления старых файлов если память переполняется
deleteLastFile();
}
/*
void SetDoByInterval(String valse) {
String value = valse;
// если значение логгирования пустое
if (value == "") {
SerialPrint("E", F("Loging3Event"), "'" + id + "' loging value is empty, return");
return;
}
// если время не было получено из интернета
if (!isTimeSynch) {
SerialPrint("E", F("Loging3Event"), "'" + id + "' Сant loging - time not synchronized, return");
return;
}
regEvent(value, F("Loging3Event"));
String logData3;
jsonWriteInt(logData3, "x", unixTime, false);
jsonWriteFloat(logData3, "y1", value.toFloat(), false);
jsonWriteFloat(logData3, "y2", value.toFloat(), false);
jsonWriteFloat(logData3, "y3", value.toFloat(), false);
// прочитаем путь к файлу последнего сохранения
String filePath = readDataDB(id);
// если данные о файле отсутствуют, создадим новый
if (filePath == "failed" || filePath == "") {
SerialPrint("E", F("Loging3Event"), "'" + id + "' file path not found, start create new file");
createNewFileWithData(logData3);
return;
} else {
// если файл все же есть но был создан не сегодня, то создаем сегодняшний
if (getTodayDateDotFormated() != getDateDotFormatedFromUnix(getFileUnixLocalTime(filePath))) {
SerialPrint("E", F("Loging3Event"), "'" + id + "' file too old, start create new file");
createNewFileWithData(logData3);
return;
}
}
// считаем количество строк и определяем размер файла
size_t size = 0;
int lines = countJsonObj(filePath, size);
SerialPrint("i", F("Loging3Event"), "'" + id + "' " + "lines = " + String(lines) + ", size = " + String(size));
// если количество строк до заданной величины и дата не менялась
if (lines <= points && !hasDayChanged()) {
// просто добавим в существующий файл новые данные
addNewDataToExistingFile(filePath, logData3);
// если больше или поменялась дата то создадим следующий файл
} else {
createNewFileWithData(logData3);
}
// запускаем процедуру удаления старых файлов если память переполняется
deleteLastFile();
}
*/
void createNewFileWithData(String &logData)
{
logData = logData + ",";
String path = "/lg3/" + id + "/" + String(unixTimeShort) + ".txt"; // создадим путь вида /lg/id/133256622333.txt
// создадим пустой файл
if (writeEmptyFile(path) != "success")
{
SerialPrint("E", F("Loging"), "'" + id + "' file writing error, return");
return;
}
// запишем в него данные
if (addFile(path, logData) != "success")
{
SerialPrint("E", F("Loging3"), "'" + id + "' data writing error, return");
return;
}
// запишем путь к нему в базу данных
if (saveDataDB(id, path) != "success")
{
SerialPrint("E", F("Loging3"), "'" + id + "' db file writing error, return");
return;
}
SerialPrint("i", F("Loging3"), "'" + id + "' file created http://" + WiFi.localIP().toString() + path);
}
void addNewDataToExistingFile(String &path, String &logData)
{
logData = logData + ",";
if (addFile(path, logData) != "success")
{
SerialPrint("i", F("Loging3"), "'" + id + "' file writing error, return");
return;
};
SerialPrint("i", F("Loging3"), "'" + 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 = "/lg3/" + id;
filesList = getFilesList(dir);
SerialPrint("i", F("Loging3"), "file list: " + filesList);
int f = 0;
bool noData = true;
while (filesList.length())
{
String path = selectToMarker(filesList, ";");
path = "/lg3/" + 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("Loging3"), String(f) + ") " + path + ", " + getDateTimeDotFormatedFromUnix(fileUnixTimeLocal) + ", sent");
}
else
{
SerialPrint("i", F("Loging3"), 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 value3 = getItemValue(logid3);
String json = "{\"maxCount\":" + String(calculateMaxCount()) + ",\"topic\":\"" + topic + "\",\"status\":[{\"x\":" + String(unixTime) + ",\"y1\":" + value + ",\"y2\":" + value2 + ",\"y3\":" + value3 + "}]}";
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 = "/lg3/" + id;
cleanDirectory(dir);
}
void deleteLastFile()
{
IoTFSInfo tmp = getFSInfo();
SerialPrint("i", "Loging3", String(tmp.freePer) + " % free flash remaining");
if (tmp.freePer <= 20.00)
{
String dir = "/lg3/" + id;
filesList = getFilesList(dir);
int i = 0;
while (filesList.length())
{
String path = selectToMarker(filesList, ";");
path = dir + path;
i++;
if (i == 1)
{
removeFile(path);
SerialPrint("!", "Loging3", 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", "Loging3", "setValue:" + String(value.valD));
regEvent(value.valS, "Loging3", false, genEvent);
}
*/
};
void *getAPI_Loging3(String subtype, String param)
{
if (subtype == F("Loging3"))
{
return new Loging3(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() == "Loging3")
{
if ((*it)->getID() == selectToMarker(id, "-"))
{
(*it)->setPublishDestination(TO_MQTT_WS, -1);
(*it)->publishValue();
}
}
}
}
void setTodayDate()
{
setValue(getTodayDateDotFormated());
SerialPrint("E", F("Loging3"), "today date set " + getTodayDateDotFormated());
}
void doByInterval()
{
if (isTimeSynch)
{
if (firstTime)
{
setTodayDate();
firstTime = false;
}
}
}
};
void *getAPI_Date3(String param)
{
return new Date(param);
}

View File

@@ -0,0 +1,51 @@
{
"menuSection": "virtual_elments",
"configItem": [
{
"global": 0,
"name": "Тройной график",
"type": "Writing",
"subtype": "Loging3",
"id": "log3",
"widget": "chart6",
"page": "Графики",
"descr": "Датчик",
"num": 1,
"int": 5,
"logid1": "t",
"logid2": "h",
"logid3": "p",
"points": 300,
"series1": "Температура, С",
"series2": "Влажность, %",
"series3": "Давление, кПа"
}
],
"about": {
"authorName": "Serghei Crasnicov",
"authorContact": "https://t.me/Serghei63",
"authorGit": "https://github.com/Serghei63",
"specialThanks": "@itsid1 @Valiuhaaa Serg",
"moduleName": "Loging3",
"moduleVersion": "0.0",
"usedRam": {
"esp32_4mb": 15,
"esp8266_4mb": 15
},
"title": "Логирование в график",
"moduleDesc": "Расширение позволяющее логировать любую величину в график. Графики доступны в мобильном приложении и в веб интерфейсе. Данные графиков хранятся в встроенной памяти esp. В окне ввода даты можно выбирать день, историю которого вы хотите посмотреть. Старые файлы будут удаляться автоматически после того как объем оставшейся flesh памяти устройства будет менее 20 процентов",
"propInfo": {
"int": "Интервал логирования в мнутах, рекомендуется для esp8266 использоать интервал не менее 5-ти минут",
"logid1": "ID 1 величины которую будем логировать (температура)",
"logid2": "ID 2 величины которую будем логировать (влажность)",
"logid3": "ID 3 величины которую будем логировать (давление)",
"points": "Максимальное количество точек в одном файле, может быть не более 300. Не рекомендуется менять этот параметр"
}
},
"defActive": false,
"usedLibs": {
"esp32*": [],
"esp82*": []
}
}

View File

@@ -160,7 +160,11 @@ public:
SerialPrint("E", F("LogingHourly"), "'" + id + "' db file writing error, return"); SerialPrint("E", F("LogingHourly"), "'" + id + "' db file writing error, return");
return; return;
} }
#ifdef LIBRETINY
SerialPrint("i", F("LogingHourly"), "'" + id + "' file created http://" + ipToString(WiFi.localIP()) + path);
#else
SerialPrint("i", F("LogingHourly"), "'" + id + "' file created http://" + WiFi.localIP().toString() + path); SerialPrint("i", F("LogingHourly"), "'" + id + "' file created http://" + WiFi.localIP().toString() + path);
#endif
} }
void addNewDataToExistingFile(String &path, String &logData) void addNewDataToExistingFile(String &path, String &logData)
@@ -171,7 +175,11 @@ public:
SerialPrint("i", F("LogingHourly"), "'" + id + "' file writing error, return"); SerialPrint("i", F("LogingHourly"), "'" + id + "' file writing error, return");
return; return;
}; };
#ifdef LIBRETINY
SerialPrint("i", F("LogingHourly"), "'" + id + "' LogingHourly in file http://" + ipToString(WiFi.localIP()) + path);
#else
SerialPrint("i", F("LogingHourly"), "'" + id + "' LogingHourly in file http://" + WiFi.localIP().toString() + path); SerialPrint("i", F("LogingHourly"), "'" + id + "' LogingHourly in file http://" + WiFi.localIP().toString() + path);
#endif
} }
const String getTimeLocal_hh() const String getTimeLocal_hh()
{ {

View File

@@ -3,9 +3,43 @@
#if defined(ESP32) #if defined(ESP32)
#include <esp_task_wdt.h> #include <esp_task_wdt.h>
#endif #endif
#include "DebugTrace.h"
#define TRIESONE 20 // количество секунд ожидания подключения к одной сети из несколких #define TRIESONE 20 // количество секунд ожидания подключения к одной сети из несколких
#define TRIES 30 // количество секунд ожидания подключения сети если она одна #define TRIES 30 // количество секунд ожидания подключения сети если она одна
#if defined(esp32_wifirep)
#include "lwip/lwip_napt.h"
// #include "lwip/ip_route.h"
#define PROTO_TCP 6
#define PROTO_UDP 17
IPAddress stringToIp(String strIp)
{
IPAddress ip;
ip.fromString(strIp);
return ip;
}
#endif
void addPortMap(String TCP_UDP, String maddr, u16_t mport, String daddr, u16_t dport)
{
#if defined(esp32_wifirep)
uint8_t tcp_udp;
if (TCP_UDP == "TCP")
tcp_udp = PROTO_TCP;
else if (TCP_UDP == "UDP")
tcp_udp = PROTO_UDP;
else
SerialPrint("E", "WIFI", "Add port map: ERROR, Must be 'TCP' or 'UDP'");
ip_portmap_add(tcp_udp, stringToIp(maddr), mport, stringToIp(daddr), dport);
SerialPrint("i", "WIFI", "Add port map: " + String(tcp_udp) + ", " + maddr + ":" + String(mport) + " -> " + daddr + ":" + String(dport));
#else
SerialPrint("E", "WIFI", "Add port map: ERROR, change board to esp32_wifirep");
#endif
}
#ifdef WIFI_ASYNC #ifdef WIFI_ASYNC
std::vector<String> _ssidList; std::vector<String> _ssidList;
std::vector<String> _passwordList; std::vector<String> _passwordList;
@@ -50,6 +84,10 @@ void WiFiEvent(arduino_event_t *event)
mqttInit(); mqttInit();
SerialPrint("i", F("WIFI"), F("Network Init")); SerialPrint("i", F("WIFI"), F("Network Init"));
bool postMsgTelegram;
if (!jsonRead(settingsFlashJson, "debugTraceMsgTlgrm", postMsgTelegram, false)) postMsgTelegram = 1;
sendDebugTraceAndFreeMemory(postMsgTelegram);
// Отключаем AP при успешном подключении // Отключаем AP при успешном подключении
WiFi.softAPdisconnect(true); WiFi.softAPdisconnect(true);
break; break;
@@ -70,6 +108,7 @@ void WiFiEvent(arduino_event_t *event)
} }
else else
{ // если попытки подключения исчерпаны, то переходим в AP { // если попытки подключения исчерпаны, то переходим в AP
sendDebugTraceAndFreeMemory(false);
startAPMode(); startAPMode();
} }
break; break;
@@ -280,10 +319,65 @@ void ScanAsync()
WiFi.scanNetworks(true, false); WiFi.scanNetworks(true, false);
} }
} }
#else #else //WIFI_ASYNC
// ESP8266
void routerConnect() void routerConnect()
{ {
#if defined(esp32_wifirep)
// Set custom dns server address for dhcp server
#define MY_DNS_IP_ADDR 0xC0A80401 // 192.168.4.1 // 0x08080808 // 8.8.8.8
ip_addr_t dnsserver;
String _ssidAP = jsonReadStr(settingsFlashJson, "apssid");
String _passwordAP = jsonReadStr(settingsFlashJson, "appass");
int _chanelAP = 0;
jsonRead(settingsFlashJson, "wifirep_apchanel", _chanelAP);
if (_chanelAP == 0)
_chanelAP = 7;
// WiFi.begin(ssid, password);
WiFi.mode(WIFI_AP_STA);
String s_apip = "";
bool ap_ip = jsonRead(settingsFlashJson, "wifirep_apip", s_apip);
if (ap_ip && s_apip != "")
{
WiFi.softAPConfig(stringToIp(s_apip), stringToIp(s_apip), stringToIp("255.255.255.0"));
// bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dhcp_lease_start = (uint32_t) 0);
dnsserver.u_addr.ip4.addr = stringToIp(s_apip);
}
else
dnsserver.u_addr.ip4.addr = htonl(MY_DNS_IP_ADDR);
dnsserver.type = IPADDR_TYPE_V4;
dhcps_dns_setserver(&dnsserver);
WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str(), _chanelAP, 0, 5);
jsonWriteStr(settingsFlashJson, "ip", WiFi.softAPIP().toString());
SerialPrint("i", "WIFI", "AP SSID: " + WiFi.softAPSSID());
SerialPrint("i", "WIFI", "AP IP: " + WiFi.softAPIP().toString());
SerialPrint("i", "WIFI", "AP pass: " + _passwordAP);
String s_staip = "";
bool static_ip = jsonRead(settingsFlashJson, "wifirep_staip", s_staip);
String s_gateway = jsonReadStr(settingsFlashJson, "wifirep_gateway");
String s_netmask = jsonReadStr(settingsFlashJson, "wifirep_netmask");
String s_dns = jsonReadStr(settingsFlashJson, "wifirep_dns");
if (static_ip == true && s_staip != "")
{
SerialPrint("i", "WIFI", "Use static IP");
WiFi.config(stringToIp(s_staip), stringToIp(s_gateway), stringToIp(s_netmask), stringToIp(s_dns));
// bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000);
SerialPrint("i", "WIFI", "Static IP: " + s_staip);
SerialPrint("i", "WIFI", "Gateway: " + s_gateway);
SerialPrint("i", "WIFI", "Netmask: " + s_netmask);
SerialPrint("i", "WIFI", "DNS: " + s_dns);
}
#else
WiFi.mode(WIFI_STA);
#endif
#if !defined LIBRETINY #if !defined LIBRETINY
#if defined(esp32c6_4mb) || defined(esp32c6_8mb) #if defined(esp32c6_4mb) || defined(esp32c6_8mb)
WiFi.setAutoReconnect(false); WiFi.setAutoReconnect(false);
@@ -303,7 +397,7 @@ void routerConnect()
SerialPrint("i", "WIFI", "Gateway: " + s_gateway); SerialPrint("i", "WIFI", "Gateway: " + s_gateway);
SerialPrint("i", "WIFI", "Netmask: " + s_netmask); SerialPrint("i", "WIFI", "Netmask: " + s_netmask);
SerialPrint("i", "WIFI", "DNS: " + s_dns); */ SerialPrint("i", "WIFI", "DNS: " + s_dns); */
WiFi.mode(WIFI_STA); //WiFi.mode(WIFI_STA);
byte triesOne = TRIESONE; byte triesOne = TRIESONE;
std::vector<String> _ssidList; std::vector<String> _ssidList;
@@ -390,6 +484,25 @@ void routerConnect()
jsonWriteStr(settingsFlashJson, "ip", WiFi.localIP().toString()); jsonWriteStr(settingsFlashJson, "ip", WiFi.localIP().toString());
#endif #endif
createItemFromNet("onWifi", "1", 1); createItemFromNet("onWifi", "1", 1);
#if defined(esp32_wifirep)
// Enable DNS (offer) for dhcp server
dhcps_offer_t dhcps_dns_value = OFFER_DNS;
dhcps_set_option_info(6, &dhcps_dns_value, sizeof(dhcps_dns_value));
u32_t napt_netif_ip;
if (ap_ip && s_apip != "")
napt_netif_ip = stringToIp(s_apip);
else
{
napt_netif_ip = 0xC0A80401; // Set to ip address of softAP netif (Default is 192.168.4.1)
napt_netif_ip = htonl(napt_netif_ip);
}
// get_esp_interface_netif(ESP_IF_WIFI_AP)
ip_napt_enable(napt_netif_ip, 1);
// ip_napt_enable_no(ESP_IF_WIFI_AP, 1);
#endif
mqttInit(); mqttInit();
} }
SerialPrint("i", F("WIFI"), F("Network Init")); SerialPrint("i", F("WIFI"), F("Network Init"));