Merge branch 'ver4dev' into FixLog

This commit is contained in:
2023-10-03 22:26:05 +03:00
committed by GitHub
63 changed files with 1737 additions and 1319 deletions

View File

@@ -712,7 +712,7 @@
"type": "Writing", "type": "Writing",
"subtype": "IoTServo", "subtype": "IoTServo",
"id": "servo", "id": "servo",
"widget": "range", "widget": "rangeServo",
"page": "servo", "page": "servo",
"descr": "угол", "descr": "угол",
"int": 1, "int": 1,

View File

@@ -3,8 +3,14 @@
"name": "IoTmanagerVer4", "name": "IoTmanagerVer4",
"apssid": "IoTmanager", "apssid": "IoTmanager",
"appass": "", "appass": "",
"routerssid": "iot", "routerssid": [
"routerpass": "hostel3333", "iot",
"wifi"
],
"routerpass": [
"hostel3333",
"pswd"
],
"timezone": 2, "timezone": 2,
"ntp": "pool.ntp.org", "ntp": "pool.ntp.org",
"weblogin": "admin", "weblogin": "admin",
@@ -32,6 +38,11 @@
"firmware": "0x00000", "firmware": "0x00000",
"littlefs": "0x300000" "littlefs": "0x300000"
}, },
{
"name": "esp8266_16mb",
"firmware": "0x00000",
"littlefs": "0x200000"
},
{ {
"name": "esp32_4mb", "name": "esp32_4mb",
"boot_app0": "0xe000", "boot_app0": "0xe000",
@@ -40,6 +51,14 @@
"partitions": "0x8000", "partitions": "0x8000",
"littlefs": "0x290000" "littlefs": "0x290000"
}, },
{
"name": "esp32_16mb",
"boot_app0": "0xe000",
"bootloader_qio_80m": "0x1000",
"firmware": "0x10000",
"partitions": "0x8000",
"littlefs": "0x910000"
},
{ {
"name": "esp8266_1mb", "name": "esp8266_1mb",
"firmware": "0x00000000", "firmware": "0x00000000",
@@ -381,6 +400,10 @@
"path": "src/modules/display/NextionUpload", "path": "src/modules/display/NextionUpload",
"active": false "active": false
}, },
{
"path": "src/modules/display/Oled128",
"active": false
},
{ {
"path": "src/modules/display/Smi2_m", "path": "src/modules/display/Smi2_m",
"active": true "active": true

View File

@@ -2,8 +2,14 @@
"name": "IoTmanagerVer4", "name": "IoTmanagerVer4",
"apssid": "IoTmanager", "apssid": "IoTmanager",
"appass": "", "appass": "",
"routerssid": "iot", "routerssid": [
"routerpass": "hostel3333", "iot",
"wifi"
],
"routerpass": [
"hostel3333",
"pswd"
],
"timezone": 2, "timezone": 2,
"ntp": "pool.ntp.org", "ntp": "pool.ntp.org",
"weblogin": "admin", "weblogin": "admin",

View File

@@ -246,11 +246,11 @@
"debounce": 500 "debounce": 500
}, },
{ {
"name": "range", "name": "rangeServo",
"label": "Ползунок (Servo)", "label": "Ползунок (Servo)",
"widget": "range", "widget": "range",
"descrColor": "red", "descrColor": "red",
"after": "%", "after": "°",
"k": 1, "k": 1,
"min": 0, "min": 0,
"max": 180, "max": 180,

View File

@@ -1,308 +0,0 @@
[
{
"name": "anydataRed",
"label": "Сообщение1",
"widget": "anydata",
"icon": "body",
"color": "red",
"descrColor": "red"
},
{
"name": "anydataDgr",
"label": "Сообщение2",
"widget": "anydata",
"after": "",
"color": "red",
"icon": "walk"
},
{
"name": "anydataDef",
"label": "Текст",
"widget": "anydata",
"after": "",
"icon": ""
},
{
"name": "anydataVlt",
"label": "Вольты",
"widget": "anydata",
"after": "V",
"icon": "speedometer"
},
{
"name": "anydataAmp",
"label": "Амперы",
"widget": "anydata",
"after": "A",
"icon": "speedometer"
},
{
"name": "anydataWt",
"label": "Ватты",
"widget": "anydata",
"after": "Wt",
"icon": "speedometer",
"color": [
{
"level": 0,
"value": ""
},
{
"level": 200,
"value": "#009933"
},
{
"level": 2000,
"value": "#FF9900"
},
{
"level": 4000,
"value": "red"
}
]
},
{
"name": "anydataWth",
"label": "Энергия",
"widget": "anydata",
"after": "kWh",
"icon": "speedometer"
},
{
"name": "anydataHtz",
"label": "Герцы",
"widget": "anydata",
"after": "Hz",
"icon": "speedometer"
},
{
"name": "anydataTmp",
"label": "Температура",
"widget": "anydata",
"after": "°С",
"icon": "thermometer",
"font": "OCR A Std",
"color": [
{
"level": -20,
"value": "#0000CC"
},
{
"level": -10,
"value": "#0000CC"
},
{
"level": 0,
"value": "#0000CC"
},
{
"level": 12,
"value": "#3366FF"
},
{
"level": 16,
"value": "#33CCFF"
},
{
"level": 18,
"value": "#009933"
},
{
"level": 30,
"value": "#FF9900"
},
{
"level": 40,
"value": "red"
}
]
},
{
"name": "anydataMm",
"label": "Давление",
"widget": "anydata",
"after": "mm",
"icon": "speedometer"
},
{
"name": "anydataHum",
"label": "Влажность",
"widget": "anydata",
"after": "%",
"icon": "water",
"color": "#88AADF"
},
{
"name": "anydataTm",
"label": "Время",
"widget": "anydata",
"after": "",
"icon": "speedometer"
},
{
"name": "button",
"label": "Кнопка",
"widget": "btn",
"size": "large",
"color": "green",
"send": "test"
},
{
"name": "toggle",
"label": "Переключатель",
"widget": "toggle",
"icon": "",
"iconOff": ""
},
{
"name": "chart1",
"label": "График без точек",
"widget": "chart",
"dateFormat": "HH:mm",
"maxCount": 86400,
"pointRadius": 0
},
{
"name": "chart2",
"label": "График с точками",
"widget": "chart",
"maxCount": 86400,
"dateFormat": "HH:mm"
},
{
"name": "chart3",
"label": "График Дневной",
"widget": "chart",
"dateFormat": "DD.MM.YYYY",
"maxCount": 86400,
"type": "bar"
},
{
"name": "fillgauge",
"label": "Бочка",
"widget": "fillgauge",
"circleColor": "#00FFFF",
"textColor": "#FFFFFF",
"waveTextColor": "#000000",
"waveColor": "#00FFFF"
},
{
"name": "inputDate",
"label": "Ввод даты",
"widget": "input",
"size": "small",
"color": "orange",
"type": "date"
},
{
"name": "inputDgt",
"label": "Ввод числа",
"widget": "input",
"color": "blue",
"type": "number"
},
{
"name": "inputTxt",
"label": "Ввод текста",
"widget": "input",
"size": "small",
"color": "orange",
"type": "text"
},
{
"name": "inputTm",
"label": "Ввод времени",
"widget": "input",
"color": "blue",
"type": "time"
},
{
"name": "progressLine",
"label": "Статус линия",
"widget": "progress-line",
"icon": "sunny",
"max": "100",
"stroke": "10"
},
{
"name": "progressRound",
"label": "Статус круг",
"widget": "progress-round",
"max": "100",
"stroke": "20",
"color": "#45ccce",
"background": "#777",
"semicircle": "1"
},
{
"name": "range",
"label": "Ползунок",
"widget": "range",
"descrColor": "red",
"after": "%",
"k": 0.0977,
"min": 0,
"max": 100,
"debounce": 500
},
{
"name": "range",
"label": "Ползунок (Servo)",
"widget": "range",
"descrColor": "red",
"after": "%",
"k": 1,
"min": 0,
"max": 180,
"debounce": 500
},
{
"name": "select",
"label": "Выпадающий",
"widget": "select",
"options": [
"Выключен",
"Включен"
],
"status": 0
},
{
"name": "anydataPpm",
"label": "PPM",
"widget": "anydata",
"after": "ppm",
"icon": "speedometer"
},
{
"name": "anydatamAmp",
"label": "миллиАмперы",
"widget": "anydata",
"after": "mAmp",
"icon": "speedometer"
},
{
"name": "anydatamVlt",
"label": "миллиВольты",
"widget": "anydata",
"after": "mVlt",
"icon": "speedometer"
},
{
"name": "anydatamWt",
"label": "миллиВатты",
"widget": "anydata",
"after": "mWt",
"icon": "speedometer"
},
{
"name": "anydataCm",
"label": "Сантиметры",
"widget": "anydata",
"after": "cm",
"icon": "speedometer"
},
{
"name": "nil",
"label": "Без виджета"
}
]

View File

@@ -246,11 +246,11 @@
"debounce": 500 "debounce": 500
}, },
{ {
"name": "range", "name": "rangeServo",
"label": "Ползунок (Servo)", "label": "Ползунок (Servo)",
"widget": "range", "widget": "range",
"descrColor": "red", "descrColor": "red",
"after": "%", "after": "°",
"k": 1, "k": 1,
"min": 0, "min": 0,
"max": 180, "max": 180,

View File

@@ -24,10 +24,18 @@
#define FIRMWARE_NAME "esp8266_4mb" #define FIRMWARE_NAME "esp8266_4mb"
#endif #endif
#ifdef esp8266_16mb
#define FIRMWARE_NAME "esp8266_16mb"
#endif
#ifdef esp32_4mb #ifdef esp32_4mb
#define FIRMWARE_NAME "esp32_4mb" #define FIRMWARE_NAME "esp32_4mb"
#endif #endif
#ifdef esp32_16mb
#define FIRMWARE_NAME "esp32_16mb"
#endif
#ifdef esp32s2_4mb #ifdef esp32s2_4mb
#define FIRMWARE_NAME "esp32s2_4mb" #define FIRMWARE_NAME "esp32s2_4mb"
#endif #endif

View File

@@ -14,6 +14,7 @@ boolean mqttConnect();
void mqttReconnect(); void mqttReconnect();
void mqttLoop(); void mqttLoop();
void mqttSubscribe(); void mqttSubscribe();
bool mqttIsConnect();
boolean publish(const String& topic, const String& data); boolean publish(const String& topic, const String& data);
boolean publishData(const String& topic, const String& data); boolean publishData(const String& topic, const String& data);
@@ -21,6 +22,7 @@ boolean publishChartMqtt(const String& topic, const String& data);
boolean publishJsonMqtt(const String& topic, const String& json); boolean publishJsonMqtt(const String& topic, const String& json);
boolean publishStatusMqtt(const String& topic, const String& data); boolean publishStatusMqtt(const String& topic, const String& data);
boolean publishEvent(const String& topic, const String& data); boolean publishEvent(const String& topic, const String& data);
void mqttSubscribeExternal(String topic, bool usePrefix);
bool publishChartFileToMqtt(String path, String id, int maxCount); bool publishChartFileToMqtt(String path, String id, int maxCount);

View File

@@ -11,7 +11,7 @@ struct IoTValue {
class IoTItem { class IoTItem {
public: public:
IoTItem(const String& parameters); IoTItem(const String& parameters);
virtual ~IoTItem() {} virtual ~IoTItem() {};
virtual void loop(); virtual void loop();
virtual void doByInterval(); virtual void doByInterval();
virtual IoTValue execute(String command, std::vector<IoTValue>& param); virtual IoTValue execute(String command, std::vector<IoTValue>& param);
@@ -35,9 +35,12 @@ class IoTItem {
void setInterval(long interval); void setInterval(long interval);
void setIntFromNet(int interval); void setIntFromNet(int interval);
unsigned long currentMillis; // unsigned long currentMillis;
unsigned long prevMillis; // unsigned long prevMillis;
unsigned long difference; // unsigned long difference;
unsigned long nextMillis=0; // достаточно 1 переменной, надо экономить память
// задержка следующего вызова, не изменяет текущий _interval
void suspendNextDoByInt(unsigned long _delay); // 0 - force
IoTValue value; // хранение основного значения, которое обновляется из сценария, execute(), loop() или doByInterval() IoTValue value; // хранение основного значения, которое обновляется из сценария, execute(), loop() или doByInterval()

View File

@@ -15,6 +15,7 @@ extern bool jsonRead(const String& json, String key, float& value, bool e = true
extern bool jsonRead(const String& json, String key, String& value, bool e = true); extern bool jsonRead(const String& json, String key, String& value, bool e = true);
extern bool jsonRead(const String& json, String key, bool& value, bool e = true); extern bool jsonRead(const String& json, String key, bool& value, bool e = true);
extern bool jsonRead(const String& json, String key, int& value, bool e = true); extern bool jsonRead(const String& json, String key, int& value, bool e = true);
extern bool jsonReadArray(const String& json, String key, std::vector<String>& jArray, bool e = true);
extern String jsonReadStr(const String& json, String name, bool e = true); extern String jsonReadStr(const String& json, String name, bool e = true);
extern int jsonReadInt(const String& json, String name, bool e = true); extern int jsonReadInt(const String& json, String name, bool e = true);

View File

@@ -2,11 +2,10 @@
#include "Global.h" #include "Global.h"
#include "MqttClient.h" #include "MqttClient.h"
boolean isNetworkActive(); boolean isNetworkActive();
uint8_t getNumAPClients(); uint8_t getNumAPClients();
void routerConnect(); void routerConnect();
bool startAPMode(); bool startAPMode();
boolean RouterFind(String ssid); boolean RouterFind(std::vector<String> jArray);
uint8_t RSSIquality(); uint8_t RSSIquality();
extern void wifiSignalInit(); extern void wifiSignalInit();

View File

@@ -32,6 +32,11 @@
"firmware": "0x00000", "firmware": "0x00000",
"littlefs": "0x300000" "littlefs": "0x300000"
}, },
{
"name": "esp8266_16mb",
"firmware": "0x00000",
"littlefs": "0x200000"
},
{ {
"name": "esp32_4mb", "name": "esp32_4mb",
"boot_app0": "0xe000", "boot_app0": "0xe000",
@@ -40,6 +45,14 @@
"partitions": "0x8000", "partitions": "0x8000",
"littlefs": "0x290000" "littlefs": "0x290000"
}, },
{
"name": "esp32_16mb",
"boot_app0": "0xe000",
"bootloader_qio_80m": "0x1000",
"firmware": "0x10000",
"partitions": "0x8000",
"littlefs": "0x910000"
},
{ {
"name": "esp8266_1mb", "name": "esp8266_1mb",
"firmware": "0x00000000", "firmware": "0x00000000",
@@ -381,6 +394,10 @@
"path": "src/modules/display/NextionUpload", "path": "src/modules/display/NextionUpload",
"active": false "active": false
}, },
{
"path": "src/modules/display/Oled128",
"active": false
},
{ {
"path": "src/modules/display/Smi2_m", "path": "src/modules/display/Smi2_m",
"active": true "active": true

View File

@@ -32,6 +32,11 @@
"firmware": "0x00000", "firmware": "0x00000",
"littlefs": "0x300000" "littlefs": "0x300000"
}, },
{
"name": "esp8266_16mb",
"firmware": "0x00000",
"littlefs": "0x200000"
},
{ {
"name": "esp32_4mb", "name": "esp32_4mb",
"boot_app0": "0xe000", "boot_app0": "0xe000",
@@ -40,6 +45,14 @@
"partitions": "0x8000", "partitions": "0x8000",
"littlefs": "0x290000" "littlefs": "0x290000"
}, },
{
"name": "esp32_16mb",
"boot_app0": "0xe000",
"bootloader_qio_80m": "0x1000",
"firmware": "0x10000",
"partitions": "0x8000",
"littlefs": "0x910000"
},
{ {
"name": "esp8266_1mb", "name": "esp8266_1mb",
"firmware": "0x00000000", "firmware": "0x00000000",
@@ -381,6 +394,10 @@
"path": "src/modules/display/NextionUpload", "path": "src/modules/display/NextionUpload",
"active": false "active": false
}, },
{
"path": "src/modules/display/Oled128",
"active": false
},
{ {
"path": "src/modules/display/Smi2_m", "path": "src/modules/display/Smi2_m",
"active": true "active": true

View File

@@ -157,6 +157,28 @@ build_src_filter =
+<modules/*.cpp> +<modules/*.cpp>
${env:esp8266_4mb_fromitems.build_src_filter} ${env:esp8266_4mb_fromitems.build_src_filter}
[env:esp8266_16mb]
extra_scripts = pre:tools/patch8266_16m.py
lib_deps =
${common_env_data.lib_deps_external}
${env:esp8266_16mb_fromitems.lib_deps}
ESPAsyncUDP
build_flags = -Desp8266_16mb="esp8266_16mb"
framework = arduino
board = nodemcuv2
platform = espressif8266 @4.0.1
board_build.ldscript = eagle.flash.16m14m.ld
monitor_filters = esp8266_exception_decoder
upload_speed = 921600
monitor_speed = 115200
board_build.filesystem = littlefs
build_src_filter =
+<*.cpp>
+<classes/*.cpp>
+<utils/*.cpp>
+<modules/*.cpp>
${env:esp8266_16mb_fromitems.build_src_filter}
[env:esp32_4mb] [env:esp32_4mb]
lib_deps = lib_deps =
${common_env_data.lib_deps_external} ${common_env_data.lib_deps_external}
@@ -200,6 +222,29 @@ build_src_filter =
+<modules/*.cpp> +<modules/*.cpp>
${env:esp32s2_4mb_fromitems.build_src_filter} ${env:esp32s2_4mb_fromitems.build_src_filter}
[env:esp32_16mb]
lib_deps =
${common_env_data.lib_deps_external}
${env:esp32_16mb_fromitems.lib_deps}
build_flags = -Desp32_16mb="esp32_16mb"
framework = arduino
board = esp32dev
platform = espressif32 @5.1.1
monitor_filters = esp32_exception_decoder
upload_port = COM11
upload_speed = 921600
monitor_speed = 115200
debug_tool = esp-prog
board_build.partitions = tools/large_spiffs_16MB.csv
board_upload.flash_size = 16MB
board_build.filesystem = littlefs
build_src_filter =
+<*.cpp>
+<classes/*.cpp>
+<utils/*.cpp>
+<modules/*.cpp>
${env:esp32_16mb_fromitems.build_src_filter}
[env:esp8266_1mb_ota_fromitems] [env:esp8266_1mb_ota_fromitems]
lib_deps = lib_deps =
adafruit/Adafruit BME280 Library adafruit/Adafruit BME280 Library
@@ -414,6 +459,7 @@ lib_deps =
marcoschwartz/LiquidCrystal_I2C@^1.1.4 marcoschwartz/LiquidCrystal_I2C@^1.1.4
https://github.com/maxint-rd/TM16xx https://github.com/maxint-rd/TM16xx
adafruit/Adafruit GFX Library @ ^1.11.5 adafruit/Adafruit GFX Library @ ^1.11.5
adafruit/Adafruit BusIO @ ^1.13.2
build_src_filter = build_src_filter =
+<modules/virtual/Cron> +<modules/virtual/Cron>
+<modules/virtual/Loging> +<modules/virtual/Loging>
@@ -526,3 +572,31 @@ build_src_filter =
+<modules/exec/Ftp> +<modules/exec/Ftp>
+<modules/exec/TelegramLT> +<modules/exec/TelegramLT>
[env:esp8266_16mb_fromitems]
lib_deps =
gyverlibs/EncButton @ ^2.0
build_src_filter =
+<modules/virtual/Cron>
+<modules/virtual/Loging>
+<modules/virtual/LogingDaily>
+<modules/virtual/Timer>
+<modules/virtual/Variable>
+<modules/virtual/VariableColor>
+<modules/virtual/VButton>
+<modules/exec/ButtonIn>
+<modules/exec/ButtonOut>
+<modules/exec/Enconder>
+<modules/exec/TelegramLT>
[env:esp32_16mb_fromitems]
lib_deps =
build_src_filter =
+<modules/virtual/Cron>
+<modules/virtual/Loging>
+<modules/virtual/LogingDaily>
+<modules/virtual/Timer>
+<modules/virtual/Variable>
+<modules/virtual/VButton>
+<modules/exec/ButtonOut>
+<modules/exec/TelegramLT>

View File

@@ -10,8 +10,8 @@
IoTScenario iotScen; // объект управления сценарием IoTScenario iotScen; // объект управления сценарием
String volStrForSave = ""; String volStrForSave = "";
unsigned long currentMillis; // unsigned long currentMillis; // это сдесь лишнее
unsigned long prevMillis; // unsigned long prevMillis;
void elementsLoop() { void elementsLoop() {
// передаем управление каждому элементу конфигурации для выполнения своих функций // передаем управление каждому элементу конфигурации для выполнения своих функций

View File

@@ -5,7 +5,7 @@ void mqttInit() {
ts.add( ts.add(
WIFI_MQTT_CONNECTION_CHECK, MQTT_RECONNECT_INTERVAL, WIFI_MQTT_CONNECTION_CHECK, MQTT_RECONNECT_INTERVAL,
[&](void*) { [&](void*) {
if (WiFi.status() == WL_CONNECTED) { if (isNetworkActive()) {
SerialPrint("i", F("WIFI"), "http://" + jsonReadStr(settingsFlashJson, F("ip"))); SerialPrint("i", F("WIFI"), "http://" + jsonReadStr(settingsFlashJson, F("ip")));
wifiUptimeCalc(); wifiUptimeCalc();
if (mqtt.connected()) { if (mqtt.connected()) {
@@ -95,6 +95,10 @@ void mqttReconnect() {
mqttConnect(); mqttConnect();
} }
bool mqttIsConnect(){
return mqtt.connected();
}
void getMqttData() { void getMqttData() {
mqttServer = jsonReadStr(settingsFlashJson, F("mqttServer")); mqttServer = jsonReadStr(settingsFlashJson, F("mqttServer"));
mqttPort = jsonReadInt(settingsFlashJson, F("mqttPort")); mqttPort = jsonReadInt(settingsFlashJson, F("mqttPort"));
@@ -116,6 +120,16 @@ void mqttSubscribe() {
} }
} }
void mqttSubscribeExternal(String topic, bool usePrefix) {
SerialPrint("i", F("MQTT"), ("subscribed external" + topic).c_str());
// SerialPrint("i", F("MQTT"), mqttRootDevice);
if (usePrefix)
{
mqtt.subscribe((mqttPrefix + topic).c_str());
}
mqtt.subscribe(topic.c_str());
}
void mqttCallback(char* topic, uint8_t* payload, size_t length) { void mqttCallback(char* topic, uint8_t* payload, size_t length) {
String topicStr = String(topic); String topicStr = String(topic);
// SerialPrint("i", "=>MQTT", topicStr); // SerialPrint("i", "=>MQTT", topicStr);

View File

@@ -101,7 +101,7 @@ String ESP32GetResetReason(uint32_t cpu_no) {
} }
} }
#endif #endif
#ifdef esp32_4mb #if defined(esp32_4mb) || defined(esp32_16mb)
String ESP_getResetReason(void) { String ESP_getResetReason(void) {
return ESP32GetResetReason(0); // CPU 0 return ESP32GetResetReason(0); // CPU 0
} }

View File

@@ -7,24 +7,22 @@ String unsupportedFiles = String();
static const char TEXT_PLAIN[] PROGMEM = "text/plain"; static const char TEXT_PLAIN[] PROGMEM = "text/plain";
static const char FS_INIT_ERROR[] PROGMEM = "FS INIT ERROR"; 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";
void standWebServerInit() void standWebServerInit() {
{
// Кэшировать файлы для быстрой работы // Кэшировать файлы для быстрой работы
HTTP.serveStatic("/bundle.js", FileFS, "/", "max-age=31536000"); // кеширование на 1 год // если указана директория то все файлы будут отмечены как Directory Request Handler
HTTP.serveStatic("/bundle.css", FileFS, "/", "max-age=31536000"); // кеширование на 1 год // если указан файл то он будет отмечен как File Request Handler
HTTP.serveStatic("/bundle.js.gz", FileFS, "/", "max-age=31536000"); // кеширование на 1 год HTTP.serveStatic("/build", FileFS, "/build", "max-age=31536000"); // кеширование на 1 год
HTTP.serveStatic("/bundle.css.gz", FileFS, "/", "max-age=31536000"); // кеширование на 1 год HTTP.serveStatic("/favicon.ico", FileFS, "/favicon.ico", "max-age=31536000"); // кеширование на 1 год
HTTP.serveStatic("/favicon.png", FileFS, "/", "max-age=31536000"); // кеширование на 1 год
// HTTP.on("/devicelist.json", HTTP_GET, []() { // HTTP.on("/devicelist.json", HTTP_GET, []() {
// HTTP.send(200, "application/json", devListHeapJson); // HTTP.send(200, "application/json", devListHeapJson);
// }); // });
HTTP.on("/settings.h.json", HTTP_GET, []() { // HTTP.on("/settings.h.json", HTTP_GET, []() {
HTTP.send(200, "application/json", settingsFlashJson); // HTTP.send(200, "application/json", settingsFlashJson);
}); //});
// HTTP.on("/settings.f.json", HTTP_GET, []() { // HTTP.on("/settings.f.json", HTTP_GET, []() {
// HTTP.send(200, "application/json", readFile(F("settings.json"), 20000)); // HTTP.send(200, "application/json", readFile(F("settings.json"), 20000));
// }); // });
@@ -46,21 +44,19 @@ void standWebServerInit()
// HTTP.send(200, "text/plain", "ok"); // HTTP.send(200, "text/plain", "ok");
// }); // });
HTTP.on("/set", HTTP_GET, []() { HTTP.on("/set", HTTP_GET, []() {
if (HTTP.hasArg(F("routerssid")) && WiFi.getMode() == WIFI_AP) { if (HTTP.hasArg(F("routerssid")) && WiFi.getMode() == WIFI_AP) {
jsonWriteStr(settingsFlashJson, F("routerssid"), HTTP.arg(F("routerssid"))); jsonWriteStr(settingsFlashJson, F("routerssid"), HTTP.arg(F("routerssid")));
syncSettingsFlashJson(); syncSettingsFlashJson();
HTTP.send(200, "text/plain", "ok"); HTTP.send(200, "text/plain", "ok");
} }
if (HTTP.hasArg(F("routerpass")) && WiFi.getMode() == WIFI_AP) { if (HTTP.hasArg(F("routerpass")) && WiFi.getMode() == WIFI_AP) {
jsonWriteStr(settingsFlashJson, F("routerpass"), HTTP.arg(F("routerpass"))); jsonWriteStr(settingsFlashJson, F("routerpass"), HTTP.arg(F("routerpass")));
syncSettingsFlashJson(); syncSettingsFlashJson();
HTTP.send(200, "text/plain", "ok"); HTTP.send(200, "text/plain", "ok");
} }
});
});
// Добавляем функцию Update для перезаписи прошивки по WiFi при 1М(256K FileFS) и выше // Добавляем функцию Update для перезаписи прошивки по WiFi при 1М(256K FileFS) и выше
// httpUpdater.setup(&HTTP); // httpUpdater.setup(&HTTP);
@@ -101,39 +97,33 @@ void standWebServerInit()
//////////////////////////////// ////////////////////////////////
// Utils to return HTTP codes, and determine content-type // Utils to return HTTP codes, and determine content-type
void replyOK() void replyOK() {
{
HTTP.send(200, FPSTR(TEXT_PLAIN), ""); HTTP.send(200, FPSTR(TEXT_PLAIN), "");
} }
void replyOKWithMsg(String msg) void replyOKWithMsg(String msg) {
{
HTTP.send(200, FPSTR(TEXT_PLAIN), msg); HTTP.send(200, FPSTR(TEXT_PLAIN), msg);
} }
void replyNotFound(String msg) void replyNotFound(String msg) {
{
HTTP.send(404, FPSTR(TEXT_PLAIN), msg); HTTP.send(404, FPSTR(TEXT_PLAIN), msg);
} }
void replyBadRequest(String msg) void replyBadRequest(String msg) {
{ // DBG_OUTPUT_PORT.println(msg);
// DBG_OUTPUT_PORT.println(msg);
HTTP.send(400, FPSTR(TEXT_PLAIN), msg + "\r\n"); HTTP.send(400, FPSTR(TEXT_PLAIN), msg + "\r\n");
} }
void replyServerError(String msg) void replyServerError(String msg) {
{ // DBG_OUTPUT_PORT.println(msg);
// DBG_OUTPUT_PORT.println(msg);
HTTP.send(500, FPSTR(TEXT_PLAIN), msg + "\r\n"); HTTP.send(500, FPSTR(TEXT_PLAIN), msg + "\r\n");
} }
/* /*
Return the FS type, status and size info Return the FS type, status and size info
*/ */
void handleStatus() void handleStatus() {
{ // DBG_OUTPUT_PORT.println("handleStatus");
// DBG_OUTPUT_PORT.println("handleStatus");
String json; String json;
json.reserve(128); json.reserve(128);
@@ -141,22 +131,22 @@ void handleStatus()
json += FS_NAME; json += FS_NAME;
json += "\", \"isOk\":"; json += "\", \"isOk\":";
#ifdef ESP8266 #ifdef ESP8266
FSInfo fs_info; FSInfo fs_info;
FileFS.info(fs_info); FileFS.info(fs_info);
json += F("\"true\", \"totalBytes\":\""); json += F("\"true\", \"totalBytes\":\"");
json += fs_info.totalBytes; json += fs_info.totalBytes;
json += F("\", \"usedBytes\":\""); json += F("\", \"usedBytes\":\"");
json += fs_info.usedBytes; json += fs_info.usedBytes;
json += "\""; json += "\"";
#endif #endif
#ifdef ESP32 #ifdef ESP32
json += F("\"true\", \"totalBytes\":\""); json += F("\"true\", \"totalBytes\":\"");
json += String(FileFS.totalBytes()); json += String(FileFS.totalBytes());
json += F("\", \"usedBytes\":\""); json += F("\", \"usedBytes\":\"");
json += String(FileFS.usedBytes()); json += String(FileFS.usedBytes());
json += "\""; json += "\"";
#endif #endif
json += F(",\"unsupportedFiles\":\""); json += F(",\"unsupportedFiles\":\"");
@@ -168,74 +158,66 @@ void handleStatus()
#ifdef ESP32 #ifdef ESP32
String getContentType(String filename) { String getContentType(String filename) {
if (HTTP.hasArg("download")) { if (HTTP.hasArg("download")) {
return "application/octet-stream"; return "application/octet-stream";
} else if (filename.endsWith(".htm")) { } else if (filename.endsWith(".htm")) {
return "text/html"; return "text/html";
} else if (filename.endsWith(".html")) { } else if (filename.endsWith(".html")) {
return "text/html"; return "text/html";
} else if (filename.endsWith(".css")) { } else if (filename.endsWith(".css")) {
return "text/css"; return "text/css";
} else if (filename.endsWith(".js")) { } else if (filename.endsWith(".js")) {
return "application/javascript"; return "application/javascript";
} else if (filename.endsWith(".png")) { } else if (filename.endsWith(".png")) {
return "image/png"; return "image/png";
} else if (filename.endsWith(".gif")) { } else if (filename.endsWith(".gif")) {
return "image/gif"; return "image/gif";
} else if (filename.endsWith(".jpg")) { } else if (filename.endsWith(".jpg")) {
return "image/jpeg"; return "image/jpeg";
} else if (filename.endsWith(".ico")) { } else if (filename.endsWith(".ico")) {
return "image/x-icon"; return "image/x-icon";
} else if (filename.endsWith(".xml")) { } else if (filename.endsWith(".xml")) {
return "text/xml"; return "text/xml";
} else if (filename.endsWith(".pdf")) { } else if (filename.endsWith(".pdf")) {
return "application/x-pdf"; return "application/x-pdf";
} else if (filename.endsWith(".zip")) { } else if (filename.endsWith(".zip")) {
return "application/x-zip"; return "application/x-zip";
} else if (filename.endsWith(".gz")) { } else if (filename.endsWith(".gz")) {
return "application/x-gzip"; return "application/x-gzip";
} }
return "text/plain"; return "text/plain";
} }
#endif #endif
/* /*
Read the given file from the filesystem and stream it back to the client Read the given file from the filesystem and stream it back to the client
*/ */
bool handleFileRead(String path) bool handleFileRead(String path) {
{ // DBG_OUTPUT_PORT.println(String("handleFileRead: ") + path);
// DBG_OUTPUT_PORT.println(String("handleFileRead: ") + path); if (path.endsWith("/")) {
if (path.endsWith("/"))
{
path += "index.html"; path += "index.html";
} }
String contentType; String contentType;
if (HTTP.hasArg("download")) if (HTTP.hasArg("download")) {
{
contentType = F("application/octet-stream"); contentType = F("application/octet-stream");
} } else {
else #ifdef ESP32
{
#ifdef ESP32
contentType = getContentType(path); contentType = getContentType(path);
#endif #endif
#ifdef ESP8266 #ifdef ESP8266
contentType = mime::getContentType(path); contentType = mime::getContentType(path);
#endif #endif
} }
if (!FileFS.exists(path)) if (!FileFS.exists(path)) {
{
// File not found, try gzip version // File not found, try gzip version
path = path + ".gz"; path = path + ".gz";
} }
if (FileFS.exists(path)) if (FileFS.exists(path)) {
{
File file = FileFS.open(path, "r"); File file = FileFS.open(path, "r");
if (HTTP.streamFile(file, contentType) != file.size()) if (HTTP.streamFile(file, contentType) != file.size()) {
{ // DBG_OUTPUT_PORT.println("Sent less data than expected!");
// DBG_OUTPUT_PORT.println("Sent less data than expected!");
} }
file.close(); file.close();
return true; return true;
@@ -248,90 +230,69 @@ bool handleFileRead(String path)
As some FS (e.g. LittleFS) delete the parent folder when the last child has been removed, As some FS (e.g. LittleFS) delete the parent folder when the last child has been removed,
return the path of the closest parent still existing return the path of the closest parent still existing
*/ */
String lastExistingParent(String path) String lastExistingParent(String path) {
{ while (!path.isEmpty() && !FileFS.exists(path)) {
while (!path.isEmpty() && !FileFS.exists(path)) if (path.lastIndexOf('/') > 0) {
{
if (path.lastIndexOf('/') > 0)
{
path = path.substring(0, path.lastIndexOf('/')); path = path.substring(0, path.lastIndexOf('/'));
} } else {
else path = String(); // No slash => the top folder does not exist
{
path = String(); // No slash => the top folder does not exist
} }
} }
// DBG_OUTPUT_PORT.println(String("Last existing parent: ") + path); // DBG_OUTPUT_PORT.println(String("Last existing parent: ") + path);
return path; return path;
} }
/* /*
Handle a file upload request Handle a file upload request
*/ */
void handleFileUpload() void handleFileUpload() {
{ if (HTTP.uri() != "/edit") {
if (HTTP.uri() != "/edit")
{
return; return;
} }
HTTPUpload &upload = HTTP.upload(); HTTPUpload &upload = HTTP.upload();
if (upload.status == UPLOAD_FILE_START) if (upload.status == UPLOAD_FILE_START) {
{
String filename = upload.filename; String filename = upload.filename;
// Make sure paths always start with "/" // Make sure paths always start with "/"
if (!filename.startsWith("/")) if (!filename.startsWith("/")) {
{
filename = "/" + filename; filename = "/" + filename;
} }
// DBG_OUTPUT_PORT.println(String("handleFileUpload Name: ") + filename); // DBG_OUTPUT_PORT.println(String("handleFileUpload Name: ") + filename);
uploadFile = FileFS.open(filename, "w"); uploadFile = FileFS.open(filename, "w");
if (!uploadFile) if (!uploadFile) {
{
return replyServerError(F("CREATE FAILED")); return replyServerError(F("CREATE FAILED"));
} }
// DBG_OUTPUT_PORT.println(String("Upload: START, filename: ") + filename); // DBG_OUTPUT_PORT.println(String("Upload: START, filename: ") + filename);
} } else if (upload.status == UPLOAD_FILE_WRITE) {
else if (upload.status == UPLOAD_FILE_WRITE) if (uploadFile) {
{
if (uploadFile)
{
size_t bytesWritten = uploadFile.write(upload.buf, upload.currentSize); size_t bytesWritten = uploadFile.write(upload.buf, upload.currentSize);
if (bytesWritten != upload.currentSize) if (bytesWritten != upload.currentSize) {
{
return replyServerError(F("WRITE FAILED")); return replyServerError(F("WRITE FAILED"));
} }
} }
// DBG_OUTPUT_PORT.println(String("Upload: WRITE, Bytes: ") + upload.currentSize); // DBG_OUTPUT_PORT.println(String("Upload: WRITE, Bytes: ") + upload.currentSize);
} } else if (upload.status == UPLOAD_FILE_END) {
else if (upload.status == UPLOAD_FILE_END) if (uploadFile) {
{
if (uploadFile)
{
uploadFile.close(); uploadFile.close();
} }
// DBG_OUTPUT_PORT.println(String("Upload: END, Size: ") + upload.totalSize); // DBG_OUTPUT_PORT.println(String("Upload: END, Size: ") + upload.totalSize);
} }
} }
#ifdef ESP8266 #ifdef ESP8266
void deleteRecursive(String path) void deleteRecursive(String path) {
{
File file = FileFS.open(path, "r"); File file = FileFS.open(path, "r");
bool isDir = file.isDirectory(); bool isDir = file.isDirectory();
file.close(); file.close();
// If it's a plain file, delete it // If it's a plain file, delete it
if (!isDir) if (!isDir) {
{
FileFS.remove(path); FileFS.remove(path);
return; return;
} }
Dir dir = FileFS.openDir(path); Dir dir = FileFS.openDir(path);
while (dir.next()) while (dir.next()) {
{
deleteRecursive(path + '/' + dir.fileName()); deleteRecursive(path + '/' + dir.fileName());
} }
// Then delete the folder itself // Then delete the folder itself
FileFS.rmdir(path); FileFS.rmdir(path);
@@ -339,41 +300,37 @@ void deleteRecursive(String path)
#endif #endif
#ifdef ESP32 #ifdef ESP32
struct treename{ struct treename {
uint8_t type; uint8_t type;
char *name; char *name;
}; };
void deleteRecursive(String path) {
fs::File dir = FileFS.open(path);
void deleteRecursive( String path ){ if (!dir.isDirectory()) {
fs::File dir = FileFS.open( path ); Serial.printf("%s is a file\n", path);
dir.close();
if(!dir.isDirectory()){ Serial.printf("result of removing file %s: %d\n", path, FileFS.remove(path));
Serial.printf("%s is a file\n", path); return;
dir.close();
Serial.printf( "result of removing file %s: %d\n", path, FileFS.remove( path ) );
return;
} }
Serial.printf("%s is a directory\n", path); Serial.printf("%s is a directory\n", path);
fs::File entry, nextentry; fs::File entry, nextentry;
while ( entry = dir.openNextFile() ){ while (entry = dir.openNextFile()) {
if (entry.isDirectory()) {
if ( entry.isDirectory() ){ deleteRecursive(entry.path());
deleteRecursive( entry.path() ); } else {
} else{ String tmpname = path + "/" + strdup(entry.name()); // buffer file name
String tmpname = path+"/"+strdup( entry.name() ); // buffer file name entry.close();
entry.close(); Serial.printf("result of removing file %s: %d\n", tmpname, FileFS.remove(tmpname));
Serial.printf( "result of removing file %s: %d\n", tmpname, FileFS.remove( tmpname ) ); }
}
} }
dir.close(); dir.close();
Serial.printf( "result of removing directory %s: %d\n", path, FileFS.rmdir( path ) ); Serial.printf("result of removing directory %s: %d\n", path, FileFS.rmdir(path));
} }
#endif #endif
/* /*
@@ -383,23 +340,18 @@ if ( entry.isDirectory() ){
Delete file | parent of deleted file, or remaining ancestor Delete file | parent of deleted file, or remaining ancestor
Delete folder | parent of deleted folder, or remaining ancestor Delete folder | parent of deleted folder, or remaining ancestor
*/ */
void handleFileDelete() void handleFileDelete() {
{
String path = HTTP.arg(0); String path = HTTP.arg(0);
if (path.isEmpty() || path == "/") if (path.isEmpty() || path == "/") {
{
return replyBadRequest("BAD PATH"); return replyBadRequest("BAD PATH");
} }
// DBG_OUTPUT_PORT.println(String("handleFileDelete: ") + path); // DBG_OUTPUT_PORT.println(String("handleFileDelete: ") + path);
if (!FileFS.exists(path)) if (!FileFS.exists(path)) {
{
return replyNotFound(FPSTR(FILE_NOT_FOUND)); return replyNotFound(FPSTR(FILE_NOT_FOUND));
} }
deleteRecursive(path); deleteRecursive(path);
replyOKWithMsg(lastExistingParent(path)); replyOKWithMsg(lastExistingParent(path));
} }
@@ -414,93 +366,72 @@ void handleFileDelete()
Rename folder | parent of source folder Rename folder | parent of source folder
Move folder | parent of source folder, or remaining ancestor Move folder | parent of source folder, or remaining ancestor
*/ */
void handleFileCreate() void handleFileCreate() {
{
String path = HTTP.arg("path"); String path = HTTP.arg("path");
if (path.isEmpty()) if (path.isEmpty()) {
{
return replyBadRequest(F("PATH ARG MISSING")); return replyBadRequest(F("PATH ARG MISSING"));
} }
#ifdef USE_SPIFFS #ifdef USE_SPIFFS
if (checkForUnsupportedPath(path).length() > 0) if (checkForUnsupportedPath(path).length() > 0) {
{
return replyServerError(F("INVALID FILENAME")); return replyServerError(F("INVALID FILENAME"));
} }
#endif #endif
if (path == "/") if (path == "/") {
{
return replyBadRequest("BAD PATH"); return replyBadRequest("BAD PATH");
} }
if (FileFS.exists(path)) if (FileFS.exists(path)) {
{
return replyBadRequest(F("PATH FILE EXISTS")); return replyBadRequest(F("PATH FILE EXISTS"));
} }
String src = HTTP.arg("src"); String src = HTTP.arg("src");
if (src.isEmpty()) if (src.isEmpty()) {
{
// No source specified: creation // No source specified: creation
// DBG_OUTPUT_PORT.println(String("handleFileCreate: ") + path); // DBG_OUTPUT_PORT.println(String("handleFileCreate: ") + path);
if (path.endsWith("/")) if (path.endsWith("/")) {
{
// Create a folder // Create a folder
path.remove(path.length() - 1); path.remove(path.length() - 1);
if (!FileFS.mkdir(path)) if (!FileFS.mkdir(path)) {
{
return replyServerError(F("MKDIR FAILED")); return replyServerError(F("MKDIR FAILED"));
} }
} } else {
else
{
// Create a file // Create a file
File file = FileFS.open(path, "w"); File file = FileFS.open(path, "w");
if (file) if (file) {
{ #ifdef ESP8266
#ifdef ESP8266
file.write((const char *)0); file.write((const char *)0);
#endif #endif
#ifdef ESP32 #ifdef ESP32
file.write(0); file.write(0);
#endif #endif
file.close(); file.close();
} } else {
else
{
return replyServerError(F("CREATE FAILED")); return replyServerError(F("CREATE FAILED"));
} }
} }
if (path.lastIndexOf('/') > -1) if (path.lastIndexOf('/') > -1) {
{
path = path.substring(0, path.lastIndexOf('/')); path = path.substring(0, path.lastIndexOf('/'));
} }
replyOKWithMsg(path); replyOKWithMsg(path);
} } else {
else
{
// Source specified: rename // Source specified: rename
if (src == "/") if (src == "/") {
{
return replyBadRequest("BAD SRC"); return replyBadRequest("BAD SRC");
} }
if (!FileFS.exists(src)) if (!FileFS.exists(src)) {
{
return replyBadRequest(F("SRC FILE NOT FOUND")); return replyBadRequest(F("SRC FILE NOT FOUND"));
} }
// DBG_OUTPUT_PORT.println(String("handleFileCreate: ") + path + " from " + src); // DBG_OUTPUT_PORT.println(String("handleFileCreate: ") + path + " from " + src);
if (path.endsWith("/")) if (path.endsWith("/")) {
{
path.remove(path.length() - 1); path.remove(path.length() - 1);
} }
if (src.endsWith("/")) if (src.endsWith("/")) {
{
src.remove(src.length() - 1); src.remove(src.length() - 1);
} }
if (!FileFS.rename(src, path)) if (!FileFS.rename(src, path)) {
{
return replyServerError(F("RENAME FAILED")); return replyServerError(F("RENAME FAILED"));
} }
replyOKWithMsg(lastExistingParent(src)); replyOKWithMsg(lastExistingParent(src));
@@ -512,26 +443,22 @@ void handleFileCreate()
Also demonstrates the use of chunked responses. Also demonstrates the use of chunked responses.
*/ */
#ifdef ESP8266 #ifdef ESP8266
void handleFileList() void handleFileList() {
{ if (!HTTP.hasArg("dir")) {
if (!HTTP.hasArg("dir"))
{
return replyBadRequest(F("DIR ARG MISSING")); return replyBadRequest(F("DIR ARG MISSING"));
} }
String path = HTTP.arg("dir"); String path = HTTP.arg("dir");
if (path != "/" && !FileFS.exists(path)) if (path != "/" && !FileFS.exists(path)) {
{
return replyBadRequest("BAD PATH"); return replyBadRequest("BAD PATH");
} }
// DBG_OUTPUT_PORT.println(String("handleFileList: ") + path); // DBG_OUTPUT_PORT.println(String("handleFileList: ") + path);
Dir dir = FileFS.openDir(path); Dir dir = FileFS.openDir(path);
path.clear(); path.clear();
// use HTTP/1.1 Chunked response to avoid building a huge temporary string // use HTTP/1.1 Chunked response to avoid building a huge temporary string
if (!HTTP.chunkedResponseModeStart(200, "text/json")) if (!HTTP.chunkedResponseModeStart(200, "text/json")) {
{
HTTP.send(505, F("text/html"), F("HTTP1.1 required")); HTTP.send(505, F("text/html"), F("HTTP1.1 required"));
return; return;
} }
@@ -539,47 +466,36 @@ void handleFileList()
// use the same string for every line // use the same string for every line
String output; String output;
output.reserve(64); output.reserve(64);
while (dir.next()) while (dir.next()) {
{
#ifdef USE_SPIFFS #ifdef USE_SPIFFS
String error = checkForUnsupportedPath(dir.fileName()); String error = checkForUnsupportedPath(dir.fileName());
if (error.length() > 0) if (error.length() > 0) {
{ // DBG_OUTPUT_PORT.println(String("Ignoring ") + error + dir.fileName());
// DBG_OUTPUT_PORT.println(String("Ignoring ") + error + dir.fileName());
continue; continue;
} }
#endif #endif
if (output.length()) if (output.length()) {
{
// send string from previous iteration // send string from previous iteration
// as an HTTP chunk // as an HTTP chunk
HTTP.sendContent(output); HTTP.sendContent(output);
output = ','; output = ',';
} } else {
else
{
output = '['; output = '[';
} }
output += "{\"type\":\""; output += "{\"type\":\"";
if (dir.isDirectory()) if (dir.isDirectory()) {
{
output += "dir"; output += "dir";
} } else {
else
{
output += F("file\",\"size\":\""); output += F("file\",\"size\":\"");
output += dir.fileSize(); output += dir.fileSize();
} }
output += F("\",\"name\":\""); output += F("\",\"name\":\"");
// Always return names without leading "/" // Always return names without leading "/"
if (dir.fileName()[0] == '/') if (dir.fileName()[0] == '/') {
{
output += &(dir.fileName()[1]); output += &(dir.fileName()[1]);
} } else {
else
{
output += dir.fileName(); output += dir.fileName();
} }
@@ -595,65 +511,57 @@ void handleFileList()
#ifdef ESP32 #ifdef ESP32
void handleFileList() { void handleFileList() {
if (!HTTP.hasArg("dir")) { if (!HTTP.hasArg("dir")) {
HTTP.send(500, "text/plain", "BAD ARGS"); HTTP.send(500, "text/plain", "BAD ARGS");
return; return;
} }
String path = HTTP.arg("dir"); String path = HTTP.arg("dir");
// DBG_OUTPUT_PORT.println("handleFileList: " + path); // DBG_OUTPUT_PORT.println("handleFileList: " + path);
File root = FileFS.open(path);
path = String();
File root = FileFS.open(path); String output = "[";
path = String(); if (root.isDirectory()) {
File file = root.openNextFile();
while (file) {
if (output != "[") {
output += ',';
}
output += "{\"type\":\"";
// output += (file.isDirectory()) ? "dir" : "file";
if (file.isDirectory()) {
output += "dir";
} else {
output += F("file\",\"size\":\"");
output += file.size();
}
String output = "["; output += "\",\"name\":\"";
if(root.isDirectory()){
File file = root.openNextFile();
while(file){
if (output != "[") {
output += ',';
}
output += "{\"type\":\"";
// output += (file.isDirectory()) ? "dir" : "file";
if (file.isDirectory())
{
output += "dir";
}
else
{
output += F("file\",\"size\":\"");
output += file.size();
}
output += "\",\"name\":\"";
output += String(file.name()); output += String(file.name());
output += "\"}"; output += "\"}";
file = root.openNextFile(); file = root.openNextFile();
} }
} }
output += "]"; output += "]";
HTTP.send(200, "text/json", output); HTTP.send(200, "text/json", output);
} }
#endif #endif
/* /*
The "Not Found" handler catches all URI not explicitly declared in code The "Not Found" handler catches all URI not explicitly declared in code
First try to find and return the requested file from the filesystem, First try to find and return the requested file from the filesystem,
and if it fails, return a 404 page with debug information and if it fails, return a 404 page with debug information
*/ */
void handleNotFound() void handleNotFound() {
{
#ifdef ESP8266 #ifdef ESP8266
String uri = ESP8266WebServer::urlDecode(HTTP.uri()); // required to read paths with blanks String uri = ESP8266WebServer::urlDecode(HTTP.uri()); // required to read paths with blanks
#endif #endif
#ifdef ESP32 #ifdef ESP32
String uri = WebServer::urlDecode(HTTP.uri()); // required to read paths with blanks String uri = WebServer::urlDecode(HTTP.uri()); // required to read paths with blanks
#endif #endif
if (handleFileRead(uri)) if (handleFileRead(uri)) {
{
return; return;
} }
@@ -667,8 +575,7 @@ void handleNotFound()
message += F("\nArguments: "); message += F("\nArguments: ");
message += HTTP.args(); message += HTTP.args();
message += '\n'; message += '\n';
for (uint8_t i = 0; i < HTTP.args(); i++) for (uint8_t i = 0; i < HTTP.args(); i++) {
{
message += F(" NAME:"); message += F(" NAME:");
message += HTTP.argName(i); message += HTTP.argName(i);
message += F("\n VALUE:"); message += F("\n VALUE:");
@@ -678,7 +585,7 @@ void handleNotFound()
message += "path="; message += "path=";
message += HTTP.arg("path"); message += HTTP.arg("path");
message += '\n'; message += '\n';
// DBG_OUTPUT_PORT.print(message); // DBG_OUTPUT_PORT.print(message);
return replyNotFound(message); return replyNotFound(message);
} }
@@ -689,10 +596,8 @@ void handleNotFound()
embedded in the program code. embedded in the program code.
Otherwise, fails with a 404 page with debug information Otherwise, fails with a 404 page with debug information
*/ */
void handleGetEdit() void handleGetEdit() {
{ if (handleFileRead(F("/edit.htm"))) {
if (handleFileRead(F("/edit.htm")))
{
return; return;
} }

View File

@@ -74,7 +74,7 @@ bool upgradeBuild() {
handleUpdateStatus(true, PATH_ERROR); handleUpdateStatus(true, PATH_ERROR);
return ret; return ret;
} }
#if defined(esp8266_4mb) || defined(esp8266_1mb) || defined(esp8266_1mb_ota) || defined(esp8266_2mb) || defined(esp8266_2mb_ota) #if defined(esp8266_4mb) || defined(esp8266_16mb) || defined(esp8266_1mb) || defined(esp8266_1mb_ota) || defined(esp8266_2mb) || defined(esp8266_2mb_ota)
ESPhttpUpdate.rebootOnUpdate(false); ESPhttpUpdate.rebootOnUpdate(false);
t_httpUpdate_return retBuild = ESPhttpUpdate.update(wifiClient, getBinPath("firmware.bin")); t_httpUpdate_return retBuild = ESPhttpUpdate.update(wifiClient, getBinPath("firmware.bin"));
#endif #endif

View File

@@ -4,413 +4,449 @@ extern IoTScenario iotScen;
#ifdef STANDARD_WEB_SOCKETS #ifdef STANDARD_WEB_SOCKETS
void standWebSocketsInit() { void standWebSocketsInit() {
standWebSocket.begin(); standWebSocket.begin();
standWebSocket.onEvent(webSocketEvent); standWebSocket.onEvent(webSocketEvent);
SerialPrint("i", "WS", "WS server initialized"); SerialPrint("i", "WS", "WS server initialized");
} }
void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) { void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload,
switch (type) { size_t length) {
case WStype_ERROR: { switch (type) {
Serial.printf("[%u] Error!\n", num); case WStype_ERROR: {
} break; Serial.printf("[%u] Error!\n", num);
} break;
case WStype_DISCONNECTED: { case WStype_DISCONNECTED: {
Serial.printf("[%u] Disconnected!\n", num); Serial.printf("[%u] Disconnected!\n", num);
} break; } break;
case WStype_CONNECTED: { case WStype_CONNECTED: {
// IPAddress ip = standWebSocket.remoteIP(num); // IPAddress ip = standWebSocket.remoteIP(num);
SerialPrint("i", "WS " + String(num), "WS client connected"); SerialPrint("i", "WS " + String(num), "WS client connected");
if (num >= 3) { if (num >= 3) {
SerialPrint("E", "WS", "Too many clients, connection closed!!!"); SerialPrint("E", "WS", "Too many clients, connection closed!!!");
jsonWriteInt(errorsHeapJson, "wse1", 1); jsonWriteInt(errorsHeapJson, "wse1", 1);
standWebSocket.close(); standWebSocket.close();
standWebSocketsInit(); standWebSocketsInit();
}
// Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0],
// ip[1], ip[2], ip[3], payload); standWebSocket.sendTXT(num,
// "Connected");
} break;
case WStype_TEXT: {
bool endOfHeaderFound = false;
size_t maxAllowedHeaderSize =
15; // максимальное количество символов заголовка
size_t headerLenth = 0;
String headerStr;
for (size_t i = 0; i <= maxAllowedHeaderSize; i++) {
headerLenth++;
char s = (char)payload[i];
headerStr += s;
if (s == '|') {
endOfHeaderFound = true;
break;
}
}
if (!endOfHeaderFound) {
SerialPrint("E", "WS " + String(num), "Package without header");
}
//----------------------------------------------------------------------//
// Страница веб интерфейса dashboard
//----------------------------------------------------------------------//
// публикация всех виджетов
if (headerStr == "/|") {
sendFileToWsByFrames("/layout.json", "layout", "", num,
WEB_SOCKETS_FRAME_SIZE);
}
if (headerStr == "/params|") {
// публикация всех статус сообщений при подключении svelte приложения
String params = "{}";
for (std::list<IoTItem*>::iterator it = IoTItems.begin();
it != IoTItems.end(); ++it) {
if ((*it)->getSubtype() != "Loging") {
if ((*it)->getSubtype() != "LogingDaily") {
if ((*it)->iAmLocal)
jsonWriteStr(params, (*it)->getID(), (*it)->getValue());
} }
// Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); }
// standWebSocket.sendTXT(num, "Connected"); }
} break; sendStringToWs("params", params, num);
case WStype_TEXT: { // генерация события подключения в модулях
bool endOfHeaderFound = false; for (std::list<IoTItem*>::iterator it = IoTItems.begin();
size_t maxAllowedHeaderSize = 15; // максимальное количество символов заголовка it != IoTItems.end(); ++it) {
size_t headerLenth = 0; if ((*it)->iAmLocal) (*it)->onMqttWsAppConnectEvent();
String headerStr; }
for (size_t i = 0; i <= maxAllowedHeaderSize; i++) { }
headerLenth++;
char s = (char)payload[i];
headerStr += s;
if (s == '|') {
endOfHeaderFound = true;
break;
}
}
if (!endOfHeaderFound) {
SerialPrint("E", "WS " + String(num), "Package without header");
}
//----------------------------------------------------------------------// // отвечаем на запрос графиков
// Страница веб интерфейса dashboard if (headerStr == "/charts|") {
//----------------------------------------------------------------------// // обращение к логированию из ядра
// отправка данных графиков только в выбранный сокет
for (std::list<IoTItem*>::iterator it = IoTItems.begin();
it != IoTItems.end(); ++it) {
// сбрасываем даты графиков
// if ((*it)->getID().endsWith("-date")) {
// (*it)->setTodayDate();
// }
if ((*it)->getSubtype() == "Loging" || "LogingDaily") {
(*it)->setPublishDestination(TO_WS, num);
(*it)->publishValue();
}
}
}
// публикация всех виджетов //----------------------------------------------------------------------//
if (headerStr == "/|") { // Страница веб интерфейса configutation
sendFileToWsByFrames("/layout.json", "layout", "", num, WEB_SOCKETS_FRAME_SIZE); //----------------------------------------------------------------------//
}
if (headerStr == "/params|") { // отвечаем данными на запрос страницы
// публикация всех статус сообщений при подключении svelte приложения if (headerStr == "/config|") {
String params = "{}"; sendFileToWsByFrames("/items.json", "itemsj", "", num,
for (std::list<IoTItem*>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { WEB_SOCKETS_FRAME_SIZE);
if ((*it)->getSubtype() != "Loging") { sendFileToWsByFrames("/widgets.json", "widget", "", num,
if ((*it)->getSubtype() != "LogingDaily") { WEB_SOCKETS_FRAME_SIZE);
if ((*it)->iAmLocal) jsonWriteStr(params, (*it)->getID(), (*it)->getValue()); sendFileToWsByFrames("/config.json", "config", "", num,
} WEB_SOCKETS_FRAME_SIZE);
} sendFileToWsByFrames("/scenario.txt", "scenar", "", num,
} WEB_SOCKETS_FRAME_SIZE);
sendStringToWs("params", params, num); sendStringToWs("settin", settingsFlashJson, num);
}
// генерация события подключения в модулях // обработка кнопки сохранить
for (std::list<IoTItem*>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { if (headerStr == "/gifnoc|") {
if ((*it)->iAmLocal) (*it)->onMqttWsAppConnectEvent(); writeFileUint8tByFrames("config.json", payload, length, headerLenth,
} 256);
} }
if (headerStr == "/tuoyal|") {
writeFileUint8tByFrames("layout.json", payload, length, headerLenth,
256);
}
if (headerStr == "/oiranecs|") {
writeFileUint8tByFrames("scenario.txt", payload, length, headerLenth,
256);
clearConfigure();
configure("/config.json");
iotScen.loadScenario("/scenario.txt");
// создаем событие завершения конфигурирования для возможности
// выполнения блока кода при загрузке
createItemFromNet("onStart", "1", 1);
}
// отвечаем на запрос графиков //----------------------------------------------------------------------//
if (headerStr == "/charts|") { // Страница веб интерфейса connection
// обращение к логированию из ядра //----------------------------------------------------------------------//
// отправка данных графиков только в выбранный сокет
for (std::list<IoTItem*>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) {
// сбрасываем даты графиков
// if ((*it)->getID().endsWith("-date")) {
// (*it)->setTodayDate();
// }
if ((*it)->getSubtype() == "Loging" || "LogingDaily") {
(*it)->setPublishDestination(TO_WS, num);
(*it)->publishValue();
}
}
}
//----------------------------------------------------------------------// // отвечаем данными на запрос страницы
// Страница веб интерфейса configutation if (headerStr == "/connection|") {
//----------------------------------------------------------------------// sendStringToWs("settin", settingsFlashJson, num);
sendStringToWs("ssidli", ssidListHeapJson, num);
sendStringToWs("errors", errorsHeapJson, num);
// запуск асинхронного сканирования wifi сетей при переходе на страницу
// соединений RouterFind(jsonReadStr(settingsFlashJson,
// F("routerssid")));
}
// отвечаем данными на запрос страницы // обработка кнопки сохранить settings.json
if (headerStr == "/config|") { if (headerStr == "/sgnittes|") {
sendFileToWsByFrames("/items.json", "itemsj", "", num, WEB_SOCKETS_FRAME_SIZE); writeUint8tToString(payload, length, headerLenth, settingsFlashJson);
sendFileToWsByFrames("/widgets.json", "widget", "", num, WEB_SOCKETS_FRAME_SIZE); writeFileUint8tByFrames("settings.json", payload, length, headerLenth,
sendFileToWsByFrames("/config.json", "config", "", num, WEB_SOCKETS_FRAME_SIZE); 256);
sendFileToWsByFrames("/scenario.txt", "scenar", "", num, WEB_SOCKETS_FRAME_SIZE); sendStringToWs("errors", errorsHeapJson, num);
sendStringToWs("settin", settingsFlashJson, num); // если не было создано приема данных по udp - то создадим его
} addThisDeviceToList();
}
// обработка кнопки сохранить // обработка кнопки сохранить настройки mqtt
if (headerStr == "/gifnoc|") { if (headerStr == "/mqtt|") {
writeFileUint8tByFrames("config.json", payload, length, headerLenth, 256); sendStringToWs("settin", settingsFlashJson,
} num); // отправляем в ответ новые полученные настройки
if (headerStr == "/tuoyal|") { handleMqttStatus(false, 8); // меняем статус на неопределенный
writeFileUint8tByFrames("layout.json", payload, length, headerLenth, 256); mqttReconnect(); // начинаем переподключение
} sendStringToWs("errors", errorsHeapJson,
if (headerStr == "/oiranecs|") { num); // отправляем что статус неопределен
writeFileUint8tByFrames("scenario.txt", payload, length, headerLenth, 256); sendStringToWs("ssidli", ssidListHeapJson, num);
clearConfigure(); }
configure("/config.json");
iotScen.loadScenario("/scenario.txt");
// создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке
createItemFromNet("onStart", "1", 1);
}
//----------------------------------------------------------------------// // запуск асинхронного сканирования wifi сетей при нажатии выпадающего
// Страница веб интерфейса connection // списка
//----------------------------------------------------------------------// if (headerStr == "/scan|") {
std::vector<String> jArray;
jsonReadArray(settingsFlashJson, "routerssid", jArray);
RouterFind(jArray);
sendStringToWs("ssidli", ssidListHeapJson, num);
}
// отвечаем данными на запрос страницы //----------------------------------------------------------------------//
if (headerStr == "/connection|") { // Страница веб интерфейса list
sendStringToWs("settin", settingsFlashJson, num); //----------------------------------------------------------------------//
sendStringToWs("ssidli", ssidListHeapJson, num);
sendStringToWs("errors", errorsHeapJson, num);
// запуск асинхронного сканирования wifi сетей при переходе на страницу соединений
// RouterFind(jsonReadStr(settingsFlashJson, F("routerssid")));
}
// обработка кнопки сохранить settings.json // отвечаем данными на запрос страницы list
if (headerStr == "/sgnittes|") { if (headerStr == "/list|") {
writeUint8tToString(payload, length, headerLenth, settingsFlashJson); sendStringToWs("settin", settingsFlashJson, num);
writeFileUint8tByFrames("settings.json", payload, length, headerLenth, 256); // отправим список устройств в зависимости от того что выбрал user
sendStringToWs("errors", errorsHeapJson, num); // sendDeviceList(num);
// если не было создано приема данных по udp - то создадим его }
addThisDeviceToList();
}
// обработка кнопки сохранить настройки mqtt // отвечаем на запрос списка устройств (это отдельный запрос который
if (headerStr == "/mqtt|") { // делает приложение при подключении)
sendStringToWs("settin", settingsFlashJson, num); // отправляем в ответ новые полученные настройки if (headerStr == "/devlist|") {
handleMqttStatus(false, 8); // меняем статус на неопределенный // отправим список устройств в зависимости от того что выбрал user
mqttReconnect(); // начинаем переподключение sendDeviceList(num);
sendStringToWs("errors", errorsHeapJson, num); // отправляем что статус неопределен }
sendStringToWs("ssidli", ssidListHeapJson, num);
}
// запуск асинхронного сканирования wifi сетей при нажатии выпадающего списка // сохраняем данные листа
if (headerStr == "/scan|") { if (headerStr == "/tsil|") {
RouterFind(jsonReadStr(settingsFlashJson, F("routerssid"))); writeFileUint8tByFrames("devlist.json", payload, length, headerLenth,
sendStringToWs("ssidli", ssidListHeapJson, num); 256);
} }
//----------------------------------------------------------------------// //----------------------------------------------------------------------//
// Страница веб интерфейса list // Страница веб интерфейса system
//----------------------------------------------------------------------// //----------------------------------------------------------------------//
// отвечаем данными на запрос страницы list // отвечаем данными на запрос страницы
if (headerStr == "/list|") { if (headerStr == "/system|") {
sendStringToWs("settin", settingsFlashJson, num); sendStringToWs("errors", errorsHeapJson, num);
// отправим список устройств в зависимости от того что выбрал user sendStringToWs("settin", settingsFlashJson, num);
// sendDeviceList(num); }
}
// отвечаем на запрос списка устройств (это отдельный запрос который делает приложение при подключении) //----------------------------------------------------------------------//
if (headerStr == "/devlist|") { // Страница веб интерфейса dev
// отправим список устройств в зависимости от того что выбрал user //----------------------------------------------------------------------//
sendDeviceList(num); if (headerStr == "/dev|") {
} sendStringToWs("errors", errorsHeapJson, num);
sendStringToWs("settin", settingsFlashJson, num);
sendFileToWsByFrames("/config.json", "config", "", num,
WEB_SOCKETS_FRAME_SIZE);
sendFileToWsByFrames("/items.json", "itemsj", "", num,
WEB_SOCKETS_FRAME_SIZE);
// sendFileToWsByFrames("/layout.json", "layout", "", num,
// WEB_SOCKETS_FRAME_SIZE);
}
// сохраняем данные листа if (headerStr == "/test|") {
if (headerStr == "/tsil|") { }
writeFileUint8tByFrames("devlist.json", payload, length, headerLenth, 256);
}
//----------------------------------------------------------------------// //----------------------------------------------------------------------//
// Страница веб интерфейса system // отдельные команды веб интерфейса
//----------------------------------------------------------------------// //----------------------------------------------------------------------//
// отвечаем данными на запрос страницы // переписать любое поле в errors json
if (headerStr == "/system|") { if (headerStr == "/rorre|") {
sendStringToWs("errors", errorsHeapJson, num); writeUint8tValueToJsonString(payload, length, headerLenth,
sendStringToWs("settin", settingsFlashJson, num); errorsHeapJson);
} }
//----------------------------------------------------------------------// // команда перезагрузки esp
// Страница веб интерфейса dev if (headerStr == "/reboot|") {
//----------------------------------------------------------------------// ESP.restart();
if (headerStr == "/dev|") { }
sendStringToWs("errors", errorsHeapJson, num);
sendStringToWs("settin", settingsFlashJson, num);
sendFileToWsByFrames("/config.json", "config", "", num, WEB_SOCKETS_FRAME_SIZE);
sendFileToWsByFrames("/items.json", "itemsj", "", num, WEB_SOCKETS_FRAME_SIZE);
// sendFileToWsByFrames("/layout.json", "layout", "", num, WEB_SOCKETS_FRAME_SIZE);
}
if (headerStr == "/test|") { // команда очистки всех логов esp
} if (headerStr == "/clean|") {
cleanLogs();
}
//----------------------------------------------------------------------// // команда обновления прошивки esp
// отдельные команды веб интерфейса if (headerStr == "/update|") {
//----------------------------------------------------------------------// upgrade_firmware(3);
}
// переписать любое поле в errors json // Прием команд control c dashboard
if (headerStr == "/rorre|") { if (headerStr == "/control|") {
writeUint8tValueToJsonString(payload, length, headerLenth, errorsHeapJson); String msg;
} writeUint8tToString(payload, length, headerLenth, msg);
String key = selectFromMarkerToMarker(msg, "/", 0);
String value = selectFromMarkerToMarker(msg, "/", 1);
generateOrder(key, value);
SerialPrint(
"i", F("=>WS"),
"Msg from svelte web, WS No: " + String(num) + ", msg: " + msg);
}
// команда перезагрузки esp if (headerStr == "/tst|") {
if (headerStr == "/reboot|") { standWebSocket.sendTXT(num, "/tstr|");
ESP.restart(); }
}
// команда очистки всех логов esp // получаем команду посланную из модуля
if (headerStr == "/clean|") { if (headerStr == "/order|") {
cleanLogs(); String json;
} writeUint8tToString(payload, length, headerLenth, json);
// команда обновления прошивки esp String id, key, value;
if (headerStr == "/update|") { jsonRead(json, "id", id);
upgrade_firmware(3); jsonRead(json, "key", key);
} jsonRead(json, "value", value);
// Прием команд control c dashboard SerialPrint("i", F("=>WS"), "Msg from module, id: " + id);
if (headerStr == "/control|") {
String msg;
writeUint8tToString(payload, length, headerLenth, msg);
String key = selectFromMarkerToMarker(msg, "/", 0);
String value = selectFromMarkerToMarker(msg, "/", 1);
generateOrder(key, value);
SerialPrint("i", F("=>WS"), "Msg from svelte web, WS No: " + String(num) + ", msg: " + msg);
}
if (headerStr == "/tst|") { for (std::list<IoTItem*>::iterator it = IoTItems.begin();
standWebSocket.sendTXT(num, "/tstr|"); it != IoTItems.end(); ++it) {
} if ((*it)->getID() == id) {
(*it)->onModuleOrder(key, value);
}
}
}
// получаем команду посланную из модуля } break;
if (headerStr == "/order|") {
String json;
writeUint8tToString(payload, length, headerLenth, json);
String id, key, value; case WStype_BIN: {
jsonRead(json, "id", id); Serial.printf("[%u] get binary length: %u\n", num, length);
jsonRead(json, "key", key); // hexdump(payload, length);
jsonRead(json, "value", value); // standWebSocket.sendBIN(num, payload, length);
} break;
SerialPrint("i", F("=>WS"), "Msg from module, id: " + id); case WStype_FRAGMENT_TEXT_START: {
Serial.printf("[%u] fragment test start: %u\n", num, length);
} break;
for (std::list<IoTItem*>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { case WStype_FRAGMENT_BIN_START: {
if ((*it)->getID() == id) { Serial.printf("[%u] fragment bin start: %u\n", num, length);
(*it)->onModuleOrder(key, value); } break;
}
}
}
} break; case WStype_FRAGMENT: {
Serial.printf("[%u] fragment: %u\n", num, length);
} break;
case WStype_BIN: { case WStype_FRAGMENT_FIN: {
Serial.printf("[%u] get binary length: %u\n", num, length); Serial.printf("[%u] fragment finish: %u\n", num, length);
// hexdump(payload, length); } break;
// standWebSocket.sendBIN(num, payload, length);
} break;
case WStype_FRAGMENT_TEXT_START: { case WStype_PING: {
Serial.printf("[%u] fragment test start: %u\n", num, length); Serial.printf("[%u] ping: %u\n", num, length);
} break; } break;
case WStype_FRAGMENT_BIN_START: { case WStype_PONG: {
Serial.printf("[%u] fragment bin start: %u\n", num, length); Serial.printf("[%u] pong: %u\n", num, length);
} break; } break;
case WStype_FRAGMENT: { default: { Serial.printf("[%u] not recognized: %u\n", num, length); } break;
Serial.printf("[%u] fragment: %u\n", num, length); }
} break;
case WStype_FRAGMENT_FIN: {
Serial.printf("[%u] fragment finish: %u\n", num, length);
} break;
case WStype_PING: {
Serial.printf("[%u] ping: %u\n", num, length);
} break;
case WStype_PONG: {
Serial.printf("[%u] pong: %u\n", num, length);
} break;
default: {
Serial.printf("[%u] not recognized: %u\n", num, length);
} break;
}
} }
// публикация статус сообщений в ws (недостаток в том что делаем бродкаст всем клиентам поднятым в свелте!!!) // публикация статус сообщений в ws (недостаток в том что делаем бродкаст всем
// клиентам поднятым в свелте!!!)
void publishStatusWs(const String& topic, const String& data) { void publishStatusWs(const String& topic, const String& data) {
String path = mqttRootDevice + "/" + topic; String path = mqttRootDevice + "/" + topic;
String json = "{}"; String json = "{}";
jsonWriteStr(json, "status", data); jsonWriteStr(json, "status", data);
jsonWriteStr(json, "topic", path); jsonWriteStr(json, "topic", path);
sendStringToWs("status", json, -1); sendStringToWs("status", json, -1);
} }
// публикация дополнительных json сообщений в ws // публикация дополнительных json сообщений в ws
void publishJsonWs(const String& topic, String& json) { void publishJsonWs(const String& topic, String& json) {
String path = mqttRootDevice + "/" + topic; String path = mqttRootDevice + "/" + topic;
jsonWriteStr(json, "topic", path); jsonWriteStr(json, "topic", path);
// TO DO отправка полей в веб // TO DO отправка полей в веб
// sendStringToWs("status", json, -1); // sendStringToWs("status", json, -1);
} }
// данные которые мы отправляем в сокеты переодически // данные которые мы отправляем в сокеты переодически
void periodicWsSend() { void periodicWsSend() {
sendStringToWs("ssidli", ssidListHeapJson, -1); sendStringToWs("ssidli", ssidListHeapJson, -1);
sendStringToWs("errors", errorsHeapJson, -1); sendStringToWs("errors", errorsHeapJson, -1);
// отправляем переодичестки только в авто режиме // отправляем переодичестки только в авто режиме
if (jsonReadInt(settingsFlashJson, F("udps")) != 0) { if (jsonReadInt(settingsFlashJson, F("udps")) != 0) {
sendStringToWs("devlis", devListHeapJson, -1); sendStringToWs("devlis", devListHeapJson, -1);
} }
} }
#ifdef ESP32 #ifdef ESP32
void hexdump(const void* mem, uint32_t len, uint8_t cols = 16) { void hexdump(const void* mem, uint32_t len, uint8_t cols = 16) {
const uint8_t* src = (const uint8_t*)mem; const uint8_t* src = (const uint8_t*)mem;
Serial.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); Serial.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src,
for (uint32_t i = 0; i < len; i++) { len, len);
if (i % cols == 0) { for (uint32_t i = 0; i < len; i++) {
Serial.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); if (i % cols == 0) {
} Serial.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
Serial.printf("%02X ", *src);
src++;
} }
Serial.printf("\n"); Serial.printf("%02X ", *src);
src++;
}
Serial.printf("\n");
} }
#endif #endif
#endif #endif
void sendFileToWsByFrames(const String& filename, const String& header, const String& json, int client_id, size_t frameSize) { void sendFileToWsByFrames(const String& filename, const String& header,
if (header.length() != 6) { const String& json, int client_id, size_t frameSize) {
SerialPrint("E", "FS", F("wrong header size")); if (header.length() != 6) {
return; SerialPrint("E", "FS", F("wrong header size"));
return;
}
auto path = filepath(filename);
auto file = FileFS.open(path, "r");
if (!file) {
SerialPrint("E", "FS", F("reed file error"));
return;
}
size_t totalSize = file.size();
// Serial.println("Send file '" + String(filename) + "', file size: " +
// String(totalSize));
char buf[32];
sprintf(buf, "%04d", json.length() + 12);
String data = header + "|" + String(buf) + "|" + json;
size_t headerSize = data.length();
auto frameBuf = new uint8_t[frameSize];
size_t maxPayloadSize = frameSize - headerSize;
uint8_t* payloadBuf = nullptr;
int i = 0;
while (file.available()) {
if (i == 0) {
data.toCharArray((char*)frameBuf, frameSize);
payloadBuf = &frameBuf[headerSize];
} else {
maxPayloadSize = frameSize;
headerSize = 0;
payloadBuf = &frameBuf[0];
} }
auto path = filepath(filename); size_t payloadSize = file.read(payloadBuf, maxPayloadSize);
auto file = FileFS.open(path, "r"); if (payloadSize) {
if (!file) { size_t size = headerSize + payloadSize;
SerialPrint("E", "FS", F("reed file error"));
return; bool fin = false;
if (size == frameSize) {
fin = false;
} else {
fin = true;
}
bool continuation = false;
if (i == 0) {
continuation = false;
} else {
continuation = true;
}
// Serial.println(String(i) + ") " + "ws: " + String(client_id) + " fr sz:
// " + String(size) + " fin: " + String(fin) + " cnt: " +
// String(continuation));
if (client_id == -1) {
standWebSocket.broadcastBIN(frameBuf, size, fin, continuation);
} else {
standWebSocket.sendBIN(client_id, frameBuf, size, fin, continuation);
}
} }
i++;
size_t totalSize = file.size(); }
// Serial.println("Send file '" + String(filename) + "', file size: " + String(totalSize)); payloadBuf = &frameBuf[0];
delete[] payloadBuf;
char buf[32]; file.close();
sprintf(buf, "%04d", json.length() + 12);
String data = header + "|" + String(buf) + "|" + json;
size_t headerSize = data.length();
auto frameBuf = new uint8_t[frameSize];
size_t maxPayloadSize = frameSize - headerSize;
uint8_t* payloadBuf = nullptr;
int i = 0;
while (file.available()) {
if (i == 0) {
data.toCharArray((char*)frameBuf, frameSize);
payloadBuf = &frameBuf[headerSize];
} else {
maxPayloadSize = frameSize;
headerSize = 0;
payloadBuf = &frameBuf[0];
}
size_t payloadSize = file.read(payloadBuf, maxPayloadSize);
if (payloadSize) {
size_t size = headerSize + payloadSize;
bool fin = false;
if (size == frameSize) {
fin = false;
} else {
fin = true;
}
bool continuation = false;
if (i == 0) {
continuation = false;
} else {
continuation = true;
}
// Serial.println(String(i) + ") " + "ws: " + String(client_id) + " fr sz: " + String(size) + " fin: " + String(fin) + " cnt: " + String(continuation));
if (client_id == -1) {
standWebSocket.broadcastBIN(frameBuf, size, fin, continuation);
} else {
standWebSocket.sendBIN(client_id, frameBuf, size, fin, continuation);
}
}
i++;
}
payloadBuf = &frameBuf[0];
delete[] payloadBuf;
file.close();
} }
void sendStringToWs(const String& header, String& payload, int client_id) { void sendStringToWs(const String& header, String& payload, int client_id) {
@@ -438,15 +474,16 @@ void sendStringToWs(const String& header, String& payload, int client_id) {
} }
void sendDeviceList(uint8_t num) { void sendDeviceList(uint8_t num) {
if (jsonReadInt(settingsFlashJson, F("udps")) != 0) { if (jsonReadInt(settingsFlashJson, F("udps")) != 0) {
// если включен автопоиск то отдаем список из оперативной памяти // если включен автопоиск то отдаем список из оперативной памяти
SerialPrint("i", "FS", "heap list"); SerialPrint("i", "FS", "heap list");
sendStringToWs("devlis", devListHeapJson, num); sendStringToWs("devlis", devListHeapJson, num);
} else { } else {
// если выключен автопоиск то отдаем список из флешь памяти // если выключен автопоиск то отдаем список из флешь памяти
sendFileToWsByFrames("/devlist.json", "devlis", "", num, WEB_SOCKETS_FRAME_SIZE); sendFileToWsByFrames("/devlist.json", "devlis", "", num,
SerialPrint("i", "FS", "flash list"); WEB_SOCKETS_FRAME_SIZE);
} SerialPrint("i", "FS", "flash list");
}
} }
int getNumWSClients() { int getNumWSClients() {

View File

@@ -7,9 +7,7 @@
IoTItem::IoTItem(const String& parameters) { IoTItem::IoTItem(const String& parameters) {
jsonRead(parameters, F("int"), _interval, false); jsonRead(parameters, F("int"), _interval, false);
if (_interval == 0) enableDoByInt = false; // выключаем использование периодического выполнения в модуле setInterval(_interval);
if (_interval > 0) _interval = _interval * 1000; // если int положителен, то считаем, что получены секунды
if (_interval < 0) _interval = _interval * -1; // если int отрицательный, то миллисекунды
jsonRead(parameters, F("subtype"), _subtype, false); jsonRead(parameters, F("subtype"), _subtype, false);
jsonRead(parameters, F("id"), _id); jsonRead(parameters, F("id"), _id);
if (!jsonRead(parameters, F("multiply"), _multiply, false)) _multiply = 1; if (!jsonRead(parameters, F("multiply"), _multiply, false)) _multiply = 1;
@@ -38,12 +36,16 @@ IoTItem::IoTItem(const String& parameters) {
setValue(valAsStr, false); setValue(valAsStr, false);
} }
void IoTItem::suspendNextDoByInt(unsigned long _delay) { // 0 - force
nextMillis = millis() + _delay;
}
void IoTItem::loop() { void IoTItem::loop() {
if (enableDoByInt) { if (enableDoByInt) {
currentMillis = millis(); unsigned long currentMillis = millis(); // _interval должен быть < 2147483647 мс (24 суток)
difference = currentMillis - prevMillis; if (nextMillis - currentMillis > 2147483647UL /*ULONG_MAX/2*/ ) {
if (difference >= _interval) { nextMillis = currentMillis + _interval;
prevMillis = millis(); // SerialPrint(F("i"), _id, "this->doByInterval");
this->doByInterval(); this->doByInterval();
} }
} }
@@ -201,7 +203,13 @@ bool IoTItem::isStrInID(const String& str) {
} }
void IoTItem::setInterval(long interval) { void IoTItem::setInterval(long interval) {
_interval = interval; if (interval == 0) enableDoByInt = false; // выключаем использование периодического выполнения в модуле
else {
enableDoByInt = true;
if (interval > 0) _interval = interval * 1000; // если int положителен, то считаем, что получены секунды
else if (interval < 0) _interval = interval * -1; // если int отрицательный, то миллисекунды
}
// SerialPrint(F("i"), F("IoTItem"), "setInterval: " + _interval.toString);
} }
IoTGpio* IoTItem::getGpioDriver() { IoTGpio* IoTItem::getGpioDriver() {

View File

@@ -341,7 +341,8 @@ enum SysOp {
sysop_getRSSI, sysop_getRSSI,
sysop_getIP, sysop_getIP,
sysop_mqttPub, sysop_mqttPub,
sysop_getUptime sysop_getUptime,
sysop_mqttIsConnect
}; };
IoTValue sysExecute(SysOp command, std::vector<IoTValue> &param) { IoTValue sysExecute(SysOp command, std::vector<IoTValue> &param) {
@@ -442,6 +443,9 @@ IoTValue sysExecute(SysOp command, std::vector<IoTValue> &param) {
value.valS = jsonReadStr(errorsHeapJson, F("upt")); value.valS = jsonReadStr(errorsHeapJson, F("upt"));
value.isDecimal = false; value.isDecimal = false;
break; break;
case sysop_mqttIsConnect:
value.valD = mqttIsConnect();
break;
} }
return value; return value;
@@ -496,6 +500,8 @@ class SysCallExprAST : public ExprAST {
operation = sysop_getTime; operation = sysop_getTime;
else if (Callee == F("getUptime")) else if (Callee == F("getUptime"))
operation = sysop_getUptime; operation = sysop_getUptime;
else if (Callee == F("mqttIsConnect"))
operation = sysop_mqttIsConnect;
else else
operation = sysop_notfound; operation = sysop_notfound;
} }

View File

@@ -43,13 +43,16 @@ public:
#if defined ESP8266 #if defined ESP8266
if (!http.begin(_host, 80, _url)) if (!http.begin(_host, 80, _url))
{ {
#elif defined ESP32
if (!http.begin(String("http://") + _host + _url))
{
#endif
// Serial.println("connection failed"); // Serial.println("connection failed");
SerialPrint("I", F("NextionUpdate"), "connection failed "); SerialPrint("I", F("NextionUpdate"), "connection failed ");
} }
#elif defined ESP32
if (!http.begin(String("http://") + _host + _url))
{
// Serial.println("connection failed");
SerialPrint("I", F("NextionUpdate"), "connection failed ");
}
#endif
SerialPrint("I", F("NextionUpdate"), "Requesting file: " + (String)_url); SerialPrint("I", F("NextionUpdate"), "Requesting file: " + (String)_url);
int code = http.GET(); int code = http.GET();

View File

@@ -0,0 +1,174 @@
#include "Global.h"
#include "classes/IoTItem.h"
#include <GyverOLED.h>
GyverOLED<SSD1306_128x64, OLED_BUFFER> oled;
// GyverOLED<SSD1306_128x32, OLED_BUFFER> oled;
// GyverOLED<SSD1306_128x32, OLED_NO_BUFFER> oled;
// GyverOLED<SSD1306_128x64, OLED_NO_BUFFER> oled;
// GyverOLED<SSD1306_128x64, OLED_BUFFER, OLED_SPI, 8, 7, 6> oled;
// GyverOLED<SSH1106_128x64> oled;
class Oled128 : public IoTItem {
private:
unsigned int _x;
unsigned int _y;
unsigned int _k;
int _shrift;
String _id2show;
String _descr;
String _descr1;
int _prevStrSize;
bool _isShow = true; // экран показывает
public:
Oled128(String parameters) : IoTItem(parameters) {
String addr, size, xy, k;
_prevStrSize = 0;
jsonRead(parameters, "addr", addr);
if (addr == "") {
// scanI2C();
return;
}
jsonRead(parameters, "coord", xy);
_x = selectFromMarkerToMarker(xy, ",", 0).toInt();
_y = selectFromMarkerToMarker(xy, ",", 1).toInt();
jsonRead(parameters, "descr", _descr);
jsonRead(parameters, "id2show", _id2show);
jsonRead(parameters, "descr1", _descr1);
// jsonRead(parameters, "scale", _k);
jsonRead(parameters, "shrift", _shrift);
// Wire.begin(2,0); // Инициализация шины I2C для модуля E01
oled.init(); // инициализация экрана
}
void doByInterval() {
printBlankStr(_prevStrSize);
String tmpStr = "";
// if (_descr != "none") tmpStr = _descr + " " + getItemValue(_id2show);
if (_descr != "none")
tmpStr = _descr + " " + getItemValue(_id2show) + " " + _descr1;
else
tmpStr = getItemValue(_id2show);
// oled.setScale(2);
oled.setScale(_shrift);
oled.setCursorXY(_x, _y);
oled.print(tmpStr);
oled.update();
_prevStrSize = tmpStr.length();
}
IoTValue execute(String command, std::vector<IoTValue> &param) { // будет возможным использовать, когда сценарии запустятся
if (command == "scroll") {
String tmpStr = "";
oled.clear();
uint32_t tmr = millis();
oled.autoPrintln(false);
int val = 128;
for (;;) {
// oled.clear(); // ЗАКОММЕНТИРУЙ, ЕСЛИ ВКЛЮЧЕН БУФЕР
// oled.setScale(2);
oled.setScale(_shrift);
oled.setCursor(val, _y);
oled.print(tmpStr);
oled.update();
val--;
if (millis() - tmr > 5000)
; // return;
_isShow = true;
}
}
else if (command == "stopscroll") {
_isShow = true;
// display->backlight();
// else if (command == "noDisplay") {
// display->noDisplay();
// _isShow = false;
} else if (command == "display") {
// display.display();
_isShow = true;
} else if (command == "toggle") {
if (_isShow) {
// display->noDisplay();
_isShow = false;
} else {
// display.display();
_isShow = true;
}
} else if (command == "x") {
if (param.size()) {
_x = param[0].valD;
}
} else if (command == "y") {
if (param.size()) {
_y = param[0].valD;
}
} else if (command == "descr") {
if (param.size()) {
_descr = param[0].valS;
}
} else if (command == "descr1") {
if (param.size()) {
_descr1 = param[0].valS;
}
} else if (command == "id2show") {
if (param.size()) {
_id2show = param[0].valS;
}
}
doByInterval();
return {};
}
// печать пустой строки нужной длинны для затирания предыдущего значения на экране
void printBlankStr(int strSize) {
String tmpStr = "";
for (int i = 0; i < strSize; i++) tmpStr += " ";
// oled.setScale(2);
oled.setScale(_shrift);
oled.setCursorXY(_x, _y);
oled.print(tmpStr);
}
~Oled128(){};
};
void *getAPI_Oled128(String subtype, String param) {
if (subtype == F("Oled128")) {
return new Oled128(param);
} else {
return nullptr;
}
}

View File

@@ -0,0 +1,86 @@
{
"menuSection": "screens",
"configItem": [
{
"name": "OLED экран 128*64",
"type": "Reading",
"subtype": "Oled128",
"id": "oled",
"widget": "",
"page": "",
"descr": "T",
"descr1": "C",
"int": 1,
"addr": "0x3C",
"coord": "0,10",
"id2show": "id датчика",
"shrift": "2"
}
],
"about": {
"authorName": "Serghei Crasnicov",
"authorContact": "https://t.me/Serghei63",
"authorGit": "https://github.com/Serghei63",
"specialThanks": "Ilya Belyakov @Biveraxe",
"moduleName": "Oled128",
"moduleVersion": "1.0",
"moduleDesc": "Позволяет выводить на матричные Oled экраны по указанным позициям значения других элементов конфигурации.",
"usedRam": 15,
"propInfo": {
"int": "Период времени в секундах обновления информации на экране по конкретному элементу.",
"addr": "Адрес устройства на шине, обычно 0x3c.",
"coord": "Координата позиции для вывода данных элемента конфигурации.",
"id2show": "id элемента конфигурации.",
"shrift": "Шрифт текста от 1 до 4 "
},
"funcInfo": [
{
"name": "x",
"descr": "Устанавливает первую координату",
"params": [
"Номер строки первого символа"
]
},
{
"name": "y",
"descr": "Устанавливает вторую координату",
"params": [
"Номер столбца первого символа"
]
},
{
"name": "descr",
"descr": "Задает приставку слева от значения, если none значит пусто",
"params": [
"Строка"
]
},
{
"name": "descr1",
"descr": "Задает приставку справа от значения. Если descr none , то не выводится",
"params": [
"Строка"
]
},
{
"name": "id2show",
"descr": "Задает ИД элемента, значение которого хотим отображать на экране",
"params": [
"Имя элемента конфигурации"
]
}
]
},
"defActive": false,
"usedLibs": {
"esp32_4mb": [
"gyverlibs/GyverOLED @ 1.4"
],
"esp32_16mb": [
"gyverlibs/GyverOLED @ 1.4"
],
"esp8266_4mb": [
"gyverlibs/GyverOLED @ 1.4"
]
}
}

View File

@@ -104,35 +104,43 @@
"usedLibs": { "usedLibs": {
"esp32_4mb": [ "esp32_4mb": [
"https://github.com/maxint-rd/TM16xx", "https://github.com/maxint-rd/TM16xx",
"adafruit/Adafruit GFX Library @ ^1.11.5" "adafruit/Adafruit GFX Library @ ^1.11.5",
"adafruit/Adafruit BusIO @ ^1.13.2"
], ],
"esp8266_4mb": [ "esp8266_4mb": [
"https://github.com/maxint-rd/TM16xx", "https://github.com/maxint-rd/TM16xx",
"adafruit/Adafruit GFX Library @ ^1.11.5" "adafruit/Adafruit GFX Library @ ^1.11.5",
"adafruit/Adafruit BusIO @ ^1.13.2"
], ],
"esp8266_1mb": [ "esp8266_1mb": [
"https://github.com/maxint-rd/TM16xx", "https://github.com/maxint-rd/TM16xx",
"adafruit/Adafruit GFX Library @ ^1.11.5" "adafruit/Adafruit GFX Library @ ^1.11.5",
"adafruit/Adafruit BusIO @ ^1.13.2"
], ],
"esp8266_1mb_ota": [ "esp8266_1mb_ota": [
"https://github.com/maxint-rd/TM16xx", "https://github.com/maxint-rd/TM16xx",
"adafruit/Adafruit GFX Library @ ^1.11.5" "adafruit/Adafruit GFX Library @ ^1.11.5",
"adafruit/Adafruit BusIO @ ^1.13.2"
], ],
"esp8285_1mb": [ "esp8285_1mb": [
"https://github.com/maxint-rd/TM16xx", "https://github.com/maxint-rd/TM16xx",
"adafruit/Adafruit GFX Library @ ^1.11.5" "adafruit/Adafruit GFX Library @ ^1.11.5",
"adafruit/Adafruit BusIO @ ^1.13.2"
], ],
"esp8285_1mb_ota": [ "esp8285_1mb_ota": [
"https://github.com/maxint-rd/TM16xx", "https://github.com/maxint-rd/TM16xx",
"adafruit/Adafruit GFX Library @ ^1.11.5" "adafruit/Adafruit GFX Library @ ^1.11.5",
"adafruit/Adafruit BusIO @ ^1.13.2"
], ],
"esp8266_2mb": [ "esp8266_2mb": [
"https://github.com/maxint-rd/TM16xx", "https://github.com/maxint-rd/TM16xx",
"adafruit/Adafruit GFX Library @ ^1.11.5" "adafruit/Adafruit GFX Library @ ^1.11.5",
"adafruit/Adafruit BusIO @ ^1.13.2"
], ],
"esp8266_2mb_ota": [ "esp8266_2mb_ota": [
"https://github.com/maxint-rd/TM16xx", "https://github.com/maxint-rd/TM16xx",
"adafruit/Adafruit GFX Library @ ^1.11.5" "adafruit/Adafruit GFX Library @ ^1.11.5",
"adafruit/Adafruit BusIO @ ^1.13.2"
] ]
} }
} }

View File

@@ -46,7 +46,10 @@
"defActive": true, "defActive": true,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -3,24 +3,28 @@
extern IoTGpio IoTgpio; extern IoTGpio IoTgpio;
class ButtonOut : public IoTItem { class ButtonOut : public IoTItem {
private: private:
int _pin, _inv; int _pin;
bool _inv;
public: public:
ButtonOut(String parameters): IoTItem(parameters) { ButtonOut(String parameters): IoTItem(parameters) {
jsonRead(parameters, "pin", _pin); jsonRead(parameters, "pin", _pin);
jsonRead(parameters, "inv", _inv); jsonRead(parameters, "inv", _inv);
_round = 0; _round = 0;
IoTgpio.pinMode(_pin, OUTPUT); IoTgpio.pinMode(_pin, OUTPUT);
IoTgpio.digitalWrite(_pin, _inv?!value.valD:value.valD); IoTgpio.digitalWrite(_pin, _inv?!value.valD:value.valD);
enableDoByInt = false;
} }
void doByInterval() { void doByInterval() {
//value.valD = IoTgpio.analogRead(_pin); int val = _inv?1:0;
IoTgpio.digitalWrite(_pin, val);
// SerialPrint("I", "ButtonOut","single pulse end");
value.valD = 0;
regEvent(0, "ButtonOut");
enableDoByInt = false;
//regEvent(value.valD, "ButtonOut"); //обязательный вызов хотяб один //regEvent(value.valD, "ButtonOut"); //обязательный вызов хотяб один
} }
@@ -30,24 +34,40 @@ class ButtonOut : public IoTItem {
// param - вектор ("массив") значений параметров переданных вместе с командой: ID.Команда("пар1", 22, 33) -> param[0].ValS = "пар1", param[1].ValD = 22 // param - вектор ("массив") значений параметров переданных вместе с командой: ID.Команда("пар1", 22, 33) -> param[0].ValS = "пар1", param[1].ValD = 22
if (command == "change") { if (command == "change") {
value.valD = 1 - IoTgpio.digitalRead(_pin); value.valD = 1 - (int)value.valD;
IoTgpio.digitalWrite(_pin, value.valD); IoTgpio.digitalWrite(_pin, _inv?!value.valD:value.valD);
regEvent(value.valD, "ButtonOut"); regEvent(value.valD, "ButtonOut");
} }
else if (command == "pulse") {
if (param[0].isDecimal && (param[0].valD != 0)) {
value.valD = !_inv?1:0;
enableDoByInt = true;
// SerialPrint("I", "ButtonOut","single pulse start");
regEvent((String)(int)!_inv?1:0, "ButtonOut");
suspendNextDoByInt(param[0].valD);
IoTgpio.digitalWrite(_pin, !_inv?1:0);
}
}
return {}; // команда поддерживает возвращаемое значения. Т.е. по итогу выполнения команды или общения с внешней системой, можно вернуть значение в сценарий для дальнейшей обработки return {}; // команда поддерживает возвращаемое значения. Т.е. по итогу выполнения команды или общения с внешней системой, можно вернуть значение в сценарий для дальнейшей обработки
} }
void setValue(const IoTValue& Value, bool genEvent = true) { void setValue(const IoTValue& Value, bool genEvent = true) {
value = Value; value = Value;
IoTgpio.digitalWrite(_pin, _inv?!value.valD:value.valD); if ((value.valD == !_inv?1:0) && (_interval != 0)) {
value.valD = !_inv?1:0;
enableDoByInt = true;
// SerialPrint("I", "ButtonOut","single pulse start");
suspendNextDoByInt(_interval);
} else {
enableDoByInt = false;
}
regEvent((String)(int)value.valD, "ButtonOut", false, genEvent); regEvent((String)(int)value.valD, "ButtonOut", false, genEvent);
IoTgpio.digitalWrite(_pin, _inv?!value.valD:value.valD);
} }
String getValue() { String getValue() {
return (String)(int)value.valD; return (String)(int)value.valD;
} }
//=======================================================================================================
~ButtonOut() {}; ~ButtonOut() {};
}; };

View File

@@ -39,13 +39,21 @@
"name": "change", "name": "change",
"descr": "Инвертирует значение переключателя", "descr": "Инвертирует значение переключателя",
"params": [] "params": []
},
{
"name": "pulse",
"descr": "Генерирует одиночный импульс",
"params": ["Длительность (ms)"]
} }
] ]
}, },
"defActive": true, "defActive": true,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -79,16 +79,7 @@ public:
case 1: case 1:
// for doByIntervals // for doByIntervals
if (enableDoByInt) IoTItem::loop();
{
currentMillis = millis();
difference = currentMillis - prevMillis;
if (difference >= _interval)
{
prevMillis = millis();
this->doByInterval();
}
}
break; break;
case 2: case 2:

View File

@@ -49,6 +49,9 @@
"esp8266_4mb": [ "esp8266_4mb": [
"gyverlibs/EncButton @ ^2.0" "gyverlibs/EncButton @ ^2.0"
], ],
"esp8266_16mb": [
"gyverlibs/EncButton @ ^2.0"
],
"esp8266_1mb": [ "esp8266_1mb": [
"gyverlibs/EncButton @ ^2.0" "gyverlibs/EncButton @ ^2.0"
], ],

View File

@@ -35,7 +35,9 @@
"defActive": false, "defActive": false,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [], "esp32s2_4mb": [],
"esp8266_4mb": [] "esp8266_4mb": [],
"esp8266_16mb": []
} }
} }

View File

@@ -10,7 +10,7 @@ public:
void sendHttpPOST(String url, String msg) void sendHttpPOST(String url, String msg)
{ {
if (WiFi.status() == WL_CONNECTED) if (isNetworkActive())
{ {
WiFiClient client; WiFiClient client;

View File

@@ -7,7 +7,7 @@
"type": "Writing", "type": "Writing",
"subtype": "IoTServo", "subtype": "IoTServo",
"id": "servo", "id": "servo",
"widget": "range", "widget": "rangeServo",
"page": "servo", "page": "servo",
"descr": "угол", "descr": "угол",
"int": 1, "int": 1,

View File

@@ -3,6 +3,11 @@
#include "Arduino.h" #include "Arduino.h"
#include "MySensorsGate.h" #include "MySensorsGate.h"
// временное решение
unsigned long currentMillis;
unsigned long prevMillis;
unsigned long difference;
#ifdef MYSENSORS #ifdef MYSENSORS
// callback библиотеки mysensors // callback библиотеки mysensors
void receive(const MyMessage& message) { void receive(const MyMessage& message) {

View File

@@ -58,6 +58,9 @@
"esp32_4mb": [ "esp32_4mb": [
"CTBot @2.1.9" "CTBot @2.1.9"
], ],
"esp32_16mb": [
"CTBot @2.1.9"
],
"esp8266_4mb": [ "esp8266_4mb": [
"CTBot @2.1.9" "CTBot @2.1.9"
] ]

View File

@@ -13,7 +13,7 @@ class TelegramLT : public IoTItem {
} }
void sendTelegramMsg(bool often, String msg) { void sendTelegramMsg(bool often, String msg) {
if (WiFi.status() == WL_CONNECTED && (often || !often && _prevMsg != msg)) { if (isNetworkActive() && (often || !often && _prevMsg != msg)) {
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
http.begin(client, "http://live-control.com/iotm/telegram.php"); http.begin(client, "http://live-control.com/iotm/telegram.php");

View File

@@ -52,8 +52,10 @@
"defActive": true, "defActive": true,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [], "esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -246,6 +246,11 @@ protected:
pv_last = pv; pv_last = pv;
} }
// временное решение
unsigned long currentMillis;
unsigned long prevMillis;
unsigned long difference;
void loop() void loop()
{ {
if (enableDoByInt) if (enableDoByInt)

View File

@@ -69,6 +69,11 @@
"descr": "Отправить значение в топик MQTT", "descr": "Отправить значение в топик MQTT",
"params": ["Топик", "Значение"] "params": ["Топик", "Значение"]
}, },
{
"name": "mqttIsConnect",
"descr": "Получить состояние подключения к MQTT",
"params": []
},
{ {
"name": "getHours", "name": "getHours",
"descr": "Получить текущее число часов. Если время не получено из сети Интернет или внешнего RTC, то условие пропускается", "descr": "Получить текущее число часов. Если время не получено из сети Интернет или внешнего RTC, то условие пропускается",

View File

@@ -64,13 +64,7 @@ class AnalogAdc : public IoTItem {
_avgSumm = _avgSumm + IoTgpio.analogRead(_pin); _avgSumm = _avgSumm + IoTgpio.analogRead(_pin);
_avgCount++; _avgCount++;
} }
IoTItem::loop();
currentMillis = millis();
difference = currentMillis - prevMillis;
if (difference >= _interval) {
prevMillis = millis();
this->doByInterval();
}
} }
~AnalogAdc(){}; ~AnalogAdc(){};

View File

@@ -7,16 +7,16 @@
#include "Global.h" #include "Global.h"
#include "classes/IoTItem.h" #include "classes/IoTItem.h"
//!Здесь подключаем стороннюю библиотеку при необходимости (ExternalLibrary заменить) //! Здесь подключаем стороннюю библиотеку при необходимости (ExternalLibrary заменить)
//#include <ExternalLibrary.h> // #include <ExternalLibrary.h>
#include "ExternalLibrary.h" //удалить, только для примера. Внешние библиотеки правильно в <> #include "ExternalLibrary.h" //удалить, только для примера. Внешние библиотеки правильно в <>
//! Объяевляем класс IoTGpio для работы с GPIO //! Объяевляем класс IoTGpio для работы с GPIO
extern IoTGpio IoTgpio; extern IoTGpio IoTgpio;
//========================================================================================================= //=========================================================================================================
//========================================================================================================= //=========================================================================================================
// Объявление сторонней библиотекит с использованием глобавльных объектов // Объявление сторонней библиотекит с использованием глобавльных объектов
//======================================================================================================= //=======================================================================================================
//! Объявляем стороннюю библиотеку при необходимости (ExternalLibrary заменить) //! Объявляем стороннюю библиотеку при необходимости (ExternalLibrary заменить)
// !!! ЗДЕСЬ И ДАЛЕЕ libXX НАЗВАТЬ уникальным именем) // !!! ЗДЕСЬ И ДАЛЕЕ libXX НАЗВАТЬ уникальным именем)
@@ -25,9 +25,15 @@ ExternalLibrary *libXX = nullptr;
// Функция инициализации библиотечного класса, возвращает Единстрвенный указать на библиотеку // Функция инициализации библиотечного класса, возвращает Единстрвенный указать на библиотеку
// instanceLibXX НАЗВАТЬ по наименованию модуля (instanceДатчикХ) // instanceLibXX НАЗВАТЬ по наименованию модуля (instanceДатчикХ)
// ПРИ НЕОБХДИМОСТИ передаем любые нужные параметры для инициализации библиотеки (в данном случае PIN) // ПРИ НЕОБХДИМОСТИ передаем любые нужные параметры для инициализации библиотеки (в данном случае PIN)
// !!! ВЫзвать данную функцию нужно хотябы один раз, //
// !!! ВЫзвать данную функцию нужно хотябы один раз,
// но в каждом конструкторе класса модуля ExampleModule_A, ExampleModule_B и т.д. // но в каждом конструкторе класса модуля ExampleModule_A, ExampleModule_B и т.д.
// или можно вывывать постоянно при обращении к библиотеке, типа: instanceLibXX().READ_LIB_DATA_OTHER(); // или можно вывывать постоянно при обращении к библиотеке, типа: instanceLibXX().READ_LIB_DATA_OTHER();
//
// !!!!!! В деструкторах ~ExampleModule_B() и ~ExampleModule_A() надо УДАЛЯТЬ объект libXX, ЕСЛИ в функцию instanceLibXX чтото передается.
// Удаляем класс библиотеки, а то при переконфигурации в нем не поменяются PIN и дугие параметры передаваемые в библиотеку.
// P.S. Не для всех, если используется map или vector то лучше не надо.
ExternalLibrary *instanceLibXX(int pin) ExternalLibrary *instanceLibXX(int pin)
{ {
if (!libXX) if (!libXX)
@@ -39,7 +45,6 @@ ExternalLibrary *instanceLibXX(int pin)
return libXX; return libXX;
} }
//========================================================================================================= //=========================================================================================================
//========================================================================================================= //=========================================================================================================
// Первый класс модуля для определения 1-го элемента (параметра) // Первый класс модуля для определения 1-го элемента (параметра)
@@ -69,7 +74,7 @@ public:
// jsonReadStr, jsonReadBool, jsonReadInt // jsonReadStr, jsonReadBool, jsonReadInt
ExampleModule_A(String parameters) : IoTItem(parameters) ExampleModule_A(String parameters) : IoTItem(parameters)
{ {
//Читаем пользовательскую переменную PIN, должна быть объявлена в в modeinfo.json // Читаем пользовательскую переменную PIN, должна быть объявлена в в modeinfo.json
_pin = jsonReadInt(parameters, "pin"); _pin = jsonReadInt(parameters, "pin");
// другой вариант чтения парметров модуля // другой вариант чтения парметров модуля
jsonRead(parameters, F("int"), _interval, false); jsonRead(parameters, F("int"), _interval, false);
@@ -102,16 +107,15 @@ public:
adc = IoTgpio.analogRead(_pin); adc = IoTgpio.analogRead(_pin);
// Блок вызова doByInterval, так как если определили loop, то сам он не вызовится // Блок вызова doByInterval, так как если определили loop, то сам он не вызовится
currentMillis = millis(); IoTItem::loop();
difference = currentMillis - prevMillis;
if (difference >= _interval)
{
prevMillis = millis();
this->doByInterval();
}
} }
~ExampleModule_A(){}; ~ExampleModule_A()
{
// Удаляем класс библиотеки, а то при переконфигурации в нем не поменяются PIN и дугие параметры передаваемые в библиотеку.
delete libXX;
libXX = nullptr;
};
}; };
//========================================================================================================= //=========================================================================================================
@@ -126,14 +130,15 @@ public:
class ExampleModule_B : public IoTItem class ExampleModule_B : public IoTItem
{ {
private: private:
//Пользовательские переменные // Пользовательские переменные
unsigned int _pin; unsigned int _pin;
public: public:
ExampleModule_B(String parameters) : IoTItem(parameters) ExampleModule_B(String parameters) : IoTItem(parameters)
{ {
//Читаем пользовательскую переменную PIN, должна быть объявлена в в modeinfo.json // Читаем пользовательскую переменную PIN, должна быть объявлена в в modeinfo.json
_pin = jsonReadInt(parameters, "pin"); _pin = jsonReadInt(parameters, "pin");
//Можно инициализировать библиотеку один раз, а потом используем указатель // Можно инициализировать библиотеку один раз, а потом используем указатель
instanceLibXX(_pin); instanceLibXX(_pin);
libXX->READ_LIB_DATA_OTHER(); libXX->READ_LIB_DATA_OTHER();
} }
@@ -146,7 +151,7 @@ public:
regEvent(value.valD, "ExampleModule"); // обязательный вызов хотяб один для регистрации события в ядре IoTM regEvent(value.valD, "ExampleModule"); // обязательный вызов хотяб один для регистрации события в ядре IoTM
} }
//================ обработка кнопок из конфигурации =================== //================ обработка кнопок из конфигурации ===================
// Хук (переопределение виртуальной функции) для обработки кнопки (в value будут данные с собственной панели ввода) // Хук (переопределение виртуальной функции) для обработки кнопки (в value будут данные с собственной панели ввода)
// Что бы кнопка была без поля ввода, нужно в modeinfo.json указать "btn-Example": nil // Что бы кнопка была без поля ввода, нужно в modeinfo.json указать "btn-Example": nil
void onModuleOrder(String &key, String &value) void onModuleOrder(String &key, String &value)
@@ -158,7 +163,7 @@ public:
} }
} }
//================ обработка команд из сценария=================== //================ обработка команд из сценария===================
// Хук (переопределение виртуальной функции) для обработки команды из сценария (в param будут даныые переданные в функции в сценарии) // Хук (переопределение виртуальной функции) для обработки команды из сценария (в param будут даныые переданные в функции в сценарии)
IoTValue execute(String command, std::vector<IoTValue> &param) IoTValue execute(String command, std::vector<IoTValue> &param)
{ {
@@ -204,10 +209,14 @@ public:
// Прсото пример кокой-то функции // Прсото пример кокой-то функции
} }
~ExampleModule_B(){}; ~ExampleModule_B()
{
// Удаляем класс библиотеки, а то при переконфигурации в нем не поменяются PIN и дугие параметры передаваемые в библиотеку.
delete libXX;
libXX = nullptr;
};
}; };
//========================================================================================================= //=========================================================================================================
//========================================================================================================= //=========================================================================================================
// Функция для связи модуля с ядром IoTM // Функция для связи модуля с ядром IoTM

View File

@@ -13,16 +13,24 @@ private:
int red = 0; int red = 0;
int offline = 0; int offline = 0;
bool dataFromNode = false; bool dataFromNode = false;
String _topic = "";
bool _isJson;
bool _addPrefix;
bool _debug;
public: public:
ExternalMQTT(String parameters) : IoTItem(parameters) ExternalMQTT(String parameters) : IoTItem(parameters)
{ {
_MAC = jsonReadStr(parameters, "MAC");
_sensor = jsonReadStr(parameters, "sensor"); _sensor = jsonReadStr(parameters, "sensor");
jsonRead(parameters, F("orange"), orange); jsonRead(parameters, F("orange"), orange);
jsonRead(parameters, F("red"), red); jsonRead(parameters, F("red"), red);
jsonRead(parameters, F("offline"), offline); jsonRead(parameters, F("offline"), offline);
_topic = jsonReadStr(parameters, "topic");
_isJson = jsonReadBool(parameters, "isJson");
_addPrefix = jsonReadBool(parameters, "addPrefix");
_debug = jsonReadBool(parameters, "debug");
dataFromNode = false; dataFromNode = false;
mqttSubscribeExternal(_topic, _addPrefix);
} }
char *TimeToString(unsigned long t) char *TimeToString(unsigned long t)
{ {
@@ -38,38 +46,58 @@ public:
{ {
if (msg.indexOf("HELLO") == -1) if (msg.indexOf("HELLO") == -1)
{ {
if (_debug)
// SerialPrint("i", "onMqttRecive", "Прилетело " + topic); {
// SerialPrint("i", "onMqttRecive", "Прилетело " + msg); SerialPrint("i", "onMqttRecive", "Прилетело " + topic + " msg: " + msg);
// SerialPrint("i", "onMqttRecive", "Прилетело " + msg);
}
String dev = selectToMarkerLast(topic, "/"); String dev = selectToMarkerLast(topic, "/");
dev.toUpperCase(); dev.toUpperCase();
dev.replace(":", ""); dev.replace(":", "");
if (_MAC == "") if (_topic != topic)
{ {
SerialPrint("i", "onMqttRecive", dev + " --> " + msg); return;
} }
DynamicJsonDocument doc(JSON_BUFFER_SIZE); if (_isJson)
DeserializationError error = deserializeJson(doc, msg);
if (error)
{ {
SerialPrint("E", F("onMqttRecive"), error.f_str()); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
} DeserializationError error = deserializeJson(doc, msg);
JsonObject jsonObject = doc.as<JsonObject>(); if (error)
for (JsonPair kv : jsonObject)
{
String key = kv.key().c_str();
String val = kv.value();
if (_MAC == dev && _sensor == key)
{ {
dataFromNode = true; SerialPrint("E", F("onMqttRecive"), error.f_str());
_minutesPassed = 0;
setValue(val);
// setNewWidgetAttributes();
} }
JsonObject jsonObject = doc.as<JsonObject>();
// Serial.println("Key: " + key); for (JsonPair kv : jsonObject)
// Serial.println("Value: " + val); {
String key = kv.key().c_str();
String val = kv.value();
if (_debug)
{
SerialPrint("i", "onMqttRecive", "Прилетело MAC: " + dev + " key=" + key + " val=" + val);
}
if (_sensor == key)
{
dataFromNode = true;
_minutesPassed = 0;
setValue(val);
// setNewWidgetAttributes();
}
// Serial.println("Key: " + key);
// Serial.println("Value: " + val);
}
}
else
{
if (_debug)
{
SerialPrint("i", "onMqttRecive", "Прилетело MAC: " + dev + " val=" + msg);
}
dataFromNode = true;
_minutesPassed = 0;
setValue(msg);
// setNewWidgetAttributes();
} }
} }
} }
@@ -116,7 +144,22 @@ public:
} }
sendSubWidgetsValues(_id, json); sendSubWidgetsValues(_id, json);
} }
/*
IoTValue execute(String command, std::vector<IoTValue> &param)
{
if (command == "mqttSubscribe")
{
if (param.size() == 2)
{
if (!param[0].isDecimal && param[1].isDecimal)
{
mqttSubscribeExternal(param[0].valS, (bool)param[0].valD);
}
}
}
return {};
}
*/
~ExternalMQTT(){}; ~ExternalMQTT(){};
}; };

View File

@@ -10,13 +10,16 @@
"widget": "", "widget": "",
"page": "", "page": "",
"descr": "", "descr": "",
"MAC": "",
"sensor": "", "sensor": "",
"topic": "",
"addPrefix": 0,
"isJson": 1,
"round": "", "round": "",
"orange": 60, "orange": 60,
"red": 120, "red": 120,
"offline": 180, "offline": 180,
"int": 60 "int": 60,
"debug": 0
} }
], ],
"about": { "about": {
@@ -25,7 +28,7 @@
"authorGit": "https://github.com/avaksru", "authorGit": "https://github.com/avaksru",
"specialThanks": "", "specialThanks": "",
"moduleName": "ExternalMQTT", "moduleName": "ExternalMQTT",
"moduleVersion": "1", "moduleVersion": "1.2",
"usedRam": { "usedRam": {
"esp32_4mb": 15, "esp32_4mb": 15,
"esp8266_4mb": 15 "esp8266_4mb": 15
@@ -38,13 +41,18 @@
"orange": "количество минут после которого окрасить виджет в оранжевый цвет", "orange": "количество минут после которого окрасить виджет в оранжевый цвет",
"red": "количество минут после которого окрасить виджет в красный цвет", "red": "количество минут после которого окрасить виджет в красный цвет",
"offline": "количество минут после которого отобразить что устройство offline, если все три orange red и offline поставить в ноль - то функция окраски выключится", "offline": "количество минут после которого отобразить что устройство offline, если все три orange red и offline поставить в ноль - то функция окраски выключится",
"MAC": "MAC адрес беспроводного датчика", "sensor": "Тип сенсора: температура / влажность / время / ... Он же ключ в json пакете ",
"sensor": "Тип сенсора: температура / влажность / время / ... " "topic":"Подписаться на произвольный топик (полный путь), в модуле данный топик буде проверяться с отправителем, например homed/fd/zigbee/temp",
"addPrefix":"1 (число), будет добавлен стандартный префикс из настроек, 0 - не добавлять префикс",
"isJson":"1 - ожидаем в топике json, 0 - в топике просто значение (при 0 поле sensor заполнять не требуется)",
"debug":"1 - выводить дополнительный лог в сериал"
} }
}, },
"defActive": false, "defActive": false,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],

View File

@@ -157,16 +157,17 @@ public:
void loop() void loop()
{ {
ts_sds.update(); ts_sds.update();
if (enableDoByInt) IoTItem::loop();
{ // if (enableDoByInt)
currentMillis = millis(); // {
difference = currentMillis - prevMillis; // currentMillis = millis();
if (difference >= _interval) // difference = currentMillis - prevMillis;
{ // if (difference >= _interval)
prevMillis = millis(); // {
this->doByInterval(); // prevMillis = millis();
} // this->doByInterval();
} // }
// }
} }
//======================================================================================================= //=======================================================================================================
// doByInterval() // doByInterval()

View File

@@ -235,7 +235,11 @@ public:
} }
} }
} }
~ld2410m(){}; ~ld2410m()
{
delete ld2410;
radar = nullptr;
};
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -291,7 +295,11 @@ public:
} }
} }
~ld2410t(){}; ~ld2410t()
{
delete ld2410;
radar = nullptr;
};
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -346,7 +354,11 @@ public:
} }
} }
} }
~ld2410d(){}; ~ld2410d()
{
delete ld2410;
radar = nullptr;
};
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -404,7 +416,11 @@ public:
} }
} }
} }
~ld2410e(){}; ~ld2410e()
{
delete ld2410;
radar = nullptr;
};
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void *getAPI_ld2410(String subtype, String param) void *getAPI_ld2410(String subtype, String param)

