Merge pull request #262 from biveraxe/ver4dev

Исправление ошибки контроля сетевых элементов
This commit is contained in:
2023-02-08 12:02:10 +03:00
committed by GitHub
14 changed files with 121 additions and 35 deletions

View File

@@ -35,7 +35,7 @@ extern FS* filesystem;
extern bool fileSystemInit(); extern bool fileSystemInit();
extern void globalVarsSync(); extern void globalVarsSync();
extern String getParamsJson(); //extern String getParamsJson();
extern void syncSettingsFlashJson(); extern void syncSettingsFlashJson();
extern void syncValuesFlashJson(); extern void syncValuesFlashJson();

View File

@@ -73,8 +73,8 @@ class IoTItem {
String _id = "errorId"; // если будет попытка создания Item без указания id, то элемент оставит это значение String _id = "errorId"; // если будет попытка создания Item без указания id, то элемент оставит это значение
long _interval = 0; long _interval = 0;
int _intFromNet = -2; // количество секунд доверия, пришедших из сети вместе с данными для текущего ИД int _intFromNet = -2; // количество секунд доверия, пришедших из сети вместе с данными для текущего ИД
// -2 - данные не приходили, скорее всего, элемент локальный, доверие есть // -2 - данные не приходили, скорее всего, элемент локальный, доверие есть, в случае прихода сетевого значения с int=0, будет выключен механизм проверки доверия
// -1 - данные приходили и обратный отсчет дошел до нуля, значит доверия нет // -1 - данные приходили и обратный отсчет дошел до нуля, значит доверия нет и элемент будет удален при следующем такте loop
float _multiply; // умножаем на значение float _multiply; // умножаем на значение
float _plus; // увеличиваем на значение float _plus; // увеличиваем на значение
@@ -90,7 +90,7 @@ class IoTItem {
IoTItem* findIoTItem(const String& name); // поиск экземпляра элемента модуля по имени IoTItem* findIoTItem(const String& name); // поиск экземпляра элемента модуля по имени
String getItemValue(const String& name); // поиск плюс получение значения String getItemValue(const String& name); // поиск плюс получение значения
bool isItemExist(const String& name); // существует ли айтем bool isItemExist(const String& name); // существует ли айтем
StaticJsonDocument<JSON_BUFFER_SIZE>* getLocalItemsAsJSON(); // сбор всех локальных значений Items //StaticJsonDocument<JSON_BUFFER_SIZE>* getLocalItemsAsJSON(); // сбор всех локальных значений Items
IoTItem* createItemFromNet(const String& itemId, const String& value, int interval); IoTItem* createItemFromNet(const String& itemId, const String& value, int interval);
IoTItem* createItemFromNet(const String& msgFromNet); IoTItem* createItemFromNet(const String& msgFromNet);

View File

@@ -27,12 +27,12 @@ void globalVarsSync() {
} }
//к удалению. не используется //к удалению. не используется
String getParamsJson() { // String getParamsJson() {
String json; // String json;
serializeJson(*getLocalItemsAsJSON(), json); // serializeJson(*getLocalItemsAsJSON(), json);
jsonWriteStr_(json, "params", ""); // jsonWriteStr_(json, "params", "");
return json; // return json;
} // }
void syncSettingsFlashJson() { void syncSettingsFlashJson() {
writeFile(F("settings.json"), settingsFlashJson); writeFile(F("settings.json"), settingsFlashJson);

View File

@@ -91,7 +91,7 @@ void setup() {
iotScen.loadScenario("/scenario.txt"); iotScen.loadScenario("/scenario.txt");
// создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке // создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке
createItemFromNet("onStart", "1", -4); createItemFromNet("onStart", "1", 1);
stInit(); stInit();

View File

@@ -9,6 +9,7 @@ void periodicTasksInit() {
// heap // heap
String heap = prettyBytes(ESP.getFreeHeap()); String heap = prettyBytes(ESP.getFreeHeap());
SerialPrint(F("i"), F("HEAP"), heap); SerialPrint(F("i"), F("HEAP"), heap);
SerialPrint(F("i"), F("IoTItems"), (String)IoTItems.size());
printGlobalVarSize(); printGlobalVarSize();
jsonWriteStr_(errorsHeapJson, F("heap"), heap); jsonWriteStr_(errorsHeapJson, F("heap"), heap);
// rssi // rssi

View File

@@ -119,7 +119,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
configure("/config.json"); configure("/config.json");
iotScen.loadScenario("/scenario.txt"); iotScen.loadScenario("/scenario.txt");
// создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке // создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке
createItemFromNet("onStart", "1", -4); createItemFromNet("onStart", "1", 1);
} }
//----------------------------------------------------------------------// //----------------------------------------------------------------------//

View File

@@ -7,8 +7,9 @@
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; if (_interval == 0) enableDoByInt = false; // выключаем использование периодического выполнения в модуле
_interval = _interval * 1000; 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;
@@ -170,7 +171,7 @@ void IoTItem::setIntFromNet(int interval) {
void IoTItem::checkIntFromNet() { void IoTItem::checkIntFromNet() {
// проверяем элемент на доверие данным. // проверяем элемент на доверие данным.
if (_intFromNet >= 0) { if (_intFromNet >= 0) {
// если время жизни истекло, то удаляем элемент // если время жизни истекло, то удаляем элемент чуть позже на следующем такте loop
// если это было уведомление не об ошибке или начале работы, то сообщаем, что сетевое событие давно не приходило // если это было уведомление не об ошибке или начале работы, то сообщаем, что сетевое событие давно не приходило
if (_intFromNet == 0 && _id.indexOf("onError") == -1 && _id.indexOf("onStart") == -1) { 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); 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* createItemFromNet(const String& msgFromNet) {
IoTItem* tmpp = new IoTItem(msgFromNet); IoTItem* tmpp = new IoTItem(msgFromNet);
//Serial.println("vvvvvvvvvvv " + msgFromNet + " " + (String)tmpp->getInterval());
if (tmpp->getInterval()) tmpp->setIntFromNet(tmpp->getInterval() / 1000 + 5); if (tmpp->getInterval()) tmpp->setIntFromNet(tmpp->getInterval() / 1000 + 5);
tmpp->iAmLocal = false; tmpp->iAmLocal = false;
IoTItems.push_back(tmpp); IoTItems.push_back(tmpp);
@@ -278,7 +282,7 @@ IoTItem* createItemFromNet(const String& msgFromNet) {
} }
void analyzeMsgFromNet(const String& msg, String altId) { 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); IoTItem* itemExist = findIoTItem(altId);
if (itemExist) { if (itemExist) {
String valAsStr = msg; String valAsStr = msg;
@@ -293,16 +297,17 @@ void analyzeMsgFromNet(const String& msg, String altId) {
} else { } else {
// временно зафиксируем данные в базе, если локально элемент отсутствует // временно зафиксируем данные в базе, если локально элемент отсутствует
createItemFromNet(msg); createItemFromNet(msg);
//Serial.println("ffffffffff " + msg + " altId=" + altId);
} }
} }
StaticJsonDocument<JSON_BUFFER_SIZE> docForExport; //StaticJsonDocument<JSON_BUFFER_SIZE> docForExport;
StaticJsonDocument<JSON_BUFFER_SIZE>* getLocalItemsAsJSON() { // StaticJsonDocument<JSON_BUFFER_SIZE>* getLocalItemsAsJSON() {
docForExport.clear(); // docForExport.clear();
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) docForExport[(*it)->getID()] = (*it)->getValue(); // if ((*it)->iAmLocal) docForExport[(*it)->getID()] = (*it)->getValue();
} // }
return &docForExport; // return &docForExport;
} // }

View File

@@ -28,6 +28,9 @@ class AnalogAdc : public IoTItem {
AnalogAdc(String parameters) : IoTItem(parameters) { AnalogAdc(String parameters) : IoTItem(parameters) {
_pin = jsonReadInt(parameters, "pin"); _pin = jsonReadInt(parameters, "pin");
_avgSteps = jsonReadInt(parameters, "avgSteps"); _avgSteps = jsonReadInt(parameters, "avgSteps");
if (!_avgSteps) {
jsonRead(parameters, F("int"), _interval, false);
}
_avgSumm = 0; _avgSumm = 0;
_avgCount = 0; _avgCount = 0;
} }

View File

@@ -35,8 +35,8 @@
"moduleDesc": "Позволяет получить текущее значение на аналоговом GPIO или усредненное для avgSteps измерений каждого вызова loop.", "moduleDesc": "Позволяет получить текущее значение на аналоговом GPIO или усредненное для avgSteps измерений каждого вызова loop.",
"propInfo": { "propInfo": {
"pin": "Аналоговый GPIO номер, к которому подключен датчик.", "pin": "Аналоговый GPIO номер, к которому подключен датчик.",
"avgSteps": "Количество считываний для усреднения. При <=1, считывается одно значение за каждый период опроса.", "avgSteps": "Количество считываний для усреднения. При =1, считывается одно значение за каждый период опроса., при =0, int считается в миллисекундах",
"int": "Количество секунд между опросами датчика." "int": "Количество секунд между опросами датчика, если avgSteps > 0. Установите avgSteps = 0 и int будет считаться в миллисекундах (ВНИМАНИЕ! генерация событий чаще секунды может привести к нестабильности системы.)"
} }
}, },
"defActive": true, "defActive": true,

View File

@@ -92,7 +92,7 @@ class UART : public IoTItem {
void onRegEvent(IoTItem* eventItem) { void onRegEvent(IoTItem* eventItem) {
if (!_myUART || !eventItem) return; if (!_myUART || !eventItem) return;
int indexOf_;
String printStr = ""; String printStr = "";
switch (_eventFormat) { switch (_eventFormat) {
case 0: return; // не указан формат, значит не следим за событиями case 0: return; // не указан формат, значит не следим за событиями
@@ -105,7 +105,7 @@ class UART : public IoTItem {
case 2: // формат событий для Nextion ID=Value0xFF0xFF0xFF case 2: // формат событий для Nextion ID=Value0xFF0xFF0xFF
printStr += eventItem->getID(); printStr += eventItem->getID();
int indexOf_ = printStr.indexOf("_"); indexOf_ = printStr.indexOf("_");
//Serial.println(printStr + " fff " + indexOf_); //Serial.println(printStr + " fff " + indexOf_);
if (indexOf_ == -1) return; // пропускаем событие, если нет используемого признака типа данных - _txt или _vol if (indexOf_ == -1) return; // пропускаем событие, если нет используемого признака типа данных - _txt или _vol
@@ -126,9 +126,86 @@ class UART : public IoTItem {
uartPrintFFF(printStr); uartPrintFFF(printStr);
break; 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() { virtual void loop() {
uartHandle(); uartHandle();
} }

View File

@@ -37,7 +37,7 @@
"rx": "RX пин", "rx": "RX пин",
"speed": "Скорость UART", "speed": "Скорость UART",
"line": "Актуально только для ESP32: номер линии hardUART. =2 rx=16 tx=17", "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 сообщение.", "retInfo": "Содержит полученное последнее по UART сообщение.",
"funcInfo": [ "funcInfo": [

View File

@@ -32,7 +32,7 @@
"title": "Таймер обратного отсчета", "title": "Таймер обратного отсчета",
"moduleDesc": "Добавляет инструмент таймеров обратного отсчета для организации периодичных операций или логических конструкций. Часто используется как вспомогательный элемент для автоматизации.", "moduleDesc": "Добавляет инструмент таймеров обратного отсчета для организации периодичных операций или логических конструкций. Часто используется как вспомогательный элемент для автоматизации.",
"propInfo": { "propInfo": {
"int": "Задает размер в миллисекундах (1000 = 1сек) одного шага(тика) таймера.", "int": "Задает размер в секундах одного шага(тика) таймера.",
"countDown": "Начальное значение таймера, с которого начинается обратный отсчет. countDown=0 - бесконечный счет (имеет смысл при ticker=1, иначе таймер будет выключен), countDown=-1 - отключает таймер совсем (используется для запуска системы с выключенным таймером)", "countDown": "Начальное значение таймера, с которого начинается обратный отсчет. countDown=0 - бесконечный счет (имеет смысл при ticker=1, иначе таймер будет выключен), countDown=-1 - отключает таймер совсем (используется для запуска системы с выключенным таймером)",
"ticker": "Генерировать(1) или нет(0) события при каждом тике таймера.", "ticker": "Генерировать(1) или нет(0) события при каждом тике таймера.",
"repeat": "Сбрасывать(1) или нет(0) таймер в начальное состояние при достижении нуля.", "repeat": "Сбрасывать(1) или нет(0) таймер в начальное состояние при достижении нуля.",

View File

@@ -22,7 +22,7 @@ bool jsonRead(const String& json, String key, long& value, bool e) {
return false; return false;
} else if (!doc.containsKey(key)) { } else if (!doc.containsKey(key)) {
if (e) { if (e) {
SerialPrint("E", F("jsonRead"), key + " missing"); SerialPrint("E", F("jsonRead"), key + " missing in " + json);
jsonErrorDetected(); jsonErrorDetected();
} }
return false; return false;
@@ -42,7 +42,7 @@ bool jsonRead(const String& json, String key, float& value, bool e) {
return false; return false;
} else if (!doc.containsKey(key)) { } else if (!doc.containsKey(key)) {
if (e) { if (e) {
SerialPrint("E", F("jsonRead"), key + " missing"); SerialPrint("E", F("jsonRead"), key + " missing in " + json);
jsonErrorDetected(); jsonErrorDetected();
} }
return false; return false;
@@ -62,7 +62,7 @@ bool jsonRead(const String& json, String key, String& value, bool e) {
return false; return false;
} else if (!doc.containsKey(key)) { } else if (!doc.containsKey(key)) {
if (e) { if (e) {
SerialPrint("E", F("jsonRead"), key + " missing"); SerialPrint("E", F("jsonRead"), key + " missing in " + json);
jsonErrorDetected(); jsonErrorDetected();
} }
return false; return false;
@@ -89,7 +89,7 @@ bool jsonRead(const String& json, String key, int& value, bool e) {
return false; return false;
} else if (!doc.containsKey(key)) { } else if (!doc.containsKey(key)) {
if (e) { if (e) {
SerialPrint("E", F("jsonRead"), key + " missing"); SerialPrint("E", F("jsonRead"), key + " missing in " + json);
jsonErrorDetected(); jsonErrorDetected();
} }
return false; return false;

View File

@@ -21,7 +21,7 @@ void SerialPrint(const String& errorLevel, const String& module, const String& m
cleanString(tosend); cleanString(tosend);
// создаем событие об ошибке для возможной реакции в сценарии // создаем событие об ошибке для возможной реакции в сценарии
if (itemId != "") { if (itemId != "") {
createItemFromNet(itemId + F("_onError"), tosend, -4); createItemFromNet(itemId + F("_onError"), tosend, 1);
} else { } else {
// createItemFromNet("onError", tosend, -4); // createItemFromNet("onError", tosend, -4);
} }