From b4919bddd68312fd0bd6bba73bcd991b4361451d Mon Sep 17 00:00:00 2001 From: Mit4el Date: Mon, 26 Feb 2024 23:29:02 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9C=D0=BE=D0=B4=D1=83=D0=BB=D1=8C=20Benchmar?= =?UTF-8?q?k?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/ESPConfiguration.h | 1 + include/Global.h | 3 + include/classes/IoTBench.h | 30 + include/classes/IoTItem.h | 6 + src/ESPConfiguration.cpp | 7 +- src/Global.cpp | 2 + src/Main.cpp | 24 +- src/modules/exec/OpenThermSlave/OpenTherm.cpp | 812 ------------------ src/modules/exec/OpenThermSlave/OpenTherm.h | 208 ----- .../exec/OpenThermSlave/OpenThermSlave.cpp | 589 ------------- src/modules/exec/OpenThermSlave/modinfo.json | 111 --- src/modules/virtual/Benchmark/Benchmark.cpp | 165 ++++ src/modules/virtual/Benchmark/modinfo.json | 69 ++ 13 files changed, 297 insertions(+), 1730 deletions(-) create mode 100644 include/classes/IoTBench.h delete mode 100644 src/modules/exec/OpenThermSlave/OpenTherm.cpp delete mode 100644 src/modules/exec/OpenThermSlave/OpenTherm.h delete mode 100644 src/modules/exec/OpenThermSlave/OpenThermSlave.cpp delete mode 100644 src/modules/exec/OpenThermSlave/modinfo.json create mode 100644 src/modules/virtual/Benchmark/Benchmark.cpp create mode 100644 src/modules/virtual/Benchmark/modinfo.json diff --git a/include/ESPConfiguration.h b/include/ESPConfiguration.h index 1e185219..7832008f 100644 --- a/include/ESPConfiguration.h +++ b/include/ESPConfiguration.h @@ -7,3 +7,4 @@ extern std::list IoTItems; // вектор ссылок базово extern void configure(String path); void clearConfigure(); extern IoTItem* myIoTItem; +extern IoTBench* myIoTBernch; diff --git a/include/Global.h b/include/Global.h index 4922d660..ac94ead5 100644 --- a/include/Global.h +++ b/include/Global.h @@ -50,6 +50,7 @@ #include "utils/StringUtils.h" #include "PeriodicTasks.h" #include "classes/IoTGpio.h" +#include "classes/IoTBench.h" /********************************************************************************************************************* *****************************************глобальные объекты классов*************************************************** @@ -58,6 +59,8 @@ extern IoTGpio IoTgpio; extern IoTItem* rtcItem; //extern IoTItem* camItem; extern IoTItem* tlgrmItem; +extern IoTBench* benchLoadItem; +extern IoTBench* benchTaskItem; extern TickerScheduler ts; extern WiFiClient espClient; diff --git a/include/classes/IoTBench.h b/include/classes/IoTBench.h new file mode 100644 index 00000000..d8743d72 --- /dev/null +++ b/include/classes/IoTBench.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include "Global.h" +#include "classes/IoTItem.h" +#include + +struct ItemBench +{ + uint32_t sumloopTime = 0; + uint32_t loopTime = 0; + uint32_t loopTimeMax_p = 0; + uint32_t loopTimeMax_glob = 0; + uint32_t count = 0; +}; + + + +class IoTBench : public IoTItem +{ +public: + IoTBench(const String ¶meters); + ~IoTBench(); + + virtual void preLoadFunction(); + virtual void postLoadFunction(); + virtual void preTaskFunction(const String &id); + virtual void postTaskFunction(const String &id); +protected: +std::map banchItems; +}; \ No newline at end of file diff --git a/include/classes/IoTItem.h b/include/classes/IoTItem.h index 8eab3261..cfdb33e2 100644 --- a/include/classes/IoTItem.h +++ b/include/classes/IoTItem.h @@ -1,5 +1,8 @@ #pragma once #include "classes/IoTGpio.h" +//#include "classes/IoTBench.h" + +class IoTBench; struct IoTValue { float valD = 0; @@ -53,6 +56,9 @@ class IoTItem { virtual IoTItem* getRtcDriver(); //virtual IoTItem* getCAMDriver(); virtual IoTItem* getTlgrmDriver(); + //virtual IoTBench* getBenchmark(); + virtual IoTBench*getBenchmarkTask(); + virtual IoTBench*getBenchmarkLoad(); virtual unsigned long getRtcUnixTime(); // делаем доступным модулям отправку сообщений в телеграм diff --git a/src/ESPConfiguration.cpp b/src/ESPConfiguration.cpp index d0ee0bc8..fa15b2a1 100644 --- a/src/ESPConfiguration.cpp +++ b/src/ESPConfiguration.cpp @@ -33,6 +33,9 @@ void configure(String path) { if (driver = myIoTItem->getRtcDriver()) rtcItem = (IoTItem*)driver; // пробуем спросить драйвер CAM //if (driver = myIoTItem->getCAMDriver()) camItem = (IoTItem*)driver; + // пробуем спросить драйвер Benchmark + if (driver = myIoTItem->getBenchmarkTask()) benchTaskItem = ((IoTBench*)driver); + if (driver = myIoTItem->getBenchmarkLoad()) benchLoadItem = ((IoTBench*)driver); // пробуем спросить драйвер Telegram_v2 if (driver = myIoTItem->getTlgrmDriver()) tlgrmItem = (IoTItem*)driver; IoTItems.push_back(myIoTItem); @@ -48,7 +51,7 @@ void clearConfigure() { Serial.printf("Start clearing config\n"); rtcItem = nullptr; //camItem = nullptr; - tlgrmItem = nullptr; + tlgrmItem = nullptr; IoTgpio.clearDrivers(); for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { @@ -58,4 +61,6 @@ void clearConfigure() { IoTItems.clear(); valuesFlashJson.clear(); + benchTaskItem = nullptr; + benchLoadItem = nullptr; } \ No newline at end of file diff --git a/src/Global.cpp b/src/Global.cpp index 1130691c..7f6fe4d1 100644 --- a/src/Global.cpp +++ b/src/Global.cpp @@ -33,6 +33,8 @@ IoTGpio IoTgpio(0); IoTItem* rtcItem = nullptr; //IoTItem* camItem = nullptr; IoTItem* tlgrmItem = nullptr; +IoTBench* benchTaskItem = nullptr; +IoTBench* benchLoadItem = nullptr; String settingsFlashJson = "{}"; // переменная в которой хранятся все настройки, находится в оперативной памяти и синхронизированна с flash памятью String valuesFlashJson = "{}"; // переменная в которой хранятся все значения элементов, которые необходимо сохранить на flash. Находится в оперативной памяти и синхронизированна с flash памятью String errorsHeapJson = "{}"; // переменная в которой хранятся все ошибки, находится в оперативной памяти только diff --git a/src/Main.cpp b/src/Main.cpp index 75341d64..6e076812 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -16,8 +16,9 @@ String volStrForSave = ""; void elementsLoop() { // передаем управление каждому элементу конфигурации для выполнения своих функций for (std::list::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) { + if (benchTaskItem) benchTaskItem->preTaskFunction((*it)->getID()); (*it)->loop(); - + if (benchTaskItem) benchTaskItem->postTaskFunction((*it)->getID()); // if ((*it)->iAmDead) { if (!((*it)->iAmLocal) && (*it)->getIntFromNet() == -1) { delete *it; @@ -150,13 +151,13 @@ void setup() { iotScen.loadScenario("/scenario.txt"); // создаем событие завершения инициализации основных моментов для возможности выполнения блока кода при загрузке createItemFromNet("onInit", "1", 1); - elementsLoop(); +// elementsLoop(); //Для работы MQTT Брокера перенес ниже, иначе брокер падает если вызван до routerConnect(); stopErrorMarker(SETUPSCEN_ERRORMARKER); initErrorMarker(SETUPINET_ERRORMARKER); - // подключаемся к роутеру +// подключаемся к роутеру routerConnect(); // инициализация асинхронного веб сервера и веб сокетов @@ -179,6 +180,7 @@ void setup() { initErrorMarker(SETUPLAST_ERRORMARKER); + elementsLoop(); // NTP ntpInit(); @@ -224,31 +226,35 @@ void loop() { #ifdef LOOP_DEBUG unsigned long st = millis(); #endif - + if (benchLoadItem) benchLoadItem->preLoadFunction(); + if (benchTaskItem) benchTaskItem->preTaskFunction("TickerScheduler"); initErrorMarker(TICKER_ERRORMARKER); ts.update(); stopErrorMarker(TICKER_ERRORMARKER); - + if (benchTaskItem) benchTaskItem->postTaskFunction("TickerScheduler"); + if (benchTaskItem) benchTaskItem->preTaskFunction("webServer"); #ifdef STANDARD_WEB_SERVER initErrorMarker(HTTP_ERRORMARKER); HTTP.handleClient(); stopErrorMarker(HTTP_ERRORMARKER); #endif - + if (benchTaskItem) benchTaskItem->postTaskFunction("webServer"); + if (benchTaskItem) benchTaskItem->preTaskFunction("webSocket"); #ifdef STANDARD_WEB_SOCKETS initErrorMarker(SOCKETS_ERRORMARKER); standWebSocket.loop(); stopErrorMarker(SOCKETS_ERRORMARKER); #endif - + if (benchTaskItem) benchTaskItem->postTaskFunction("webSocket"); + if (benchTaskItem) benchTaskItem->preTaskFunction("mqtt"); initErrorMarker(MQTT_ERRORMARKER); mqttLoop(); stopErrorMarker(MQTT_ERRORMARKER); - + if (benchTaskItem) benchTaskItem->postTaskFunction("mqtt"); initErrorMarker(MODULES_ERRORMARKER); elementsLoop(); stopErrorMarker(MODULES_ERRORMARKER); - + if (benchLoadItem) benchLoadItem->postLoadFunction(); // #ifdef LOOP_DEBUG // loopPeriod = millis() - st; // if (loopPeriod > 2) Serial.println(loopPeriod); diff --git a/src/modules/exec/OpenThermSlave/OpenTherm.cpp b/src/modules/exec/OpenThermSlave/OpenTherm.cpp deleted file mode 100644 index 8f6f7467..00000000 --- a/src/modules/exec/OpenThermSlave/OpenTherm.cpp +++ /dev/null @@ -1,812 +0,0 @@ -/* -OpenTherm.cpp - OpenTherm Communication Library For Arduino, ESP8266 -Copyright 2018, Ihor Melnyk -*/ - -#include "OpenTherm.h" - -OpenTherm::OpenTherm(int inPin, int outPin, bool isSlave) : status(OpenThermStatus::NOT_INITIALIZED), - inPin(inPin), - outPin(outPin), - isSlave(isSlave), - response(0), - responseStatus(OpenThermResponseStatus::NONE), - responseTimestamp(0), - handleInterruptCallback(NULL), - processResponseCallback(NULL) -{ - imitFlag = false; -} - -void OpenTherm::begin(void (*handleInterruptCallback)(void), void (*processResponseCallback)(unsigned long, OpenThermResponseStatus)) -{ - pinMode(inPin, INPUT); - pinMode(outPin, OUTPUT); - if (handleInterruptCallback != NULL) - { - this->handleInterruptCallback = handleInterruptCallback; - attachInterrupt(digitalPinToInterrupt(inPin), handleInterruptCallback, CHANGE); - } - activateBoiler(); - status = OpenThermStatus::READY; - this->processResponseCallback = processResponseCallback; -} - -void OpenTherm::begin(void (*handleInterruptCallback)(void)) -{ - begin(handleInterruptCallback, NULL); -} - -bool IRAM_ATTR OpenTherm::isReady() -{ - return status == OpenThermStatus::READY; -} - -int IRAM_ATTR OpenTherm::readState() -{ - return digitalRead(inPin); -} - -void OpenTherm::setActiveState() -{ - digitalWrite(outPin, LOW); -} - -void OpenTherm::setIdleState() -{ - digitalWrite(outPin, HIGH); -} - -void OpenTherm::activateBoiler() -{ - setIdleState(); - delay(1000); -} - -void OpenTherm::sendBit(bool high) -{ - if (high) - setActiveState(); - else - setIdleState(); - delayMicroseconds(500); - if (high) - setIdleState(); - else - setActiveState(); - delayMicroseconds(500); -} - -bool OpenTherm::sendRequestAync(unsigned long request) -{ - // Serial.println("Request: " + String(request, HEX)); - noInterrupts(); - const bool ready = isReady(); - interrupts(); - - if (!ready) - return false; - - status = OpenThermStatus::REQUEST_SENDING; - response = 0; - responseStatus = OpenThermResponseStatus::NONE; -// Prevent switching to other tasks as there is a delay within sendBit -#ifdef ESP32 -// vTaskSuspendAll(); -#endif - sendBit(HIGH); // start bit - for (int i = 31; i >= 0; i--) - { - sendBit(bitRead(request, i)); - } - sendBit(HIGH); // stop bit - setIdleState(); -#ifdef ESP32 -// xTaskResumeAll(); -#endif - status = OpenThermStatus::RESPONSE_WAITING; - responseTimestamp = micros(); - if (imitFlag) - ImitationResponse(request); - return true; -} - -unsigned long OpenTherm::sendRequest(unsigned long request) -{ - if (!sendRequestAync(request)) - return 0; - while (!isReady()) - { - process(); - yield(); - } - return response; -} - -bool OpenTherm::sendResponse(unsigned long request) -{ - status = OpenThermStatus::REQUEST_SENDING; - response = 0; - responseStatus = OpenThermResponseStatus::NONE; - // Prevent switching to other tasks as there is a delay within sendBit -#ifdef ESP32 -// vTaskSuspendAll(); -#endif - sendBit(HIGH); // start bit - for (int i = 31; i >= 0; i--) - { - sendBit(bitRead(request, i)); - } - sendBit(HIGH); // stop bit - setIdleState(); -#ifdef ESP32 -// xTaskResumeAll(); -#endif - status = OpenThermStatus::READY; - return true; -} - -unsigned long OpenTherm::getLastResponse() -{ - return response; -} - -OpenThermResponseStatus OpenTherm::getLastResponseStatus() -{ - return responseStatus; -} - -void IRAM_ATTR OpenTherm::handleInterrupt() -{ - if (isReady()) - { - if (isSlave && readState() == HIGH) - { - status = OpenThermStatus::RESPONSE_WAITING; - } - else - { - return; - } - } - - unsigned long newTs = micros(); - if (status == OpenThermStatus::RESPONSE_WAITING) - { - if (readState() == HIGH) - { - status = OpenThermStatus::RESPONSE_START_BIT; - responseTimestamp = newTs; - } - else - { - // Error start bit / Ошибка стартового бита - status = OpenThermStatus::RESPONSE_INVALID; - responseTimestamp = newTs; - } - } - else if (status == OpenThermStatus::RESPONSE_START_BIT) - { - if ((newTs - responseTimestamp < 750) && readState() == LOW) - { - status = OpenThermStatus::RESPONSE_RECEIVING; - responseTimestamp = newTs; - responseBitIndex = 0; - } - else - { - // Error Start_bit LOW 750mks / Ошибка стартового бита по тылу (нет LOW через 750мкс) - status = OpenThermStatus::RESPONSE_INVALID; - responseTimestamp = newTs; - } - } - else if (status == OpenThermStatus::RESPONSE_RECEIVING) - { - // unsigned long bitDuration = newTs - responseTimestamp; - // В новой спецификации стоповый бит не обязателен. Если не дождались, всё равно попробуем разобрать - if ((newTs - responseTimestamp) > 750 && (newTs - responseTimestamp) < 1300) - { - if (responseBitIndex < 32) - { - response = (response << 1) | !readState(); - responseTimestamp = newTs; - responseBitIndex++; - } - else - { // stop bit - status = OpenThermStatus::RESPONSE_READY; - responseTimestamp = newTs; - } - } - } -} - -void OpenTherm::process() -{ - noInterrupts(); - OpenThermStatus st = status; - unsigned long ts = responseTimestamp; - interrupts(); - - if (st == OpenThermStatus::READY) - return; - unsigned long newTs = micros(); - if (st != OpenThermStatus::NOT_INITIALIZED && st != OpenThermStatus::DELAY && (newTs - ts) > 1000000) - { - status = OpenThermStatus::READY; - responseStatus = OpenThermResponseStatus::TIMEOUT; - if (processResponseCallback != NULL) - { - processResponseCallback(response, responseStatus); - } - } - else if (st == OpenThermStatus::RESPONSE_INVALID) - { - status = OpenThermStatus::DELAY; - responseStatus = OpenThermResponseStatus::INVALID; - if (processResponseCallback != NULL) - { - processResponseCallback(response, responseStatus); - } - } - else if (st == OpenThermStatus::RESPONSE_READY) - { - status = OpenThermStatus::DELAY; - responseStatus = (isSlave ? isValidRequest(response) : isValidResponse(response)) ? OpenThermResponseStatus::SUCCESS : OpenThermResponseStatus::INVALID; - // Error msgType (READ_ACK | WRITE_ACK) is Header - if (processResponseCallback != NULL) - { - processResponseCallback(response, responseStatus); - } - } - else if (st == OpenThermStatus::DELAY) - { - if ((newTs - ts) > 100000) - { - status = OpenThermStatus::READY; - } - } -} - -bool OpenTherm::parity(unsigned long frame) // odd parity -{ - byte p = 0; - while (frame > 0) - { - if (frame & 1) - p++; - frame = frame >> 1; - } - return (p & 1); -} - -OpenThermMessageType OpenTherm::getMessageType(unsigned long message) -{ - OpenThermMessageType msg_type = static_cast((message >> 28) & 7); - return msg_type; -} - -OpenThermMessageID OpenTherm::getDataID(unsigned long frame) -{ - return (OpenThermMessageID)((frame >> 16) & 0xFF); -} - -unsigned long OpenTherm::buildRequest(OpenThermMessageType type, OpenThermMessageID id, unsigned int data) -{ - unsigned long request = data; - if (type == OpenThermMessageType::WRITE_DATA) - { - request |= 1ul << 28; - } - request |= ((unsigned long)id) << 16; - if (parity(request)) - request |= (1ul << 31); - return request; -} -unsigned long OpenTherm::buildRequestID(OpenThermMessageType type, unsigned int id, unsigned int data) -{ - unsigned long request = data; - if (type == OpenThermMessageType::WRITE_DATA) - { - request |= 1ul << 28; - } - request |= ((unsigned long)id) << 16; - if (parity(request)) - request |= (1ul << 31); - return request; -} - -unsigned long OpenTherm::buildResponse(OpenThermMessageType type, OpenThermMessageID id, unsigned int data) -{ - unsigned long response = data; - response |= ((unsigned long)type) << 28; - response |= ((unsigned long)id) << 16; - if (parity(response)) - response |= (1ul << 31); - return response; -} - -bool OpenTherm::isValidResponse(unsigned long response) -{ - if (parity(response)) - return false; - byte msgType = (response << 1) >> 29; - return msgType == READ_ACK || msgType == WRITE_ACK; -} - -bool OpenTherm::isValidRequest(unsigned long request) -{ - if (parity(request)) - return false; - byte msgType = (request << 1) >> 29; - return msgType == READ_DATA || msgType == WRITE_DATA; -} - -void OpenTherm::end() -{ - if (this->handleInterruptCallback != NULL) - { - detachInterrupt(digitalPinToInterrupt(inPin)); - } -} - -const char *OpenTherm::statusToString(OpenThermResponseStatus status) -{ - switch (status) - { - case NONE: - return "NONE"; - case SUCCESS: - return "SUCCESS"; - case INVALID: - return "INVALID"; - case TIMEOUT: - return "TIMEOUT"; - default: - return "UNKNOWN"; - } -} - -const char *OpenTherm::messageTypeToString(OpenThermMessageType message_type) -{ - switch (message_type) - { - case READ_DATA: - return "READ_DATA"; - case WRITE_DATA: - return "WRITE_DATA"; - case INVALID_DATA: - return "INVALID_DATA"; - case RESERVED: - return "RESERVED"; - case READ_ACK: - return "READ_ACK"; - case WRITE_ACK: - return "WRITE_ACK"; - case DATA_INVALID: - return "DATA_INVALID"; - case UNKNOWN_DATA_ID: - return "UNKNOWN_DATA_ID"; - default: - return "UNKNOWN"; - } -} - -// building requests - -unsigned long OpenTherm::buildSetBoilerStatusRequest(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2, bool enableSummerMode, bool dhwBlock) -{ - unsigned int data = enableCentralHeating | (enableHotWater << 1) | (enableCooling << 2) | (enableOutsideTemperatureCompensation << 3) | (enableCentralHeating2 << 4) | (enableSummerMode << 5) | (dhwBlock << 6); - data <<= 8; - return buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Status, data); -} - -unsigned long OpenTherm::buildSetBoilerTemperatureRequest(float temperature) -{ - unsigned int data = temperatureToData(temperature); - return buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::TSet, data); -} - -unsigned long OpenTherm::buildGetBoilerTemperatureRequest() -{ - return buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Tboiler, 0); -} - -// parsing responses -bool OpenTherm::isFault(unsigned long response) -{ - return response & 0x1; -} - -bool OpenTherm::isCentralHeatingActive(unsigned long response) -{ - return response & 0x2; -} - -bool OpenTherm::isHotWaterActive(unsigned long response) -{ - return response & 0x4; -} - -bool OpenTherm::isFlameOn(unsigned long response) -{ - return response & 0x8; -} - -bool OpenTherm::isCoolingActive(unsigned long response) -{ - return response & 0x10; -} - -bool OpenTherm::isDiagnostic(unsigned long response) -{ - return response & 0x40; -} - -uint16_t OpenTherm::getUInt(const unsigned long response) const -{ - const uint16_t u88 = response & 0xffff; - return u88; -} - -float OpenTherm::getFloat(const unsigned long response) const -{ - const uint16_t u88 = getUInt(response); - const float f = (u88 & 0x8000) ? -(0x10000L - u88) / 256.0f : u88 / 256.0f; - return f; -} - -unsigned int OpenTherm::temperatureToData(float temperature) -{ - if (temperature < 0) - temperature = 0; - if (temperature > 100) - temperature = 100; - unsigned int data = (unsigned int)(temperature * 256); - return data; -} - -// basic requests - -unsigned long OpenTherm::setBoilerStatus(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2, bool enableSummerMode, bool dhwBlock) -{ - return sendRequest(buildSetBoilerStatusRequest(enableCentralHeating, enableHotWater, enableCooling, enableOutsideTemperatureCompensation, enableCentralHeating2, enableSummerMode, dhwBlock)); -} - -bool OpenTherm::setBoilerTemperature(float temperature) -{ - unsigned long response = sendRequest(buildSetBoilerTemperatureRequest(temperature)); - return isValidResponse(response); -} - -float OpenTherm::getBoilerTemperature() -{ - unsigned long response = sendRequest(buildGetBoilerTemperatureRequest()); - return isValidResponse(response) ? getFloat(response) : 0; -} - -float OpenTherm::getReturnTemperature() -{ - unsigned long response = sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Tret, 0)); - return isValidResponse(response) ? getFloat(response) : 0; -} - -bool OpenTherm::setDHWSetpoint(float temperature) -{ - unsigned int data = temperatureToData(temperature); - unsigned long response = sendRequest(buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::TdhwSet, data)); - return isValidResponse(response); -} - -float OpenTherm::getDHWTemperature() -{ - unsigned long response = sendRequest(buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Tdhw, 0)); - return isValidResponse(response) ? getFloat(response) : 0; -} - -float OpenTherm::getModulation() -{ - unsigned long response = sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::RelModLevel, 0)); - return isValidResponse(response) ? getFloat(response) : 0; -} - -float OpenTherm::getPressure() -{ - unsigned long response = sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::CHPressure, 0)); - return isValidResponse(response) ? getFloat(response) : 0; -} - -unsigned char OpenTherm::getFault() -{ - return ((sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::ASFflags, 0)) >> 8) & 0xff); -} -int8_t flame_timer = 0; -void OpenTherm::ImitationResponse(unsigned long request) -{ - - // unsigned long response; - unsigned int data = getUInt(request); - OpenThermMessageType msgType; - byte ID; - OpenThermMessageID id = getDataID(request); - uint8_t flags; - - switch (id) - { - case OpenThermMessageID::Status: - // Статус котла получен - msgType = OpenThermMessageType::READ_ACK; - static int8_t flame = 0; - flame_timer++; - if (flame_timer > 10) - flame = 1; - if (flame_timer > 20) - { - flame_timer = 0; - flame = 0; - } - static int8_t fault = 0; - // fault = 1 - fault; - data = (bool)fault | (true << 1) | (true << 2) | ((bool)flame << 3) | (false << 4); - break; - case OpenThermMessageID::SConfigSMemberIDcode: - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::SlaveVersion: - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::MasterVersion: - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::RelModLevel: - static float RelModLevel = 10; - // RelModLevel = RelModLevel > 100 ? 10 : RelModLevel + 1; - if (flame_timer < 11) - { - RelModLevel = 0; - } - else - { - RelModLevel = RelModLevel == 0 ? 10 : RelModLevel + 1; - } - // data = RelModLevel; - data = temperatureToData(RelModLevel); - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::Tboiler: - // Получили температуру котла - static float Tboiler = 40; - Tboiler = Tboiler > 60 ? 40 : Tboiler + 1; - data = temperatureToData(Tboiler); - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::Tdhw: - // Получили температуру ГВС - static float Tdhw = 60; - Tdhw = Tdhw > 80 ? 60 : Tdhw + 1; - data = temperatureToData(Tdhw); - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::Toutside: - // Получили внешнюю температуру - static float Toutside = -10; - Toutside = Toutside > 10 ? -10 : Toutside + 1; - data = temperatureToData(Toutside); - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::ASFflags: - msgType = OpenThermMessageType::READ_ACK; - break; - - case OpenThermMessageID::TdhwSetUBTdhwSetLB: - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::MaxTSetUBMaxTSetLB: - msgType = OpenThermMessageType::READ_ACK; - break; - - case OpenThermMessageID::OEMDiagnosticCode: - msgType = OpenThermMessageType::READ_ACK; - break; - - case OpenThermMessageID::OpenThermVersionSlave: - msgType = OpenThermMessageType::READ_ACK; - break; - - case OpenThermMessageID::CHPressure: - msgType = OpenThermMessageType::READ_ACK; - break; - - break; - case OpenThermMessageID::DHWFlowRate: - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::DayTime: - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::Date: - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::Year: - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - - case OpenThermMessageID::Tret: - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::Tstorage: - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::Tcollector: - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::TflowCH2: - // - msgType = OpenThermMessageType::READ_ACK; - - break; - case OpenThermMessageID::Tdhw2: - // - msgType = OpenThermMessageType::READ_ACK; - - break; - case OpenThermMessageID::Texhaust: - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::TheatExchanger: - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::BoilerFanSpeed: - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::ElectricBurnerFlame: - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::BurnerStarts: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::CHPumpStarts: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::DHWPumpValveStarts: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::DHWBurnerStarts: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::BurnerOperationHours: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::CHPumpOperationHours: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::DHWPumpValveOperationHours: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::DHWBurnerOperationHours: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::RBPflags: - // - // Pre-Defined Remote Boiler Parameters - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::TdhwSet: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::TSet: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::MaxTSet: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::Hcratio: - // - if (getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::TSP: - // - // Transparent Slave Parameters - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::FHBsize: - // - // Fault History Data - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::MaxCapacityMinModLevel: - // - // Boiler Sequencer Control - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::TrOverride: - // - // Remote override room setpoint - // - msgType = OpenThermMessageType::READ_ACK; - break; - case OpenThermMessageID::RemoteOverrideFunction: - msgType = OpenThermMessageType::READ_ACK; - break; - - default: - msgType = OpenThermMessageType::UNKNOWN_DATA_ID; - break; - } - response = buildResponse(msgType, id, data); - status = OpenThermStatus::RESPONSE_READY; - responseStatus = OpenThermResponseStatus::SUCCESS; - /* - if (processResponseCallback != NULL) - { - processResponseCallback(response, OpenThermResponseStatus::SUCCESS); - } - */ -} \ No newline at end of file diff --git a/src/modules/exec/OpenThermSlave/OpenTherm.h b/src/modules/exec/OpenThermSlave/OpenTherm.h deleted file mode 100644 index aeea5d1b..00000000 --- a/src/modules/exec/OpenThermSlave/OpenTherm.h +++ /dev/null @@ -1,208 +0,0 @@ -/* -OpenTherm.h - OpenTherm Library for the ESP8266/Arduino platform -https://github.com/ihormelnyk/OpenTherm -http://ihormelnyk.com/pages/OpenTherm -Licensed under MIT license -Copyright 2018, Ihor Melnyk - -Frame Structure: -P MGS-TYPE SPARE DATA-ID DATA-VALUE -0 000 0000 00000000 00000000 00000000 -*/ - -#ifndef OpenTherm_h -#define OpenTherm_h - -#include -#include - -enum OpenThermResponseStatus : uint8_t -{ - NONE, - SUCCESS, - INVALID, - TIMEOUT -}; - -enum OpenThermMessageType : uint8_t -{ - /* Master to Slave */ - READ_DATA = B000, - READ = READ_DATA, // for backwared compatibility - WRITE_DATA = B001, - WRITE = WRITE_DATA, // for backwared compatibility - INVALID_DATA = B010, - RESERVED = B011, - /* Slave to Master */ - READ_ACK = B100, - WRITE_ACK = B101, - DATA_INVALID = B110, - UNKNOWN_DATA_ID = B111 -}; - -typedef OpenThermMessageType OpenThermRequestType; // for backwared compatibility - -enum OpenThermMessageID : uint8_t -{ - Status, // flag8 / flag8 Master and Slave Status flags. - TSet, // f8.8 Control setpoint ie CH water temperature setpoint (°C) - MConfigMMemberIDcode, // flag8 / u8 Master Configuration Flags / Master MemberID Code - SConfigSMemberIDcode, // flag8 / u8 Slave Configuration Flags / Slave MemberID Code - Command, // u8 / u8 Remote Command - ASFflags, // / OEM-fault-code flag8 / u8 Application-specific fault flags and OEM fault code - RBPflags, // flag8 / flag8 Remote boiler parameter transfer-enable & read/write flags - CoolingControl, // f8.8 Cooling control signal (%) - TsetCH2, // f8.8 Control setpoint for 2e CH circuit (°C) - TrOverride, // f8.8 Remote override room setpoint - TSP, // u8 / u8 Number of Transparent-Slave-Parameters supported by slave - TSPindexTSPvalue, // u8 / u8 Index number / Value of referred-to transparent slave parameter. - FHBsize, // u8 / u8 Size of Fault-History-Buffer supported by slave - FHBindexFHBvalue, // u8 / u8 Index number / Value of referred-to fault-history buffer entry. - MaxRelModLevelSetting, // f8.8 Maximum relative modulation level setting (%) - MaxCapacityMinModLevel, // u8 / u8 Maximum boiler capacity (kW) / Minimum boiler modulation level(%) - TrSet, // f8.8 Room Setpoint (°C) - RelModLevel, // f8.8 Relative Modulation Level (%) - CHPressure, // f8.8 Water pressure in CH circuit (bar) - DHWFlowRate, // f8.8 Water flow rate in DHW circuit. (litres/minute) - DayTime, // special / u8 Day of Week and Time of Day - Date, // u8 / u8 Calendar date - Year, // u16 Calendar year - TrSetCH2, // f8.8 Room Setpoint for 2nd CH circuit (°C) - Tr, // f8.8 Room temperature (°C) - Tboiler, // f8.8 Boiler flow water temperature (°C) - Tdhw, // f8.8 DHW temperature (°C) - Toutside, // f8.8 Outside temperature (°C) - Tret, // f8.8 Return water temperature (°C) - Tstorage, // f8.8 Solar storage temperature (°C) - Tcollector, // f8.8 Solar collector temperature (°C) - TflowCH2, // f8.8 Flow water temperature CH2 circuit (°C) - Tdhw2, // f8.8 Domestic hot water temperature 2 (°C) - Texhaust, // s16 Boiler exhaust temperature (°C) - TheatExchanger, // f8.8 Boiler heat exchanger temperature (°C) - BoilerFanSpeed, // u16 Boiler fan speed Setpiont and actual value - ElectricBurnerFlame, // f8.8?? Electric current through burner flame (mюA) - TdhwSetUBTdhwSetLB = 48, // s8 / s8 DHW setpoint upper & lower bounds for adjustment (°C) - MaxTSetUBMaxTSetLB, // s8 / s8 Max CH water setpoint upper & lower bounds for adjustment (°C) - HcratioUBHcratioLB, // s8 / s8 OTC heat curve ratio upper & lower bounds for adjustment - TdhwSet = 56, // f8.8 DHW setpoint (°C) (Remote parameter 1) - MaxTSet, // f8.8 Max CH water setpoint (°C) (Remote parameters 2) - Hcratio, // f8.8 OTC heat curve ratio (°C) (Remote parameter 3) - RemoteOverrideFunction = 100, // flag8 / - Function of manual and program changes in master and remote room setpoint. - OEMDiagnosticCode = 115, // u16 OEM-specific diagnostic/service code - BurnerStarts, // u16 Number of starts burner - CHPumpStarts, // u16 Number of starts CH pump - DHWPumpValveStarts, // u16 Number of starts DHW pump/valve - DHWBurnerStarts, // u16 Number of starts burner during DHW mode - BurnerOperationHours, // u16 Number of hours that burner is in operation (i.e. flame on) - CHPumpOperationHours, // u16 Number of hours that CH pump has been running - DHWPumpValveOperationHours, // u16 Number of hours that DHW pump has been running or DHW valve has been opened - DHWBurnerOperationHours, // u16 Number of hours that burner is in operation during DHW mode - OpenThermVersionMaster, // f8.8 The implemented version of the OpenTherm Protocol Specification in the master. - OpenThermVersionSlave, // f8.8 The implemented version of the OpenTherm Protocol Specification in the slave. - MasterVersion, // u8 / u8 Master product version number and type - SlaveVersion, // u8 / u8 Slave product version number and type -}; - -enum OpenThermStatus : uint8_t -{ - NOT_INITIALIZED, - READY, - DELAY, - REQUEST_SENDING, - RESPONSE_WAITING, - RESPONSE_START_BIT, - RESPONSE_RECEIVING, - RESPONSE_READY, - RESPONSE_INVALID -}; - -class OpenTherm -{ -public: - OpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false); - volatile OpenThermStatus status; - void begin(void (*handleInterruptCallback)(void)); - void begin(void (*handleInterruptCallback)(void), void (*processResponseCallback)(unsigned long, OpenThermResponseStatus)); - bool isReady(); - unsigned long sendRequest(unsigned long request); - bool sendResponse(unsigned long request); - bool sendRequestAync(unsigned long request); - unsigned long buildRequest(OpenThermMessageType type, OpenThermMessageID id, unsigned int data); - unsigned long buildRequestID(OpenThermMessageType type, unsigned int id, unsigned int data); - unsigned long buildResponse(OpenThermMessageType type, OpenThermMessageID id, unsigned int data); - unsigned long getLastResponse(); - OpenThermResponseStatus getLastResponseStatus(); - const char *statusToString(OpenThermResponseStatus status); - void handleInterrupt(); - void process(); - void end(); - - bool parity(unsigned long frame); - OpenThermMessageType getMessageType(unsigned long message); - OpenThermMessageID getDataID(unsigned long frame); - const char *messageTypeToString(OpenThermMessageType message_type); - bool isValidRequest(unsigned long request); - bool isValidResponse(unsigned long response); - - // requests - unsigned long buildSetBoilerStatusRequest(bool enableCentralHeating, bool enableHotWater = false, bool enableCooling = false, bool enableOutsideTemperatureCompensation = false, bool enableCentralHeating2 = false, bool enableSummerMode = false, bool dhwBlock = false); - unsigned long buildSetBoilerTemperatureRequest(float temperature); - unsigned long buildGetBoilerTemperatureRequest(); - - // responses - bool isFault(unsigned long response); - bool isCentralHeatingActive(unsigned long response); - bool isHotWaterActive(unsigned long response); - bool isFlameOn(unsigned long response); - bool isCoolingActive(unsigned long response); - bool isDiagnostic(unsigned long response); - uint16_t getUInt(const unsigned long response) const; - float getFloat(const unsigned long response) const; - unsigned int temperatureToData(float temperature); - - // basic requests - unsigned long setBoilerStatus(bool enableCentralHeating, bool enableHotWater = false, bool enableCooling = false, bool enableOutsideTemperatureCompensation = false, bool enableCentralHeating2 = false, bool enableSummerMode = false, bool dhwBlock = false); - bool setBoilerTemperature(float temperature); - float getBoilerTemperature(); - float getReturnTemperature(); - bool setDHWSetpoint(float temperature); - float getDHWTemperature(); - float getModulation(); - float getPressure(); - unsigned char getFault(); - - //Имитация ответов от котла, TRUE - идет имитация ответов котла, в котел так же шлется (лучше его отключить), FALSE - штатная работа - void imitation(bool fl) {imitFlag = fl;} - -private: - bool imitFlag; - void ImitationResponse(unsigned long request); - - const int inPin; - const int outPin; - const bool isSlave; - - volatile unsigned long response; - volatile OpenThermResponseStatus responseStatus; - volatile unsigned long responseTimestamp; - volatile byte responseBitIndex; - - int readState(); - void setActiveState(); - void setIdleState(); - void activateBoiler(); - - void sendBit(bool high); - void (*handleInterruptCallback)(); - void (*processResponseCallback)(unsigned long, OpenThermResponseStatus); -}; - -#ifndef ICACHE_RAM_ATTR -#define ICACHE_RAM_ATTR -#endif - -#ifndef IRAM_ATTR -#define IRAM_ATTR ICACHE_RAM_ATTR -#endif - -#endif // OpenTherm_h diff --git a/src/modules/exec/OpenThermSlave/OpenThermSlave.cpp b/src/modules/exec/OpenThermSlave/OpenThermSlave.cpp deleted file mode 100644 index 59357de9..00000000 --- a/src/modules/exec/OpenThermSlave/OpenThermSlave.cpp +++ /dev/null @@ -1,589 +0,0 @@ -#include "Global.h" -#include "classes/IoTItem.h" -#include -#include "OpenTherm.h" - -#define SLAVE true -#define TIMEOUT_TRESHOLD 5 - -namespace _OpenThermSlave -{ - OpenTherm *ot_driver = nullptr; - OpenTherm *instance_OTdriver(int _RX_pin, int _TX_pin) - { - if (!ot_driver) - { - ot_driver = new OpenTherm(_RX_pin, _TX_pin, SLAVE); - // ot_driver->begin(); - } - return ot_driver; - } - - // Обработчик прерываний от ОТ - void IRAM_ATTR handleInterruptSlave() - { - if (ot_driver != nullptr) - ot_driver->handleInterrupt(); - } - - // команды/установки от термостата - struct SetpointBoiler - { - uint8_t cmd_chEnable = 0; - uint8_t cmd_dhwEnable = 0; - float TSetCH = 0; - float TSetDhw = 0; - } set; - - struct failCode - { - bool service_required = 0; - bool lockout_reset = 0; - bool low_water_pressure = 0; - bool gas_fault = 0; - bool air_fault = 0; - bool water_overtemp = 0; - uint8_t fault_code = 0; - }; - - // текущее реальное состояние котла - struct StateBoiler - { - uint8_t stateCH = 0; - uint8_t stateDHW = 0; - uint8_t fl_flame = 0; - uint8_t fl_fail = 0; - failCode fCode; - float RelModLevel = 0; - float Tboiler = 0; - float Tret = 0; - float Tdhw = 0; - float Toutside = 0; - } state; - - // конфигурация котла - struct ConfigBoiler - { - bool dhw = false; // 1- есть реле(трехходовой) ГВС - bool ctrlType = false; // 0 - модуляция, 1- вкл/выкл - bool confDhw = true; // 1 - бак, 0 - проточная //TODO ПОКА НЕ ЗНАЮ ЧТО ДЕЛАТЬ - bool pumpControlMaster = false; // в протоколе ОТ: мастер управляет насосом ????????????????????? //TODO Команды кправления насосом от мастера не помню - - int minDhw; - int maxDhw; - int minCH; - int maxCH; - - } conf; - - // DynamicJsonDocument OpenThemData(JSON_BUFFER_SIZE / 2); - - IoTItem *tmp; - - IoTItem *_idTboiler = nullptr; - IoTItem *_idTret = nullptr; - IoTItem *_idToutside = nullptr; - IoTItem *_idStateCH = nullptr; - IoTItem *_idStateDHW = nullptr; - IoTItem *_idStateFlame = nullptr; - IoTItem *_idModLevel = nullptr; - IoTItem *_idTDhw = nullptr; - IoTItem *_idCmdCH = nullptr; - IoTItem *_idCmdDHW = nullptr; - IoTItem *_idSetCH = nullptr; - IoTItem *_idSetDHW = nullptr; - IoTItem *_idCtrlType = nullptr; - - unsigned long timeout_count = 0; - - uint8_t _debug = 0; - bool _telegram = false; - unsigned long ot_response = 0; - uint8_t SlaveMemberIDcode = 0; - - - void publishNew(String widget, String value) - { - tmp = findIoTItem(widget); - if (tmp) - { - tmp->setValue(value, true); - } - else - { - if (_debug > 0) - SerialPrint("new", "SmartBoiler", widget + " = " + value); - } - } - - void sendTelegramm(String msg) - { - if (_telegram == 1) - { - if (tlgrmItem) - tlgrmItem->sendTelegramMsg(false, msg); - } - } - - /* - * ========================================================================================= - * КЛАСС РАБОТЫ ПО ПРОТОКОЛУ OPENTHERM - * ========================================================================================= - */ - class OpenThermSlave : public IoTItem - { - private: - // unsigned long ts = 0; - - - - public: - OpenThermSlave(String parameters) : IoTItem(parameters) - { - int _RX_pin = 16; - int _TX_pin = 4; - SerialPrint("i", F("OpenThermSlave"), " START... "); - - jsonRead(parameters, "RX_pin", _RX_pin); - jsonRead(parameters, "TX_pin", _TX_pin); - jsonRead(parameters, "MemberID", (int &)SlaveMemberIDcode); - - jsonRead(parameters, "LogLevel", (int &)_debug); - jsonRead(parameters, "telegram", _telegram); - - String tmpID; - jsonRead(parameters, "idTboiler", tmpID); - _idTboiler = findIoTItem(tmpID); - jsonRead(parameters, "idTret", tmpID); - _idTret = findIoTItem(tmpID); - jsonRead(parameters, "idToutside", tmpID); - _idToutside = findIoTItem(tmpID); - jsonRead(parameters, "idStateCH", tmpID); - _idStateCH = findIoTItem(tmpID); - jsonRead(parameters, "idStateDHW", tmpID); - _idStateDHW = findIoTItem(tmpID); - jsonRead(parameters, "idStateFlame", tmpID); - _idStateFlame = findIoTItem(tmpID); - jsonRead(parameters, "idModLevel", tmpID); - _idModLevel = findIoTItem(tmpID); - jsonRead(parameters, "idTDhw", tmpID); - _idTDhw = findIoTItem(tmpID); - jsonRead(parameters, "idCmdCH", tmpID); - _idCmdCH = findIoTItem(tmpID); - jsonRead(parameters, "idCmdDHW", tmpID); - _idCmdDHW = findIoTItem(tmpID); - jsonRead(parameters, "idCtrlType", tmpID); - _idCtrlType = findIoTItem(tmpID); - - jsonRead(parameters, "idSetCH", tmpID); - _idSetCH = findIoTItem(tmpID); - jsonRead(parameters, "idSetDHW", tmpID); - _idSetDHW = findIoTItem(tmpID); - - jsonRead(parameters, "minCH", conf.minCH); - jsonRead(parameters, "maxCH", conf.maxCH); - jsonRead(parameters, "minDhw", conf.minDhw); - jsonRead(parameters, "maxDhw", conf.maxDhw); - - instance_OTdriver(_RX_pin, _TX_pin); - ot_driver->begin(handleInterruptSlave, processRequest); // responseCallback -// ot_boiler = this; - } - - void doByInterval() - { - } - - // Основной цикл программы - void loop() - { - ot_driver->process(); - IoTItem::loop(); - } - - // Комманды из сценария - IoTValue execute(String command, std::vector ¶m) - { - return {}; - } - - // Обработка управления и отправка статуса - static void processStatus(unsigned int &data) - { - - uint8_t statusRequest = data >> 8; // забрали старший байт с командами мастера - set.cmd_chEnable = statusRequest & 0x1; // забрали 0 бит из этого байта - включение СО (маска 01) - - set.cmd_dhwEnable = statusRequest & 0x2; // забрали 1 бит из этого байта - включение СО (маска 10) - IoTValue val; - val.valD = set.cmd_chEnable; - _idCmdCH->setValue(val, true); - val.valD = set.cmd_dhwEnable; - _idCmdDHW->setValue(val, true); - data &= 0xFF00; // старший бит не трогаем, а младший обнулили, что бы его заполнить состоянием котла и вернуть data термостату - - // if (_idFail) - // state.fl_fail = ::atof(_idFail->getValue().c_str()); - if (_idStateCH) - state.stateCH = ::atoi(_idStateCH->getValue().c_str()); - if (_idStateDHW) - state.stateDHW = ::atoi(_idStateDHW->getValue().c_str()); - if (_idStateFlame) - state.fl_flame = ::atoi(_idStateFlame->getValue().c_str()); - - if (state.fl_fail) - data |= 0x01; // fault indication - if (state.stateCH) - data |= 0x02; // CH active - if (state.stateDHW) - data |= 0x04; // DHW active - if (state.fl_flame) - data |= 0x08; // flame on - // data |= 0x10; //cooling active - // data |= 0x20; //CH2 active - // data |= 0x40; //diagnostic/service event - // data |= 0x80; //electricity production on - } - - // обработка сброса ошибок - static void processCommand(unsigned int &data) - { - uint8_t command = data >> 8; // забрали старший байт с командами мастера - if (command == 1) - { - state.fl_fail = 0; - data |= 128; // ответ 128-255: команда выполнена - } - } - - //=================================== Обработка входящих сообщение ОТ ====================================== - static void processRequest(unsigned long request, OpenThermResponseStatus status) - { - switch (status) - { - case OpenThermResponseStatus::NONE: - if (_debug > 0) - { - SerialPrint("E", "OpenThermSlave", "Error: OpenTherm не инициализирован"); - } - break; - case OpenThermResponseStatus::INVALID: - if (_debug > 0) - { - SerialPrint("E", "OpenThermSlave", "ID:" + String(ot_driver->getDataID(request)) + " / Error: Ошибка разбора команды: " + String(request, HEX)); - // build UNKNOWN-DATAID response - unsigned long response = ot_driver->buildResponse(OpenThermMessageType::DATA_INVALID, ot_driver->getDataID(request), 0); - - // send response - ot_driver->sendResponse(response); - } - break; - case OpenThermResponseStatus::TIMEOUT: - if (_debug > 0) - { - SerialPrint("E", "OpenThermSlave", " ID: " + String(ot_driver->getDataID(request)) + " / Error: Таймаут команд от управляющего устройства (термостата)"); - } - timeout_count++; - if (timeout_count > TIMEOUT_TRESHOLD) - { - publishNew("boilerslave", "❌"); - // publishNew("status", "не подключен"); - timeout_count = TIMEOUT_TRESHOLD; - sendTelegramm(("OpenTherm: потеря связи с управляющим устройством (термостатом) ❌")); - } - break; - case OpenThermResponseStatus::SUCCESS: - timeout_count = 0; - publishNew("boilerslave", "✅"); - // publishNew("status", "подключен"); - // sendTelegramm(("OpenTherm: котёл подключен ✅")); - // respondense_flag = true; - // ts_ = new_ts_; - HandleRequest(request); - break; - default: - break; - } - } - - // Парсинг запросов - static void HandleRequest(unsigned long request) - { - if (_idCtrlType) - conf.ctrlType = ::atoi(_idCtrlType->getValue().c_str()); - // unsigned long response; - unsigned int data = ot_driver->getUInt(request); - OpenThermMessageType msgType; - byte ID; - OpenThermMessageID id = ot_driver->getDataID(request); - uint8_t flags; - if (_debug > 2) - { - SerialPrint("i", "OpenThermSlave <-", String(millis()) + " ID: " + String(id) + " / requestHEX: " + String(request, HEX) + " / request: " + String(request)); - } - switch (id) - { - /*----------------------------Инициализация и конфигурация----------------------------*/ - case OpenThermMessageID::SConfigSMemberIDcode: // запрос Конфигурации Котла и SlaveMemberID - msgType = OpenThermMessageType::READ_ACK; - data = conf.dhw | (conf.ctrlType << 1) | (false << 2) | (conf.confDhw << 3) | (conf.pumpControlMaster << 4) | (false << 5); // 2-cooling, 5-CH2 - data <<= 8; - data |= SlaveMemberIDcode; - // data = (int)SlaveMemberIDcode; - break; - // case OpenThermMessageID::MConfigMMemberIDcode: // Получили Master Member ID - // msgType = OpenThermMessageType::WRITE_ACK; - // break; - // case OpenThermMessageID::SlaveVersion: // TODO вернуть версию модуля - // msgType = OpenThermMessageType::READ_ACK; - // data = (int)1; - // break; - // case OpenThermMessageID::MasterVersion: - // msgType = OpenThermMessageType::WRITE_ACK; - // break; - // case OpenThermMessageID::OpenThermVersionSlave: - // msgType = OpenThermMessageType::READ_ACK; - // break; - /*----------------------------Управление (уставки и команды)----------------------------*/ - case OpenThermMessageID::TdhwSetUBTdhwSetLB: // границы уставки ГВС - msgType = OpenThermMessageType::READ_ACK; - data |= (uint8_t)conf.minDhw; - data |= (uint8_t)conf.maxDhw << 8; - break; - case OpenThermMessageID::MaxTSetUBMaxTSetLB: // границы уставки СО - msgType = OpenThermMessageType::READ_ACK; - data |= (uint8_t)conf.minCH; - data |= (uint8_t)conf.maxCH << 8; - break; - case OpenThermMessageID::Command: // Сброс ошибок/сброс блокировки котла. Ответ: команды (не)выполнена - msgType = OpenThermMessageType::READ_ACK; - processCommand(data); - break; - case OpenThermMessageID::TdhwSet: // TODO Получили температуру ГВС - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - { - msgType = OpenThermMessageType::READ_ACK; - if (_idSetDHW) - set.TSetDhw = ::atof(_idSetDHW->getValue().c_str()); - data = ot_driver->temperatureToData(set.TSetDhw); - } - else - { - msgType = OpenThermMessageType::WRITE_ACK; - // processDHWSet(ot_driver->getFloat(data)); - set.TSetDhw = ot_driver->getFloat(data); - set.TSetDhw = constrain(set.TSetDhw, conf.minDhw, conf.maxDhw); - // publishNew("TDHWSet", String(set.TSetDhw)); - IoTValue val; - val.valD = set.TSetDhw; - _idSetDHW->setValue(val, true); - } - break; - case OpenThermMessageID::TSet: // TODO Получили температуру СО - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - { - msgType = OpenThermMessageType::READ_ACK; - if (_idSetCH) - set.TSetCH = ::atof(_idSetCH->getValue().c_str()); - data = ot_driver->temperatureToData(set.TSetCH); - } - else - { - msgType = OpenThermMessageType::WRITE_ACK; - // processCHSet(ot_driver->getFloat(data)); - set.TSetCH = ot_driver->getFloat(data); - set.TSetCH = constrain(set.TSetCH, conf.minCH, conf.maxCH); - // publishNew("TCHSet", String(set.TSetCH)); - IoTValue val; - val.valD = set.TSetCH; - _idSetCH->setValue(val, true); - } - break; - /* case OpenThermMessageID::MaxTSet: // максимальная уставка ГВС ?????? - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::Hcratio: // Коэффециент тепловой кривой - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - */ - /*----------------------------Состояние и статусы----------------------------*/ - case OpenThermMessageID::Status: // TODO Вернуть Статус котла - msgType = OpenThermMessageType::READ_ACK; - processStatus(data); - break; - case OpenThermMessageID::RelModLevel: // запрос модуляции - msgType = OpenThermMessageType::READ_ACK; - if (_idModLevel) - state.RelModLevel = ::atoi(_idModLevel->getValue().c_str()); - data = ot_driver->temperatureToData(state.RelModLevel); - break; - case OpenThermMessageID::Tboiler: // запрос температуры котла - msgType = OpenThermMessageType::READ_ACK; - if (_idTboiler) - state.Tboiler = ::atof(_idTboiler->getValue().c_str()); - data = ot_driver->temperatureToData(state.Tboiler); - break; - case OpenThermMessageID::Tdhw: // запрос температуры ГВС - msgType = OpenThermMessageType::READ_ACK; - if (_idTDhw) - { - state.Tdhw = ::atof(_idTDhw->getValue().c_str()); - data = ot_driver->temperatureToData(state.Tdhw); - } - else - { - msgType = OpenThermMessageType::UNKNOWN_DATA_ID; - } - break; - case OpenThermMessageID::Toutside: // запрос внешней температуры - msgType = OpenThermMessageType::READ_ACK; - if (_idToutside) - { - state.Toutside = ::atof(_idToutside->getValue().c_str()); - data = ot_driver->temperatureToData(state.Toutside); - } - else - { - msgType = OpenThermMessageType::UNKNOWN_DATA_ID; - } - break; - case OpenThermMessageID::ASFflags: // запрос ошибок - msgType = OpenThermMessageType::READ_ACK; - data = 0; - if (state.fl_fail) - { - data = state.fCode.service_required | (state.fCode.lockout_reset << 1) | (state.fCode.low_water_pressure << 2) | (state.fCode.gas_fault << 3) | (state.fCode.air_fault << 4) | (state.fCode.water_overtemp << 5); - data |= (uint8_t)state.fCode.fault_code << 8; - } - break; - case OpenThermMessageID::Tret: // температура обратки - msgType = OpenThermMessageType::READ_ACK; - if (_idTret) - { - state.Tret = ::atof(_idTret->getValue().c_str()); - data = ot_driver->temperatureToData(state.Tret); - } - else - { - msgType = OpenThermMessageType::UNKNOWN_DATA_ID; - } - break; - // case OpenThermMessageID::OEMDiagnosticCode: - // msgType = OpenThermMessageType::READ_ACK; - // break; - // case OpenThermMessageID::ElectricBurnerFlame: // Ток работы горелки ????? - // msgType = OpenThermMessageType::READ_ACK; - // break; - // case OpenThermMessageID::MaxCapacityMinModLevel: // максимальная мощность котла кВт и минимальная модуляция % - // msgType = OpenThermMessageType::READ_ACK; - // break; - - /*----------------------------Двусторонние информационные сообщения----------------------------*/ - /* case OpenThermMessageID::DayTime: - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::Date: - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::Year: - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - // ========>>>>>>>>>>> СБРОС КОЛИЧЕСТВА 0 от мастера - case OpenThermMessageID::BurnerStarts: // Количество стартов горелки - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::CHPumpStarts: // Количество стартов насоса СО - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::DHWPumpValveStarts: // Количество стартов насоса/клапана ГВС - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::DHWBurnerStarts: // Количество стартов горелки ГВС - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::BurnerOperationHours: // часы работы горелки - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::CHPumpOperationHours: // часы работы горелки СО - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::DHWPumpValveOperationHours: // часы работы насоса/клапана ГВС - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - case OpenThermMessageID::DHWBurnerOperationHours: // часы работы горелки ГВС - if (ot_driver->getMessageType(request) == OpenThermMessageType::READ_DATA) - msgType = OpenThermMessageType::READ_ACK; - else - msgType = OpenThermMessageType::WRITE_ACK; - break; - */ - /*------------------------------------ ВСЁ ------------------------------------*/ - - default: - msgType = OpenThermMessageType::UNKNOWN_DATA_ID; - break; - } - ot_response = ot_driver->buildResponse(msgType, id, data); - ot_driver->sendResponse(ot_response); - if (_debug > 2) - { - SerialPrint("i", "OpenThermSlave ->", String(millis()) + " ID: " + String(id) + " / responseHEX: " + String(ot_response, HEX) + " / response: " + String(ot_response)); - } - } - - ~OpenThermSlave() - { - delete ot_driver; - ot_driver = nullptr; - } - }; -} - - -void *getAPI_OpenThermSlave(String subtype, String param) -{ - if (subtype == F("OpenThermSlave")) - { - return new _OpenThermSlave::OpenThermSlave(param); - } - else - { - return nullptr; - } -} diff --git a/src/modules/exec/OpenThermSlave/modinfo.json b/src/modules/exec/OpenThermSlave/modinfo.json deleted file mode 100644 index 2125a60f..00000000 --- a/src/modules/exec/OpenThermSlave/modinfo.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "menuSection": "executive_devices", - "configItem": [ - { - "global": 0, - "name": "OpenThermSlave", - "type": "Reading", - "subtype": "OpenThermSlave", - "id": "otslave", - "widget": "", - "page": "Boiler", - "descr": "Котёл", - "int": 60, - "value": "...", - "RX_pin": 13, - "TX_pin": 15, - "LogLevel": 0, - "telegram": 1, - "MemberID": 0, - "confDhw":0, - "minCH": 35, - "maxCH": 85, - "minDhw": 30, - "maxDhw": 60, - "idTboiler": "Tboiler", - "idTret": "Tret", - "idToutside": "Toutside", - "idTDhw":"TDhw", - "idStateCH":"StateCH", - "idStateDHW":"StateDHW", - "idStateFlame":"StateFlame", - "idModLevel":"ModLevel", - "idCmdCH":"CmdCH", - "idCmdDHW":"CmdDHW", - "idSetCH":"SetCH", - "idSetDHW":"SetDHW", - "idCtrlType":"CtrlType" - } - ], - "about": { - "authorName": "Mikhail Bubnov", - "authorContact": "https://t.me/Mit4bmw", - "authorGit": "https://github.com/Mit4el", - "specialThanks": "", - "moduleName": "OpenThermSlave", - "moduleVersion": "0.1", - "usedRam": { - "esp32_4mb": 15, - "esp8266_4mb": 15 - }, - "title": "OpenThermSlave", - "moduleDesc": "Модуль для автоматизации электрического котла. Мозги котла с внешним протоколом opentherm", - "propInfo": { - "int": "Интервал отправки данных в MQTT и web интерфейс", - "telegram": "1- Будет отправлять в телеграмм оповещения при ошибках котла и пропаже сигнала от котла, остальные необходимо реализовывать через сценарий", - "MemberID": "SlaveMemberIDcode - код производителя котла, кем притворится котёл;) Менять в большинстве случаев не надо", - "idPID":"ID модуля ПИД регулятора, для расчета модуляции и включения тэнов в зависимости от температуры теплоносителя, в модуле TCHSet будет уставка СО, создать TCHSet и указать его в модуле ПИД", - "idTboiler": "ID датчика температуры подачи котла", - "idTret": "ID датчика температуры обратки котла", - "idToutside": "ID датчика уличной температуры", - "rele1_Pwr": "Мощность тэна на первом реле, ID реле должно называться rele1", - "rele2_Pwr": "Мощность тэна на первом реле, ID реле должно называться rele2, если нет, то 0 (ноль)", - "rele3_Pwr": "Мощность тэна на первом реле, ID реле должно называться rele3, если нет, то 0 (ноль)", - "Pupm": "1-есть реле насоса (ID реле должно называться relePump), 0-нет реле насоса, насос управляется котлом без нас", - "minCH": "Граница установки температуры СО", - "maxCH": "Граница установки температуры СО", - "gistCH": "Гистерезис СО - нагрев СО включится если температура теплоносителя ниже уставки на указанные градусы (CHSet = 45гр, gistCH = 5гр, нагрев включится когда idTboiler = 40гр)", - "idTdhw": "ID датчика температуры ГВС, например в датчик в БКН", - "idReleDhw":"ID реле трехходового крана ГВС", - "gistDhw": "Гистерезис ГВС - нагрев ГВС включится если температура воды ниже уставки на указанные градусы", - "minDhw": "Граница установки температуры ГВС", - "maxDhw": "Граница установки температуры ГВС" - }, - "funcInfo": [ - { - "name": "CHSet", - "descr": "Установить целевую температуру СО", - "params": [ - "тепмература СО (подачи) - bolier.CHSet(60)" - ] - }, - { - "name": "CHEnable", - "descr": "включить / выключить отопление", - "params": [ - "bolier.CHEnable(1) - вкл, bolier.CHEnable(0) - выкл, " - ] - }, - { - "name": "DHWSet", - "descr": "Установить целевую температуру ГВС", - "params": [ - "тепмература ГВС - dhw.DHWSet(40)" - ] - }, - { - "name": "DHWEnable", - "descr": "включить / выключить ГВС", - "params": [ - "dhw.DHWEnable(1) - вкл, dhw.DHWEnable(0) - выкл, " - ] - } - ] - }, - "defActive": true, - "usedLibs": { - "esp32_4mb3f": [], - "esp32*": [], - "esp82*": [] - } -} \ No newline at end of file diff --git a/src/modules/virtual/Benchmark/Benchmark.cpp b/src/modules/virtual/Benchmark/Benchmark.cpp new file mode 100644 index 00000000..9a3edb69 --- /dev/null +++ b/src/modules/virtual/Benchmark/Benchmark.cpp @@ -0,0 +1,165 @@ +#include "Global.h" +#include "classes/IoTBench.h" +#include +// #include + +class BenchmarkLoad : public IoTBench +{ +private: + bool _log = false; + uint32_t _loadP = 1; // период подсчета загруженности процессора + + uint32_t startLoad = 0; // время начало цикла loop + uint32_t loadPrev = 0; // время предыдущего подсчета benchmark + uint32_t loadSum = 0; // время выполнния всех циклов loop за период _loadP + float load = 0; // загруженность процессора в процентах за период _loadP (loadSum / 1000) / _loadP * 100 + uint32_t count = 0; // количестов циклов loop в сек в среднем за период _loadP + +public: + BenchmarkLoad(String parameters) : IoTBench(parameters) + { + // jsonRead(parameters, "log", _log); + // jsonRead(parameters, "int", _loadP); // в минутах + _loadP = _interval ; //* 1000 + // SerialPrint("i", "Benchmark", + // "_interval: " + String(_interval) + " _loadP: " + String(_loadP)); + if (_loadP < 10000) + _loadP = 10000; + } + + void doByInterval() + { + printBenchmarkLoad(); + } + + void loop() + { + count++; + IoTItem::loop(); + } + + void preLoadFunction() + { + startLoad = micros(); // время начала выполнения одного цикла + } + void postLoadFunction() + { + loadSum += (micros() - startLoad); // высчитываем время выполнения одного цикла (после нагрузки) и прибавляем к сумме за вреям контроля _loadP + } + + void printBenchmarkLoad() + { + load = (loadSum / 10ul) / _loadP; // (loadSum / 1000) / _loadP * 100 + + SerialPrint("i", "Benchmark", + "CPU load time: " + String(loadSum) + "us, in RealTime: " + String((micros() - loadPrev)) + "us"); + SerialPrint("i", "Benchmark", + "CPU load in " + String(_loadP) + "ms :" + String((load)) + "%" + + " loop/sec: " + String(count / (_loadP / 1000))); + loadPrev = micros(); //+= _loadP; + loadSum = 0; + count = 0; + } + + IoTBench *getBenchmarkLoad() + { + return this; + } + ~BenchmarkLoad(){ + // clearBenchConfig(); + }; +}; + +class BenchmarkTask : public IoTBench +{ +private: + uint32_t _loadP = 1; + bool _log = false; + +public: + BenchmarkTask(String parameters) : IoTBench(parameters) + { + // jsonRead(parameters, "log", _log); + // jsonRead(parameters, "int", _loadP); // в минутах + _loadP = _interval;// * 1000; + if (_loadP < 10000) + _loadP = 10000; + } + + void doByInterval() + { + printBenchmarkTask(); + } + + void preTaskFunction(const String &id) + { + if (banchItems.find(id) != banchItems.end()) + { + banchItems[id]->loopTime = micros(); // micros(); + } + else + { + banchItems[id] = new ItemBench; + banchItems[id]->loopTime = micros(); // micros(); + } + } + void postTaskFunction(const String &id) + { + if (banchItems.find(id) != banchItems.end()) + { + banchItems[id]->loopTime = micros() - banchItems[id]->loopTime; + banchItems[id]->sumloopTime += banchItems[id]->loopTime; + if (banchItems[id]->loopTime > banchItems[id]->loopTimeMax_glob) + banchItems[id]->loopTimeMax_glob = banchItems[id]->loopTime; + if (banchItems[id]->loopTime > banchItems[id]->loopTimeMax_p) + banchItems[id]->loopTimeMax_p = banchItems[id]->loopTime; + } + } + + void printBenchmarkTask() + { + for (auto it = banchItems.begin(); it != banchItems.end(); it++) + { + SerialPrint( + "i", "Benchmark", + " load (" + String((float)(it->second)->sumloopTime / 10ul / _loadP) + "%) " + + " max: per (" + String((it->second)->loopTimeMax_p) + "us)" + + " glob (" + String((it->second)->loopTimeMax_glob) + "us) - " + it->first); + (it->second)->sumloopTime = 0; + (it->second)->loopTimeMax_p = 0; + } + } + + void clearBenchConfig() + { + for (auto it = banchItems.begin(); it != banchItems.end(); it++) + { + delete it->second; + } + banchItems.clear(); + } + IoTBench *getBenchmarkTask() + { + return this; + } + ~BenchmarkTask() + { + clearBenchConfig(); + }; +}; + +void *getAPI_Benchmark(String subtype, String param) +{ + if (subtype == F("loadBench")) + { + return new BenchmarkTask(param); + } + else if (subtype == F("taskBench")) + { + return new BenchmarkLoad(param); + } + else + { + return nullptr; + } +} diff --git a/src/modules/virtual/Benchmark/modinfo.json b/src/modules/virtual/Benchmark/modinfo.json new file mode 100644 index 00000000..9ab7088c --- /dev/null +++ b/src/modules/virtual/Benchmark/modinfo.json @@ -0,0 +1,69 @@ +{ + "menuSection": "virtual_elments", + + "configItem": [ + { + "global": 0, + "name": "Load Processor", + "type": "Reading", + "subtype": "loadBench", + "id": "bench", + "needSave": 0, + "widget": "nil", + "page": "Benchmark", + "descr": "Загруженность процессора", + "int": 10, + "log": 1 + }, + { + "global": 0, + "name": "Load Task", + "type": "Reading", + "subtype": "taskBench", + "id": "bench", + "needSave": 0, + "widget": "nil", + "page": "Benchmark", + "descr": "Загруженность задач", + "int": 10, + "log": 1 + } + ], + + "about": { + "authorName": "Mikhail Bubnov", + "authorContact": "https://t.me/Mit4bmw", + "authorGit": "https://github.com/Mit4el", + "specialThanks": "", + "moduleName": "Benchmark", + "moduleVersion": "1.0", + "usedRam": { + "esp32_4mb": 15, + "esp8266_4mb": 15 + }, + "title": "Производительонсть системы", + "moduleDesc": "Оценочные показатели производительности системы и выполнения модулей", + "propInfo": { + "int": "Интервал подсчета загруженности процессора в секундах" + } + }, + + "defActive": true, + + "usedLibs": { + "esp32_4mb": [], + "esp32_4mb3f": [], + "esp32s2_4mb": [], + "esp32_16mb": [], + "esp32s3_16mb": [], + "esp32c3m_4mb": [], + "esp8266_4mb": [], + "esp8266_16mb": [], + "esp8266_1mb": [], + "esp8266_1mb_ota": [], + "esp8285_1mb": [], + "esp8285_1mb_ota": [], + "esp8266_2mb": [], + "esp8266_2mb_ota": [] + } +}