View File

@@ -50,8 +50,10 @@
"defActive": true, "defActive": true,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [], "esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -10,7 +10,7 @@ private:
String scid = ""; String scid = "";
String shname = ""; String shname = "";
// bool init = false; // bool init = false;
int interval = 1; // int interval = 1;
// long interval; // long interval;
String URL = ("http://iotmanager.org/projects/google.php?/macros/s/"); // F("https://script.google.com/macros/s/"); String URL = ("http://iotmanager.org/projects/google.php?/macros/s/"); // F("https://script.google.com/macros/s/");
String urlFinal; String urlFinal;
@@ -24,14 +24,17 @@ public:
jsonRead(parameters, F("logid"), logid); jsonRead(parameters, F("logid"), logid);
jsonRead(parameters, F("scid"), scid); jsonRead(parameters, F("scid"), scid);
jsonRead(parameters, F("shname"), shname); jsonRead(parameters, F("shname"), shname);
jsonRead(parameters, F("int"), interval); // jsonRead(parameters, F("int"), interval);
interval = interval * 1000 * 60; // так как у нас в минутах long interval;
jsonRead(parameters, F("int"), interval); // в минутах
setInterval(interval * 60);
// interval = interval * 1000 * 60; // так как у нас в минутах
urlFinal = URL + scid + F("/exec?") + F("sheet=") + shname; urlFinal = URL + scid + F("/exec?") + F("sheet=") + shname;
} }
void doByInterval() void doByInterval()
{ {
if (WiFi.status() == WL_CONNECTED) if (isNetworkActive())
{ {
String value = getItemValue(logid); String value = getItemValue(logid);
if (value != "") if (value != "")
@@ -39,23 +42,23 @@ public:
} }
} }
void loop() // void loop()
{ // {
if (enableDoByInt) // if (enableDoByInt)
{ // {
currentMillis = millis(); // currentMillis = millis();
difference = currentMillis - prevMillis; // difference = currentMillis - prevMillis;
if (difference >= interval) // if (difference >= interval)
{ // {
prevMillis = millis(); // prevMillis = millis();
this->doByInterval(); // this->doByInterval();
} // }
} // }
} // }
IoTValue execute(String command, std::vector<IoTValue> &param) IoTValue execute(String command, std::vector<IoTValue> &param)
{ {
if (WiFi.status() == WL_CONNECTED) if (isNetworkActive())
{ {
if (command == F("logGoogle")) if (command == F("logGoogle"))
{ // Логирование определенного элемента по его идентификатору в GoogleSheet { // Логирование определенного элемента по его идентификатору в GoogleSheet

View File

@@ -23,7 +23,7 @@ class Loging : public IoTItem {
String prevDate = ""; String prevDate = "";
bool firstTimeInit = true; bool firstTimeInit = true;
long interval; // long interval;
public: public:
Loging(String parameters) : IoTItem(parameters) { Loging(String parameters) : IoTItem(parameters) {
@@ -34,8 +34,9 @@ class Loging : public IoTItem {
points = 300; points = 300;
SerialPrint("E", F("Loging"), "'" + id + "' user set more points than allowed, value reset to 300"); SerialPrint("E", F("Loging"), "'" + id + "' user set more points than allowed, value reset to 300");
} }
jsonRead(parameters, F("int"), interval); long interval;
interval = interval * 1000 * 60; // приводим к милисекундам jsonRead(parameters, F("int"), interval); // в минутах
setInterval(interval * 60);
//jsonRead(parameters, F("keepdays"), keepdays, false); //jsonRead(parameters, F("keepdays"), keepdays, false);
// создадим экземпляр класса даты // создадим экземпляр класса даты
@@ -303,18 +304,18 @@ class Loging : public IoTItem {
return ""; return "";
} }
void loop() { // void loop() {
if (enableDoByInt) { // if (enableDoByInt) {
currentMillis = millis(); // currentMillis = millis();
difference = currentMillis - prevMillis; // difference = currentMillis - prevMillis;
if (difference >= interval) { // if (difference >= interval) {
prevMillis = millis(); // prevMillis = millis();
if (interval != 0) { // if (interval != 0) {
this->doByInterval(); // this->doByInterval();
} // }
} // }
} // }
} // }
void regEvent(const String &value, const String &consoleInfo, bool error = false, bool genEvent = true) { void regEvent(const String &value, const String &consoleInfo, bool error = false, bool genEvent = true) {
String userDate = getItemValue(id + "-date"); String userDate = getItemValue(id + "-date");

View File

@@ -51,8 +51,10 @@
"defActive": true, "defActive": true,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [], "esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -25,7 +25,7 @@ class LogingDaily : public IoTItem {
String prevDate = ""; String prevDate = "";
bool firstTimeInit = true; bool firstTimeInit = true;
long interval; // long interval;
public: public:
LogingDaily(String parameters) : IoTItem(parameters) { LogingDaily(String parameters) : IoTItem(parameters) {
@@ -40,8 +40,9 @@ class LogingDaily : public IoTItem {
points = 365; points = 365;
SerialPrint("E", F("LogingDaily"), "'" + id + "' user set more points than allowed, value reset to 365"); SerialPrint("E", F("LogingDaily"), "'" + id + "' user set more points than allowed, value reset to 365");
} }
jsonRead(parameters, F("int"), interval); long interval;
interval = interval * 1000 * 60; // приводим к милисекундам jsonRead(parameters, F("int"), interval); // в минутах
setInterval(interval * 60);
} }
void doByInterval() { void doByInterval() {
@@ -225,16 +226,16 @@ class LogingDaily : public IoTItem {
return ""; return "";
} }
void loop() { // void loop() {
if (enableDoByInt) { // if (enableDoByInt) {
currentMillis = millis(); // currentMillis = millis();
difference = currentMillis - prevMillis; // difference = currentMillis - prevMillis;
if (difference >= interval) { // if (difference >= interval) {
prevMillis = millis(); // prevMillis = millis();
this->doByInterval(); // this->doByInterval();
} // }
} // }
} // }
// просто максимальное количество точек // просто максимальное количество точек
int calculateMaxCount() { int calculateMaxCount() {

View File

@@ -44,8 +44,10 @@
"defActive": true, "defActive": true,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [], "esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -74,8 +74,10 @@
"defActive": true, "defActive": true,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [], "esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -36,8 +36,10 @@
"defActive": true, "defActive": true,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [], "esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -96,8 +96,10 @@
"defActive": true, "defActive": true,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [], "esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -35,8 +35,10 @@
"defActive": true, "defActive": true,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [], "esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -11,22 +11,23 @@ class Weather : public IoTItem
private: private:
String _location; String _location;
String _param; String _param;
long interval; // long interval;
public: public:
Weather(String parameters) : IoTItem(parameters) Weather(String parameters) : IoTItem(parameters)
{ {
_location = jsonReadStr(parameters, "location"); _location = jsonReadStr(parameters, "location");
_param = jsonReadStr(parameters, "param"); _param = jsonReadStr(parameters, "param");
jsonRead(parameters, F("int"), interval); long interval;
interval = interval * 1000 * 60 * 60; // интервал проверки погоды в часах jsonRead(parameters, F("int"), interval); // интервал проверки погоды в часах
setInterval(interval * 60 * 60);
} }
void getWeather() void getWeather()
{ {
String ret; String ret;
if (WiFi.status() == WL_CONNECTED) if (isNetworkActive())
{ {
// char c; // char c;
String payload; String payload;
@@ -113,19 +114,21 @@ public:
regEvent(value.valS, "Weather"); regEvent(value.valS, "Weather");
} }
} }
void loop()
{ // void loop()
if (enableDoByInt) // {
{ // if (enableDoByInt)
currentMillis = millis(); // {
difference = currentMillis - prevMillis; // currentMillis = millis();
if (difference >= interval) // difference = currentMillis - prevMillis;
{ // if (difference >= interval)
prevMillis = millis(); // {
this->doByInterval(); // prevMillis = millis();
} // this->doByInterval();
} // }
} // }
// }
IoTValue execute(String command, std::vector<IoTValue> &param) IoTValue execute(String command, std::vector<IoTValue> &param)
{ {
if (command == "get") if (command == "get")

View File

@@ -40,8 +40,10 @@
"defActive": false, "defActive": false,
"usedLibs": { "usedLibs": {
"esp32_4mb": [], "esp32_4mb": [],
"esp32_16mb": [],
"esp32s2_4mb": [], "esp32s2_4mb": [],
"esp8266_4mb": [], "esp8266_4mb": [],
"esp8266_16mb": [],
"esp8266_1mb": [], "esp8266_1mb": [],
"esp8266_1mb_ota": [], "esp8266_1mb_ota": [],
"esp8285_1mb": [], "esp8285_1mb": [],

View File

@@ -2,26 +2,34 @@
#include "utils/FileUtils.h" #include "utils/FileUtils.h"
// new================================================================================ // new================================================================================
String jsonReadStrDoc(DynamicJsonDocument& doc, String name) { String jsonReadStrDoc(DynamicJsonDocument &doc, String name)
{
return doc[name].as<String>(); return doc[name].as<String>();
} }
void jsonWriteStrDoc(DynamicJsonDocument& doc, String name, String value) { void jsonWriteStrDoc(DynamicJsonDocument &doc, String name, String value)
{
doc[name] = value; doc[name] = value;
} }
// new============================================================================== // new==============================================================================
bool jsonRead(const String& json, String key, long& value, bool e) { bool jsonRead(const String &json, String key, long &value, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonRead"), error.f_str()); SerialPrint("E", F("jsonRead"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
return false; return false;
} else if (!doc.containsKey(key)) { }
if (e) { else if (!doc.containsKey(key))
{
if (e)
{
SerialPrint("E", F("jsonRead"), key + " missing in " + json); SerialPrint("E", F("jsonRead"), key + " missing in " + json);
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -31,17 +39,23 @@ bool jsonRead(const String& json, String key, long& value, bool e) {
return true; return true;
} }
bool jsonRead(const String& json, String key, float& value, bool e) { bool jsonRead(const String &json, String key, float &value, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonRead"), error.f_str()); SerialPrint("E", F("jsonRead"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
return false; return false;
} else if (!doc.containsKey(key)) { }
if (e) { else if (!doc.containsKey(key))
{
if (e)
{
SerialPrint("E", F("jsonRead"), key + " missing in " + json); SerialPrint("E", F("jsonRead"), key + " missing in " + json);
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -51,17 +65,23 @@ bool jsonRead(const String& json, String key, float& value, bool e) {
return true; return true;
} }
bool jsonRead(const String& json, String key, String& value, bool e) { bool jsonRead(const String &json, String key, String &value, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonRead"), error.f_str()); SerialPrint("E", F("jsonRead"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
return false; return false;
} else if (!doc.containsKey(key)) { }
if (e) { else if (!doc.containsKey(key))
{
if (e)
{
SerialPrint("E", F("jsonRead"), key + " missing in " + json); SerialPrint("E", F("jsonRead"), key + " missing in " + json);
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -71,24 +91,31 @@ bool jsonRead(const String& json, String key, String& value, bool e) {
return true; return true;
} }
bool jsonRead(const String& json, String key, bool& value, bool e) { bool jsonRead(const String &json, String key, bool &value, bool e)
{
int lvalue = value; int lvalue = value;
bool ret = jsonRead(json, key, lvalue, e); bool ret = jsonRead(json, key, lvalue, e);
value = lvalue; value = lvalue;
return ret; return ret;
} }
bool jsonRead(const String& json, String key, int& value, bool e) { bool jsonRead(const String &json, String key, int &value, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonRead"), error.f_str()); SerialPrint("E", F("jsonRead"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
return false; return false;
} else if (!doc.containsKey(key)) { }
if (e) { else if (!doc.containsKey(key))
{
if (e)
{
SerialPrint("E", F("jsonRead"), key + " missing in " + json); SerialPrint("E", F("jsonRead"), key + " missing in " + json);
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -98,13 +125,59 @@ bool jsonRead(const String& json, String key, int& value, bool e) {
return true; return true;
} }
bool jsonReadArray(const String &json, String key, std::vector<String> &jArray, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json);
if (error)
{
if (e)
{
SerialPrint("E", F("jsonReadArray"), error.f_str());
jsonErrorDetected();
}
return false;
}
else if (!doc.containsKey(key))
{
if (e)
{
SerialPrint("E", F("jsonReadArray"), key + " missing in " + json);
jsonErrorDetected();
}
return false;
}
// SerialPrint("E", F("jsonReadArray"), key + " doc " + doc[key].as<String>());
if (doc[key].is<JsonArray>())
{
for (int8_t i = 0; i < doc[key].size(); i++)
jArray.push_back(doc[key][i].as<String>());
// SerialPrint("E", F("jsonReadArray"), "isArray"+key + " doc " + doc[key].as<String>());
}
else
{
jArray.push_back(doc[key].as<String>());
// DynamicJsonDocument docArr(JSON_BUFFER_SIZE/5);
// jArray = doc[key].as<JsonArray>();
// String tmp = doc[key].as<String>();
// jArray.add("dsdsd");
// SerialPrint("E", F("jsonReadArray"), "notArray"+key + " doc " + doc[key].as<String>());
// SerialPrint("E", F("jsonReadArray"), "count: " + String(jArray.size()) +" key: " + key + " arr " + jArray[0]);
}
// SerialPrint("E", F("jsonReadArray"), "count: " + String(jArray.size()) +" key: " + key + " doc " + jArray[0].as<String>());
return true;
}
// new============================================================================== // new==============================================================================
bool jsonWriteStr_(String& json, const String& key, const String& value, bool e) { bool jsonWriteStr_(String &json, const String &key, const String &value, bool e)
{
bool ret = true; bool ret = true;
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonWrite"), error.f_str()); SerialPrint("E", F("jsonWrite"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -116,12 +189,15 @@ bool jsonWriteStr_(String& json, const String& key, const String& value, bool e)
return ret; return ret;
} }
bool jsonWriteBool_(String& json, const String& key, bool value, bool e) { bool jsonWriteBool_(String &json, const String &key, bool value, bool e)
{
bool ret = true; bool ret = true;
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonWrite"), error.f_str()); SerialPrint("E", F("jsonWrite"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -133,12 +209,15 @@ bool jsonWriteBool_(String& json, const String& key, bool value, bool e) {
return ret; return ret;
} }
bool jsonWriteInt_(String& json, const String& key, int value, bool e) { bool jsonWriteInt_(String &json, const String &key, int value, bool e)
{
bool ret = true; bool ret = true;
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonWrite"), error.f_str()); SerialPrint("E", F("jsonWrite"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -150,12 +229,15 @@ bool jsonWriteInt_(String& json, const String& key, int value, bool e) {
return ret; return ret;
} }
bool jsonWriteFloat_(String& json, const String &key, float value, bool e) { bool jsonWriteFloat_(String &json, const String &key, float value, bool e)
{
bool ret = true; bool ret = true;
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonWrite"), error.f_str()); SerialPrint("E", F("jsonWrite"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -167,24 +249,29 @@ bool jsonWriteFloat_(String& json, const String &key, float value, bool e) {
return ret; return ret;
} }
void writeUint8tValueToJsonString(uint8_t* payload, size_t length, size_t headerLenth, String& json) { void writeUint8tValueToJsonString(uint8_t *payload, size_t length, size_t headerLenth, String &json)
{
String payloadStr; String payloadStr;
payloadStr.reserve(length + 1); payloadStr.reserve(length + 1);
for (size_t i = headerLenth; i < length; i++) { for (size_t i = headerLenth; i < length; i++)
{
payloadStr += (char)payload[i]; payloadStr += (char)payload[i];
} }
jsonMergeObjects(json, payloadStr); jsonMergeObjects(json, payloadStr);
} }
bool jsonMergeObjects(String& json1, String& json2, bool e) { bool jsonMergeObjects(String &json1, String &json2, bool e)
{
bool ret = true; bool ret = true;
DynamicJsonDocument doc1(JSON_BUFFER_SIZE); DynamicJsonDocument doc1(JSON_BUFFER_SIZE);
DeserializationError error1 = deserializeJson(doc1, json1); DeserializationError error1 = deserializeJson(doc1, json1);
DynamicJsonDocument doc2(JSON_BUFFER_SIZE); DynamicJsonDocument doc2(JSON_BUFFER_SIZE);
DeserializationError error2 = deserializeJson(doc2, json2); DeserializationError error2 = deserializeJson(doc2, json2);
jsonMergeDocs(doc1.as<JsonObject>(), doc2.as<JsonObject>()); jsonMergeDocs(doc1.as<JsonObject>(), doc2.as<JsonObject>());
if (error1 || error2) { if (error1 || error2)
if (e) { {
if (e)
{
SerialPrint("E", F("json"), "jsonMergeObjects error"); SerialPrint("E", F("json"), "jsonMergeObjects error");
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -195,18 +282,23 @@ bool jsonMergeObjects(String& json1, String& json2, bool e) {
return ret; return ret;
} }
void jsonMergeDocs(JsonObject dest, JsonObjectConst src) { void jsonMergeDocs(JsonObject dest, JsonObjectConst src)
for (auto kvp : src) { {
for (auto kvp : src)
{
dest[kvp.key()] = kvp.value(); dest[kvp.key()] = kvp.value();
} }
} }
// depricated====================================================================== // depricated======================================================================
String jsonReadStr(const String& json, String name, bool e) { String jsonReadStr(const String &json, String name, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonRead"), error.f_str()); SerialPrint("E", F("jsonRead"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -214,11 +306,14 @@ String jsonReadStr(const String& json, String name, bool e) {
return doc[name].as<String>(); return doc[name].as<String>();
} }
boolean jsonReadBool(const String& json, String name, bool e) { boolean jsonReadBool(const String &json, String name, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonRead"), error.f_str()); SerialPrint("E", F("jsonRead"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -226,11 +321,14 @@ boolean jsonReadBool(const String& json, String name, bool e) {
return doc[name].as<bool>(); return doc[name].as<bool>();
} }
int jsonReadInt(const String& json, String name, bool e) { int jsonReadInt(const String &json, String name, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonRead"), error.f_str()); SerialPrint("E", F("jsonRead"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -238,11 +336,14 @@ int jsonReadInt(const String& json, String name, bool e) {
return doc[name].as<int>(); return doc[name].as<int>();
} }
long int jsonReadLInt(const String& json, String name, bool e) { long int jsonReadLInt(const String &json, String name, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonRead"), error.f_str()); SerialPrint("E", F("jsonRead"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -251,11 +352,14 @@ long int jsonReadLInt(const String& json, String name, bool e) {
} }
// depricated======================================================================== // depricated========================================================================
String jsonWriteStr(String& json, String name, String value, bool e) { String jsonWriteStr(String &json, String name, String value, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonWrite"), error.f_str()); SerialPrint("E", F("jsonWrite"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -266,11 +370,14 @@ String jsonWriteStr(String& json, String name, String value, bool e) {
return json; return json;
} }
String jsonWriteBool(String& json, String name, boolean value, bool e) { String jsonWriteBool(String &json, String name, boolean value, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonWrite"), error.f_str()); SerialPrint("E", F("jsonWrite"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -281,11 +388,14 @@ String jsonWriteBool(String& json, String name, boolean value, bool e) {
return json; return json;
} }
String jsonWriteInt(String& json, String name, int value, bool e) { String jsonWriteInt(String &json, String name, int value, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonWrite"), error.f_str()); SerialPrint("E", F("jsonWrite"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -296,11 +406,14 @@ String jsonWriteInt(String& json, String name, int value, bool e) {
return json; return json;
} }
String jsonWriteFloat(String& json, String name, float value, bool e) { String jsonWriteFloat(String &json, String name, float value, bool e)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, json); DeserializationError error = deserializeJson(doc, json);
if (error) { if (error)
if (e) { {
if (e)
{
SerialPrint("E", F("jsonWrite"), error.f_str()); SerialPrint("E", F("jsonWrite"), error.f_str());
jsonErrorDetected(); jsonErrorDetected();
} }
@@ -311,7 +424,8 @@ String jsonWriteFloat(String& json, String name, float value, bool e) {
return json; return json;
} }
void jsonErrorDetected() { void jsonErrorDetected()
{
// пример как отправить ошибку с количеством // пример как отправить ошибку с количеством
// jsonWriteInt(errorsHeapJson, F("jse2"), 1); // jsonWriteInt(errorsHeapJson, F("jse2"), 1);
// int number = jsonReadInt(errorsHeapJson, F("jse2n")); // int number = jsonReadInt(errorsHeapJson, F("jse2n"));

View File

@@ -20,7 +20,7 @@ void updateDeviceStatus() {
// jsonRead(settingsFlashJson, F("serverip"), serverIP); // jsonRead(settingsFlashJson, F("serverip"), serverIP);
String url = serverIP + F("/projects/esprebootstat.php"); String url = serverIP + F("/projects/esprebootstat.php");
// SerialPrint("i", "Stat", "url " + url); // SerialPrint("i", "Stat", "url " + url);
if ((WiFi.status() == WL_CONNECTED)) { if ((isNetworkActive())) {
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
http.begin(client, url); http.begin(client, url);

View File

@@ -1,118 +1,174 @@
#include "utils/WiFiUtils.h" #include "utils/WiFiUtils.h"
#include <vector>
#define TRIESONE 25 // количество попыток подключения к одной сети из несколких
#define TRIES 40 // количество попыток подключения сети если она одна
void routerConnect() { void routerConnect()
WiFi.setAutoConnect(false); {
WiFi.persistent(false); WiFi.setAutoConnect(false);
WiFi.persistent(false);
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
byte tries = 40; byte triesOne = TRIESONE;
String _ssid = jsonReadStr(settingsFlashJson, "routerssid"); std::vector<String> _ssidList;
String _password = jsonReadStr(settingsFlashJson, "routerpass"); std::vector<String> _passwordList;
jsonReadArray(settingsFlashJson, "routerssid", _ssidList);
jsonReadArray(settingsFlashJson, "routerpass", _passwordList);
if (_ssidList.size() > 1)
triesOne = TRIES;
if (_ssid == "" && _password == "") { if (_passwordList.size() == 0 && _ssidList[0] == "" && _passwordList[0] == "")
WiFi.begin(); {
} else { WiFi.begin();
WiFi.begin(_ssid.c_str(), _password.c_str()); }
else
{
WiFi.begin(_ssidList[0].c_str(), _passwordList[0].c_str());
#ifdef ESP32 #ifdef ESP32
WiFi.setTxPower(WIFI_POWER_19_5dBm); WiFi.setTxPower(WIFI_POWER_19_5dBm);
#else #else
WiFi.setOutputPower(20.5); WiFi.setOutputPower(20.5);
#endif #endif
SerialPrint("i", "WIFI", "ssid: " + _ssid); String _ssid;
SerialPrint("i", "WIFI", "pass: " + _password); String _password;
for (int8_t i = 0; i < _ssidList.size(); i++)
{
_ssid = _ssid + _ssidList[i] + "; ";
} }
for (int8_t i = 0; i < _passwordList.size(); i++)
while (--tries && WiFi.status() != WL_CONNECTED) { {
if (WiFi.status() == WL_CONNECT_FAILED) { _password = _password + _passwordList[i] + "; ";
SerialPrint("E", "WIFI", "password is not correct");
tries = 1;
jsonWriteInt(errorsHeapJson, "passer", 1);
break;
}
Serial.print(".");
delay(1000);
} }
SerialPrint("i", "WIFI", "ssid list: " + _ssid);
if (WiFi.status() != WL_CONNECTED) { SerialPrint("i", "WIFI", "pass list: " + _password);
Serial.println(""); }
startAPMode(); for (size_t i = 0; i < _ssidList.size(); i++)
} else { {
Serial.println(""); triesOne = TRIESONE;
SerialPrint("i", "WIFI", "http://" + WiFi.localIP().toString()); if (WiFi.status() == WL_CONNECTED)
jsonWriteStr(settingsFlashJson, "ip", WiFi.localIP().toString()); break;
WiFi.begin(_ssidList[i].c_str(), _passwordList[i].c_str());
mqttInit(); SerialPrint("i", "WIFI", "ssid connect: " + _ssidList[i]);
SerialPrint("i", "WIFI", "pass connect: " + _passwordList[i]);
while (--triesOne && WiFi.status() != WL_CONNECTED)
{
// SerialPrint("i", "WIFI", ": " + String((int)WiFi.status()));
#ifdef ESP8266
if (WiFi.status() == WL_CONNECT_FAILED || WiFi.status() == WL_WRONG_PASSWORD)
#else
if (WiFi.status() == WL_CONNECT_FAILED)
#endif
{
SerialPrint("E", "WIFI", "password is not correct");
triesOne = 1;
jsonWriteInt(errorsHeapJson, "passer", 1);
break;
}
Serial.print(".");
delay(1000);
} }
SerialPrint("i", F("WIFI"), F("Network Init")); Serial.println("");
}
if (WiFi.status() != WL_CONNECTED)
{
Serial.println("");
startAPMode();
}
else
{
Serial.println("");
SerialPrint("i", "WIFI", "http://" + WiFi.localIP().toString());
jsonWriteStr(settingsFlashJson, "ip", WiFi.localIP().toString());
mqttInit();
}
SerialPrint("i", F("WIFI"), F("Network Init"));
} }
bool startAPMode() { bool startAPMode()
SerialPrint("i", "WIFI", "AP Mode"); {
SerialPrint("i", "WIFI", "AP Mode");
WiFi.disconnect(); WiFi.disconnect();
WiFi.mode(WIFI_AP); WiFi.mode(WIFI_AP);
String _ssidAP = jsonReadStr(settingsFlashJson, "apssid"); String _ssidAP = jsonReadStr(settingsFlashJson, "apssid");
String _passwordAP = jsonReadStr(settingsFlashJson, "appass"); String _passwordAP = jsonReadStr(settingsFlashJson, "appass");
WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str()); WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str());
IPAddress myIP = WiFi.softAPIP(); IPAddress myIP = WiFi.softAPIP();
SerialPrint("i", "WIFI", "AP IP: " + myIP.toString()); SerialPrint("i", "WIFI", "AP IP: " + myIP.toString());
jsonWriteStr(settingsFlashJson, "ip", myIP.toString()); jsonWriteStr(settingsFlashJson, "ip", myIP.toString());
if (jsonReadInt(errorsHeapJson, "passer") != 1) { if (jsonReadInt(errorsHeapJson, "passer") != 1)
ts.add( {
WIFI_SCAN, 30 * 1000, [&](void*) { ts.add(
String sta_ssid = jsonReadStr(settingsFlashJson, "routerssid"); WIFI_SCAN, 30 * 1000,
[&](void *)
SerialPrint("i", "WIFI", "scanning for " + sta_ssid); {
std::vector<String> jArray;
if (RouterFind(sta_ssid)) { jsonReadArray(settingsFlashJson, "routerssid", jArray);
ts.remove(WIFI_SCAN); for (int8_t i = 0; i < jArray.size(); i++)
WiFi.scanDelete(); {
routerConnect(); SerialPrint("i", "WIFI", "scanning for " + jArray[i]);
} }
}, if (RouterFind(jArray))
nullptr, true); {
} ts.remove(WIFI_SCAN);
return true; WiFi.scanDelete();
routerConnect();
}
},
nullptr, true);
}
return true;
} }
boolean RouterFind(String ssid) { boolean RouterFind(std::vector<String> jArray)
bool res = false; {
int n = WiFi.scanComplete(); bool res = false;
SerialPrint("i", "WIFI", "scan result: " + String(n, DEC)); int n = WiFi.scanComplete();
SerialPrint("i", "WIFI", "scan result: " + String(n, DEC));
if (n == -2) { //Сканирование не было запущено, запускаем if (n == -2)
SerialPrint("i", "WIFI", "start scanning"); { // Сканирование не было запущено, запускаем
WiFi.scanNetworks(true, false); // async, show_hidden SerialPrint("i", "WIFI", "start scanning");
} WiFi.scanNetworks(true, false); // async, show_hidden
}
else if (n == -1) { //Сканирование все еще выполняется else if (n == -1)
SerialPrint("i", "WIFI", "scanning in progress"); { // Сканирование все еще выполняется
} SerialPrint("i", "WIFI", "scanning in progress");
}
else if (n == 0) { //ни одна сеть не найдена else if (n == 0)
SerialPrint("i", "WIFI", "no networks found"); { // ни одна сеть не найдена
WiFi.scanNetworks(true, false); SerialPrint("i", "WIFI", "no networks found");
} WiFi.scanNetworks(true, false);
}
else if (n > 0) { else if (n > 0)
for (int8_t i = 0; i < n; i++) { {
if (WiFi.SSID(i) == ssid) { for (int8_t i = 0; i < n; i++)
res = true; {
} for (int8_t k = 0; k < jArray.size(); k++)
// SerialPrint("i", "WIFI", (res ? "*" : "") + String(i, DEC) + ") " + WiFi.SSID(i)); {
jsonWriteStr_(ssidListHeapJson, String(i), WiFi.SSID(i)); if (WiFi.SSID(i) == jArray[k])
{
// String(WiFi.RSSI(i) res = true;
} }
}
// SerialPrint("i", "WIFI", (res ? "*" : "") + String(i, DEC) + ") " + WiFi.SSID(i));
jsonWriteStr_(ssidListHeapJson, String(i), WiFi.SSID(i));
// String(WiFi.RSSI(i)
} }
SerialPrint("i", "WIFI", ssidListHeapJson); }
WiFi.scanDelete(); SerialPrint("i", "WIFI", ssidListHeapJson);
return res; WiFi.scanDelete();
return res;
} }
boolean isNetworkActive() { boolean isNetworkActive() {
@@ -125,7 +181,7 @@ uint8_t getNumAPClients() {
uint8_t RSSIquality() { uint8_t RSSIquality() {
uint8_t res = 0; uint8_t res = 0;
if (WiFi.status() == WL_CONNECTED) { if (isNetworkActive()) {
int rssi = WiFi.RSSI(); int rssi = WiFi.RSSI();
if (rssi >= -50) { if (rssi >= -50) {
res = 6; //"Excellent"; res = 6; //"Excellent";

View File

@@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x480000,
app1, app, ota_1, 0x490000,0x480000,
spiffs, data, spiffs, 0x910000,0x6E0000,
coredump, data, coredump,0xFF0000,0x10000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x480000
5 app1 app ota_1 0x490000 0x480000
6 spiffs data spiffs 0x910000 0x6E0000
7 coredump data coredump 0xFF0000 0x10000

16
tools/patch8266_16m.py Normal file
View File

@@ -0,0 +1,16 @@
# правим %USERPROFILE%\.platformio\platforms\espressif8266\builder\main.py 103-115
# для добавления возможности прошивки 16мб модуля esp8266
import os
import shutil
mainPyPath = os.environ['USERPROFILE'] + '\\.platformio\\platforms\\espressif8266@4.0.1\\builder\\main.py'
with open(mainPyPath) as fr:
oldData = fr.read()
if not 'if _value == -0x6000:' in oldData:
shutil.copyfile(mainPyPath, mainPyPath+'.bak')
newData = oldData.replace('_value += 0xE00000 # correction', '_value += 0xE00000 # correction\n\n if _value == -0x6000:\n _value = env[k]-0x40200000')
with open(mainPyPath, 'w') as fw:
fw.write(newData)