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,7 +44,6 @@ 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")));
@@ -59,7 +56,6 @@ void standWebServerInit()
syncSettingsFlashJson(); syncSettingsFlashJson();
HTTP.send(200, "text/plain", "ok"); HTTP.send(200, "text/plain", "ok");
} }
}); });
// Добавляем функцию Update для перезаписи прошивки по WiFi при 1М(256K FileFS) и выше // Добавляем функцию Update для перезаписи прошивки по WiFi при 1М(256K FileFS) и выше
@@ -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,7 +131,7 @@ 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);
@@ -202,21 +192,16 @@ String getContentType(String filename) {
/* /*
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
@@ -225,16 +210,13 @@ bool handleFileRead(String 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();
@@ -248,88 +230,67 @@ 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());
} }
@@ -339,19 +300,18 @@ 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 );
if(!dir.isDirectory()){
Serial.printf("%s is a file\n", path); Serial.printf("%s is a file\n", path);
dir.close(); dir.close();
Serial.printf( "result of removing file %s: %d\n", path, FileFS.remove( path ) ); Serial.printf("result of removing file %s: %d\n", path, FileFS.remove(path));
return; return;
} }
@@ -359,21 +319,18 @@ void deleteRecursive( String 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,50 +366,39 @@ 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
@@ -465,42 +406,32 @@ void handleFileCreate()
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();
} }
@@ -601,27 +517,23 @@ void handleFileList() {
} }
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); File root = FileFS.open(path);
path = String(); path = String();
String output = "["; String output = "[";
if(root.isDirectory()){ if (root.isDirectory()) {
File file = root.openNextFile(); File file = root.openNextFile();
while(file){ while (file) {
if (output != "[") { if (output != "[") {
output += ','; output += ',';
} }
output += "{\"type\":\""; output += "{\"type\":\"";
// output += (file.isDirectory()) ? "dir" : "file"; // output += (file.isDirectory()) ? "dir" : "file";
if (file.isDirectory()) if (file.isDirectory()) {
{
output += "dir"; output += "dir";
} } else {
else
{
output += F("file\",\"size\":\""); output += F("file\",\"size\":\"");
output += file.size(); output += file.size();
} }
@@ -634,26 +546,22 @@ void handleFileList() {
} }
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

@@ -9,7 +9,8 @@ void standWebSocketsInit() {
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,
size_t length) {
switch (type) { switch (type) {
case WStype_ERROR: { case WStype_ERROR: {
Serial.printf("[%u] Error!\n", num); Serial.printf("[%u] Error!\n", num);
@@ -28,13 +29,15 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
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); // Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0],
// standWebSocket.sendTXT(num, "Connected"); // ip[1], ip[2], ip[3], payload); standWebSocket.sendTXT(num,
// "Connected");
} break; } break;
case WStype_TEXT: { case WStype_TEXT: {
bool endOfHeaderFound = false; bool endOfHeaderFound = false;
size_t maxAllowedHeaderSize = 15; // максимальное количество символов заголовка size_t maxAllowedHeaderSize =
15; // максимальное количество символов заголовка
size_t headerLenth = 0; size_t headerLenth = 0;
String headerStr; String headerStr;
for (size_t i = 0; i <= maxAllowedHeaderSize; i++) { for (size_t i = 0; i <= maxAllowedHeaderSize; i++) {
@@ -56,23 +59,27 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
// публикация всех виджетов // публикация всех виджетов
if (headerStr == "/|") { if (headerStr == "/|") {
sendFileToWsByFrames("/layout.json", "layout", "", num, WEB_SOCKETS_FRAME_SIZE); sendFileToWsByFrames("/layout.json", "layout", "", num,
WEB_SOCKETS_FRAME_SIZE);
} }
if (headerStr == "/params|") { if (headerStr == "/params|") {
// публикация всех статус сообщений при подключении svelte приложения // публикация всех статус сообщений при подключении svelte приложения
String params = "{}"; String params = "{}";
for (std::list<IoTItem*>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { for (std::list<IoTItem*>::iterator it = IoTItems.begin();
it != IoTItems.end(); ++it) {
if ((*it)->getSubtype() != "Loging") { if ((*it)->getSubtype() != "Loging") {
if ((*it)->getSubtype() != "LogingDaily") { if ((*it)->getSubtype() != "LogingDaily") {
if ((*it)->iAmLocal) jsonWriteStr(params, (*it)->getID(), (*it)->getValue()); if ((*it)->iAmLocal)
jsonWriteStr(params, (*it)->getID(), (*it)->getValue());
} }
} }
} }
sendStringToWs("params", params, num); sendStringToWs("params", params, num);
// генерация события подключения в модулях // генерация события подключения в модулях
for (std::list<IoTItem*>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { for (std::list<IoTItem*>::iterator it = IoTItems.begin();
it != IoTItems.end(); ++it) {
if ((*it)->iAmLocal) (*it)->onMqttWsAppConnectEvent(); if ((*it)->iAmLocal) (*it)->onMqttWsAppConnectEvent();
} }
} }
@@ -81,7 +88,8 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
if (headerStr == "/charts|") { if (headerStr == "/charts|") {
// обращение к логированию из ядра // обращение к логированию из ядра
// отправка данных графиков только в выбранный сокет // отправка данных графиков только в выбранный сокет
for (std::list<IoTItem*>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { for (std::list<IoTItem*>::iterator it = IoTItems.begin();
it != IoTItems.end(); ++it) {
// сбрасываем даты графиков // сбрасываем даты графиков
// if ((*it)->getID().endsWith("-date")) { // if ((*it)->getID().endsWith("-date")) {
// (*it)->setTodayDate(); // (*it)->setTodayDate();
@@ -99,26 +107,34 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
// отвечаем данными на запрос страницы // отвечаем данными на запрос страницы
if (headerStr == "/config|") { if (headerStr == "/config|") {
sendFileToWsByFrames("/items.json", "itemsj", "", num, WEB_SOCKETS_FRAME_SIZE); sendFileToWsByFrames("/items.json", "itemsj", "", num,
sendFileToWsByFrames("/widgets.json", "widget", "", num, WEB_SOCKETS_FRAME_SIZE); WEB_SOCKETS_FRAME_SIZE);
sendFileToWsByFrames("/config.json", "config", "", num, WEB_SOCKETS_FRAME_SIZE); sendFileToWsByFrames("/widgets.json", "widget", "", num,
sendFileToWsByFrames("/scenario.txt", "scenar", "", num, WEB_SOCKETS_FRAME_SIZE); WEB_SOCKETS_FRAME_SIZE);
sendFileToWsByFrames("/config.json", "config", "", num,
WEB_SOCKETS_FRAME_SIZE);
sendFileToWsByFrames("/scenario.txt", "scenar", "", num,
WEB_SOCKETS_FRAME_SIZE);
sendStringToWs("settin", settingsFlashJson, num); sendStringToWs("settin", settingsFlashJson, num);
} }
// обработка кнопки сохранить // обработка кнопки сохранить
if (headerStr == "/gifnoc|") { if (headerStr == "/gifnoc|") {
writeFileUint8tByFrames("config.json", payload, length, headerLenth, 256); writeFileUint8tByFrames("config.json", payload, length, headerLenth,
256);
} }
if (headerStr == "/tuoyal|") { if (headerStr == "/tuoyal|") {
writeFileUint8tByFrames("layout.json", payload, length, headerLenth, 256); writeFileUint8tByFrames("layout.json", payload, length, headerLenth,
256);
} }
if (headerStr == "/oiranecs|") { if (headerStr == "/oiranecs|") {
writeFileUint8tByFrames("scenario.txt", payload, length, headerLenth, 256); writeFileUint8tByFrames("scenario.txt", payload, length, headerLenth,
256);
clearConfigure(); clearConfigure();
configure("/config.json"); configure("/config.json");
iotScen.loadScenario("/scenario.txt"); iotScen.loadScenario("/scenario.txt");
// создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке // создаем событие завершения конфигурирования для возможности
// выполнения блока кода при загрузке
createItemFromNet("onStart", "1", 1); createItemFromNet("onStart", "1", 1);
} }
@@ -131,14 +147,16 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
sendStringToWs("settin", settingsFlashJson, num); sendStringToWs("settin", settingsFlashJson, num);
sendStringToWs("ssidli", ssidListHeapJson, num); sendStringToWs("ssidli", ssidListHeapJson, num);
sendStringToWs("errors", errorsHeapJson, num); sendStringToWs("errors", errorsHeapJson, num);
// запуск асинхронного сканирования wifi сетей при переходе на страницу соединений // запуск асинхронного сканирования wifi сетей при переходе на страницу
// RouterFind(jsonReadStr(settingsFlashJson, F("routerssid"))); // соединений RouterFind(jsonReadStr(settingsFlashJson,
// F("routerssid")));
} }
// обработка кнопки сохранить settings.json // обработка кнопки сохранить settings.json
if (headerStr == "/sgnittes|") { if (headerStr == "/sgnittes|") {
writeUint8tToString(payload, length, headerLenth, settingsFlashJson); writeUint8tToString(payload, length, headerLenth, settingsFlashJson);
writeFileUint8tByFrames("settings.json", payload, length, headerLenth, 256); writeFileUint8tByFrames("settings.json", payload, length, headerLenth,
256);
sendStringToWs("errors", errorsHeapJson, num); sendStringToWs("errors", errorsHeapJson, num);
// если не было создано приема данных по udp - то создадим его // если не было создано приема данных по udp - то создадим его
addThisDeviceToList(); addThisDeviceToList();
@@ -146,16 +164,21 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
// обработка кнопки сохранить настройки mqtt // обработка кнопки сохранить настройки mqtt
if (headerStr == "/mqtt|") { if (headerStr == "/mqtt|") {
sendStringToWs("settin", settingsFlashJson, num); // отправляем в ответ новые полученные настройки sendStringToWs("settin", settingsFlashJson,
num); // отправляем в ответ новые полученные настройки
handleMqttStatus(false, 8); // меняем статус на неопределенный handleMqttStatus(false, 8); // меняем статус на неопределенный
mqttReconnect(); // начинаем переподключение mqttReconnect(); // начинаем переподключение
sendStringToWs("errors", errorsHeapJson, num); // отправляем что статус неопределен sendStringToWs("errors", errorsHeapJson,
num); // отправляем что статус неопределен
sendStringToWs("ssidli", ssidListHeapJson, num); sendStringToWs("ssidli", ssidListHeapJson, num);
} }
// запуск асинхронного сканирования wifi сетей при нажатии выпадающего списка // запуск асинхронного сканирования wifi сетей при нажатии выпадающего
// списка
if (headerStr == "/scan|") { if (headerStr == "/scan|") {
RouterFind(jsonReadStr(settingsFlashJson, F("routerssid"))); std::vector<String> jArray;
jsonReadArray(settingsFlashJson, "routerssid", jArray);
RouterFind(jArray);
sendStringToWs("ssidli", ssidListHeapJson, num); sendStringToWs("ssidli", ssidListHeapJson, num);
} }
@@ -170,7 +193,8 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
// sendDeviceList(num); // sendDeviceList(num);
} }
// отвечаем на запрос списка устройств (это отдельный запрос который делает приложение при подключении) // отвечаем на запрос списка устройств (это отдельный запрос который
// делает приложение при подключении)
if (headerStr == "/devlist|") { if (headerStr == "/devlist|") {
// отправим список устройств в зависимости от того что выбрал user // отправим список устройств в зависимости от того что выбрал user
sendDeviceList(num); sendDeviceList(num);
@@ -178,7 +202,8 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
// сохраняем данные листа // сохраняем данные листа
if (headerStr == "/tsil|") { if (headerStr == "/tsil|") {
writeFileUint8tByFrames("devlist.json", payload, length, headerLenth, 256); writeFileUint8tByFrames("devlist.json", payload, length, headerLenth,
256);
} }
//----------------------------------------------------------------------// //----------------------------------------------------------------------//
@@ -197,9 +222,12 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
if (headerStr == "/dev|") { if (headerStr == "/dev|") {
sendStringToWs("errors", errorsHeapJson, num); sendStringToWs("errors", errorsHeapJson, num);
sendStringToWs("settin", settingsFlashJson, num); sendStringToWs("settin", settingsFlashJson, num);
sendFileToWsByFrames("/config.json", "config", "", num, WEB_SOCKETS_FRAME_SIZE); sendFileToWsByFrames("/config.json", "config", "", num,
sendFileToWsByFrames("/items.json", "itemsj", "", num, WEB_SOCKETS_FRAME_SIZE); WEB_SOCKETS_FRAME_SIZE);
// sendFileToWsByFrames("/layout.json", "layout", "", 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 == "/test|") {
@@ -211,7 +239,8 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
// переписать любое поле в errors json // переписать любое поле в errors json
if (headerStr == "/rorre|") { if (headerStr == "/rorre|") {
writeUint8tValueToJsonString(payload, length, headerLenth, errorsHeapJson); writeUint8tValueToJsonString(payload, length, headerLenth,
errorsHeapJson);
} }
// команда перезагрузки esp // команда перезагрузки esp
@@ -236,7 +265,9 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
String key = selectFromMarkerToMarker(msg, "/", 0); String key = selectFromMarkerToMarker(msg, "/", 0);
String value = selectFromMarkerToMarker(msg, "/", 1); String value = selectFromMarkerToMarker(msg, "/", 1);
generateOrder(key, value); generateOrder(key, value);
SerialPrint("i", F("=>WS"), "Msg from svelte web, WS No: " + String(num) + ", msg: " + msg); SerialPrint(
"i", F("=>WS"),
"Msg from svelte web, WS No: " + String(num) + ", msg: " + msg);
} }
if (headerStr == "/tst|") { if (headerStr == "/tst|") {
@@ -255,7 +286,8 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
SerialPrint("i", F("=>WS"), "Msg from module, id: " + id); SerialPrint("i", F("=>WS"), "Msg from module, id: " + id);
for (std::list<IoTItem*>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { for (std::list<IoTItem*>::iterator it = IoTItems.begin();
it != IoTItems.end(); ++it) {
if ((*it)->getID() == id) { if ((*it)->getID() == id) {
(*it)->onModuleOrder(key, value); (*it)->onModuleOrder(key, value);
} }
@@ -294,13 +326,12 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
Serial.printf("[%u] pong: %u\n", num, length); Serial.printf("[%u] pong: %u\n", num, length);
} break; } break;
default: { default: { Serial.printf("[%u] not recognized: %u\n", num, length); } break;
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 = "{}";
@@ -330,7 +361,8 @@ void periodicWsSend() {
#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,
len, len);
for (uint32_t i = 0; i < len; i++) { for (uint32_t i = 0; i < len; i++) {
if (i % cols == 0) { if (i % cols == 0) {
Serial.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); Serial.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
@@ -343,7 +375,8 @@ void hexdump(const void* mem, uint32_t len, uint8_t cols = 16) {
#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,
const String& json, int client_id, size_t frameSize) {
if (header.length() != 6) { if (header.length() != 6) {
SerialPrint("E", "FS", F("wrong header size")); SerialPrint("E", "FS", F("wrong header size"));
return; return;
@@ -357,7 +390,8 @@ void sendFileToWsByFrames(const String& filename, const String& header, const St
} }
size_t totalSize = file.size(); size_t totalSize = file.size();
// Serial.println("Send file '" + String(filename) + "', file size: " + String(totalSize)); // Serial.println("Send file '" + String(filename) + "', file size: " +
// String(totalSize));
char buf[32]; char buf[32];
sprintf(buf, "%04d", json.length() + 12); sprintf(buf, "%04d", json.length() + 12);
@@ -397,7 +431,9 @@ void sendFileToWsByFrames(const String& filename, const String& header, const St
continuation = true; continuation = true;
} }
// Serial.println(String(i) + ") " + "ws: " + String(client_id) + " fr sz: " + String(size) + " fin: " + String(fin) + " cnt: " + String(continuation)); // Serial.println(String(i) + ") " + "ws: " + String(client_id) + " fr sz:
// " + String(size) + " fin: " + String(fin) + " cnt: " +
// String(continuation));
if (client_id == -1) { if (client_id == -1) {
standWebSocket.broadcastBIN(frameBuf, size, fin, continuation); standWebSocket.broadcastBIN(frameBuf, size, fin, continuation);
@@ -444,7 +480,8 @@ void sendDeviceList(uint8_t num) {
sendStringToWs("devlis", devListHeapJson, num); sendStringToWs("devlis", devListHeapJson, num);
} else { } else {
// если выключен автопоиск то отдаем список из флешь памяти // если выключен автопоиск то отдаем список из флешь памяти
sendFileToWsByFrames("/devlist.json", "devlis", "", num, WEB_SOCKETS_FRAME_SIZE); sendFileToWsByFrames("/devlist.json", "devlis", "", num,
WEB_SOCKETS_FRAME_SIZE);
SerialPrint("i", "FS", "flash list"); SerialPrint("i", "FS", "flash list");
} }
} }

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,8 +7,8 @@
#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
@@ -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,16 +46,20 @@ public:
{ {
if (msg.indexOf("HELLO") == -1) if (msg.indexOf("HELLO") == -1)
{ {
if (_debug)
// SerialPrint("i", "onMqttRecive", "Прилетело " + topic); {
SerialPrint("i", "onMqttRecive", "Прилетело " + topic + " msg: " + msg);
// SerialPrint("i", "onMqttRecive", "Прилетело " + 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;
} }
if (_isJson)
{
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(doc, msg); DeserializationError error = deserializeJson(doc, msg);
if (error) if (error)
@@ -60,7 +72,11 @@ public:
{ {
String key = kv.key().c_str(); String key = kv.key().c_str();
String val = kv.value(); String val = kv.value();
if (_MAC == dev && _sensor == key) if (_debug)
{
SerialPrint("i", "onMqttRecive", "Прилетело MAC: " + dev + " key=" + key + " val=" + val);
}
if (_sensor == key)
{ {
dataFromNode = true; dataFromNode = true;
_minutesPassed = 0; _minutesPassed = 0;
@@ -72,6 +88,18 @@ public:
// Serial.println("Value: " + val); // Serial.println("Value: " + val);
} }
} }
else
{
if (_debug)
{
SerialPrint("i", "onMqttRecive", "Прилетело MAC: " + dev + " val=" + msg);
}
dataFromNode = true;
_minutesPassed = 0;
setValue(msg);
// setNewWidgetAttributes();
}
}
} }
void doByInterval() void doByInterval()
@@ -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,43 +1,83 @@
#include "utils/WiFiUtils.h" #include "utils/WiFiUtils.h"
#include <vector>
#define TRIESONE 25 // количество попыток подключения к одной сети из несколких
#define TRIES 40 // количество попыток подключения сети если она одна
void routerConnect() { void routerConnect()
{
WiFi.setAutoConnect(false); WiFi.setAutoConnect(false);
WiFi.persistent(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(); WiFi.begin();
} else { }
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("i", "WIFI", "ssid list: " + _ssid);
SerialPrint("i", "WIFI", "pass list: " + _password);
}
for (size_t i = 0; i < _ssidList.size(); i++)
{
triesOne = TRIESONE;
if (WiFi.status() == WL_CONNECTED)
break;
WiFi.begin(_ssidList[i].c_str(), _passwordList[i].c_str());
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"); SerialPrint("E", "WIFI", "password is not correct");
tries = 1; triesOne = 1;
jsonWriteInt(errorsHeapJson, "passer", 1); jsonWriteInt(errorsHeapJson, "passer", 1);
break; break;
} }
Serial.print("."); Serial.print(".");
delay(1000); delay(1000);
} }
Serial.println("");
}
if (WiFi.status() != WL_CONNECTED) { if (WiFi.status() != WL_CONNECTED)
{
Serial.println(""); Serial.println("");
startAPMode(); startAPMode();
} else { }
else
{
Serial.println(""); Serial.println("");
SerialPrint("i", "WIFI", "http://" + WiFi.localIP().toString()); SerialPrint("i", "WIFI", "http://" + WiFi.localIP().toString());
jsonWriteStr(settingsFlashJson, "ip", WiFi.localIP().toString()); jsonWriteStr(settingsFlashJson, "ip", WiFi.localIP().toString());
@@ -47,7 +87,8 @@ void routerConnect() {
SerialPrint("i", F("WIFI"), F("Network Init")); 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();
@@ -62,14 +103,20 @@ bool startAPMode() {
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( ts.add(
WIFI_SCAN, 30 * 1000, [&](void*) { WIFI_SCAN, 30 * 1000,
String sta_ssid = jsonReadStr(settingsFlashJson, "routerssid"); [&](void *)
{
SerialPrint("i", "WIFI", "scanning for " + sta_ssid); std::vector<String> jArray;
jsonReadArray(settingsFlashJson, "routerssid", jArray);
if (RouterFind(sta_ssid)) { for (int8_t i = 0; i < jArray.size(); i++)
{
SerialPrint("i", "WIFI", "scanning for " + jArray[i]);
}
if (RouterFind(jArray))
{
ts.remove(WIFI_SCAN); ts.remove(WIFI_SCAN);
WiFi.scanDelete(); WiFi.scanDelete();
routerConnect(); routerConnect();
@@ -80,30 +127,39 @@ bool startAPMode() {
return true; return true;
} }
boolean RouterFind(String ssid) { boolean RouterFind(std::vector<String> jArray)
{
bool res = false; bool res = false;
int n = WiFi.scanComplete(); int n = WiFi.scanComplete();
SerialPrint("i", "WIFI", "scan result: " + String(n, DEC)); SerialPrint("i", "WIFI", "scan result: " + String(n, DEC));
if (n == -2) { //Сканирование не было запущено, запускаем if (n == -2)
{ // Сканирование не было запущено, запускаем
SerialPrint("i", "WIFI", "start scanning"); SerialPrint("i", "WIFI", "start scanning");
WiFi.scanNetworks(true, false); // async, show_hidden 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"); SerialPrint("i", "WIFI", "no networks found");
WiFi.scanNetworks(true, false); WiFi.scanNetworks(true, false);
} }
else if (n > 0)
else if (n > 0) { {
for (int8_t i = 0; i < n; i++) { for (int8_t i = 0; i < n; i++)
if (WiFi.SSID(i) == ssid) { {
for (int8_t k = 0; k < jArray.size(); k++)
{
if (WiFi.SSID(i) == jArray[k])
{
res = true; res = true;
} }
}
// SerialPrint("i", "WIFI", (res ? "*" : "") + String(i, DEC) + ") " + WiFi.SSID(i)); // SerialPrint("i", "WIFI", (res ? "*" : "") + String(i, DEC) + ") " + WiFi.SSID(i));
jsonWriteStr_(ssidListHeapJson, String(i), WiFi.SSID(i)); jsonWriteStr_(ssidListHeapJson, String(i), WiFi.SSID(i));
@@ -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)