#include "utils/JsonUtils.h" #include "utils/SerialPrint.h" #include "classes/IoTItem.h" #include "WsServer.h" #include "ESPConfiguration.h" #include "EventsAndOrders.h" //получение параметров в экземпляр класса IoTItem::IoTItem(const String& parameters) { jsonRead(parameters, F("int"), _interval, false); if (_interval <= 0) enableDoByInt = false; _interval = _interval * 1000; jsonRead(parameters, F("subtype"), _subtype, false); jsonRead(parameters, F("id"), _id); if (!jsonRead(parameters, F("multiply"), _multiply, false)) _multiply = 1; if (!jsonRead(parameters, F("plus"), _plus, false)) _plus = 0; if (!jsonRead(parameters, F("round"), _round, false)) _round = -1; if (!jsonRead(parameters, F("global"), _global, false)) _global = false; String map; jsonRead(parameters, F("map"), map, false); if (map != "") { _map1 = selectFromMarkerToMarker(map, ",", 0).toInt(); _map2 = selectFromMarkerToMarker(map, ",", 1).toInt(); _map3 = selectFromMarkerToMarker(map, ",", 2).toInt(); _map4 = selectFromMarkerToMarker(map, ",", 3).toInt(); } else _map1 = _map2 = _map3 = _map4 = 0; String valAsStr = ""; if (jsonRead(parameters, F("val"), valAsStr, false)) // значение переменной или датчика при инициализации если есть в конфигурации setValue(valAsStr, false); jsonRead(parameters, F("needSave"), _needSave, false); if (_needSave && jsonRead(valuesFlashJson, _id, valAsStr, false)) // пробуем достать из сохранения значение элемента, если указано, что нужно сохранять setValue(valAsStr, false); } //луп выполняющий переодическое дерганье void IoTItem::loop() { if (enableDoByInt) { currentMillis = millis(); difference = currentMillis - prevMillis; if (difference >= _interval) { prevMillis = millis(); this->doByInterval(); } } } //получить String IoTItem::getValue() { if (value.isDecimal) { return getRoundValue(); } else return value.valS; } long IoTItem::getInterval() { return _interval; } bool IoTItem::isGlobal() { return _global;} //определяем тип прилетевшей величины void IoTItem::setValue(const String& valStr, bool genEvent) { value.isDecimal = isDigitDotCommaStr(valStr); if (value.isDecimal) { value.valD = valStr.toFloat(); } else { value.valS = valStr; } setValue(value, genEvent); } // void IoTItem::setValue(const IoTValue& Value, bool genEvent) { value = Value; if (value.isDecimal) { regEvent(value.valD, "", false, genEvent); } else { regEvent(value.valS, "", false, genEvent); } } //когда событие случилось void IoTItem::regEvent(const String& value, const String& consoleInfo, bool error, bool genEvent) { if (_needSave) { jsonWriteStr_(valuesFlashJson, _id, value); needSaveValues = true; } publishStatusMqtt(_id, value); publishStatusWs(_id, value); //SerialPrint("i", "Sensor", consoleInfo + " '" + _id + "' data: " + value + "'"); if (genEvent) { generateEvent(_id, value); // распространяем событие через хуки for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { (*it)->onRegEvent(this); } //отправка события другим устройствам в сети если не было ошибки============================== if (jsonReadBool(settingsFlashJson, "mqttin") && _global && !error) { String json = "{}"; jsonWriteStr_(json, "id", _id); jsonWriteStr_(json, "val", value); jsonWriteInt_(json, "int", _interval/1000); publishEvent(_id, json); SerialPrint("i", F("<=MQTT"), "Broadcast event: " + json); } //======================================================================== } } String IoTItem::getRoundValue() { if (_round >= 0 && _round <= 6) { int sot = _round ? pow(10, (int)_round) : 1; value.valD = round(value.valD * sot) / sot; char buf[15]; sprintf(buf, ("%1." + (String)_round + "f").c_str(), value.valD); return (String)buf; } else { return (String)value.valD; } } void IoTItem::regEvent(float regvalue, const String& consoleInfo, bool error, bool genEvent) { value.valD = regvalue; if (_multiply) value.valD = value.valD * _multiply; if (_plus) value.valD = value.valD + _plus; if (_map1 != _map2) value.valD = map(value.valD, _map1, _map2, _map3, _map4); regEvent(getRoundValue(), consoleInfo, error, genEvent); } void IoTItem::doByInterval() {} IoTValue IoTItem::execute(String command, std::vector& param) { return {}; } String IoTItem::getSubtype() { return _subtype; } int IoTItem::getIntFromNet() { return _intFromNet; } void IoTItem::getNetEvent(String& event) { event = "{}"; jsonWriteStr_(event, "id", _id); jsonWriteStr_(event, "val", getValue()); jsonWriteInt_(event, "int", _interval/1000); } void IoTItem::setIntFromNet(int interval) { _intFromNet = interval; } void IoTItem::checkIntFromNet() { // проверяем элемент на доверие данным. if (_intFromNet >= 0) { // если время жизни истекло, то удаляем элемент // если это было уведомление не об ошибке или начале работы, то сообщаем, что сетевое событие давно не приходило 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); } _intFromNet--; } } void IoTItem::onRegEvent(IoTItem* item) {} void IoTItem::onMqttRecive(String& topic, String& msg) {} void IoTItem::publishValue() {} void IoTItem::clearValue() {} void IoTItem::setPublishDestination(int publishType, int wsNum){}; void IoTItem::clearHistory() {} void IoTItem::setTodayDate() {} String IoTItem::getID() { return _id; }; void IoTItem::setInterval(long interval) { _interval = interval; } IoTGpio* IoTItem::getGpioDriver() { return nullptr; } //сетевое общение==================================================================================================================================== // externalVariable::externalVariable(const String& parameters) : IoTItem(parameters) { // prevMillis = millis(); // запоминаем текущее значение таймера для выполения doByInterval после int сек // iAmLocal = false; // указываем, что это сущность прилетела из сети // //Serial.printf("Call from externalVariable: parameters %s %d\n", parameters.c_str(), _interval); // } // externalVariable::~externalVariable() { // Serial.printf("Call from ~externalVariable: Im dead\n"); // } // void externalVariable::doByInterval() { // для данного класса doByInterval+int выполняет роль счетчика обратного отсчета до уничтожения // iAmDead = true; // } //========================================================================================================================================= IoTItem* myIoTItem; // поиск элемента модуля в существующей конфигурации IoTItem* findIoTItem(const String& name) { if (name == "") return nullptr; for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { if ((*it)->getID() == name) return *it; } return nullptr; } // поиск плюс получение значения String getItemValue(const String& name) { IoTItem* tmp = findIoTItem(name); if (tmp) return tmp->getValue(); else return ""; } // существует ли айтем bool isItemExist(const String& name) { IoTItem* tmp = findIoTItem(name); if (tmp) return true; else return false; } // создаем временную копию элемента из сети на основе события IoTItem* createItemFromNet(const String& itemId, const String& value, int interval) { String jsonStr = "{\"id\":\""; jsonStr += itemId; jsonStr += "\",\"val\":\""; jsonStr += value; jsonStr += "\",\"int\":"; jsonStr += interval; jsonStr += "}"; return createItemFromNet(jsonStr); } // создаем временную копию элемента из сети на основе события IoTItem* createItemFromNet(const String& msgFromNet) { IoTItem *tmpp = new IoTItem(msgFromNet); if (tmpp->getInterval()) tmpp->setIntFromNet(tmpp->getInterval()/1000 + 5); tmpp->iAmLocal = false; IoTItems.push_back(tmpp); generateEvent(tmpp->getID(), tmpp->getValue()); return tmpp; } void analyzeMsgFromNet(const String& msg, String altId) { if (!jsonRead(msg, F("id"), altId, altId == "") && altId == "") return; // ничего не предпринимаем, если ошибка и altId = "", вообще данная конструкция нужна для совместимости с форматом данных 3 версией IoTItem* itemExist = findIoTItem(altId); if (itemExist) { String valAsStr = msg; jsonRead(msg, F("val"), valAsStr, false); long interval = 0; jsonRead(msg, F("int"), interval, false); itemExist->setInterval(interval); // устанавливаем такой же интервал как на источнике события itemExist->setValue(valAsStr, false); // только регистрируем изменения в интерфейсе без создания цикла сетевых событий if (interval) itemExist->setIntFromNet(interval+5); // если пришедший интервал =0, значит не нужно контролировать доверие, иначе даем фору в 5 сек generateEvent(altId, valAsStr); } else { // временно зафиксируем данные в базе, если локально элемент отсутствует createItemFromNet(msg); } } 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(); } return &docForExport; }