From 08ffc74e8d885ecc4b7ff9a517f8a993edb1c920 Mon Sep 17 00:00:00 2001 From: Dmitry Borisenko <67171972+IoTManagerProject@users.noreply.github.com> Date: Sun, 4 Dec 2022 01:37:27 +0100 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B8=20=D1=83=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=D0=B8=D0=B4=D0=B6=D0=B5=D1=82?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8=20=D0=B8=D0=B7=20=D0=BC=D0=BE=D0=B4=D1=83?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/MqttClient.h | 7 +-- include/classes/IoTItem.h | 23 ++++---- platformio.ini | 4 +- src/EspFileSystem.cpp | 2 +- src/MqttClient.cpp | 55 +++++++++++++------- src/classes/IoTItem.cpp | 49 +++++++++-------- src/modules/exec/MySensors/MySensorsGate.cpp | 39 ++++++++++++++ src/modules/exec/MySensors/MySensorsGate.h | 25 +++++++-- src/modules/exec/MySensors/modinfo.json | 11 ++-- 9 files changed, 147 insertions(+), 68 deletions(-) diff --git a/include/MqttClient.h b/include/MqttClient.h index 02dce50e..17eb2255 100644 --- a/include/MqttClient.h +++ b/include/MqttClient.h @@ -19,15 +19,16 @@ boolean publish(const String& topic, const String& data); boolean publishData(const String& topic, const String& data); boolean publishChartMqtt(const String& topic, const String& data); boolean publishControl(String id, String topic, String state); -boolean publishChart_test(const String& topic, const String& data); +boolean publishJsonMqtt(const String& topic, const String& json); boolean publishStatusMqtt(const String& topic, const String& data); boolean publishEvent(const String& topic, const String& data); boolean publishInfo(const String& topic, const String& data); -boolean publishAnyJsonKey(const String& topic, const String& key, const String& data); +boolean publishAnyJsonKeyMqtt(const String& topic, const String& key, const String& data); bool publishChartFileToMqtt(String path, String id, int maxCount); void publishWidgets(); -void publishState(); +void publishMainWidgetsValues(); +void publishSubWidgetsValues(); void mqttCallback(char* topic, uint8_t* payload, size_t length); void handleMqttStatus(bool send); diff --git a/include/classes/IoTItem.h b/include/classes/IoTItem.h index 57d42a22..69f36aa7 100644 --- a/include/classes/IoTItem.h +++ b/include/classes/IoTItem.h @@ -10,7 +10,7 @@ struct IoTValue { class IoTItem { public: - IoTItem(const String ¶meters); + IoTItem(const String& parameters); virtual ~IoTItem() {} virtual void loop(); virtual void doByInterval(); @@ -28,7 +28,10 @@ class IoTItem { virtual String getValue(); long getInterval(); bool isGlobal(); - + + void sendSubWidgetsValues(String& id, String& json); + virtual void handleSendSubWidgetsValues(); + void setInterval(long interval); void setIntFromNet(int interval); @@ -38,7 +41,7 @@ class IoTItem { IoTValue value; // хранение основного значения, которое обновляется из сценария, execute(), loop() или doByInterval() - //bool iAmDead = false; // признак необходимости удалить объект из базы + // bool iAmDead = false; // признак необходимости удалить объект из базы bool iAmLocal = true; // признак того, что айтем был создан локально bool enableDoByInt = true; @@ -63,11 +66,11 @@ class IoTItem { protected: bool _needSave = false; // признак необходимости сохранять и загружать значение элемента на flash String _subtype = ""; - String _id = "errorId"; // если будет попытка создания Item без указания id, то элемент оставит это значение + String _id = "errorId"; // если будет попытка создания Item без указания id, то элемент оставит это значение long _interval = 0; - int _intFromNet = -2; // количество секунд доверия, пришедших из сети вместе с данными для текущего ИД - // -2 - данные не приходили, скорее всего, элемент локальный, доверие есть - // -1 - данные приходили и обратный отсчет дошел до нуля, значит доверия нет + int _intFromNet = -2; // количество секунд доверия, пришедших из сети вместе с данными для текущего ИД + // -2 - данные не приходили, скорее всего, элемент локальный, доверие есть + // -1 - данные приходили и обратный отсчет дошел до нуля, значит доверия нет float _multiply; // умножаем на значение float _plus; // увеличиваем на значение @@ -80,9 +83,9 @@ class IoTItem { bool _global = false; // характеристика айтема, что ему нужно слать и принимать события из внешнего мира }; -IoTItem* findIoTItem(const String& name); // поиск экземпляра элемента модуля по имени -String getItemValue(const String& name); // поиск плюс получение значения -bool isItemExist(const String& name); // существует ли айтем +IoTItem* findIoTItem(const String& name); // поиск экземпляра элемента модуля по имени +String getItemValue(const String& name); // поиск плюс получение значения +bool isItemExist(const String& name); // существует ли айтем StaticJsonDocument* getLocalItemsAsJSON(); // сбор всех локальных значений Items IoTItem* createItemFromNet(const String& itemId, const String& value, int interval); diff --git a/platformio.ini b/platformio.ini index 4f7be49f..477443b6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -113,8 +113,8 @@ build_src_filter = ${env:esp8266_4mb_fromitems.build_src_filter} [env:esp32_4mb] -upload_port = COM8 -monitor_port = COM8 +;upload_port = COM13 +;monitor_port = COM13 lib_deps = ${common_env_data.lib_deps_external} ${env:esp32_4mb_fromitems.lib_deps} diff --git a/src/EspFileSystem.cpp b/src/EspFileSystem.cpp index 5f8619e8..2b45dd7d 100644 --- a/src/EspFileSystem.cpp +++ b/src/EspFileSystem.cpp @@ -17,7 +17,6 @@ void globalVarsSync() { valuesFlashJson = readFile(F("values.json"), 4096); valuesFlashJson.replace("\r\n", ""); - mqttPrefix = jsonReadStr(settingsFlashJson, F("mqttPrefix")); mqttRootDevice = mqttPrefix + "/" + chipId; jsonWriteStr_(settingsFlashJson, "root", mqttRootDevice); @@ -27,6 +26,7 @@ void globalVarsSync() { // jsonWriteStr_(ssidListHeapJson, "ssids_", ""); //метка для парсинга удалить } +//к удалению. не используется String getParamsJson() { String json; serializeJson(*getLocalItemsAsJSON(), json); diff --git a/src/MqttClient.cpp b/src/MqttClient.cpp index 1811ac46..7c98f4db 100644 --- a/src/MqttClient.cpp +++ b/src/MqttClient.cpp @@ -133,7 +133,8 @@ void mqttCallback(char* topic, uint8_t* payload, size_t length) { if (payloadStr.startsWith("HELLO")) { SerialPrint("i", F("MQTT"), F("Full update")); publishWidgets(); - publishState(); + publishMainWidgetsValues(); + publishSubWidgetsValues(); //обращение к логированию из ядра //отправка данных графиков @@ -189,7 +190,7 @@ void mqttCallback(char* topic, uint8_t* payload, size_t length) { // loadScenario(); // SerialPrint("i", F("=>MQTT"), F("Scenario received")); // } - //} + //} } boolean publish(const String& topic, const String& data) { @@ -223,9 +224,9 @@ boolean publishControl(String id, String topic, String state) { return mqtt.publish(path.c_str(), state.c_str(), false); } -boolean publishChart_test(const String& topic, const String& data) { +boolean publishJsonMqtt(const String& topic, const String& json) { String path = mqttRootDevice + "/" + topic + "/status"; - return mqtt.publish(path.c_str(), data.c_str(), false); + return mqtt.publish(path.c_str(), json.c_str(), false); } boolean publishStatusMqtt(const String& topic, const String& data) { @@ -235,7 +236,7 @@ boolean publishStatusMqtt(const String& topic, const String& data) { return mqtt.publish(path.c_str(), json.c_str(), false); } -boolean publishAnyJsonKey(const String& topic, const String& key, const String& data) { +boolean publishAnyJsonKeyMqtt(const String& topic, const String& key, const String& data) { String path = mqttRootDevice + "/" + topic + "/status"; String json = "{}"; jsonWriteStr(json, key, data); @@ -272,21 +273,35 @@ void publishWidgets() { file.close(); } -void publishState() { - String json = getParamsJson(); - SerialPrint("i", F("DATA"), json); - json.replace("{", ""); - json.replace("}", ""); - json.replace("\"", ""); - json += ","; - while (json.length() != 0) { - String tmp = selectToMarker(json, ","); - String topic = selectToMarker(tmp, ":"); - String state = deleteBeforeDelimiter(tmp, ":"); - if (topic != "" && state != "") { - publishStatusMqtt(topic, state); - } - json = deleteBeforeDelimiter(json, ","); +//устаревшая версия к удалению +// void publishMainWidgetsValues() { +// String json = getParamsJson(); +// SerialPrint("i", F("DATA"), json); +// json.replace("{", ""); +// json.replace("}", ""); +// json.replace("\"", ""); +// json += ","; +// while (json.length() != 0) { +// String tmp = selectToMarker(json, ","); +// String topic = selectToMarker(tmp, ":"); +// String state = deleteBeforeDelimiter(tmp, ":"); +// if (topic != "" && state != "") { +// publishStatusMqtt(topic, state); +// } +// json = deleteBeforeDelimiter(json, ","); +// } +//} + +//оптимизированная версия +void publishMainWidgetsValues() { + for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { + if ((*it)->iAmLocal) publishStatusMqtt((*it)->getID(), (*it)->getValue()); + } +} + +void publishSubWidgetsValues() { + for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { + if ((*it)->iAmLocal) (*it)->handleSendSubWidgetsValues(); } } diff --git a/src/classes/IoTItem.cpp b/src/classes/IoTItem.cpp index e8afe357..cb0a89a2 100644 --- a/src/classes/IoTItem.cpp +++ b/src/classes/IoTItem.cpp @@ -5,7 +5,6 @@ #include "ESPConfiguration.h" #include "EventsAndOrders.h" -//получение параметров в экземпляр класса IoTItem::IoTItem(const String& parameters) { jsonRead(parameters, F("int"), _interval, false); if (_interval <= 0) enableDoByInt = false; @@ -33,11 +32,10 @@ IoTItem::IoTItem(const String& parameters) { setValue(valAsStr, false); jsonRead(parameters, F("needSave"), _needSave, false); - if (_needSave && jsonRead(valuesFlashJson, _id, valAsStr, false)) // пробуем достать из сохранения значение элемента, если указано, что нужно сохранять + if (_needSave && jsonRead(valuesFlashJson, _id, valAsStr, false)) // пробуем достать из сохранения значение элемента, если указано, что нужно сохранять setValue(valAsStr, false); } -//луп выполняющий переодическое дерганье void IoTItem::loop() { if (enableDoByInt) { currentMillis = millis(); @@ -49,7 +47,6 @@ void IoTItem::loop() { } } -//получить String IoTItem::getValue() { if (value.isDecimal) { return getRoundValue(); @@ -59,12 +56,11 @@ String IoTItem::getValue() { long IoTItem::getInterval() { return _interval; } -bool IoTItem::isGlobal() { return _global;} +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 { @@ -73,10 +69,9 @@ void IoTItem::setValue(const String& valStr, bool genEvent) { setValue(value, genEvent); } -// void IoTItem::setValue(const IoTValue& Value, bool genEvent) { value = Value; - + if (value.isDecimal) { regEvent(value.valD, "", false, genEvent); } else { @@ -84,6 +79,15 @@ void IoTItem::setValue(const IoTValue& Value, bool genEvent) { } } +//метод отправки из модуля дополнительных json полей виджета в приложение и веб интерфейс, необходимый для изменения виджетов "на лету" из модуля +void IoTItem::sendSubWidgetsValues(String& id, String& json) { + publishJsonMqtt(id, json); + // to do publishJsonWs +} + +//метод который нужен что бы из ядра заставить модуль отправить его дополнительные json поля виджета +void IoTItem::handleSendSubWidgetsValues() {} + //когда событие случилось void IoTItem::regEvent(const String& value, const String& consoleInfo, bool error, bool genEvent) { if (_needSave) { @@ -92,22 +96,22 @@ void IoTItem::regEvent(const String& value, const String& consoleInfo, bool erro } publishStatusMqtt(_id, value); publishStatusWs(_id, value); - //SerialPrint("i", "Sensor", consoleInfo + " '" + _id + "' data: " + 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); + jsonWriteInt_(json, "int", _interval / 1000); publishEvent(_id, json); SerialPrint("i", F("<=MQTT"), "Broadcast event: " + json); } @@ -119,7 +123,7 @@ 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; @@ -154,7 +158,7 @@ void IoTItem::getNetEvent(String& event) { event = "{}"; jsonWriteStr_(event, "id", _id); jsonWriteStr_(event, "val", getValue()); - jsonWriteInt_(event, "int", _interval/1000); + jsonWriteInt_(event, "int", _interval / 1000); } void IoTItem::setIntFromNet(int interval) { @@ -199,7 +203,6 @@ IoTGpio* IoTItem::getGpioDriver() { return nullptr; } - //сетевое общение==================================================================================================================================== // externalVariable::externalVariable(const String& parameters) : IoTItem(parameters) { @@ -256,14 +259,14 @@ IoTItem* createItemFromNet(const String& itemId, const String& value, int interv 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); + 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()); @@ -271,7 +274,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 == "") && altId == "") return; // ничего не предпринимаем, если ошибка и altId = "", вообще данная конструкция нужна для совместимости с форматом данных 3 версией IoTItem* itemExist = findIoTItem(altId); if (itemExist) { String valAsStr = msg; @@ -279,9 +282,9 @@ void analyzeMsgFromNet(const String& msg, String altId) { long interval = 0; jsonRead(msg, F("int"), interval, false); - itemExist->setInterval(interval); // устанавливаем такой же интервал как на источнике события - itemExist->setValue(valAsStr, false); // только регистрируем изменения в интерфейсе без создания цикла сетевых событий - if (interval) itemExist->setIntFromNet(interval+5); // если пришедший интервал =0, значит не нужно контролировать доверие, иначе даем фору в 5 сек + itemExist->setInterval(interval); // устанавливаем такой же интервал как на источнике события + itemExist->setValue(valAsStr, false); // только регистрируем изменения в интерфейсе без создания цикла сетевых событий + if (interval) itemExist->setIntFromNet(interval + 5); // если пришедший интервал =0, значит не нужно контролировать доверие, иначе даем фору в 5 сек generateEvent(altId, valAsStr); } else { // временно зафиксируем данные в базе, если локально элемент отсутствует diff --git a/src/modules/exec/MySensors/MySensorsGate.cpp b/src/modules/exec/MySensors/MySensorsGate.cpp index 14176adc..ab15206d 100644 --- a/src/modules/exec/MySensors/MySensorsGate.cpp +++ b/src/modules/exec/MySensors/MySensorsGate.cpp @@ -3,6 +3,7 @@ #include "Arduino.h" #include "MySensorsGate.h" +#ifdef MYSENSORS // callback библиотеки mysensors void receive(const MyMessage& message) { String inMsg = String(message.getSender()) + "," + // node-id @@ -48,6 +49,7 @@ String parseToString(const MyMessage& message) { } } +#endif class MySensorsGate : public IoTItem { private: public: @@ -344,20 +346,57 @@ class MySensorsGate : public IoTItem { class MySensorsNode : public IoTItem { private: + String id; + int _minutesPassed = 0; + String json = "{}"; + bool dataFromNode = false; + public: MySensorsNode(String parameters) : IoTItem(parameters) { SerialPrint("i", "MySensors", "Node initialized"); + jsonRead(parameters, F("id"), id); + dataFromNode = false; } void setValue(const IoTValue& Value, bool genEvent = true) { value = Value; regEvent(value.valD, "MySensorsNode", false, genEvent); + _minutesPassed = 0; + prevMillis = millis(); + dataFromNode = true; + setNewWidgetAttributes(); } void doByInterval() { + _minutesPassed++; + setNewWidgetAttributes(); } void loop() { + currentMillis = millis(); + difference = currentMillis - prevMillis; + if (difference > 60000) { + prevMillis = millis(); + this->doByInterval(); + } + } + + void handleSendSubWidgetsValues() { + setNewWidgetAttributes(); + } + + void setNewWidgetAttributes() { + if (dataFromNode) { + jsonWriteStr(json, "info", String(_minutesPassed) + " min"); + if (_minutesPassed >= 60) { + jsonWriteStr(json, "color", "orange"); //сделаем виджет оранжевым когда более 60 минут нода не выходила на связь + } else if (_minutesPassed >= 120) { + jsonWriteStr(json, "color", "red"); //сделаем виджет красным когда более 120 минут нода не выходила на связь + } + } else { + jsonWriteStr(json, "info", "awaiting"); + } + sendSubWidgetsValues(id, json); } ~MySensorsNode(){}; diff --git a/src/modules/exec/MySensors/MySensorsGate.h b/src/modules/exec/MySensors/MySensorsGate.h index 969f8343..5cacdadc 100644 --- a/src/modules/exec/MySensors/MySensorsGate.h +++ b/src/modules/exec/MySensors/MySensorsGate.h @@ -1,4 +1,22 @@ #pragma once +#include "Const.h" +#ifdef MYSENSORS + +/* + * DESCRIPTION + * The ESP32 gateway sends data received from sensors to the WiFi link. + * The gateway also accepts input on ethernet interface, which is then sent out to the radio network. + * ----------- PINOUT -------------- + * | IO | RF24 | RFM69 | RFM95 | + |------|------|-------|-------| + | MOSI | 23 | 23 | 23 | + | MISO | 19 | 19 | 19 | + | SCK | 18 | 18 | 18 | + | CSN | 5 | 5 | 5 | + | CE | 17 | - | - | + | RST | - | 17 | 17 | + | IRQ | 16* | 16 | 16 | +*/ // Enable debug prints to serial monitor //#define MY_DEBUG @@ -7,7 +25,6 @@ //#define MY_RF24_CS_PIN 9 // Use a bit lower baudrate for serial prints on ESP8266 than default in MyConfig.h - #define MY_BAUD_RATE 115200 // Enables and select radio type (if attached) @@ -22,7 +39,7 @@ // Set LOW transmit power level as default, if you have an amplified NRF-module and // power your radio separately with a good regulator you can turn up PA level. -#define MY_RF24_PA_LEVEL RF24_PA_LOW +#define MY_RF24_PA_LEVEL RF24_PA_MAX // используем гейт в режиме serial хотя нам этот режим не нужен, поэтому в библиотеки отключаем MY_SERIALDEVICE.print // в файле MyGatewayTransportSerial.cpp в строчке 35 @@ -32,4 +49,6 @@ #include -extern String parseToString(const MyMessage& message); \ No newline at end of file +extern String parseToString(const MyMessage& message); + +#endif \ No newline at end of file diff --git a/src/modules/exec/MySensors/modinfo.json b/src/modules/exec/MySensors/modinfo.json index c89384af..86638d17 100644 --- a/src/modules/exec/MySensors/modinfo.json +++ b/src/modules/exec/MySensors/modinfo.json @@ -32,17 +32,16 @@ "moduleVersion": "1.0", "usedRam": { "esp32_4mb": 15, - "esp8266_4mb": 15 + "esp8266_4mb": 0 }, - "title": "My Sensors Gate", - "moduleDesc": "", + "title": "Гейт MySensors", + "moduleDesc": "Гейт состоит из esp32 и подключенному к нему радиомодулю NRF24L01. Вместе в связке они образуют гейт, способный принимать данные датчиков. Датчики способны работать до нескольких лет на батарейках", "retInfo": "", "propInfo": { - "int": "", - "pin": "" + "id": "Для настройки следует выбрать один раз MySensorsGate и выбрать сколько необходимо раз MySensorsNode. Вместо ID нужно указать ID ноды дефис ID значения данной ноды. Например 100-1 - будет значить нода с ID 100 величина 1." } }, - "defActive": true, + "defActive": false, "usedLibs": { "esp32_4mb": [] }