diff --git a/src/modules/display/Oled128/modinfo.json b/src/modules/display/Oled128/modinfo.json index d88014e4..2f242558 100644 --- a/src/modules/display/Oled128/modinfo.json +++ b/src/modules/display/Oled128/modinfo.json @@ -74,10 +74,10 @@ "defActive": false, "usedLibs": { "esp32*": [ - "gyverlibs/GyverOLED @ 1.4" + "gyverlibs/GyverOLED @ 1.6.3" ], "esp82*": [ - "gyverlibs/GyverOLED @ 1.4" + "gyverlibs/GyverOLED @ 1.6.3" ] } } \ No newline at end of file diff --git a/src/modules/exec/BrokerMQTT/modinfo.json b/src/modules/exec/BrokerMQTT/modinfo.json index fac52f02..7b671047 100644 --- a/src/modules/exec/BrokerMQTT/modinfo.json +++ b/src/modules/exec/BrokerMQTT/modinfo.json @@ -15,7 +15,7 @@ "port": 1883, "user": "root", "pass": "4321", - "brige":1, + "brige": 1, "server":"http://iotmanager.org", "srvUser": "rise", "srvPass": "3hostel3", diff --git a/src/modules/exec/Telegram_v2/Telegram_v2.cpp b/src/modules/exec/Telegram_v2/Telegram_v2.cpp index b7b5e170..46b2d95d 100644 --- a/src/modules/exec/Telegram_v2/Telegram_v2.cpp +++ b/src/modules/exec/Telegram_v2/Telegram_v2.cpp @@ -1,5 +1,6 @@ #include "Global.h" #include "classes/IoTItem.h" +#include "UpgradeFirm.h" // #define FB_NO_UNICODE // #define FB_NO_URLENCODE // #define FB_NO_OTA @@ -27,7 +28,9 @@ String _token; String _chatID; bool _autos; bool _initSD; - +bool _resolveOTA; +bool fl_rollback; +int8_t _OTAstate = -1; struct ButtonMenu { String message = ""; @@ -35,7 +38,15 @@ struct ButtonMenu String setId = ""; String value = ""; }; - +/* +struct updateFirm { + String settingsFlashJson; + String configJson; + String layoutJson; + String scenarioTxt; + String chartsData; +}; +*/ std::map mapBtnMenu; // std::map mapBtnInline; // @@ -45,16 +56,21 @@ private: bool _receiveMsg; String _prevMsg = ""; bool _useLed = false; + uint8_t _textMode = 0; public: Telegram_v2(String parameters) : IoTItem(parameters) { jsonRead(parameters, "token", _token); jsonRead(parameters, "autos", _autos); + if (!jsonRead(parameters, "OTA", _resolveOTA)) + _resolveOTA = 0; jsonRead(parameters, "receiveMsg", _receiveMsg); jsonRead(parameters, "chatID", _chatID); + _textMode = jsonReadInt(parameters, "textMode"); + fl_rollback = false; instanceBot(); - // _myBot->setTextMode(FB_MARKDOWN); + _myBot->setTextMode(_textMode); _myBot->attach(telegramMsgParse); #ifdef ESP32 @@ -72,6 +88,37 @@ public: if (_receiveMsg && isNetworkActive()) { _myBot->tick(); + if (fl_rollback) + { + _myBot->tickManual(); // Чтобы отметить сообщение прочитанным + if (Update.rollBack()) + { + SerialPrint("I", F("Update"), F("Откат OTA успешно выполнен")); + _myBot->sendMessage("Откат OTA запущен, плата будет перезагружена", _chatID); + ESP.restart(); + } + else + { + SerialPrint("E", F("Update"), F("Откат OTA не выполнен!")); + _myBot->sendMessage("Откат OTA не выполнен!", _chatID); + } + } + // была попытка OTA обновления. Обновляемся после ответа серверу! + if (_OTAstate >= 0) + { + _myBot->tickManual(); // Чтобы отметить сообщение прочитанным + String ota; + if (_OTAstate == 0) + ota = F("Error"); + else if (_OTAstate == 1) + ota = F("No updates"); + else if (_OTAstate == 2) + ota = F("OK"); + _myBot->sendMessage(ota, _chatID); + if (_OTAstate == 2) + ESP.restart(); + _OTAstate = -1; + } } // Далее вызов doByInterval для обработки комманд IoTItem::loop(); @@ -302,6 +349,8 @@ public: //============================================================================= void static telegramMsgParse(FB_msg &msg) { + static String OTAfilepath = ""; + static uint8_t typeOTA = 0; // FB_msg msg; SerialPrint("i", F("Telegram"), "chat ID: " + msg.chatID + ", msg: " + msg.text); // _myBot->setChatID(_chatID); @@ -309,9 +358,114 @@ public: { _chatID = msg.chatID; } + // -------------- Обработка сообщения об откате -------------- + // ------------------------------------------------------------------------- + if (msg.text.indexOf("/rollback") != -1 && msg.chatID == _chatID) + { + _myBot->inlineMenu("Вы уверены, что хотите откатить прошивку? " + jsonReadStr(settingsFlashJson, F("name")) + " \n OTA_roll", F("Rollback \t Cancel")); + } + else if (msg.text.indexOf("OTA_roll") != -1) + { + // удаляем последнее сообщение от бота + _myBot->deleteMessage(_myBot->lastBotMsg()); + if (msg.data.indexOf("Rollback") != -1) + { + if (Update.canRollBack()) + { + fl_rollback = true; + } + else + { + SerialPrint("E", F("Update"), F("Откат OTA не возможен!")); + _myBot->sendMessage("Откат OTA не возможен!", _chatID); + } + } + } + // -------------- Обработка файлов *.bin для прошивки по OTA -------------- + // ------------------------------------------------------------------------- + else if (msg.OTA && _resolveOTA && msg.chatID == _chatID) + { + // _myBot->editMessage(_myBot->lastUsrMsg(), "firmware...", _chatID); + OTAfilepath = msg.fileUrl; + if (msg.fileName.indexOf("littlefs") != -1) + typeOTA = FB_SPIFFS; + else if (msg.fileName.indexOf("firmware") != -1) + typeOTA = FB_FIRMWARE; + else + SerialPrint("E", F("Update"), "Unknown file: " + msg.fileName); + _myBot->inlineMenu("Вы уверены, что хотите прошить плату? " + jsonReadStr(settingsFlashJson, F("name")) + "\n OTA_firmware", F("Firmware \t Cancel")); + } + else if (msg.text.indexOf("OTA_firmware") != -1) + { + // удаляем последнее сообщение от бота + _myBot->deleteMessage(_myBot->lastBotMsg()); + if (msg.data.indexOf("Firmware") != -1) + { + putUserDataToRam(); + if (typeOTA == FB_SPIFFS) + { + if (_updateFS((String *)&OTAfilepath) == 1) + { + saveUserDataToFlash(); + SerialPrint("!!!", F("Update"), "Start upgrade FS... "); + } + else + { + SerialPrint("E", F("Update"), F("FS Path error")); + _myBot->sendMessage("FS Path error!", _chatID); + } + } + else if (typeOTA == FB_FIRMWARE) + { + if (_update((String *)&OTAfilepath) == 1) + { + saveUserDataToFlash(); + SerialPrint("!!!", F("Update"), "Start upgrade BUILD... "); + } + else + { + SerialPrint("E", F("Update"), F("Build Path error")); + _myBot->sendMessage("Build Path error!", _chatID); + } + } + } + OTAfilepath = ""; + typeOTA = 0; + } + // -------------- обработка файлов загруженных пользователем -------------- + // ------------------------------------------------------------------------- + else if (msg.isFile) + { + if (msg.fileName.endsWith(F(".tft")) && msg.chatID == _chatID) + { + OTAfilepath = msg.fileUrl; + _myBot->inlineMenu("Хотите прошить экран Nextion? На esp " + jsonReadStr(settingsFlashJson, F("name")) + "\n Next_firmware", F("Firmware \t Cancel")); + } + else if (msg.text.indexOf("download") != -1 && msg.chatID == _chatID) + { + downloadFile(msg); + } + else if (msg.text.indexOf("Next_firmware") != -1) + { + // удаляем последнее сообщение от бота + _myBot->deleteMessage(_myBot->lastBotMsg()); + if (msg.data.indexOf("Firmware") != -1) + { + for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) + { + if ((*it)->getSubtype() == "NextionUpload" || (*it)->getSubtype() == "Nextion") + { + _myBot->sendMessage("Nextion firmware ...", _chatID); + (*it)->uploadNextionTlgrm(OTAfilepath); + } + } + OTAfilepath = ""; + } + } + } // -------------- Обработка кнопок меню созданного в сценарии -------------- // ------------------------------------------------------------------------- - if (auto search = mapBtnMenu.find(msg.text); search != mapBtnMenu.end()) + else if (auto search = mapBtnMenu.find(msg.text); search != mapBtnMenu.end()) { String outMsg; outMsg = mapBtnMenu[msg.text]->message; @@ -325,7 +479,7 @@ public: } if (mapBtnMenu[msg.text]->setId != "") { - //outMsg += ", " + mapBtnMenu[msg.text]->setId + "=" + mapBtnMenu[msg.text]->value; + // outMsg += ", " + mapBtnMenu[msg.text]->setId + "=" + mapBtnMenu[msg.text]->value; generateOrder(mapBtnMenu[msg.text]->setId, mapBtnMenu[msg.text]->value); } SerialPrint("i", F("Telegram"), "chat ID: " + _chatID + ", msg: " + String(outMsg)); @@ -348,12 +502,12 @@ public: if (item) { outMsg += ": " + item->getValue(); - //SerialPrint("i", F("Telegram"), "chat ID: " + _chatID + ", msg: " + String(msg.data)); + // SerialPrint("i", F("Telegram"), "chat ID: " + _chatID + ", msg: " + String(msg.data)); } } if (mapBtnInline[msg.data]->setId != "") { - //outMsg += ", " + mapBtnInline[msg.data]->setId + "=" + mapBtnInline[msg.data]->value; + // outMsg += ", " + mapBtnInline[msg.data]->setId + "=" + mapBtnInline[msg.data]->value; generateOrder(mapBtnInline[msg.data]->setId, mapBtnInline[msg.data]->value); } SerialPrint("i", F("Telegram"), "chat ID: " + _chatID + ", msg: " + String(outMsg)); @@ -431,7 +585,7 @@ public: } // -------------- вывод инлайн меню всех юнитов -------------- // ------------------------------------------------------------------------- - else if (msg.text.indexOf("all") != -1) + else if (msg.text.indexOf("/all") != -1) { // String list = returnListOfParams(); String out; @@ -460,7 +614,7 @@ public: } // -------------- обработка команды /set_ID_VALUE -------------- // ------------------------------------------------------------------------- - else if (msg.text.indexOf("set") != -1) + else if (msg.text.indexOf("/set") != -1) { msg.text = deleteBeforeDelimiter(msg.text, "_"); generateOrder(selectToMarker(msg.text, "_"), selectToMarkerLast(msg.text, "_")); @@ -469,7 +623,7 @@ public: } // -------------- обработка команды /get_ID -------------- // ------------------------------------------------------------------------- - else if (msg.text.indexOf("get") != -1) + else if (msg.text.indexOf("/get") != -1) { msg.text = deleteBeforeDelimiter(msg.text, "_"); IoTItem *item = findIoTItem(msg.text); @@ -481,52 +635,43 @@ public: } // -------------- обработка запроса пользователя на скачивание файла -------------- // ------------------------------------------------------------------------- - else if (msg.text.indexOf("file") != -1 && msg.chatID == _chatID) + else if (msg.text.indexOf("/file") != -1 && msg.chatID == _chatID) { - msg.text = deleteBeforeDelimiter(msg.text, "_"); - SerialPrint("i", F("Telegram"), "chat ID: " + _chatID + ", get file: " + String(msg.text)); - auto file = FileFS.open(selectToMarker(msg.text, "_"), FILE_READ); // /test.png - if (!file) + if (msg.text.indexOf("file_type") != -1) { - SerialPrint("E", F("Telegram"), "Fail send file: " + selectToMarker(msg.text, "_")); - return; + _myBot->sendMessage("Support file type download: \n 0-foto \n 1-audio \n 2-doc \n 3-video \n 4-gif \n 5-voice", _chatID); } - int type = atoi(selectToMarkerLast(msg.text, "_").c_str()); - _myBot->sendFile(file, (FB_FileType)type, selectToMarker(msg.text, "_"), _chatID); - file.close(); - } - // -------------- обработка файлов загруженных пользователем -------------- - // ------------------------------------------------------------------------- - else if (msg.isFile) - { - if (msg.text.indexOf("download") != -1 && msg.chatID == _chatID) + else { - downloadFile(msg); - } - else if (msg.text.indexOf("nextion") != -1 && msg.chatID == _chatID) - { - for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) + msg.text = deleteBeforeDelimiter(msg.text, "_"); + SerialPrint("i", F("Telegram"), "chat ID: " + _chatID + ", get file: " + String(msg.text)); + auto file = FileFS.open(selectToMarker(msg.text, "_"), FILE_READ); // /test.png + if (!file) { - if ((*it)->getSubtype() == "NextionUpload" || (*it)->getSubtype() == "Nextion") - { - (*it)->uploadNextionTlgrm(msg.fileUrl); - } + SerialPrint("E", F("Telegram"), "Fail send file: " + selectToMarker(msg.text, "_")); + return; } + int type = atoi(selectToMarkerLast(msg.text, "_").c_str()); + _myBot->sendFile(file, (FB_FileType)type, selectToMarker(msg.text, "_"), _chatID); + file.close(); } } // -------------- обработка остальных команд -------------- // ------------------------------------------------------------------------- - else if (msg.text.indexOf("help") != -1) + else if (msg.text.indexOf("/help") != -1) { - _myBot->sendMessage("ID: " + chipId, _chatID); - _myBot->sendMessage("chatID: " + _chatID, _chatID); - _myBot->sendMessage("Command: /help - this text \n /all - inline menu get all values \n /allMenu - bottom menu get all values \n /menu - bottom USER menu from scenario \n /get_id - get value by ID \n /set_id_value - set value in ID \n /file_name_type - take file from esp \n /file_type - support file type \n send file and write download - \"download\" file to esp \n send tft file and write \"nextion\" - flash file.tft to Nextion", _chatID); + if (msg.text.indexOf("/helpDebug") != -1) + { + _myBot->sendMessage("В папке toolchchain с которым собирались (Для esp32 например %%USERPROFILE%/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin) из командной строки Windows (cmd) запустить файл xtensa-esp32-elf-addr2line.exe \nС параметрами -pfiaC -e Путь_к_файлу/firmware.elf Стэк_адресов", _chatID); + } + else + { + _myBot->sendMessage("ID: " + chipId, _chatID); + _myBot->sendMessage("chatID: " + _chatID, _chatID); + _myBot->sendMessage("Command: /help - this text \n /all - inline menu get all values \n /allMenu - bottom menu get all values \n /menu - bottom USER menu from scenario \n /get_id - get value by ID \n /set_id_value - set value in ID \n /file_name_type - take file from esp \n /file_type - support file type \n send file and write download - \"download\" file to esp \n send tft file and write \"nextion\" - flash file.tft to Nextion", _chatID); + } } - else if (msg.text.indexOf("file_type") != -1) - { - _myBot->sendMessage("Support file type download: \n 0-foto \n 1-audio \n 2-doc \n 3-video \n 4-gif \n 5-voice", _chatID); - } - else + else if (msg.text.indexOf("/") != -1) { _myBot->sendMessage("Wrong order, use /help", _chatID); } @@ -638,6 +783,46 @@ public: } mapBtnInline.clear(); } + + // ===================== OTA ===================== + // ОТА обновление, вызывать внутри обработчика сообщения по флагу OTA + uint8_t static _update(String *_file_ptr, __attribute__((unused)) uint8_t type = FB_FIRMWARE) + { +#ifndef FB_NO_OTA + if (!_file_ptr) + return 8; + uint8_t OTAflag = type; + _myBot->sendMessage((type == FB_FIRMWARE) ? F("OTA firmware...") : F("OTA spiffs..."), _chatID); + +#ifdef ESP8266 + ESPhttpUpdate.rebootOnUpdate(false); +#ifdef FB_DYNAMIC + BearSSL::WiFiClientSecure client; + client.setInsecure(); +#endif + if (OTAflag == FB_FIRMWARE) + _OTAstate = ESPhttpUpdate.update(client, *_file_ptr); + else if (OTAflag == FB_SPIFFS) + _OTAstate = ESPhttpUpdate.updateFS(client, *_file_ptr); +#else + WiFiClientSecure client; + client.setInsecure(); + httpUpdate.rebootOnUpdate(false); + if (OTAflag == FB_FIRMWARE) + _OTAstate = httpUpdate.update(client, *_file_ptr); + else if (OTAflag == FB_SPIFFS) + _OTAstate = httpUpdate.updateSpiffs(client, *_file_ptr); +#endif +#endif + return 1; + } + + // ОТА обновление SPIFFS, вызывать внутри обработчика сообщения по флагу OTA + uint8_t static _updateFS(String *_file_ptr) + { + return _update(_file_ptr, FB_SPIFFS); + } + ~Telegram_v2() { clearMapMenu(); diff --git a/src/modules/exec/Telegram_v2/modinfo.json b/src/modules/exec/Telegram_v2/modinfo.json index 6c7e25f1..a3693e42 100644 --- a/src/modules/exec/Telegram_v2/modinfo.json +++ b/src/modules/exec/Telegram_v2/modinfo.json @@ -11,11 +11,12 @@ "page": "", "descr": "", "int": 10, - "token": "", + "chatID": "", "autos": 1, "receiveMsg": 1, - "chatID": "" + "textMode":"0", + "OTA": 0 }], "about": { @@ -24,18 +25,20 @@ "authorGit": "https://github.com/Mit4el", "specialThanks": "", "moduleName": "Telegram_v2", - "moduleVersion": "3.0", + "moduleVersion": "3.1", "usedRam": { "esp32_4mb": 37, "esp8266_4mb": 37 }, "title": "Телеграм-Бот v2", - "moduleDesc": "Добавляет возможность отправлять сообщения от имени бота контакту в Телеграм-чате и получать команды.", + "moduleDesc": "Добавляет возможность отправлять сообщения от имени бота контакту в Телеграм-чате и получать команды. Можно использовать для обновление ОТА, для этого отправить файл firmware.bin или littlefs.bin в чат боту", "propInfo": { "token": "Токен для авторизации бота в системе Telegram", "autos": "Автоматически(1) или нет(0) запоминать ChatID по входящим сообщениям. Т.е. бот будет информировать тех, кто последний прислал сообщение.", "receiveMsg": "Обрабатывать(1) или нет(0) входящие сообщения.", - "chatID": "ИД диалога с контактом. Необходим для отправки сообщений именно вам." + "chatID": "ИД диалога с контактом. Необходим для отправки сообщений именно вам.", + "OTA": "Разрешена(1) или запрещена(0) прошивка через чат бота. Если разрешена, то файл принимается только от пользователя прописанного в chatID или от всех если autos=1", + "textMode": "Разметка оформления сообщения в сообщениях. 0-без оформления, 1-разметка Markdown v2, 2-разметка HTML" }, "funcInfo": [ { @@ -75,12 +78,12 @@ }, { "name": "btnMenu", - "descr": "Описание кнопки меню выводит запросит значение ID и выведит сообщение => Произвольное сообщение(message): значение. Пример: btnMenu(Темп.Дома, Текущая температура, IDbme280)", + "descr": "Описание кнопки меню. По нажатию запросит значение ID и отправит сообщение. ID УКАЗЫВАТЬ В КАВЫЧКАХ! Пример: btnMenu(Темп.Дома, Текущая температура, IDbme280)", "params": ["Name - название кнопки отображается ботом", "message - Произвольное сообщения присылается в ответ на кнопку", "Id - Вернет значение элемента"] }, { "name": "btnMenu", - "descr": "Описание кнопки меню выводит запросит значение getID,установит значение value в setID и выведит сообщение => Произвольное сообщение(message): значение, IDrele=1. ВСЁ УКАЗЫВАТЬ В КАВЫЧКАХ, значение не обязательно! Пример: btnMenu(\"Обогрев\", \"Текущая температура\", \"IDbme280\", \"IDrele\", 1), btnMenu(Свет, Вклбчил свет, \"\", IDrele, 1)", + "descr": "Описание кнопки меню. Установит значение value в setID. При необходимости запросит значение getID и отправит сообщение. ID УКАЗЫВАТЬ В КАВЫЧКАХ! Пример: btnMenu(\"Обогрев\", \"Текущая температура\", \"IDbme280\", \"IDrele\", 1), btnMenu(Свет, Вклбчил свет, \"\", IDrele, 1)", "params": ["Name - название кнопки отображается ботом", "message - Произвольное сообщения присылается в ответ на кнопку", "getId - Вернет значение элемента", "setId - Установит значение элементу", "value - Устанавливаемое значение"] }, { @@ -95,12 +98,12 @@ }, { "name": "btnInline", - "descr": "Описание кнопки встроенного (inline) меню выводит запросит значение ID и выведит сообщение => Произвольное сообщение(message): значение. Пример: btnMenu(Темп.Дома, Текущая температура, IDbme280)", + "descr": "Описание кнопки встроенного (inline) меню. Запросит значение ID и отправит сообщение. ID УКАЗЫВАТЬ В КАВЫЧКАХ! Пример: btnInline(Темп.Дома, Текущая температура, IDbme280)", "params": ["Name - название кнопки отображается ботом", "message - Произвольное сообщения присылается в ответ на кнопку", "Id - Вернет значение элемента"] }, { "name": "btnInline", - "descr": "Описание кнопки встроенного (inline) меню выводит запросит значение getID,установит значение value в setID и выведит сообщение => Произвольное сообщение(message): значение, IDrele=1. ВСЁ УКАЗЫВАТЬ В КАВЫЧКАХ, значение не обязательно! Пример: btnMenu(\"Обогрев\", \"Текущая температура\", \"IDbme280\", \"IDrele\", 1), btnMenu(Свет, Вклбчил свет, \"\", IDrele, 1)", + "descr": "Описание кнопки встроенного (inline) меню выводит. Установит значение value в setID. Запросит значение getID (если указан) и отправит сообщение. ID УКАЗЫВАТЬ В КАВЫЧКАХ! Пример: btnInline(\"Обогрев\", \"Текущая температура\", \"IDbme280\", \"IDrele\", 1), btnMenu(Свет, Вклбчил свет, \"\", IDrele, 1)", "params": ["Name - название кнопки отображается ботом", "message - Произвольное сообщения присылается в ответ на кнопку", "getId - Вернет значение элемента", "setId - Установит значение элементу", "value - Устанавливаемое значение"] }, { @@ -110,12 +113,12 @@ }, { "name": "clearInline", - "descr": "Очистить встроенное (inline) меню, вызвать перед для язменения, перед созданием новых кнопок", + "descr": "Очистить встроенное (inline) меню, вызвать для изменения, перед созданием новых кнопок", "params": [] }, { "name": "clearMenu", - "descr": "Очистить меню, вызвать перед для язменения, перед созданием новых кнопок", + "descr": "Очистить меню, вызвать для изменения, перед созданием новых кнопок", "params": [] } ] diff --git a/src/modules/sensors/BL0937/BL0937.cpp b/src/modules/sensors/BL0937/BL0937.cpp index 2e207813..1e709f06 100644 --- a/src/modules/sensors/BL0937/BL0937.cpp +++ b/src/modules/sensors/BL0937/BL0937.cpp @@ -157,9 +157,12 @@ private: int BL0937_CF_GPIO = 4; // 8266 12 //Нужна возможность задавать пин из веб, это по умолчанию int BL0937_CF1_GPIO = 5; // 8266 13 //Нужна возможность задавать пин из веб, это по умолчанию int BL0937_SEL_GPIO_INV = 12; // 8266 15 // inverted //Нужна возможность задавать пин из веб, это по умолчанию - float _expV = 0; - float _expA = 0; - float _expW = 0; + float _kfV = 0; + float _kfA = 0; + float _kfW = 0; + float expV = 0; + float expA = 0; + float expW = 0; public: BL0937cmd(String parameters) : IoTItem(parameters) @@ -170,24 +173,64 @@ public: jsonRead(parameters, "CF_GPIO", BL0937_CF_GPIO); jsonRead(parameters, "CF1_GPIO", BL0937_CF1_GPIO); jsonRead(parameters, "SEL_GPIO", BL0937_SEL_GPIO_INV); - jsonRead(parameters, "expV", _expV); - jsonRead(parameters, "expA", _expA); - jsonRead(parameters, "expW", _expW); + jsonRead(parameters, "kfV", _kfV); + jsonRead(parameters, "kfA", _kfA); + jsonRead(parameters, "kfW", _kfW); bl0937 = new BL0937; bl0937->begin(BL0937_CF_GPIO, BL0937_CF1_GPIO, BL0937_SEL_GPIO_INV, LOW, true); bl0937->setResistors(CURRENT_RESISTOR, VOLTAGE_RESISTOR_UPSTREAM, VOLTAGE_RESISTOR_DOWNSTREAM); attachInterrupt(BL0937_CF1_GPIO, bl0937_cf1_interrupt, FALLING); attachInterrupt(BL0937_CF_GPIO, bl0937_cf_interrupt, FALLING); - if (_expV) - bl0937->expectedVoltage(_expV); // для калибровки вольтаж нужно вводить из веб интерфейса - if (_expV) - bl0937->expectedCurrent(_expA); // для калибровки можно так, а лучше ток вводить из веб интерфейса - if (_expV) - bl0937->expectedActivePower(_expW); // для калибровки потребляемую мощность нужно вводить из веб интерфейса + if (_kfV) + bl0937->setVoltageMultiplier(_kfV); + if (_kfA) + bl0937->setCurrentMultiplier(_kfA); + if (_kfW) + bl0937->setPowerMultiplier(_kfW); } void doByInterval() { + static bool startCalbr = false; + if (expV && expA && expW) + { + startCalbr = true; + SerialPrint("i", "BL0937", "Start calibration ..."); + } + + if (startCalbr) + { + if (expV && bl0937->getVoltage()) + { + bl0937->expectedVoltage(expV); // для калибровки вольтаж нужно вводить из веб интерфейса + _kfV = bl0937->getVoltageMultiplier(); + expV = 0; + } + if (expA && bl0937->getCurrent()) + { + bl0937->expectedCurrent(expA); // для калибровки можно так, а лучше ток вводить из веб интерфейса + _kfA = bl0937->getCurrentMultiplier(); + expA = 0; + } + if (expW && bl0937->getActivePower()) + { + bl0937->expectedActivePower(expW); // для калибровки потребляемую мощность нужно вводить из веб интерфейса + _kfW = bl0937->getPowerMultiplier(); + expW = 0; + } + if (!expV && !expA && !expW) + { + String str = "Calibration done: kfV="; + str += _kfV; + str += ", kfA="; + str += _kfA; + str += ", kfW="; + str += _kfW; + SerialPrint("i", "BL0937", str); + SerialPrint("i", "BL0937", "Enter multiplier to configuration!"); + startCalbr = false; + } + } } void onModuleOrder(String &key, String &value) @@ -201,27 +244,24 @@ public: } } } - /* - IoTValue execute(String command, std::vector ¶m) - { - if (!bl0937) - return {}; - if (command == "calibration") - { - if (param.size() == 3) - { - float v = param[0].valD; - float a = param[1].valD; - float p = param[2].valD; - bl0937->expectedVoltage(v); // для калибровки вольтаж нужно вводить из веб интерфейса - bl0937->expectedCurrent(a); // для калибровки можно так, а лучше ток вводить из веб интерфейса - bl0937->expectedActivePower(p); // для калибровки потребляемую мощность нужно вводить из веб интерфейса - return {}; - } - } + + IoTValue execute(String command, std::vector ¶m) + { + if (!bl0937) return {}; + if (command == "calibration") + { + if (param.size() == 3) + { + expV = param[0].valD; + expA = param[1].valD; + expW = param[2].valD; + return {}; + } } - */ + return {}; + } + ~BL0937cmd() { if (bl0937) diff --git a/src/modules/sensors/BL0937/BL0937lib.cpp b/src/modules/sensors/BL0937/BL0937lib.cpp index d4b46e55..a54e68b4 100644 --- a/src/modules/sensors/BL0937/BL0937lib.cpp +++ b/src/modules/sensors/BL0937/BL0937lib.cpp @@ -74,6 +74,7 @@ double BL0937::getCurrent() { // so we first check if power is 0 to set _current to 0 too if (_power == 0) { _current_pulse_width = 0; + getActivePower(); } else if (_use_interrupts) { _checkCF1Signal(); diff --git a/src/modules/sensors/BL0937/modinfo.json b/src/modules/sensors/BL0937/modinfo.json index d9be43f7..b458c34b 100644 --- a/src/modules/sensors/BL0937/modinfo.json +++ b/src/modules/sensors/BL0937/modinfo.json @@ -42,7 +42,7 @@ "name": "BL0937 Реакт.Мощность", "type": "Reading", "subtype": "BL0937reactw", - "id": "bl_w", + "id": "bl_reactw", "widget": "anydataWt", "page": "BL0937", "descr": "Реакт.Мощность", @@ -83,15 +83,16 @@ "page": "", "descr": "", "btn-reset": "", + "int": "5", "R_current": 0.001, "R_upstream": 1000000, "R_downstream": 1000, "CF_GPIO": 4, "CF1_GPIO": 5, "SEL_GPIO": 12, - "expV": 0, - "expA": 0, - "expW": 0 + "kfV": 0, + "kfA": 0, + "kfW": 0 } ], "about": { @@ -108,7 +109,7 @@ "title": "Счетчик электроэнергии BL0937", "moduleDesc": "Считает потраченную электроэнергию, измеряет напряжение, силу тока и прочие параметры.", "propInfo": { - "int": "Количество секунд между опросами датчика.", + "int": "Количество секунд между опросами датчика. В bl_set интервал между попытками калибровки (т.к. нужны сначала данные от датчика)", "btn-reset": "Энергия BL0937 будет сброшена к нулю.", "R_current": "Резистор подключенный последовательно к основной линии", "R_upstream": "это 5 резисторов по 470 Ком в делителе напряжения, который питает вывод V2P", @@ -116,10 +117,17 @@ "CF_GPIO": "пин CF", "CF1_GPIO": "пин CF1", "SEL_GPIO": "пин SEL", - "expV": "реальное напряжение, указать для калибровки", - "expA": "реальный ток, указать для калибровки", - "expW": "реальная мощность, указать для калибровки" - } + "kfV": "Коэффициент корректировки напряжение, указать после калибровки", + "kfA": "Коэффициент корректировки тока, указать после калибровки", + "kfW": "Коэффициент корректировки мощности, указать после калибровки" + }, + "funcInfo": [ + { + "name": "calibration", + "descr": "Расчет коэффициентов калибровки. Вызывать от имени BL0937 настройка. bl_set.calibration(220, 16, 3.5). Полученный коэффициенты искать в логе и ввести в конфигурацию kfV, kfA и kfW", + "params": ["Напряжение, Ток, Мощность"] + } + ] }, "defActive": true, "usedLibs": { diff --git a/src/modules/sensors/Hx710/Hx710.cpp b/src/modules/sensors/Hx710/Hx710.cpp index 210cef75..9d357b2d 100644 --- a/src/modules/sensors/Hx710/Hx710.cpp +++ b/src/modules/sensors/Hx710/Hx710.cpp @@ -11,11 +11,12 @@ class HX710b : public IoTItem { public: HX710b(String parameters) : IoTItem(parameters) { - int data, clock; + int data, clock, gain; jsonRead(parameters, "data", data); jsonRead(parameters, "clock", clock); + jsonRead(parameters, "gain", gain); - pressure_sensor.begin(data, clock); + pressure_sensor.begin(data, clock, gain); pressure_sensor.tare(); }