mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-28 23:22:19 +03:00
smartBoiler
This commit is contained in:
78
src/modules/exec/SmartBoiler/BoilerHeader.h
Normal file
78
src/modules/exec/SmartBoiler/BoilerHeader.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#define SLAVE true
|
||||
#define TIMEOUT_TRESHOLD 5
|
||||
|
||||
namespace _Boiler
|
||||
{
|
||||
// команды/установки от термостата
|
||||
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 currentRele = 0;
|
||||
uint8_t fl_fail = 0;
|
||||
failCode fCode;
|
||||
float RelModLevel = 0;
|
||||
float Tboiler = -40;
|
||||
float Tret = 0;
|
||||
float Tdhw = 0;
|
||||
float Toutside = 0;
|
||||
bool r[3] = {0, 0, 0};
|
||||
} state;
|
||||
|
||||
// конфигурация котла
|
||||
struct ConfigBoiler
|
||||
{
|
||||
int antiFreez;
|
||||
bool pump = false; // 1- наличие реле насоса СО, 0 - мы не управляем насосом СО (в протоколе ОТ нет)
|
||||
bool changeRele = false;
|
||||
// bool dhw = false; // 1- есть реле(трехходовой) ГВС
|
||||
bool ctrlType = false; // 0 - модуляция, 1- вкл/выкл
|
||||
bool confDhw = false; // 1 - бак, 0 - проточная //TODO ПОКА НЕ ЗНАЮ ЧТО ДЕЛАТЬ
|
||||
bool pumpControlMaster = false; // в протоколе ОТ: мастер управляет насосом ????????????????????? //TODO Команды кправления насосом от мастера не помню
|
||||
|
||||
int minDhw;
|
||||
int maxDhw;
|
||||
int minCH;
|
||||
int maxCH;
|
||||
|
||||
int gistDhw;
|
||||
int gistCH;
|
||||
|
||||
int countRele = 0;
|
||||
int relePwr[3]={0,0,0};
|
||||
int prcOnekWt = 0; // процент одного киловата из общей мощности всех тэнев, расчитывается для модуляции
|
||||
// int rele2Pwr = 0;
|
||||
// int rele3Pwr = 0;
|
||||
} conf;
|
||||
|
||||
|
||||
|
||||
unsigned long timeout_count = 0;
|
||||
|
||||
int _debug = 0;
|
||||
bool _telegram = false;
|
||||
unsigned long ot_response = 0;
|
||||
}
|
||||
582
src/modules/exec/SmartBoiler/SmartBoiler.cpp
Normal file
582
src/modules/exec/SmartBoiler/SmartBoiler.cpp
Normal file
@@ -0,0 +1,582 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
#include <Arduino.h>
|
||||
#include "BoilerHeader.h"
|
||||
|
||||
namespace _Boiler
|
||||
{
|
||||
DynamicJsonDocument OpenThemData(JSON_BUFFER_SIZE / 2);
|
||||
|
||||
IoTItem *_idPID = nullptr;
|
||||
IoTItem *_idTboiler = nullptr;
|
||||
IoTItem *_idTret = nullptr;
|
||||
IoTItem *_idToutside = nullptr;
|
||||
|
||||
IoTItem *_idStateCH = nullptr;
|
||||
IoTItem *_idStateFlame = nullptr;
|
||||
IoTItem *_idModLevel = nullptr;
|
||||
IoTItem *_idCmdCH = nullptr;
|
||||
IoTItem *_idSetCH = nullptr;
|
||||
IoTItem *_idCtrlType = nullptr;
|
||||
|
||||
int pid;
|
||||
IoTItem *rele[3];
|
||||
IoTItem *relePump;
|
||||
IoTItem *releDhw;
|
||||
IoTItem *tmp;
|
||||
|
||||
// проверяем если пришедшее значение отличается от предыдущего регистрируем событие
|
||||
void publishNew(String widget, String value)
|
||||
{
|
||||
if (OpenThemData[widget] != value)
|
||||
{
|
||||
OpenThemData[widget] = 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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================================
|
||||
* КЛАСС УПРАВЛЕНИЯ ГВС
|
||||
* =========================================================================================
|
||||
*/
|
||||
|
||||
IoTItem *_idTdhw = nullptr;
|
||||
IoTItem *_idStateDHW = nullptr;
|
||||
IoTItem *_idCmdDHW = nullptr;
|
||||
IoTItem *_idTDhw = nullptr;
|
||||
IoTItem *_idSetDHW = nullptr;
|
||||
|
||||
class DHWControl : public IoTItem
|
||||
{
|
||||
private:
|
||||
unsigned long ts = 0;
|
||||
|
||||
public:
|
||||
DHWControl(String parameters) : IoTItem(parameters)
|
||||
{
|
||||
SerialPrint("i", F("DHWControl"), " START... ");
|
||||
|
||||
String tmpID;
|
||||
jsonRead(parameters, "idReleDhw", tmpID);
|
||||
releDhw = findIoTItem(tmpID);
|
||||
|
||||
jsonRead(parameters, "idSetDHW", tmpID);
|
||||
_idSetDHW = findIoTItem(tmpID);
|
||||
jsonRead(parameters, "idStateDHW", tmpID);
|
||||
_idStateDHW = findIoTItem(tmpID);
|
||||
jsonRead(parameters, "idCmdDHW", tmpID);
|
||||
_idCmdDHW = findIoTItem(tmpID);
|
||||
jsonRead(parameters, "idTDhw", tmpID);
|
||||
_idTDhw = findIoTItem(tmpID);
|
||||
|
||||
jsonRead(parameters, "minDhw", conf.minDhw);
|
||||
jsonRead(parameters, "maxDhw", conf.maxDhw);
|
||||
|
||||
jsonRead(parameters, "gistDhw", conf.gistDhw);
|
||||
|
||||
// releDhw = findIoTItem("releDhw");
|
||||
if (releDhw)
|
||||
{
|
||||
SerialPrint("i", "DHWControl", "Инициализировано РЕЛЕ ГВС");
|
||||
}
|
||||
|
||||
// dhw_ctrl = this;
|
||||
}
|
||||
|
||||
// ============================== ЛОГИКА РАБОТЫ КОТЛА И ВКЛЮЧЕНИЯ ТЭНОВ ======================================
|
||||
|
||||
// Работы котла и включения тэнов
|
||||
static void logicPowerDhw()
|
||||
{
|
||||
if (_idCmdDHW)
|
||||
set.cmd_dhwEnable = ::atoi(_idCmdDHW->getValue().c_str());
|
||||
|
||||
if (_idTDhw)
|
||||
state.Tdhw = ::atof(_idTDhw->getValue().c_str());
|
||||
|
||||
if (_idSetDHW)
|
||||
set.TSetDhw = ::atof(_idSetDHW->getValue().c_str());
|
||||
|
||||
if (set.cmd_dhwEnable)
|
||||
{
|
||||
if (releDhw)
|
||||
{
|
||||
if (_idTDhw)
|
||||
state.Tdhw = ::atof(_idTDhw->getValue().c_str());
|
||||
|
||||
if (set.TSetDhw - state.Tdhw >= conf.gistDhw && state.Tdhw > -5 && state.Tdhw < 120)
|
||||
{
|
||||
// включаем ГВС
|
||||
releDhw->setValue("1", true);
|
||||
state.stateDHW = 1;
|
||||
state.stateCH = 0;
|
||||
for (uint8_t i = 0; i < conf.countRele; i++)
|
||||
{
|
||||
state.r[i] = true;
|
||||
}
|
||||
state.RelModLevel = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
releDhw->setValue("0", true);
|
||||
state.stateDHW = 0;
|
||||
state.RelModLevel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (releDhw)
|
||||
releDhw->setValue("0", true);
|
||||
}
|
||||
// publishNew("StateDHW", String(state.stateDHW));
|
||||
IoTValue val;
|
||||
if (_idStateDHW)
|
||||
{
|
||||
val.valD = state.stateDHW;
|
||||
_idStateDHW->setValue(val, true);
|
||||
}
|
||||
}
|
||||
|
||||
void doByInterval()
|
||||
{
|
||||
}
|
||||
|
||||
// Комманды из сценария
|
||||
IoTValue execute(String command, std::vector<IoTValue> ¶m)
|
||||
{
|
||||
IoTValue val;
|
||||
if (command == "SetDHW")
|
||||
{
|
||||
set.TSetDhw = param[0].valD;
|
||||
set.TSetDhw = constrain(set.TSetDhw, conf.minDhw, conf.maxDhw);
|
||||
// publishNew("SetDHW", String(set.TSetDhw));
|
||||
val.valD = set.TSetDhw;
|
||||
if (_idSetDHW)
|
||||
_idSetDHW->setValue(val, true);
|
||||
SerialPrint("i", "DHWControl", "Scenario DHWSet ");
|
||||
}
|
||||
else if (command == "DHWEnable")
|
||||
{
|
||||
set.cmd_dhwEnable = param[0].valD;
|
||||
val.valD = set.cmd_dhwEnable;
|
||||
if (_idCmdDHW)
|
||||
_idCmdDHW->setValue(val, true);
|
||||
SerialPrint("i", "DHWControl", "Scenario DHWEnable ");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
~DHWControl()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* =========================================================================================
|
||||
* КЛАСС УПРАВЛЕНИЯ КОТЛОМ
|
||||
* =========================================================================================
|
||||
*/
|
||||
class BoilerControl : public IoTItem
|
||||
{
|
||||
private:
|
||||
unsigned long ts = 0;
|
||||
|
||||
public:
|
||||
BoilerControl(String parameters) : IoTItem(parameters)
|
||||
{
|
||||
SerialPrint("i", F("BoilerControl"), " START... ");
|
||||
|
||||
jsonRead(parameters, "LogLevel", _debug);
|
||||
jsonRead(parameters, "telegram", _telegram);
|
||||
String tmpID;
|
||||
jsonRead(parameters, "idPID", tmpID);
|
||||
_idPID = findIoTItem(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, "idStateFlame", tmpID);
|
||||
_idStateFlame = findIoTItem(tmpID);
|
||||
jsonRead(parameters, "idModLevel", tmpID);
|
||||
_idModLevel = findIoTItem(tmpID);
|
||||
jsonRead(parameters, "idCmdCH", tmpID);
|
||||
_idCmdCH = findIoTItem(tmpID);
|
||||
jsonRead(parameters, "idSetCH", tmpID);
|
||||
_idSetCH = findIoTItem(tmpID);
|
||||
jsonRead(parameters, "idCtrlType", tmpID);
|
||||
_idCtrlType = findIoTItem(tmpID);
|
||||
|
||||
jsonRead(parameters, "rele1_Pwr", conf.relePwr[0]);
|
||||
jsonRead(parameters, "rele2_Pwr", conf.relePwr[1]);
|
||||
jsonRead(parameters, "rele3_Pwr", conf.relePwr[2]);
|
||||
jsonRead(parameters, "Pump", conf.pump);
|
||||
jsonRead(parameters, "changeRele", conf.changeRele);
|
||||
|
||||
jsonRead(parameters, "minCH", conf.minCH);
|
||||
jsonRead(parameters, "maxCH", conf.maxCH);
|
||||
jsonRead(parameters, "gistCH", conf.gistCH);
|
||||
jsonRead(parameters, "antiFreez", conf.antiFreez);
|
||||
|
||||
configuration();
|
||||
}
|
||||
|
||||
// ============================== ЛОГИКА РАБОТЫ КОТЛА И ВКЛЮЧЕНИЯ ТЭНОВ ======================================
|
||||
|
||||
// Работы котла и включения тэнов
|
||||
static void logicPowerOn()
|
||||
{
|
||||
// TODO ВКЛЮЧЕНИЕ РЕЛЕ ПО ИХ МОЩНОСТИ (СДЕЛАТЬ ШАГИ НАГРЕВА И КОМБИНАЦИИ ВКЛБЧЕНИЯ ТЕНОВ С РАЗНОЙ МОЩНОСТЬЮ)
|
||||
for (uint8_t i = 0; i < conf.countRele; i++)
|
||||
{
|
||||
state.r[i] = false;
|
||||
}
|
||||
// сейчас включаются по порядку
|
||||
state.RelModLevel = 0;
|
||||
pid = 0;
|
||||
state.fl_flame = false;
|
||||
if (_idPID)
|
||||
pid = ::atoi(_idPID->getValue().c_str());
|
||||
// обнуляем ГВС
|
||||
state.stateDHW = 0;
|
||||
|
||||
if (state.Tboiler < conf.maxCH)
|
||||
{
|
||||
// if (dhw_ctrl)
|
||||
//{
|
||||
// если есть модуль ГВС, то вызываем его логику включения тэнов
|
||||
DHWControl::logicPowerDhw();
|
||||
//}
|
||||
if (!state.stateDHW) // Если уже включено ГВС, то нечего смотреть на отопление
|
||||
{
|
||||
if (set.cmd_chEnable)
|
||||
{
|
||||
publishNew("status", "Штатный режим");
|
||||
// включаем отопление
|
||||
state.stateCH = 1;
|
||||
if (state.Tboiler < (set.TSetCH + conf.gistCH) && /*set.TSetCH - state.Tboiler >= conf.gistCH &&*/ state.Tboiler > -5 && state.Tboiler < 120)
|
||||
{
|
||||
if (conf.ctrlType == 0)
|
||||
{ // режим модуляции, это когда есть модуль ПИД и более одного реле
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
state.r[state.currentRele] = true;
|
||||
state.RelModLevel = conf.prcOnekWt * conf.relePwr[state.currentRele];
|
||||
}
|
||||
if (pid > 30 && pid <= 60)
|
||||
{
|
||||
uint8_t next = state.currentRele + 1;
|
||||
if (next >= conf.countRele)
|
||||
next = 0;
|
||||
state.r[next] = true;
|
||||
state.RelModLevel = (conf.prcOnekWt * conf.relePwr[state.currentRele]) + (conf.prcOnekWt * conf.relePwr[next]);
|
||||
}
|
||||
if (pid > 60)
|
||||
{
|
||||
for (uint8_t i = 0; i < conf.countRele; i++)
|
||||
{
|
||||
state.r[i] = true;
|
||||
}
|
||||
state.RelModLevel = 100;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // у нас релейный режим без ПИДа или с одним реле(тэном)
|
||||
// TODO СЕЙЧАС ВКЛЮЧАЕМ ВСЕ РЕЛЕ, НАДО ЧТО ТО ПРИДУМАТЬ УМНОЕ
|
||||
for (uint8_t i = 0; i < conf.countRele; i++)
|
||||
{
|
||||
state.r[i] = true;
|
||||
}
|
||||
state.RelModLevel = 100;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state.RelModLevel = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
publishNew("status", "Выкл отопление");
|
||||
state.stateCH = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (conf.antiFreez > 0 && state.Tboiler < (conf.antiFreez + 4))
|
||||
{
|
||||
state.r[state.currentRele] = true;
|
||||
state.RelModLevel = conf.prcOnekWt * conf.relePwr[state.currentRele];
|
||||
// setValue("Анти-Заморозка");
|
||||
publishNew("status", "Режим анти-заморозка");
|
||||
SerialPrint("i", "BoilerControl", "Режим анти-заморозка");
|
||||
sendTelegramm("Режим анти-заморозка");
|
||||
}
|
||||
|
||||
static bool prev_flame = false;
|
||||
|
||||
if (state.RelModLevel > 0)
|
||||
state.fl_flame = true; // если хоть одно реле включено, то выставляем флаг горелки
|
||||
|
||||
if (state.fl_flame && prev_flame != state.fl_flame)
|
||||
{
|
||||
if (conf.changeRele)
|
||||
{
|
||||
state.currentRele++;
|
||||
if (state.currentRele >= conf.countRele)
|
||||
state.currentRele = 0;
|
||||
}
|
||||
}
|
||||
prev_flame = state.fl_flame;
|
||||
|
||||
bool fl_pump = false;
|
||||
|
||||
// переключаем реле в соответсии с их статусами
|
||||
for (uint8_t i = 0; i < conf.countRele; i++)
|
||||
{
|
||||
if (rele[i])
|
||||
{
|
||||
rele[i]->setValue(state.r[i] ? "1" : "0", true);
|
||||
}
|
||||
if (!fl_pump) // что бы не обнулить если выстиавили true
|
||||
fl_pump = state.r[i] ? true : false; // если хоть одно реле включено, то включаем насос
|
||||
}
|
||||
if (fl_pump)
|
||||
{ // если хоть одно реле включено, то включаем насос
|
||||
if (relePump)
|
||||
relePump->setValue("1", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (relePump)
|
||||
{ // если все реле выключены
|
||||
if (state.Tboiler > conf.minCH && set.cmd_chEnable) // НО температура ещё горячая и при этом отопление включено, то включаем насос
|
||||
relePump->setValue("1", true);
|
||||
else // Если температура в котле уже остыла, или отопление нам не нужно (летом нагрели воду-пусть котел сам остывает без насоса), то выключаем насос
|
||||
relePump->setValue("0", true);
|
||||
}
|
||||
}
|
||||
IoTValue val;
|
||||
if (_idModLevel)
|
||||
{
|
||||
val.valD = state.RelModLevel;
|
||||
_idModLevel->setValue(val, true);
|
||||
}
|
||||
if (_idStateCH)
|
||||
{
|
||||
val.valD = state.stateCH;
|
||||
_idStateCH->setValue(val, true);
|
||||
}
|
||||
if (_idStateFlame)
|
||||
{
|
||||
val.valD = state.fl_flame;
|
||||
_idStateFlame->setValue(val, true);
|
||||
}
|
||||
|
||||
// publishNew("ModLevel", String(state.RelModLevel));
|
||||
// publishNew("stateCH", String(state.stateCH));
|
||||
// publishNew("controlType", String(conf.ctrlType));
|
||||
// publishNew("StateFlame", String(state.fl_flame));
|
||||
}
|
||||
|
||||
//============================== ОБЕСПЕЧЕНИЕ РАБОТЫ IoTMANAGER =====================================
|
||||
|
||||
// конфигурирование котла в зависимости от настроек
|
||||
void configuration()
|
||||
{
|
||||
state.fl_flame = state.stateCH = 0;
|
||||
conf.countRele = conf.prcOnekWt = 0;
|
||||
if (conf.relePwr[0])
|
||||
{
|
||||
rele[0] = findIoTItem("rele1");
|
||||
if (rele[0])
|
||||
{
|
||||
conf.countRele++;
|
||||
SerialPrint("i", "BoilerControl", "Инициализировано РЕЛЕ 1-го тэна");
|
||||
}
|
||||
}
|
||||
|
||||
if (conf.relePwr[1])
|
||||
{
|
||||
rele[1] = findIoTItem("rele2");
|
||||
if (rele[1])
|
||||
{
|
||||
conf.countRele++;
|
||||
SerialPrint("i", "BoilerControl", "Инициализировано РЕЛЕ 2-го тэна");
|
||||
}
|
||||
}
|
||||
|
||||
if (conf.relePwr[2])
|
||||
{
|
||||
rele[2] = findIoTItem("rele3");
|
||||
if (rele[2])
|
||||
{
|
||||
conf.countRele++;
|
||||
SerialPrint("i", "BoilerControl", "Инициализировано РЕЛЕ 3-го тэна");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < conf.countRele; i++)
|
||||
{
|
||||
conf.prcOnekWt += conf.relePwr[i];
|
||||
}
|
||||
if (conf.countRele && conf.prcOnekWt)
|
||||
{
|
||||
// conf.prcOnekWt /= conf.countRele;
|
||||
conf.prcOnekWt = 100 / conf.prcOnekWt;
|
||||
// SerialPrint("i", "BoilerControl", "Процент одного кВт = " + String (conf.prcOnekWt) + "%");
|
||||
}
|
||||
|
||||
if (conf.pump)
|
||||
{
|
||||
relePump = findIoTItem("relePump");
|
||||
if (relePump)
|
||||
{
|
||||
SerialPrint("i", "BoilerControl", "Инициализировано РЕЛЕ Насоса");
|
||||
}
|
||||
}
|
||||
conf.ctrlType = false;
|
||||
if (conf.countRele == 1 || _idPID == nullptr)
|
||||
conf.ctrlType = true;
|
||||
|
||||
// IoTValue val;
|
||||
// val.valD = conf.ctrlType;
|
||||
if (_idCtrlType)
|
||||
{
|
||||
if (conf.ctrlType)
|
||||
_idCtrlType->setValue("Вкл/Выкл", true);
|
||||
else
|
||||
_idCtrlType->setValue("Модуляция", true);
|
||||
}
|
||||
|
||||
updateStateboiler();
|
||||
}
|
||||
|
||||
void doByInterval()
|
||||
{
|
||||
// updateStateboiler();
|
||||
|
||||
// Принудительно чистим данные, что бы обновился интерфейс
|
||||
OpenThemData.clear();
|
||||
|
||||
if (_debug > 0)
|
||||
{
|
||||
SerialPrint("i", "BoilerControl", "Обновляем данные в web интерфейсе");
|
||||
}
|
||||
if (_debug > 0)
|
||||
{
|
||||
SerialPrint("i", "BoilerControl", "memoryUsage: " + String(OpenThemData.memoryUsage()));
|
||||
}
|
||||
}
|
||||
|
||||
// Основной цикл программы
|
||||
void loop()
|
||||
{
|
||||
unsigned long new_ts = millis();
|
||||
int delay = 1000;
|
||||
if (new_ts - ts > delay)
|
||||
{
|
||||
ts = new_ts;
|
||||
updateStateboiler();
|
||||
logicPowerOn();
|
||||
}
|
||||
// для новых версий IoTManager
|
||||
IoTItem::loop();
|
||||
}
|
||||
|
||||
// Комманды из сценария
|
||||
IoTValue execute(String command, std::vector<IoTValue> ¶m)
|
||||
{
|
||||
IoTValue val;
|
||||
if (command == "CHSet")
|
||||
{
|
||||
set.TSetCH = param[0].valD;
|
||||
set.TSetCH = constrain(set.TSetCH, conf.minCH, conf.maxCH);
|
||||
val.valD = set.TSetCH;
|
||||
if (_idSetCH)
|
||||
_idSetCH->setValue(val, true);
|
||||
// publishNew("SetCH", String(set.TSetCH));
|
||||
SerialPrint("i", "BoilerControl", "Scenario CHSet ");
|
||||
}
|
||||
else if (command == "CHEnable")
|
||||
{
|
||||
set.cmd_chEnable = param[0].valD;
|
||||
val.valD = set.cmd_chEnable;
|
||||
if (_idCmdCH)
|
||||
_idCmdCH->setValue(val, true);
|
||||
SerialPrint("i", "BoilerControl", "Scenario CHEnable ");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// обновление данных от датчиков
|
||||
void updateStateboiler()
|
||||
{
|
||||
if (_idTboiler)
|
||||
state.Tboiler = ::atof(_idTboiler->getValue().c_str());
|
||||
if (_idTret)
|
||||
state.Tret = ::atof(_idTret->getValue().c_str());
|
||||
if (_idToutside)
|
||||
state.Toutside = ::atof(_idToutside->getValue().c_str());
|
||||
|
||||
// if (_idStateCH)
|
||||
// state.stateCH = ::atoi(_idStateCH->getValue().c_str());
|
||||
// if (_idStateFlame)
|
||||
// state.fl_flame = ::atoi(_idStateFlame->getValue().c_str());
|
||||
// if (_idModLevel)
|
||||
// state.RelModLevel = ::atof(_idModLevel->getValue().c_str());
|
||||
if (_idCmdCH)
|
||||
set.cmd_chEnable = ::atoi(_idCmdCH->getValue().c_str());
|
||||
if (_idSetCH)
|
||||
set.TSetCH = ::atof(_idSetCH->getValue().c_str());
|
||||
}
|
||||
|
||||
~BoilerControl()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void *getAPI_SmartBoiler(String subtype, String param)
|
||||
{
|
||||
if (subtype == F("BoilerControl"))
|
||||
{
|
||||
return new _Boiler::BoilerControl(param);
|
||||
}
|
||||
else if (subtype == F("DHWControl"))
|
||||
{
|
||||
return new _Boiler::DHWControl(param);
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
136
src/modules/exec/SmartBoiler/modinfo.json
Normal file
136
src/modules/exec/SmartBoiler/modinfo.json
Normal file
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"menuSection": "executive_devices",
|
||||
"configItem": [
|
||||
{
|
||||
"global": 0,
|
||||
"name": "BoilerControl",
|
||||
"type": "Reading",
|
||||
"subtype": "BoilerControl",
|
||||
"id": "boiler",
|
||||
"widget": "anydataDef",
|
||||
"page": "Boiler",
|
||||
"descr": "Котёл",
|
||||
"int": 60,
|
||||
"value": "...",
|
||||
"LogLevel": 0,
|
||||
"telegram": 1,
|
||||
"idPID":"PID",
|
||||
"idTboiler": "Tboiler",
|
||||
"idTret": "Tret",
|
||||
"idToutside": "Toutside",
|
||||
"idStateCH":"StateCH",
|
||||
"idStateFlame":"StateFlame",
|
||||
"idModLevel":"ModLevel",
|
||||
"idCmdCH":"CmdCH",
|
||||
"idCmdDHW":"CmdDHW",
|
||||
"idSetCH":"SetCH",
|
||||
"idCtrlType":"CtrlType",
|
||||
"rele1_Pwr": 1,
|
||||
"rele2_Pwr": 2,
|
||||
"rele3_Pwr": 4,
|
||||
"changeRele":0,
|
||||
"Pump": 0,
|
||||
"minCH": 35,
|
||||
"maxCH": 85,
|
||||
"gistCH": 5,
|
||||
"antiFreez":10
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"name": "DHWControl",
|
||||
"type": "Reading",
|
||||
"subtype": "DHWControl",
|
||||
"id": "dhw",
|
||||
"widget": "anydataDef",
|
||||
"page": "Boiler",
|
||||
"descr": "Котёл",
|
||||
"int": 60,
|
||||
"value": "...",
|
||||
"idTdhw": "TDhw",
|
||||
"idReleDhw": "ReleDhw",
|
||||
"idCmdDHW":"CmdDHW",
|
||||
"idStateDHW":"StateDHW",
|
||||
"idSetDHW":"SetDHW",
|
||||
"minDhw": 20,
|
||||
"maxDhw": 60,
|
||||
"gistDhw": 2
|
||||
}
|
||||
],
|
||||
"about": {
|
||||
"authorName": "Mikhail Bubnov",
|
||||
"authorContact": "https://t.me/Mit4bmw",
|
||||
"authorGit": "https://github.com/Mit4el",
|
||||
"specialThanks": "",
|
||||
"moduleName": "SmartBoiler",
|
||||
"moduleVersion": "0.1",
|
||||
"usedRam": {
|
||||
"esp32_4mb": 15,
|
||||
"esp8266_4mb": 15
|
||||
},
|
||||
"subTypes": [
|
||||
"BoilerControl",
|
||||
"OpenThermSlave"
|
||||
],
|
||||
"title": "SmartBoiler",
|
||||
"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": "Граница установки температуры ГВС",
|
||||
"changeRele":"Будет менять каждый раз при включении тэн 1->2->3->1...",
|
||||
"antiFreez":"Режим анти-замерзания, Указывается температура, если опустится ниже указанной, то включится нарев один тэн и нагреет на +5гр от указанной"
|
||||
},
|
||||
"funcInfo": [
|
||||
{
|
||||
"name": "CHSet",
|
||||
"descr": "Установить целевую температуру СО",
|
||||
"params": [
|
||||
"тепмература СО (подачи) - bolier.CHSet(60)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CHEnable",
|
||||
"descr": "включить / выключить отопление",
|
||||
"params": [
|
||||
"bolier.CHEnable(1) - вкл, bolier.CHEnable(0) - выкл, "
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SetDHW",
|
||||
"descr": "Установить целевую температуру ГВС",
|
||||
"params": [
|
||||
"тепмература ГВС - dhw.SetDHW(40)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DHWEnable",
|
||||
"descr": "включить / выключить ГВС",
|
||||
"params": [
|
||||
"dhw.DHWEnable(1) - вкл, dhw.DHWEnable(0) - выкл, "
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"defActive": true,
|
||||
"usedLibs": {
|
||||
"esp32_4mb3f": [],
|
||||
"esp32*": [],
|
||||
"esp82*": []
|
||||
}
|
||||
}
|
||||
71
src/modules/exec/SmartBoiler/readme.txt
Normal file
71
src/modules/exec/SmartBoiler/readme.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
Модуль для автоматизации электрического котла.
|
||||
(Описание модуля SmartBoiler/modinfo.json)
|
||||
|
||||
0 TODO Сделать чтобы при связи моих модулей промежуточные итемы можно было не создавать,
|
||||
но если их создать там отобразятся актуальные значения
|
||||
|
||||
1 Управления котлом с 1-3 тэнами
|
||||
1.1 указывается количество тэнов от 1 до 3х
|
||||
1.2 задается мощность каждого тэна, должна быть по возрастающей
|
||||
1.3 задание гистерезиса включения тэнов (ограничиваем в том числе и с ПИД)
|
||||
1.4 задание минимальной и максимальной температуры теплоносителя (минимальную автоматически не поддерживает пока, просто проверяет вхождение в диапазон)
|
||||
1.5 задание минимальной и максимальной температуры ГВС (минимальную автоматически не поддерживает пока, просто проверяет вхождение в диапазон)
|
||||
1.6 реализация тремя отдельными элементами:
|
||||
BoilerControl - Основная логика котла, по сути раздутый термостат
|
||||
DHWControl - Логика управления нагрева ГВС
|
||||
OpenThermSlave - Обеспечения протоокла взаимодействи OpenTherm
|
||||
1.7 Смена тэна периодически (по флагу из конфигурации)
|
||||
1.8 Если отвалились датчика, котел не включится
|
||||
1.9 TODO режим антизамерзания
|
||||
1.998 TODO поддержание минимальной температуры СО и ГВС
|
||||
|
||||
|
||||
2 Поддержание температуры теплоносителя
|
||||
2.1 Теплоноситель нагреется до заданной целевой и поддерживает её по гистерезису (если упала на гист. то включит нагрев)
|
||||
2.2 ПИД расчитывает только количество тэнов для включения (0-30% = первый тэн, 30-60% = 1 и 2 тэны, 60-100% все тэны)
|
||||
2.3 в зависимости от включенных тэнов и их мощности показывается процент модуляции.
|
||||
2.4 Если не добавлен модуль ПИД, то включает все тэны
|
||||
2.5 Если указан всего один тэн, то модуль ПИД не нужно создавать
|
||||
2.998 TODO возможно использовать ПИД для периодического включения одного тэна
|
||||
2.999 TODO сделать больше ступеней включения с различными комбинациями тэнов
|
||||
|
||||
3 Управление из IoTManager
|
||||
3.1 Возможность управления по комнатному термостату в том числе с другой ESP
|
||||
3.2 Управление модулем из сценария
|
||||
3.3 есть проверка ошибок датчиков (если отвалились датчика, котел не включится)
|
||||
3.4 Отправка состояния в телеграмм
|
||||
3.998 3.4 TODO Автоматическая отправка состояния в модули для отображения (имена модулей в логах "new")
|
||||
3.999 другой функционал IoTManager ...
|
||||
|
||||
4 Возможность управления циркуляционным насосом
|
||||
4.1 насос включается всегда, если включено хотя бы один из тэнов
|
||||
4.2 если включено по ГВС, насос отключается сразу как ГВС нагрелся до целевой
|
||||
4.3 если включено по СО, насос отключается когда теплоноситель остынет до минимальной температуры СО
|
||||
4.999 TODO Сделать управление выбегом насоса
|
||||
|
||||
5 Возможность управления ГВС при наличии 3-х ходового крана с БКН (бойлер косвенного нагрева)
|
||||
5.1 ГВС работает только при указании реле 3-х ходового крана (а иначе как?)
|
||||
5.2 ГВС имеет приоритет над СО
|
||||
5.3 при нагреве ГВС котел включается на полную мощность (все тэны)
|
||||
5.4 ГВС нагреет до заданной целевой и поддерживает её по гистерезису (если упала на гист. то включит ГВС)
|
||||
5.5 Температура подачи котла при этом не должны превысить минимальную температуру СО (что бы не перегревал тенплоноситель, пока греется БКН)
|
||||
|
||||
6 Возможность управления по OpenTherm
|
||||
6.1 в схему платы управления необходимо добавить часть OpenThermSlave и 24В
|
||||
6.2 возможность управления любым OpenTherm адаптером/термостатом
|
||||
6.3 задание целевой температуры теплоносителя
|
||||
6.4 задание целевой температуры ГВС
|
||||
6.5 команды включения СО и ГВС
|
||||
6.6 отправка статуса Управляющему устройству OpenTherm
|
||||
6.999 TODO Явного приоритета OpenTherm над другим управлением нет, а надо сделать. Сделать настройку "OpenTherm главне сценария" (сейчас команды выполняются ото всех по мере поступления)
|
||||
|
||||
7. Название модулей в которые автоматически отправится информации при их наличии (простто добавить в конфигурацию с указанным именем)
|
||||
controlType - Тип управления тэнами: 0 - модуляция, 1- вкл/выкл
|
||||
CHEnable - Состояние включения СО (не нагрев, а включение режима) 0 - выкл, 1- вкл
|
||||
isFlame - Состояние нагрева/горелки (включенных тэнов) 0 - выкл, 1- вкл
|
||||
RelModLevel - Уровень модуляции, в процентах в зависимости мощности включенных тэнов от их общего количества
|
||||
TDHWSet - Установленная в котле целевая температура ГВС (из Сценария или OpenTherm)
|
||||
TCHSet - Установленная в котле целевая температура СО (из Сценария или OpenTherm)
|
||||
DHWEnable Состояние включения ГВС (не нагрев, а включение режима) 0 - выкл, 1- вкл
|
||||
boilerslave - Состояние подключения к Управляющему устройству OpenTherm, значком ❌ ✅
|
||||
status - Состояние подключения к Управляющему устройству OpenTherm, строкой: "не подключен" / "подключен"
|
||||
337
src/modules/exec/SmartBoiler/smartBoiler.json
Normal file
337
src/modules/exec/SmartBoiler/smartBoiler.json
Normal file
@@ -0,0 +1,337 @@
|
||||
{
|
||||
"mark": "iotm",
|
||||
"config": [
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Writing",
|
||||
"subtype": "TelegramLT",
|
||||
"id": "tg",
|
||||
"widget": "",
|
||||
"page": "",
|
||||
"descr": "",
|
||||
"token": "",
|
||||
"chatID": ""
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "Variable",
|
||||
"id": "Tboiler",
|
||||
"needSave": 0,
|
||||
"widget": "inputDgt",
|
||||
"page": "Котёл",
|
||||
"descr": "Датчик котла",
|
||||
"int": "0",
|
||||
"val": "20",
|
||||
"map": "1024,1024,1,100",
|
||||
"plus": 0,
|
||||
"multiply": 1,
|
||||
"round": 0
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "Variable",
|
||||
"id": "SetCH",
|
||||
"needSave": 0,
|
||||
"widget": "inputDgt",
|
||||
"page": "Котёл",
|
||||
"descr": "Уставка СО",
|
||||
"int": "0",
|
||||
"val": "60",
|
||||
"map": "1024,1024,1,100",
|
||||
"plus": 0,
|
||||
"multiply": 1,
|
||||
"round": 0
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "Variable",
|
||||
"id": "CtrlType",
|
||||
"needSave": 0,
|
||||
"widget": "anydataDef",
|
||||
"page": "Состояние",
|
||||
"descr": " Тип управления",
|
||||
"int": "0",
|
||||
"val": "0.0",
|
||||
"map": "1024,1024,1,100",
|
||||
"plus": 0,
|
||||
"multiply": 1,
|
||||
"round": 0
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "VButton",
|
||||
"id": "CmdCH",
|
||||
"needSave": 0,
|
||||
"widget": "toggle",
|
||||
"page": "Котёл",
|
||||
"descr": " ВКЛ СО",
|
||||
"int": "0",
|
||||
"val": "0"
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "Variable",
|
||||
"id": "StateCH",
|
||||
"needSave": 0,
|
||||
"widget": "anydataDef",
|
||||
"page": "Состояние",
|
||||
"descr": "Состояние СО",
|
||||
"int": "0",
|
||||
"val": "0.0",
|
||||
"map": "1024,1024,1,100",
|
||||
"plus": 0,
|
||||
"multiply": 1,
|
||||
"round": 0
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "Variable",
|
||||
"id": "StateFlame",
|
||||
"needSave": 0,
|
||||
"widget": "anydataDef",
|
||||
"page": "Состояние",
|
||||
"descr": "Состояние Нагрева",
|
||||
"int": "0",
|
||||
"val": "0.0",
|
||||
"map": "1024,1024,1,100",
|
||||
"plus": 0,
|
||||
"multiply": 1,
|
||||
"round": 0
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "VButton",
|
||||
"id": "rele1",
|
||||
"needSave": 0,
|
||||
"widget": "toggle",
|
||||
"page": "Котёл",
|
||||
"descr": "rele1",
|
||||
"int": "0",
|
||||
"val": "0"
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "VButton",
|
||||
"id": "rele2",
|
||||
"needSave": 0,
|
||||
"widget": "toggle",
|
||||
"page": "Котёл",
|
||||
"descr": "rele2",
|
||||
"int": "0",
|
||||
"val": "0"
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "VButton",
|
||||
"id": "rele3",
|
||||
"needSave": 0,
|
||||
"widget": "toggle",
|
||||
"page": "Котёл",
|
||||
"descr": "rele3",
|
||||
"int": "0",
|
||||
"val": "0"
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "Variable",
|
||||
"id": "ModLevel",
|
||||
"needSave": 0,
|
||||
"widget": "anydataDef",
|
||||
"page": "Состояние",
|
||||
"descr": "Модуляция",
|
||||
"int": "0",
|
||||
"val": "0.0",
|
||||
"map": "1024,1024,1,100",
|
||||
"plus": 0,
|
||||
"multiply": 1,
|
||||
"round": 0
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "VButton",
|
||||
"id": "relePump",
|
||||
"needSave": 0,
|
||||
"widget": "toggle",
|
||||
"page": "Котёл",
|
||||
"descr": "Реле цирк.насоса",
|
||||
"int": "0",
|
||||
"val": "0"
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "VButton",
|
||||
"id": "ReleDhw",
|
||||
"needSave": 0,
|
||||
"widget": "toggle",
|
||||
"page": "ГВС",
|
||||
"descr": "3-хходовой",
|
||||
"int": "0",
|
||||
"val": "0"
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "VButton",
|
||||
"id": "CmdDHW",
|
||||
"needSave": 0,
|
||||
"widget": "toggle",
|
||||
"page": "ГВС",
|
||||
"descr": " ВКЛ ГВС",
|
||||
"int": "0",
|
||||
"val": "0"
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "Variable",
|
||||
"id": "TDhw",
|
||||
"needSave": 0,
|
||||
"widget": "inputDgt",
|
||||
"page": "ГВС",
|
||||
"descr": "Датчик БКН",
|
||||
"int": "0",
|
||||
"val": "0.0",
|
||||
"map": "1024,1024,1,100",
|
||||
"plus": 0,
|
||||
"multiply": 1,
|
||||
"round": 0
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "Variable",
|
||||
"id": "SetDHW",
|
||||
"needSave": 0,
|
||||
"widget": "inputDgt",
|
||||
"page": "ГВС",
|
||||
"descr": "Уставка ГВС",
|
||||
"int": "0",
|
||||
"val": "0.0",
|
||||
"map": "1024,1024,1,100",
|
||||
"plus": 0,
|
||||
"multiply": 1,
|
||||
"round": 0
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "Variable",
|
||||
"id": "StateDHW",
|
||||
"needSave": 0,
|
||||
"widget": "anydataDef",
|
||||
"page": "Состояние",
|
||||
"descr": "Состояние ГВС",
|
||||
"int": "0",
|
||||
"val": "0.0",
|
||||
"map": "1024,1024,1,100",
|
||||
"plus": 0,
|
||||
"multiply": 1,
|
||||
"round": 0
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "DHWControl",
|
||||
"id": "dhw96",
|
||||
"widget": "nil",
|
||||
"page": "Boiler",
|
||||
"descr": "Котёл",
|
||||
"int": 60,
|
||||
"value": "...",
|
||||
"idTDhw": "TDhw",
|
||||
"idReleDhw": "ReleDhw",
|
||||
"idCmdDHW": "CmdDHW",
|
||||
"idStateDHW": "StateDHW",
|
||||
"idSetDHW": "SetDHW",
|
||||
"minDhw": 20,
|
||||
"maxDhw": 60,
|
||||
"gistDhw": 2
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"needSave": 0,
|
||||
"type": "Writing",
|
||||
"subtype": "ThermostatPID",
|
||||
"id": "PID",
|
||||
"widget": "anydataHum",
|
||||
"page": "Котёл",
|
||||
"descr": "термостат ПИД",
|
||||
"int": "10",
|
||||
"round": 1,
|
||||
"map": "0,100,0,100",
|
||||
"set_id": "SetCH",
|
||||
"term_id": "Tboiler",
|
||||
"term_rezerv_id": "",
|
||||
"rele": "",
|
||||
"KP": 5,
|
||||
"KI": 50,
|
||||
"KD": 1
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "Variable",
|
||||
"id": "status",
|
||||
"needSave": 0,
|
||||
"widget": "anydataDef",
|
||||
"page": "Состояние",
|
||||
"descr": " Состояние",
|
||||
"int": "0",
|
||||
"val": "0.0",
|
||||
"map": "1024,1024,1,100",
|
||||
"plus": 0,
|
||||
"multiply": 1,
|
||||
"round": 0
|
||||
},
|
||||
{
|
||||
"global": 0,
|
||||
"type": "Reading",
|
||||
"subtype": "BoilerControl",
|
||||
"id": "boiler81",
|
||||
"widget": "nil",
|
||||
"page": "Boiler",
|
||||
"descr": "Котёл",
|
||||
"int": 60,
|
||||
"value": "...",
|
||||
"LogLevel": 0,
|
||||
"telegram": 1,
|
||||
"idPID": "PID",
|
||||
"idTboiler": "Tboiler",
|
||||
"idTret": "Tret",
|
||||
"idToutside": "Toutside",
|
||||
"idStateCH": "StateCH",
|
||||
"idStateFlame": "StateFlame",
|
||||
"idModLevel": "ModLevel",
|
||||
"idCmdCH": "CmdCH",
|
||||
"idCmdDHW": "CmdDHW",
|
||||
"idSetCH": "SetCH",
|
||||
"idCtrlType": "CtrlType",
|
||||
"rele1_Pwr": 1,
|
||||
"rele2_Pwr": 2,
|
||||
"rele3_Pwr": 4,
|
||||
"changeRele": 0,
|
||||
"Pump": 0,
|
||||
"minCH": 35,
|
||||
"maxCH": 85,
|
||||
"gistCH": 5,
|
||||
"antiFreez": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
scenario=>if onStart then
|
||||
{
|
||||
tg.sendMsg("SmartBoiler http://" + getIP());
|
||||
}
|
||||
Reference in New Issue
Block a user