diff --git a/include/EspFileSystem.h b/include/EspFileSystem.h index 81a6a660..b77439ba 100644 --- a/include/EspFileSystem.h +++ b/include/EspFileSystem.h @@ -35,7 +35,7 @@ extern FS* filesystem; extern bool fileSystemInit(); extern void globalVarsSync(); -extern String getParamsJson(); +//extern String getParamsJson(); extern void syncSettingsFlashJson(); extern void syncValuesFlashJson(); diff --git a/include/classes/IoTItem.h b/include/classes/IoTItem.h index 81405849..c0cce8ed 100644 --- a/include/classes/IoTItem.h +++ b/include/classes/IoTItem.h @@ -73,8 +73,8 @@ class IoTItem { String _id = "errorId"; // если будет попытка создания Item без указания id, то элемент оставит это значение long _interval = 0; int _intFromNet = -2; // количество секунд доверия, пришедших из сети вместе с данными для текущего ИД - // -2 - данные не приходили, скорее всего, элемент локальный, доверие есть - // -1 - данные приходили и обратный отсчет дошел до нуля, значит доверия нет + // -2 - данные не приходили, скорее всего, элемент локальный, доверие есть, в случае прихода сетевого значения с int=0, будет выключен механизм проверки доверия + // -1 - данные приходили и обратный отсчет дошел до нуля, значит доверия нет и элемент будет удален при следующем такте loop float _multiply; // умножаем на значение float _plus; // увеличиваем на значение @@ -90,7 +90,7 @@ class IoTItem { IoTItem* findIoTItem(const String& name); // поиск экземпляра элемента модуля по имени String getItemValue(const String& name); // поиск плюс получение значения bool isItemExist(const String& name); // существует ли айтем -StaticJsonDocument* getLocalItemsAsJSON(); // сбор всех локальных значений Items +//StaticJsonDocument* getLocalItemsAsJSON(); // сбор всех локальных значений Items IoTItem* createItemFromNet(const String& itemId, const String& value, int interval); IoTItem* createItemFromNet(const String& msgFromNet); diff --git a/src/EspFileSystem.cpp b/src/EspFileSystem.cpp index 2b45dd7d..21d6f11f 100644 --- a/src/EspFileSystem.cpp +++ b/src/EspFileSystem.cpp @@ -27,12 +27,12 @@ void globalVarsSync() { } //к удалению. не используется -String getParamsJson() { - String json; - serializeJson(*getLocalItemsAsJSON(), json); - jsonWriteStr_(json, "params", ""); - return json; -} +// String getParamsJson() { +// String json; +// serializeJson(*getLocalItemsAsJSON(), json); +// jsonWriteStr_(json, "params", ""); +// return json; +// } void syncSettingsFlashJson() { writeFile(F("settings.json"), settingsFlashJson); diff --git a/src/Main.cpp b/src/Main.cpp index ea73e295..815c56dd 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -91,7 +91,7 @@ void setup() { iotScen.loadScenario("/scenario.txt"); // создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке - createItemFromNet("onStart", "1", -4); + createItemFromNet("onStart", "1", 1); stInit(); diff --git a/src/PeriodicTasks.cpp b/src/PeriodicTasks.cpp index 73e14dcc..64675569 100644 --- a/src/PeriodicTasks.cpp +++ b/src/PeriodicTasks.cpp @@ -9,6 +9,7 @@ void periodicTasksInit() { // heap String heap = prettyBytes(ESP.getFreeHeap()); SerialPrint(F("i"), F("HEAP"), heap); + SerialPrint(F("i"), F("IoTItems"), (String)IoTItems.size()); printGlobalVarSize(); jsonWriteStr_(errorsHeapJson, F("heap"), heap); // rssi diff --git a/src/WsServer.cpp b/src/WsServer.cpp index bee9cea3..6eec69aa 100644 --- a/src/WsServer.cpp +++ b/src/WsServer.cpp @@ -119,7 +119,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) configure("/config.json"); iotScen.loadScenario("/scenario.txt"); // создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке - createItemFromNet("onStart", "1", -4); + createItemFromNet("onStart", "1", 1); } //----------------------------------------------------------------------// diff --git a/src/classes/IoTItem.cpp b/src/classes/IoTItem.cpp index c39ee125..5b8c5476 100644 --- a/src/classes/IoTItem.cpp +++ b/src/classes/IoTItem.cpp @@ -7,8 +7,9 @@ IoTItem::IoTItem(const String& parameters) { jsonRead(parameters, F("int"), _interval, false); - if (_interval <= 0) enableDoByInt = false; - _interval = _interval * 1000; + if (_interval == 0) enableDoByInt = false; // выключаем использование периодического выполнения в модуле + if (_interval > 0) _interval = _interval * 1000; // если int положителен, то считаем, что получены секунды + if (_interval < 0) _interval = _interval * -1; // если int отрицательный, то миллисекунды jsonRead(parameters, F("subtype"), _subtype, false); jsonRead(parameters, F("id"), _id); if (!jsonRead(parameters, F("multiply"), _multiply, false)) _multiply = 1; @@ -170,7 +171,7 @@ void IoTItem::setIntFromNet(int interval) { void IoTItem::checkIntFromNet() { // проверяем элемент на доверие данным. if (_intFromNet >= 0) { - // если время жизни истекло, то удаляем элемент + // если время жизни истекло, то удаляем элемент чуть позже на следующем такте loop // если это было уведомление не об ошибке или начале работы, то сообщаем, что сетевое событие давно не приходило if (_intFromNet == 0 && _id.indexOf("onError") == -1 && _id.indexOf("onStart") == -1) { SerialPrint("E", _id, "The new data did not come from the network. The level of trust is low.", _id); @@ -270,6 +271,9 @@ IoTItem* createItemFromNet(const String& itemId, const String& value, int interv // создаем временную копию элемента из сети на основе события IoTItem* createItemFromNet(const String& msgFromNet) { IoTItem* tmpp = new IoTItem(msgFromNet); + + //Serial.println("vvvvvvvvvvv " + msgFromNet + " " + (String)tmpp->getInterval()); + if (tmpp->getInterval()) tmpp->setIntFromNet(tmpp->getInterval() / 1000 + 5); tmpp->iAmLocal = false; IoTItems.push_back(tmpp); @@ -278,7 +282,7 @@ IoTItem* createItemFromNet(const String& msgFromNet) { } void analyzeMsgFromNet(const String& msg, String altId) { - if (!jsonRead(msg, F("id"), altId, altId == "") && altId == "") return; // ничего не предпринимаем, если ошибка и altId = "", вообще данная конструкция нужна для совместимости с форматом данных 3 версией + if (!jsonRead(msg, F("id"), altId, altId == "")) return; // ничего не предпринимаем, если ошибка и altId = "", вообще данная конструкция нужна для совместимости с форматом данных 3 версией IoTItem* itemExist = findIoTItem(altId); if (itemExist) { String valAsStr = msg; @@ -293,16 +297,17 @@ void analyzeMsgFromNet(const String& msg, String altId) { } else { // временно зафиксируем данные в базе, если локально элемент отсутствует createItemFromNet(msg); + //Serial.println("ffffffffff " + msg + " altId=" + altId); } } -StaticJsonDocument docForExport; +//StaticJsonDocument docForExport; -StaticJsonDocument* getLocalItemsAsJSON() { - docForExport.clear(); - for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { - if ((*it)->iAmLocal) docForExport[(*it)->getID()] = (*it)->getValue(); - } +// StaticJsonDocument* getLocalItemsAsJSON() { +// docForExport.clear(); +// for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { +// if ((*it)->iAmLocal) docForExport[(*it)->getID()] = (*it)->getValue(); +// } - return &docForExport; -} \ No newline at end of file +// return &docForExport; +// } \ No newline at end of file diff --git a/src/modules/sensors/AnalogAdc/AnalogAdc.cpp b/src/modules/sensors/AnalogAdc/AnalogAdc.cpp index 4099a059..1e90f30d 100644 --- a/src/modules/sensors/AnalogAdc/AnalogAdc.cpp +++ b/src/modules/sensors/AnalogAdc/AnalogAdc.cpp @@ -28,6 +28,9 @@ class AnalogAdc : public IoTItem { AnalogAdc(String parameters) : IoTItem(parameters) { _pin = jsonReadInt(parameters, "pin"); _avgSteps = jsonReadInt(parameters, "avgSteps"); + if (!_avgSteps) { + jsonRead(parameters, F("int"), _interval, false); + } _avgSumm = 0; _avgCount = 0; } diff --git a/src/modules/sensors/AnalogAdc/modinfo.json b/src/modules/sensors/AnalogAdc/modinfo.json index be0dea1f..dd0df107 100644 --- a/src/modules/sensors/AnalogAdc/modinfo.json +++ b/src/modules/sensors/AnalogAdc/modinfo.json @@ -35,8 +35,8 @@ "moduleDesc": "Позволяет получить текущее значение на аналоговом GPIO или усредненное для avgSteps измерений каждого вызова loop.", "propInfo": { "pin": "Аналоговый GPIO номер, к которому подключен датчик.", - "avgSteps": "Количество считываний для усреднения. При <=1, считывается одно значение за каждый период опроса.", - "int": "Количество секунд между опросами датчика." + "avgSteps": "Количество считываний для усреднения. При =1, считывается одно значение за каждый период опроса., при =0, int считается в миллисекундах", + "int": "Количество секунд между опросами датчика, если avgSteps > 0. Установите avgSteps = 0 и int будет считаться в миллисекундах (ВНИМАНИЕ! генерация событий чаще секунды может привести к нестабильности системы.)" } }, "defActive": true, diff --git a/src/modules/sensors/UART/Uart.cpp b/src/modules/sensors/UART/Uart.cpp index c75b7db1..5428eecd 100644 --- a/src/modules/sensors/UART/Uart.cpp +++ b/src/modules/sensors/UART/Uart.cpp @@ -92,7 +92,7 @@ class UART : public IoTItem { void onRegEvent(IoTItem* eventItem) { if (!_myUART || !eventItem) return; - + int indexOf_; String printStr = ""; switch (_eventFormat) { case 0: return; // не указан формат, значит не следим за событиями @@ -105,7 +105,7 @@ class UART : public IoTItem { case 2: // формат событий для Nextion ID=Value0xFF0xFF0xFF printStr += eventItem->getID(); - int indexOf_ = printStr.indexOf("_"); + indexOf_ = printStr.indexOf("_"); //Serial.println(printStr + " fff " + indexOf_); if (indexOf_ == -1) return; // пропускаем событие, если нет используемого признака типа данных - _txt или _vol @@ -126,9 +126,86 @@ class UART : public IoTItem { uartPrintFFF(printStr); break; + + case 3: // формат событий для Dwin + //for (int i=0; i<2; i++) { + printStr = eventItem->getID(); + indexOf_ = printStr.indexOf("_"); + if (indexOf_ == -1 || !_myUART) return; // пропускаем событие, если нет используемого признака типа данных - _txt или _vol + + String VP = selectToMarkerLast(printStr, "_"); + + _myUART->write(0x5A); + _myUART->write(0xA5); + + if (eventItem->value.isDecimal) { // пока отправляем только целые числа + _myUART->write(0x05); // размер данных отправляемых с учетом целых чисел int + _myUART->write(0x82); // требуем запись в память + uartPrintHex(VP); // отправляем адрес в памяти VP + + byte raw[2]; + (int&)raw = eventItem->value.valD; + _myUART->write(raw[1]); + _myUART->write(raw[0]); + } else { + // подсчитываем количество символов отличающихся от ASCII, для понимания сколько символов состоит из дух байт + int u16counter = 0; + const char* valSptr = eventItem->value.valS.c_str(); + //Serial.print("iiiii "); + for (int i=0; i < eventItem->value.valS.length(); i++) { + if (valSptr[i] > 200) u16counter++; + //Serial.printf("%d ", valSptr[i]); + } + //Serial.println(); + + _myUART->write((eventItem->value.valS.length() - u16counter) * 2 + 5); // подсчитываем и отправляем размер итоговой строки + служебные байты + _myUART->write(0x82); // требуем запись в память + uartPrintHex(VP); // отправляем адрес в памяти VP + Serial.println("ffffff " + VP); + //_myUART->write(0x53); + //_myUART->write(0x00); + uartPrintStrInUTF16(eventItem->value.valS.c_str(), eventItem->value.valS.length()); // отправляем строку для записи + _myUART->write(0xFF); // терминируем строку, чтоб экран очистил все остальное в элементе своем + _myUART->write(0xFF); + + //uint8_t Data[8] = {0x00, 0x31, 0x00, 0x44, 0x04, 0x10, 0x00, 0x00}; + //uartPrintArray(Data, 6); + //Serial.printf("fffffffff %#x %#x %#x %#x \n", Data[0], Data[1], Data[2], Data[3]); + } + //} + break; } } + void uartPrintStrInUTF16(const char *strUTF8, int length) { + // очень жесткий но быстрый способ конвертирования UTF-8 в UTF-16, но с поддержкой только кириллицы и двух байт в UTF-8 + // не определяются исключения по формату UTF-8 + for (int i=0; i < length; i++) { + if (strUTF8[i] < 176) { // если байт соответствует коду ASCII, значит берем как есть, но расширяем до двух байт + _myUART->write(0x00); + _myUART->write(strUTF8[i]); + } else { // иначе понимаем, что имеем дело с двумя байтами (да UTF8 может иметь и больше, но это ограничение наше) + _myUART->write(0x04); // указываем номер диапазона символов кириллицы первым байтом на выходе + + if (strUTF8[i] == 208) { // если первый байт символа в первом диапазоне + if (strUTF8[i+1] == 129) _myUART->write(0x01); // исключение для символа 'ё' + else _myUART->write(strUTF8[i+1] - 128); // применяем смещение 128 и отправляем второй байт + } + + if (strUTF8[i] == 209) { // если первый байт символа во втором диапазоне + if (strUTF8[i+1] == 145) _myUART->write(0x51); // исключение для символа 'Ё' + else _myUART->write(strUTF8[i+1] - 64); // применяем смещение 64 и отправляем второй байт + } + + i++; // пропускаем второй байт входной строки + } + } + } + + void uartPrintArray(uint8_t *_Data, uint8_t _Size) { + for (size_t i = 0; i < _Size; i++) _myUART->write(_Data[i]); + } + virtual void loop() { uartHandle(); } diff --git a/src/modules/sensors/UART/modinfo.json b/src/modules/sensors/UART/modinfo.json index cc6a0999..3f0c1673 100644 --- a/src/modules/sensors/UART/modinfo.json +++ b/src/modules/sensors/UART/modinfo.json @@ -37,7 +37,7 @@ "rx": "RX пин", "speed": "Скорость UART", "line": "Актуально только для ESP32: номер линии hardUART. =2 rx=16 tx=17", - "eventFormat": "Выбор формата обмена сообщениями с другими контроллерами. =0 - не указан формат, значит не следим за событиями, =1 - формат событий IoTM с использованием json, =2 - формат событий для Nextion отправка событий: ID.val=Value0xFF0xFF0xFF прием ордеров: ID=Value. Отправляться будут события тех элементов, которые имеют суффикс в ИД _val или _txt, которые влияют на передаваемый формат." + "eventFormat": "Выбор формата обмена сообщениями с другими контроллерами. =0 - не указан формат, значит не следим за событиями, =1 - формат событий IoTM с использованием json, =2 - формат событий для Nextion отправка событий: ID.val=Value0xFF0xFF0xFF прием ордеров: ID=Value. Отправляться будут события тех элементов, которые имеют суффикс в ИД _val или _txt, которые влияют на передаваемый формат, =3 - формат событий для экранов Dwin. Отправляться будут события тех элементов, которые имеют суффикс в ИД с указанием адреса VP для записи значения, например ID_5000. Пока поддерживается только вывод целых чисел, значения кнопки и текст." }, "retInfo": "Содержит полученное последнее по UART сообщение.", "funcInfo": [ diff --git a/src/modules/virtual/Timer/modinfo.json b/src/modules/virtual/Timer/modinfo.json index e817b398..7f097b29 100644 --- a/src/modules/virtual/Timer/modinfo.json +++ b/src/modules/virtual/Timer/modinfo.json @@ -32,7 +32,7 @@ "title": "Таймер обратного отсчета", "moduleDesc": "Добавляет инструмент таймеров обратного отсчета для организации периодичных операций или логических конструкций. Часто используется как вспомогательный элемент для автоматизации.", "propInfo": { - "int": "Задает размер в миллисекундах (1000 = 1сек) одного шага(тика) таймера.", + "int": "Задает размер в секундах одного шага(тика) таймера.", "countDown": "Начальное значение таймера, с которого начинается обратный отсчет. countDown=0 - бесконечный счет (имеет смысл при ticker=1, иначе таймер будет выключен), countDown=-1 - отключает таймер совсем (используется для запуска системы с выключенным таймером)", "ticker": "Генерировать(1) или нет(0) события при каждом тике таймера.", "repeat": "Сбрасывать(1) или нет(0) таймер в начальное состояние при достижении нуля.", diff --git a/src/utils/JsonUtils.cpp b/src/utils/JsonUtils.cpp index f04f910f..fa89de73 100644 --- a/src/utils/JsonUtils.cpp +++ b/src/utils/JsonUtils.cpp @@ -22,7 +22,7 @@ bool jsonRead(const String& json, String key, long& value, bool e) { return false; } else if (!doc.containsKey(key)) { if (e) { - SerialPrint("E", F("jsonRead"), key + " missing"); + SerialPrint("E", F("jsonRead"), key + " missing in " + json); jsonErrorDetected(); } return false; @@ -42,7 +42,7 @@ bool jsonRead(const String& json, String key, float& value, bool e) { return false; } else if (!doc.containsKey(key)) { if (e) { - SerialPrint("E", F("jsonRead"), key + " missing"); + SerialPrint("E", F("jsonRead"), key + " missing in " + json); jsonErrorDetected(); } return false; @@ -62,7 +62,7 @@ bool jsonRead(const String& json, String key, String& value, bool e) { return false; } else if (!doc.containsKey(key)) { if (e) { - SerialPrint("E", F("jsonRead"), key + " missing"); + SerialPrint("E", F("jsonRead"), key + " missing in " + json); jsonErrorDetected(); } return false; @@ -89,7 +89,7 @@ bool jsonRead(const String& json, String key, int& value, bool e) { return false; } else if (!doc.containsKey(key)) { if (e) { - SerialPrint("E", F("jsonRead"), key + " missing"); + SerialPrint("E", F("jsonRead"), key + " missing in " + json); jsonErrorDetected(); } return false; diff --git a/src/utils/SerialPrint.cpp b/src/utils/SerialPrint.cpp index 8ed907e2..4b3d1434 100644 --- a/src/utils/SerialPrint.cpp +++ b/src/utils/SerialPrint.cpp @@ -21,7 +21,7 @@ void SerialPrint(const String& errorLevel, const String& module, const String& m cleanString(tosend); // создаем событие об ошибке для возможной реакции в сценарии if (itemId != "") { - createItemFromNet(itemId + F("_onError"), tosend, -4); + createItemFromNet(itemId + F("_onError"), tosend, 1); } else { // createItemFromNet("onError", tosend, -4); }