diff --git a/platformio.ini b/platformio.ini index 13953505..ff87dc80 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,6 +9,11 @@ lib_deps_external = [env] extra_scripts = pre:tools/prebuildscript.py +build_flags = + ; библиотека OpenTherm EctoControl Adapter + -I./src/modules/exec/EctoControlAdapter/lib + -L./src/modules/exec/EctoControlAdapter/lib + -lEctoControlAdapterLib [env:esp8266_1mb_ota] lib_deps = diff --git a/src/modules/exec/EctoControlAdapter/EctoControlAdapter.cpp b/src/modules/exec/EctoControlAdapter/EctoControlAdapter.cpp new file mode 100644 index 00000000..27e7ca73 --- /dev/null +++ b/src/modules/exec/EctoControlAdapter/EctoControlAdapter.cpp @@ -0,0 +1,273 @@ +#include "Global.h" +#include "classes/IoTItem.h" +#include +#include + +#include "rsEctoControl.h" + +// class ModbusUart; +Stream *_mbUART = nullptr; + +#define UART_LINE 2 + +// Modbus stuff +// Данные Modbus по умолчанию + +#define MODBUS_RX_PIN 18 // Rx pin +#define MODBUS_TX_PIN 19 // Tx pin +#define MODBUS_SERIAL_BAUD 9600 // Baud rate for esp32 and max485 communication + +// void modbusPreTransmission() +// { +// // delay(500); +// if (_DIR_PIN) +// digitalWrite(_DIR_PIN, HIGH); +// } + +// // Pin 4 made low for Modbus receive mode +// // Контакт 4 установлен на низком уровне для режима приема Modbus +// void modbusPostTransmission() +// { +// if (_DIR_PIN) +// digitalWrite(_DIR_PIN, LOW); +// // delay(500); +// } + +// ModbusMaster node; + +RsEctoControl *rsEC; + +class EctoControlAdapter : public IoTItem +{ +private: + int _rx = MODBUS_RX_PIN; // адреса прочитаем с веба + int _tx = MODBUS_TX_PIN; + int _baud = MODBUS_SERIAL_BAUD; + String _prot = "SERIAL_8N1"; + int protocol = SERIAL_8N1; + uint8_t _addr = 0xF0; // Адрес слейва от 1 до 247 + uint8_t _type = 0x14; // Тип устройства: 0x14 – адаптер OpenTherm (вторая версия); 0x11 – адаптер OpenTherm (первая версия, снята с производства) + bool _debugLevel; // Дебаг + //uint8_t _dir_pin; + +public: + EctoControlAdapter(String parameters) : IoTItem(parameters) + { + //_dir_pin = 0; + _addr = jsonReadInt(parameters, "addr"); // адреса slave прочитаем с веба + _rx = jsonReadInt(parameters, "RX"); // прочитаем с веба + _tx = jsonReadInt(parameters, "TX"); + //_dir_pin = jsonReadInt(parameters, "DIR_PIN"); + _baud = jsonReadInt(parameters, "baud"); + _prot = jsonReadStr(parameters, "protocol"); + jsonRead(parameters, "debug", _debugLevel); + + if (_prot == "SERIAL_8N1") + { + protocol = SERIAL_8N1; + } + else if (_prot == "SERIAL_8N2") + { + protocol = SERIAL_8N2; + } + + // Serial2.begin(baud-rate, protocol, RX pin, TX pin); + + _mbUART = new HardwareSerial(UART_LINE); + + if (_debugLevel > 2) + { + SerialPrint("I", "EctoControlAdapter", "baud: " + String(_baud) + ", protocol: " + String(protocol, HEX) + ", RX: " + String(_rx) + ", TX: " + String(_tx)); + } + ((HardwareSerial *)_mbUART)->begin(_baud, protocol, _rx, _tx); // выбираем тип протокола, скорость и все пины с веба + ((HardwareSerial *)_mbUART)->setTimeout(200); + rsEC = new RsEctoControl(parameters); + rsEC->begin(_addr, (Stream &)*_mbUART); + } + + void doByInterval() + { + if (rsEC) + rsEC->doByInterval(); + } + + void loop() + { + if (rsEC) + rsEC->loop(isNetworkActive(), mqttIsConnect()); + // для новых версий IoTManager + IoTItem::loop(); + } + + IoTValue execute(String command, std::vector ¶m) + { + if (rsEC) + rsEC->execute(command, param); + else + return {}; + if (command == "getModelVersion") + { + rsEC->getModelVersion(); + } + if (command == "getModelVersion") + { + rsEC->getModelVersion(); + } + if (command == "getBoilerInfo") + { + rsEC->getBoilerInfo(); + } + if (command == "getBoilerStatus") + { + rsEC->getBoilerStatus(); + } + if (command == "getCodeError") + { + rsEC->getCodeError(); + } + if (command == "getCodeErrorExt") + { + rsEC->getCodeErrorExt(); + } + if (command == "getFlagErrorOT") + { + rsEC->getFlagErrorOT(); + } + if (command == "getFlowRate") + { + rsEC->getFlowRate(); + } + if (command == "getMaxSetCH") + { + rsEC->getMaxSetCH(); + } + if (command == "getMaxSetDHW") + { + rsEC->getMaxSetDHW(); + } + if (command == "getMinSetCH") + { + rsEC->getMinSetCH(); + } + if (command == "getMinSetDHW") + { + rsEC->getMinSetDHW(); + } + if (command == "getModLevel") + { + rsEC->getModLevel(); + } + if (command == "getPressure") + { + rsEC->getPressure(); + } + if (command == "getTempCH") + { + rsEC->getTempCH(); + } + if (command == "getTempDHW") + { + rsEC->getTempDHW(); + } + if (command == "getTempOutside") + { + rsEC->getTempOutside(); + } + + if (command == "setTypeConnect") + { + rsEC->setTypeConnect(param[0].valD); + } + if (command == "setTCH") + { + rsEC->setTCH(param[0].valD); + } + if (command == "setTCHFaultConn") + { + rsEC->setTCHFaultConn(param[0].valD); + } + if (command == "setMinCH") + { + rsEC->setMinCH(param[0].valD); + } + if (command == "setMaxCH") + { + rsEC->setMaxCH(param[0].valD); + } + if (command == "setMinDHW") + { + rsEC->setMinDHW(param[0].valD); + } + if (command == "setMaxDHW") + { + rsEC->setMaxDHW(param[0].valD); + } + if (command == "setTDHW") + { + rsEC->setTDHW(param[0].valD); + } + if (command == "setMaxModLevel") + { + rsEC->setMaxModLevel(param[0].valD); + } + if (command == "setStatusCH") + { + rsEC->setStatusCH((bool)param[0].valD); + } + if (command == "setStatusDHW") + { + rsEC->setStatusDHW((bool)param[0].valD); + } + if (command == "setStatusCH2") + { + rsEC->setStatusCH2((bool)param[0].valD); + } + + if (command == "lockOutReset") + { + rsEC->lockOutReset(); + } + if (command == "rebootAdapter") + { + rsEC->rebootAdapter(); + } + return {}; + } + + void publishData(String widget, String status) + { + + IoTItem *tmp = findIoTItem(widget); + if (tmp) + tmp->setValue(status, true); + else + { + if (_debugLevel > 0) + SerialPrint("i", "NEW", widget + " = " + status); + } + } + + static void sendTelegramm(String msg) + { + if (tlgrmItem) + tlgrmItem->sendTelegramMsg(false, msg); + } + + ~EctoControlAdapter() + { + delete rsEC; + rsEC = nullptr; + }; +}; + +void *getAPI_EctoControlAdapter(String subtype, String param) +{ + + if (subtype == F("ecAdapter")) + { + return new EctoControlAdapter(param); + } + { + return nullptr; + } +} diff --git a/src/modules/exec/EctoControlAdapter/lib/AdapterCommon.h b/src/modules/exec/EctoControlAdapter/lib/AdapterCommon.h new file mode 100644 index 00000000..4b6b7bca --- /dev/null +++ b/src/modules/exec/EctoControlAdapter/lib/AdapterCommon.h @@ -0,0 +1,182 @@ +#pragma once +#include + +#define comm_RebootAdapter 2u +#define comm_LockOutReset 3u + +struct BoilerInfo +{ + uint8_t adapterType; // тип адаптера. 000 - Opentherm 001 - eBus 010 - Navien + uint8_t boilerStatus; // состояние связи с котлом 0 - нет ответа от котла на последнюю команду 1 - есть ответ от котла на последнюю команду + uint8_t rebootStatus; // Код последней перезагрузки адаптера. 0...255 - код + uint8_t adapterHardVer; // Аппаратная версия адаптера. 0...255 - номер версии + uint8_t adapterSoftVer; // u8 Программная версия адаптера. 0...255 - номер версии + uint16_t boilerMemberCode; // 0x0021 R u16 Код производителя котла. Зависит от марки и модели котла. 0...65535 - код производителя + uint16_t boilerModelCode; // 0x0022 R u16 Код модели котла. Зависит от марки и модели котла. 0...65535 - код модели +}; + +struct BoilerStatus +{ + uint8_t burnStatus; // бит 0 - текущее состояние горелки 0 - отключена 1 - включена + uint8_t CHStatus; // бит 1 - текущее состояние отопления 0 - отключено 1 - включено + uint8_t DHWStatus; // бит 2 - текущее состояние ГВС 0 - отключено 1 - включено +}; + +// Флаги ошибок (только для котлов с интерфейсом OpenTherm) +enum FlagErrorOT //: uitn8_t +{ + er_SecviceReq, // 0: Необходимо обслуживание + er_LockOut, // 1: Котел заблокирован + er_LowWater, // 2: Низкое давление в отопительном контуре + er_FlameFault, // 3: Ошибка розжига + er_AirPresFault, // 4: Низкое давление воздуха + er_OverTem // 5: Перегрев теплоносителя в контуре +}; + +////////////////// Данные регистров второй версии адаптера котла +//////////////////// Регистры для чтения + +enum ReadDataEctoControl //: uitn16_t +{ + ecR_AdapterInfo = 0x0010, // 0x0010 R bitfields бит 2...0 - тип адаптера. 000 - Opentherm 001 - eBus 010 - Navien + // бит 3 - состояние связи с котлом 0 - нет ответа от котла на последнюю команду 1 - есть ответ от котла на последнюю команду + // u8 Код последней перезагрузки адаптера. 0...255 - код + + ecR_AdaperVersion = 0x0011, // 0x0011 R u8 Аппаратная версия адаптера. 0...255 - номер версии + // u8 Программная версия адаптера. 0...255 - номер версии + + ecR_Time = 0x0012, // 0x0012 - 0x0013 R u32 Время работы адаптера после перезагрузки 0...4294967295 - время в секундах + ecR_MinSetCH = 0x0014, // 0x0014 R u8 Нижний предел уставки теплоносителя. 0...100 - температура уставки в град. С + ecR_MaxSetCH = 0x0015, // 0x0015 R u8 Верхний предел уставки теплоносителя 0...100 - температура уставки в град. С + ecR_MinSetDHW = 0x0016, // 0x0016 R u8 Нижний предел уставки ГВС 0...100 - температура уставки в град. С + ecR_MaxSetDHW = 0x0017, // 0x0017 R u8 Верхний предел уставки ГВС 0...100 - температура уставки в град. С + ecR_TempCH = 0x0018, // 0x0018 R i16 Текущая температура теплоносителя -100...100 - температура в 0.1 гр. С + ecR_TempDHW = 0x0019, // 0x0019 R u16 Текущая температура ГВС 0...100 - температура в 0.1 гр. С + ecR_Pressure = 0x001A, // 0x001A R u8 Текущее Давление в контуре 0...50 - давление в (0,1бар) + ecR_FlowRate = 0x001B, // 0x001B R u8? Текущий расход ГВС 1...255 - расход в (0,1 л/мин) + ecR_ModLevel = 0x001C, // 0x001C R u8? Текущая модуляция горелки 0xFF - не определено 0...100 - модуляция в (%) + ecR_BoilerStatus = 0x001D, // 0x001D R bitfields бит 0 - текущее состояние горелки 0 - отключена 1 - включена + // бит 1 - текущее состояние отопления 0 - отключено 1 - включено + // бит 2 - текущее состояние ГВС 0 - отключено 1 - включено + + ecR_CodeError = 0x001E, // 0x001E R u16 Код ошибки котла (основной). Зависит от марки и модели котла. 0...65535 - код ошибки + ecR_CodeErrorExt = 0x001F, // 0x001F R u16 Код ошибки котла (дополнительный). Зависит от марки и модели котла. 0...65535 - код ошибки + ecR_TempOutside = 0x0020, // 0x0020 R s8 Температура уличного датчика котла (при егоналичии). -65…+100 температура в градусах С + ecR_MemberCode = 0x0021, // 0x0021 R u16 Код производителя котла. Зависит от марки и модели котла. 0...65535 - код производителя + ecR_ModelCode = 0x0022, // 0x0022 R u16 Код модели котла. Зависит от марки и модели котла. 0...65535 - код модели + ecR_FlagErrorOT = 0x0023 // 0x0023 R s8 Флаги ошибок (только для котлов с интерфейсом OpenTherm) + // 0: Необходимо обслуживание + // 1: Котел заблокирован + // 2: Низкое давление в отопительном контуре + // 3: Ошибка розжига + // 4: Низкое давление воздуха + // 5: Перегрев теплоносителя в контуре +}; + +////////////////////////////// WRITE ///////////// + +enum WriteDataEctoControl //: uitn16_t +{ + ecW_SetTypeConnect = 0x0030, // 0x0030 W u8 Тип внешних подключений (будет сохранено в постоянной памяти адаптера) + // 0 - адаптер подключен к котлу + // 1 - котел подключен к внешнему устройству (панель или перемычка) + + ecW_TSetCH = 0x0031, // 0x0031 W int16 Уставка теплоносителя (будет сохранено в постоянной памяти адаптера). + // Будет передана котлу при старте адаптера, пока главным устройством не + // были записаны регистры уставки температуры. + // 0...1000 - температура уставки в десятых долях градуса С (например, для + // установки 45С нужно записать число 450). Во многих котлах необходимо до + // подключения адаптера необходимо поднять температуру теплоносителя + // отопления (нажимая “+” на панели котла) для согласования диапазона + // температуры теплоносителя, в противном случае температура теплоносителя + // может не достигнуть требуемого значения. + + ecW_TSetCHFaultConn = 0x0032, // 0x0032 W int16 Уставка теплоносителя в аварийном режиме(будет сохранено в постоянной памяти адаптера). + // Будет передана котлу в случае + // отсутствия связи с главным управляющим устройством. + // 0...1000 - температура уставки в десятых долях град. С (например, + // для установки 45С нужно записать число 450) + + ecW_TSetMinCH = 0x0033, // 0x0033 W u8 Нижний предел уставки теплоносителя 0...100 - температура уставки в град. С + // Не все котлы поддерживают этот параметр. Как правило, этот + // предел не должен быть ниже аналогичного предела, + // установленного в настройках котла. + + ecW_TSetMaxCH = 0x0034, // 0x0034 W u8 Верхний предел уставки теплоносителя 0...100 - температура уставки в град. С + // Не все котлы поддерживают этот параметр. Как правило, этот + // предел не должен быть выше аналогичного предела, + // установленного в настройках котла. + + ecW_TSetMinDHW = 0x0035, // 0x0035 W u8 Нижний предел уставки ГВС 0...100 - температура уставки в град. С + // Не все котлы поддерживают этот параметр. Как правило, этот + // предел не должен быть ниже аналогичного предела, + // установленного в настройках котла. + + ecW_TSetMaxDHW = 0x0036, // 0x0036 W u8 Верхний предел уставки ГВС 0...100 - температура уставки в град. С + // Не все котлы поддерживают этот параметр. Как правило, этот + // предел не должен быть выше аналогичного предела, + // установленного в настройках котла. + + ecW_TSetDHW = 0x0037, // 0x0037 W u8 Уставка ГВС (EPROM) 0...100 - температура уставки в град. С + // Для большинства котлов эта уставка должна находиться ниже + // предела, установленного в меню самого котла, иначе она может быть + // проигнорирована котлом. Для некоторых котлов стоит устанавливать + // этот параметр равным верхнему пределу уставки ГВС. + + ecW_SetMaxModLevel = 0x0038, // 0x0038 W u8 Уставка максимальной модуляции горелки (будет сохранено в постоянной памяти адаптера) 0...100 - уровень модуляции в процентах. + // Данный параметр поддерживается не всеми котлами. Для + // электрических трехфазных котлов возможно задать только 3 + // уровня модуляции (в диапазоне 0…100%). + + ecW_SetStatusBoiler = 0x0039, // 0x0039 W bitfields бит 0 - режим контура отопления (будет сохранено в постоянной памяти адаптера) 0 - отключен 1 - включен + // бит 1 - режим контура ГВС 0 - отключен 1 - включен + // бит 2 - “второй контур”, используется только некоторыми котлами с + // интерфейсом OpenTherm и может отвечать за активацию бойлера + // косвенного нагрева или встроенной функции ГВС. 0 - отключен 1 - включен + + + ecW_Command = 0x0080 // 0x0080 W uint16 команда + // 0 - нет команды + // 1 - CH water filling (зарезервировано) + // 2 - перезагрузка адаптера + // 3 - сброс ошибок котла + // 4..65525 - зарезервировано + // При записи любой команды, кроме «нет команды», сразу же меняется + // состояние регистра «Ответ на команду» - становится 2 – идет + // обработка команжы + + +}; + +///////////////////////////////////////// Регистры состояния: + +/* +0x0040…0x006F R i16 состояние данных в регистре ($addr - 0x30) + -2 - ошибка чтения/записи в котел + -1 - регистр не поддерживается + 0- для регистра на чтение означает, что данные из котла прочитаны и + валидны. Для регистра на запись означает, что данные успешно приняты + котлом. + 1- не инициализирован. + если регистр R: чтение соответствующих данные из котла не + приводилось, + если регистр W: адаптеру не было задано значение для записи + соответствующего значения в котле +*/ + + +/* +0x0081 R int16 Ответ на команду + -32768..-6 - зарезервировано + -5 – ошибка выполнения команды + -4 – неподдерживаемая котлом команда + -3 – не поддерживаемый котлом идентификатор устройства + -2 – не поддерживается данный адаптером + -1 – не получен ответ за отведенное врекмя + 0 – команда выполнена успешно + 1 – не было команды (значение по умолчанию) + 2 – идет обработка команды (обмен данными) + 3..32767 - зарезервировано + Если команда после перезагрузки адаптера не давалась, регистр + читается как 1 - не было команды. +*/ diff --git a/src/modules/exec/EctoControlAdapter/lib/ModbusEC.h b/src/modules/exec/EctoControlAdapter/lib/ModbusEC.h new file mode 100644 index 00000000..64105d60 --- /dev/null +++ b/src/modules/exec/EctoControlAdapter/lib/ModbusEC.h @@ -0,0 +1,97 @@ + +#ifndef ModbusEC_h +#define ModbusEC_h + +#define __MODBUSMASTER_DEBUG__ (0) +#define __MODBUSMASTER_DEBUG_PIN_A__ 4 +#define __MODBUSMASTER_DEBUG_PIN_B__ 5 + +#include "Arduino.h" +#include "util/crc16.h" +#include "util/word.h" + +/* _____CLASS DEFINITIONS____________________________________________________ */ +/** +Arduino class library for communicating with Modbus slaves over +RS232/485 (via RTU protocol). +*/ +class ModbusMaster +{ +public: + ModbusMaster(); + + void begin(uint8_t, Stream &serial); + void idle(void (*)()); + void preTransmission(void (*)()); + void postTransmission(void (*)()); + + static const uint8_t ku8MBIllegalFunction = 0x01; + static const uint8_t ku8MBIllegalDataAddress = 0x02; + static const uint8_t ku8MBIllegalDataValue = 0x03; + static const uint8_t ku8MBSlaveDeviceFailure = 0x04; + static const uint8_t ku8MBSuccess = 0x00; + static const uint8_t ku8MBInvalidSlaveID = 0xE0; + static const uint8_t ku8MBInvalidFunction = 0xE1; + static const uint8_t ku8MBResponseTimedOut = 0xE2; + static const uint8_t ku8MBInvalidCRC = 0xE3; + + uint16_t getResponseBuffer(uint8_t); + void clearResponseBuffer(); + uint8_t setTransmitBuffer(uint8_t, uint16_t); + void clearTransmitBuffer(); + + void beginTransmission(uint16_t); + uint8_t requestFrom(uint16_t, uint16_t); + void sendBit(bool); + void send(uint8_t); + void send(uint16_t); + void send(uint32_t); + uint8_t available(void); + uint16_t receive(void); + + uint8_t readHoldingRegisters(uint16_t, uint16_t); + uint8_t writeMultipleRegisters(uint16_t, uint16_t); + uint8_t writeMultipleRegisters(); + + uint8_t readAddresEctoControl(); + uint8_t writeAddresEctoControl(uint8_t); + +private: + Stream *_serial; ///< reference to serial port object + uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in begin() + static const uint8_t ku8MaxBufferSize = 20; ///< size of response/transmit buffers + uint16_t _u16ReadAddress; ///< slave register from which to read + uint16_t _u16ReadQty; ///< quantity of words to read + uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer() + uint16_t _u16WriteAddress; ///< slave register to which to write + uint16_t _u16WriteQty; ///< quantity of words to write + uint16_t _u16TransmitBuffer[ku8MaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer() + uint16_t *txBuffer; // from Wire.h -- need to clean this up Rx + uint8_t _u8TransmitBufferIndex; + uint16_t u16TransmitBufferLength; + uint16_t *rxBuffer; // from Wire.h -- need to clean this up Rx + uint8_t _u8ResponseBufferIndex; + uint8_t _u8ResponseBufferLength; + + // Modbus function codes for 16 bit access + static const uint8_t ku8MBReadHoldingRegisters = 0x03; ///< Modbus function 0x03 Read Holding Registers + static const uint8_t ku8MBWriteMultipleRegisters = 0x10; ///< Modbus function 0x10 Write Multiple Registers + + static const uint8_t ku8MBProgRead46 = 0x46; ///< EctoControl function 0x46 Устройство возвращает в ответе свой текущий адрес ADDR + static const uint8_t ku8MBProgWrite47 = 0x47; ///< EctoControl function 0x47 высылается ведущим устройством ведомому с указанием сменить свой имеющийся адрес на заданный + // высылается ведущим устройством единственному устройству на шине с неизвестным адресом + + // Modbus timeout [milliseconds] + static const uint16_t ku16MBResponseTimeout = 2000; ///< Modbus timeout [milliseconds] + + // master function that conducts Modbus transactions + uint8_t ModbusMasterTransaction(uint8_t u8MBFunction); + + // idle callback function; gets called during idle time between TX and RX + void (*_idle)(); + // preTransmission callback function; gets called before writing a Modbus message + void (*_preTransmission)(); + // postTransmission callback function; gets called after a Modbus message has been sent + void (*_postTransmission)(); +}; +#endif diff --git a/src/modules/exec/EctoControlAdapter/lib/librsEctoControl.a b/src/modules/exec/EctoControlAdapter/lib/librsEctoControl.a new file mode 100644 index 00000000..f1a36c0e Binary files /dev/null and b/src/modules/exec/EctoControlAdapter/lib/librsEctoControl.a differ diff --git a/src/modules/exec/EctoControlAdapter/lib/rsEctoControl.h b/src/modules/exec/EctoControlAdapter/lib/rsEctoControl.h new file mode 100644 index 00000000..91ce2d93 --- /dev/null +++ b/src/modules/exec/EctoControlAdapter/lib/rsEctoControl.h @@ -0,0 +1,113 @@ +#pragma once + +#include "ModbusEC.h" +#include "AdapterCommon.h" +// #include "Stream.h" +#include + +struct IoTValue; + +// static void publishData(String widget, String status); +static void (*_publishData)(String, String); + +// static void sendTelegramm(String msg); +static void (*_sendTelegramm)(String); + +static void (*_SerialPrint)(const String &, const String &, const String &); //, const String& itemId = "" + +class RsEctoControl //: public ModbusMaster +{ +private: + ModbusMaster node; + String _license; + uint8_t _addr; + uint8_t _debug; + Stream *_modbusUART; + + BoilerInfo info; + BoilerStatus status; + + uint16_t code; + uint16_t codeExt; + uint8_t flagErr; + float flow; + float maxSetCH; + float maxSetDHW; + float minSetCH; + float minSetDHW; + float modLevel; + float press; + float tCH; + float tDHW; + float tOut; + bool enableCH; + bool enableDHW; + bool enableCH2; + bool _isNetworkActive; + bool _mqttIsConnect; + int md = 0; + int md2 = 0; + + uint32_t getFlashChipIdNew(); + + uint32_t ESP_getChipId(void); + + const String getChipId(); + + bool readFunctionModBus(const uint16_t ®, uint16_t &reading); + + bool writeFunctionModBus(const uint16_t ®, uint16_t &data); + +public: + uint8_t _DIR_PIN; + //======================================================================================================= + // setup() + RsEctoControl(String parameters); //: ModbusMaster(); + + ~RsEctoControl(); + + void begin(uint8_t slave, Stream &serial); + + static void initFunction(void (*_publishData_)(String, String), void (*_sendTelegramm_)(String), void (*_SerialPrint_)(const String &, const String &, const String &)); //, const String& + + void doByInterval(); + + // Основной цикл программы + void loop(bool isNetworkActive, bool mqttIsConnect); + + // Исполнительные комманды + void execute(String command, std::vector ¶m); + + bool getModelVersion(); + bool getBoilerInfo(); + bool getBoilerStatus(); + bool getCodeError(); + bool getCodeErrorExt(); + bool getFlagErrorOT(); + bool getFlowRate(); + bool getMaxSetCH(); + bool getMaxSetDHW(); + bool getMinSetCH(); + bool getMinSetDHW(); + bool getModLevel(); + bool getPressure(); + bool getTempCH(); + bool getTempDHW(); + bool getTempOutside(); + + bool setTypeConnect(float &data); + bool setTCH(float &data); + bool setTCHFaultConn(float &data); + bool setMinCH(float &data); + bool setMaxCH(float &data); + bool setMinDHW(float &data); + bool setMaxDHW(float &data); + bool setTDHW(float &data); + bool setMaxModLevel(float &data); + bool setStatusCH(bool data); + bool setStatusDHW(bool data); + bool setStatusCH2(bool data); + + bool lockOutReset(); + bool rebootAdapter(); +}; diff --git a/src/modules/exec/EctoControlAdapter/lib/util/crc16.h b/src/modules/exec/EctoControlAdapter/lib/util/crc16.h new file mode 100644 index 00000000..27ea89ec --- /dev/null +++ b/src/modules/exec/EctoControlAdapter/lib/util/crc16.h @@ -0,0 +1,88 @@ +/** +@file +CRC Computations + +@defgroup util_crc16 "util/crc16.h": CRC Computations +@code#include "util/crc16.h"@endcode + +This header file provides functions for calculating +cyclic redundancy checks (CRC) using common polynomials. +Modified by Doc Walker to be processor-independent (removed inline +assembler to allow it to compile on SAM3X8E processors). + +@par References: +Jack Crenshaw's "Implementing CRCs" article in the January 1992 issue of @e +Embedded @e Systems @e Programming. This may be difficult to find, but it +explains CRC's in very clear and concise terms. Well worth the effort to +obtain a copy. + +*/ +/* Copyright (c) 2002, 2003, 2004 Marek Michalkiewicz + Copyright (c) 2005, 2007 Joerg Wunsch + Copyright (c) 2013 Dave Hylands + Copyright (c) 2013 Frederic Nadeau + Copyright (c) 2015 Doc Walker + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. */ + + +#ifndef _UTIL_CRC16_H_ +#define _UTIL_CRC16_H_ + + +/** @ingroup util_crc16 + Processor-independent CRC-16 calculation. + + Polynomial: x^16 + x^15 + x^2 + 1 (0xA001)
+ Initial value: 0xFFFF + + This CRC is normally used in disk-drive controllers. + + @param uint16_t crc (0x0000..0xFFFF) + @param uint8_t a (0x00..0xFF) + @return calculated CRC (0x0000..0xFFFF) +*/ +static uint16_t crc16_update(uint16_t crc, uint8_t a) +{ + int i; + + crc ^= a; + for (i = 0; i < 8; ++i) + { + if (crc & 1) + crc = (crc >> 1) ^ 0xA001; + else + crc = (crc >> 1); + } + + return crc; +} + + +#endif /* _UTIL_CRC16_H_ */ diff --git a/src/modules/exec/EctoControlAdapter/lib/util/word.h b/src/modules/exec/EctoControlAdapter/lib/util/word.h new file mode 100644 index 00000000..c72ad944 --- /dev/null +++ b/src/modules/exec/EctoControlAdapter/lib/util/word.h @@ -0,0 +1,64 @@ +/** +@file +Utility Functions for Manipulating Words + +@defgroup util_word "util/word.h": Utility Functions for Manipulating Words +@code#include "util/word.h"@endcode + +This header file provides utility functions for manipulating words. + +*/ +/* + + word.h - Utility Functions for Manipulating Words + + This file is part of ModbusMaster. + + ModbusMaster is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ModbusMaster is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ModbusMaster. If not, see . + + Written by Doc Walker (Rx) + Copyright © 2009-2015 Doc Walker <4-20ma at wvfans dot net> + +*/ + + +#ifndef _UTIL_WORD_H_ +#define _UTIL_WORD_H_ + + +/** @ingroup util_word + Return low word of a 32-bit integer. + + @param uint32_t ww (0x00000000..0xFFFFFFFF) + @return low word of input (0x0000..0xFFFF) +*/ +static inline uint16_t lowWord(uint32_t ww) +{ + return (uint16_t) ((ww) & 0xFFFF); +} + + +/** @ingroup util_word + Return high word of a 32-bit integer. + + @param uint32_t ww (0x00000000..0xFFFFFFFF) + @return high word of input (0x0000..0xFFFF) +*/ +static inline uint16_t highWord(uint32_t ww) +{ + return (uint16_t) ((ww) >> 16); +} + + +#endif /* _UTIL_WORD_H_ */ diff --git a/src/modules/exec/EctoControlAdapter/modinfo.json b/src/modules/exec/EctoControlAdapter/modinfo.json new file mode 100644 index 00000000..dbd8c178 --- /dev/null +++ b/src/modules/exec/EctoControlAdapter/modinfo.json @@ -0,0 +1,208 @@ +{ + "menuSection": "sensors", + "configItem": [ + { + "global": 0, + "name": "ectoCtrlAdapter", + "type": "Reading", + "subtype": "ecAdapter", + "id": "ecto", + "widget": "anydataTmp", + "page": "Котёл", + "descr": "Адаптер", + "int": 60, + "addr": "0xF0", + "RX": 18, + "TX": 19, + "DIR_PIN": 4, + "baud": 9600, + "protocol": "SERIAL_8N2", + "debug": 1 + } + ], + "about": { + "authorName": "Mikhail Bubnov", + "authorContact": "https://t.me/Mit4bmw", + "authorGit": "https://github.com/Mit4el", + "specialThanks": "", + "moduleName": "EctoControlAdapter", + "moduleVersion": "1.0", + "usedRam": { + "esp32_4mb": 15, + "esp8266_4mb": 15 + }, + "subTypes": [ + "ecAdapter" + ], + "title": "EctoControlAdapter", + "moduleDesc": "Управление отопительным котлом через адаптер EctoControl по протоколам OpenTherm, eBUS, Navien. Посредством Modbus RTU. Разъем 4P4C: 1-Желтый(красный)+12V; 2-Белый-GND; 3-Зелёный-A; 4-Коричневый(Синий)-B", + "propInfo": { + "addr": "Адрес slav", + "int": "Количество секунд между опросами датчика.", + "RX": "Пин RX", + "TX": "Пин TX", + "DIR_PIN": "connect DR, RE pin of MAX485 to gpio, указать 0 если не нужен", + "baud": "скорость Uart", + "protocol": "Протокол Uart: SERIAL_8N1 или SERIAL_8N2", + "debug": "0 - отключить дебаг, 1 - включить вывод дебага, 2 - лог комманд, 3 - вывод modbus" + }, + "funcInfo": [ + { + "name": "getModelVersion", + "descr": "Запрос модели и версии адаптера и бойлера", + "params": [] + }, + { + "name": "getBoilerInfo", + "descr": "Запрос состояния связи с котлом, типа адаптера и код перезагрузки адаптера", + "params": [] + }, + { + "name": "getBoilerStatus", + "descr": "Запрос состояния контуров котла и горелки", + "params": [] + }, + { + "name": "getCodeError", + "descr": "Код ошибки котла (основной). Зависит от марки и модели котла.", + "params": [] + }, + { + "name": "getCodeErrorExt", + "descr": "Код ошибки котла (дополнительный). Зависит от марки и модели котла.", + "params": [] + }, + { + "name": "getFlagErrorOT", + "descr": "Стандартные флаги ошибок котла (только для котлов с интерфейсом OpenTherm)", + "params": [] + }, + { + "name": "getFlowRate", + "descr": "Текущий расхода ГВС", + "params": [] + }, + { + "name": "getMaxSetCH", + "descr": "Верхний предел уставки теплоносителя", + "params": [] + }, + { + "name": "getMaxSetDHW", + "descr": "Верхний предел уставки ГВС", + "params": [] + }, + { + "name": "getMinSetCH", + "descr": "Нижний предел уставки теплоносителя", + "params": [] + }, + { + "name": "getMinSetDHW", + "descr": "Нижний предел уставки ГВС", + "params": [] + }, + { + "name": "getModLevel", + "descr": "Текущая модуляция горелки", + "params": [] + }, + { + "name": "getPressure", + "descr": "Текущее Давление в контуре", + "params": [] + }, + { + "name": "getTempCH", + "descr": "Текущая температура теплоносителя", + "params": [] + }, + { + "name": "getTempDHW", + "descr": "Текущая температура ГВС", + "params": [] + }, + { + "name": "getTempOutside", + "descr": "Температура уличного датчика котла", + "params": [] + }, + { + "name": "setTypeConnect", + "descr": "Установить тип внешних подключений (сохраняется в EPROM Адаптера): 0 - адаптер подключен к котлу, 1 - котел подключен к внешнему устройству (панель или перемычка)", + "params": ["Тип подключения"] + }, + { + "name": "setTCH", + "descr": "Уставка температуры теплоносителя (сохраняется в EPROM Адаптера)", + "params": ["температура передаётся до десятых градуса"] + }, + { + "name": "setTDHW", + "descr": "Уставка температуры ГВС (сохраняется в EPROM Адаптера)", + "params": ["температура передаётся до десятых градуса"] + }, + { + "name": "setTCHFaultConn", + "descr": "Уставка теплоносителя в аварийном режиме (сохраняется в EPROM Адаптера). Будет передана котлу в случае отсутствия связи адаптера с управляющим устройством", + "params": ["температура передаётся до десятых градуса"] + }, + { + "name": "setMinCH", + "descr": "Задать нижний предел уставки теплоносителя", + "params": ["температура от 0 до 100"] + }, + { + "name": "setMaxCH", + "descr": "Задать верхний предел уставки теплоносителя", + "params": ["температура от 0 до 100"] + }, + { + "name": "setMinDHW", + "descr": "Задать нижний предел уставки ГВС", + "params": ["температура от 0 до 100"] + }, + { + "name": "setMaxDHW", + "descr": "Задать верхний предел уставки ГВС", + "params": ["температура от 0 до 100"] + }, + + { + "name": "setMaxModLevel", + "descr": "Уставка максимальной модуляции горелки (сохраняется в EPROM Адаптера)", + "params": ["уровень модуляции 0-100%"] + }, + { + "name": "setStatusCH", + "descr": "Установить режим (Включить) контура отопления; 0 - отключен, 1 - включен", + "params": ["вкл/откл отопления"] + }, + { + "name": "setStatusDHW", + "descr": "Установить режим (Включить) ГВС; 0 - отключен, 1 - включен", + "params": ["вкл/откл ГВС"] + }, + { + "name": "setStatusCH2", + "descr": "Установить режим (Включить) второго контура отопления; 0 - отключен, 1 - включен. используется только некоторыми котлами с интерфейсом OpenTherm и может отвечать за активацию бойлера косвенного нагрева или встроенной функции ГВС", + "params": ["вкл/откл второго контура отопления"] + }, + { + "name": "lockOutReset", + "descr": "Сброс ошибок котла", + "params": [] + }, + { + "name": "rebootAdapter", + "descr": "Перезагрузка адаптера", + "params": [] + } + ] + }, + "defActive": false, + "usedLibs": { + "esp32*": [], + "esp82*": [] + } +} \ No newline at end of file