mirror of
https://github.com/Laxilef/OTGateway.git
synced 2025-12-10 18:24:27 +05:00
Use platformio and more updates
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
|
||||
BIN
assets/BOM.xlsx
Normal file
BIN
assets/BOM.xlsx
Normal file
Binary file not shown.
BIN
assets/equitherm calc.xlsx
Normal file
BIN
assets/equitherm calc.xlsx
Normal file
Binary file not shown.
Binary file not shown.
106
lib/CustomOpenTherm/CustomOpenTherm.h
Normal file
106
lib/CustomOpenTherm/CustomOpenTherm.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#include <Arduino.h>
|
||||
#include <OpenTherm.h>
|
||||
|
||||
extern SchedulerClass Scheduler;
|
||||
|
||||
class CustomOpenTherm : public OpenTherm {
|
||||
private:
|
||||
unsigned long send_ts = millis();
|
||||
void(*handleSendRequestCallback)(unsigned long, unsigned long, OpenThermResponseStatus status, byte attempt);
|
||||
|
||||
public:
|
||||
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false) : OpenTherm(inPin, outPin, isSlave) {}
|
||||
void setHandleSendRequestCallback(void(*handleSendRequestCallback)(unsigned long, unsigned long, OpenThermResponseStatus status, byte attempt)) {
|
||||
this->handleSendRequestCallback = handleSendRequestCallback;
|
||||
}
|
||||
|
||||
unsigned long sendRequest(unsigned long request, byte attempts = 5, byte _attempt = 0) {
|
||||
_attempt++;
|
||||
while (send_ts > 0 && millis() - send_ts < 200) {
|
||||
Scheduler.yield();
|
||||
}
|
||||
|
||||
unsigned long _response;
|
||||
if (!sendRequestAync(request)) {
|
||||
_response = 0;
|
||||
} else {
|
||||
while (!isReady()) {
|
||||
Scheduler.yield();
|
||||
process();
|
||||
}
|
||||
|
||||
_response = getLastResponse();
|
||||
}
|
||||
|
||||
if (handleSendRequestCallback != NULL) {
|
||||
handleSendRequestCallback(request, _response, getLastResponseStatus(), _attempt);
|
||||
}
|
||||
|
||||
send_ts = millis();
|
||||
if (getLastResponseStatus() == OpenThermResponseStatus::SUCCESS || _attempt >= attempts) {
|
||||
return _response;
|
||||
} else {
|
||||
return sendRequest(request, attempts, _attempt);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long setBoilerStatus(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2, bool summerWinterMode, bool dhwBlocking) {
|
||||
return sendRequest(buildSetBoilerStatusRequest(enableCentralHeating, enableHotWater, enableCooling, enableOutsideTemperatureCompensation, enableCentralHeating2, summerWinterMode, dhwBlocking));
|
||||
}
|
||||
|
||||
unsigned long buildSetBoilerStatusRequest(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2, bool summerWinterMode, bool dhwBlocking) {
|
||||
unsigned int data = enableCentralHeating | (enableHotWater << 1) | (enableCooling << 2) | (enableOutsideTemperatureCompensation << 3) | (enableCentralHeating2 << 4) | (summerWinterMode << 5) | (dhwBlocking << 6);
|
||||
data <<= 8;
|
||||
return buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Status, data);
|
||||
}
|
||||
|
||||
bool setBoilerTemperature(float temperature) {
|
||||
unsigned int data = temperatureToData(temperature);
|
||||
unsigned long response = sendRequest(buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::TSet, data));
|
||||
return isValidResponse(response);
|
||||
}
|
||||
|
||||
bool setBoilerTemperature2(float temperature) {
|
||||
unsigned int data = temperatureToData(temperature);
|
||||
unsigned long response = sendRequest(buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::TsetCH2, data));
|
||||
return isValidResponse(response);
|
||||
}
|
||||
|
||||
bool sendBoilerReset() {
|
||||
unsigned int data = 1;
|
||||
data <<= 8;
|
||||
unsigned long response = sendRequest(buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::Command, data));
|
||||
return isValidResponse(response);
|
||||
}
|
||||
|
||||
bool sendServiceReset() {
|
||||
unsigned int data = 10;
|
||||
data <<= 8;
|
||||
unsigned long response = sendRequest(buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::Command, data));
|
||||
return isValidResponse(response);
|
||||
}
|
||||
|
||||
bool sendWaterFilling() {
|
||||
unsigned int data = 2;
|
||||
data <<= 8;
|
||||
unsigned long response = sendRequest(buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::Command, data));
|
||||
return isValidResponse(response);
|
||||
}
|
||||
|
||||
// converters
|
||||
float f88(unsigned long response) {
|
||||
const byte valueLB = response & 0xFF;
|
||||
const byte valueHB = (response >> 8) & 0xFF;
|
||||
|
||||
float value = (int8_t) valueHB;
|
||||
return value + (float)valueLB / 256.0;
|
||||
}
|
||||
|
||||
int16_t s16(unsigned long response) {
|
||||
const byte valueLB = response & 0xFF;
|
||||
const byte valueHB = (response >> 8) & 0xFF;
|
||||
|
||||
int16_t value = valueHB;
|
||||
return ((value << 8) + valueLB);
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,3 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
#if defined(EQUITHERM_INTEGER)
|
||||
@@ -11,6 +10,13 @@ typedef float datatype;
|
||||
|
||||
class Equitherm {
|
||||
public:
|
||||
datatype targetTemp = 0;
|
||||
datatype indoorTemp = 0;
|
||||
datatype outdoorTemp = 0;
|
||||
float Kn = 0.0;
|
||||
float Kk = 0.0;
|
||||
float Kt = 0.0;
|
||||
|
||||
Equitherm() {}
|
||||
|
||||
// kn, kk, kt
|
||||
@@ -26,13 +32,6 @@ public:
|
||||
_maxOut = max_output;
|
||||
}
|
||||
|
||||
datatype targetTemp = 0;
|
||||
datatype indoorTemp = 0;
|
||||
datatype outdoorTemp = 0;
|
||||
float Kn = 0.0;
|
||||
float Kk = 0.0;
|
||||
float Kt = 0.0;
|
||||
|
||||
// возвращает новое значение при вызове
|
||||
datatype getResult() {
|
||||
datatype output = getResultN() + getResultK() + getResultT();
|
||||
@@ -40,6 +39,9 @@ public:
|
||||
return output;
|
||||
}
|
||||
|
||||
private:
|
||||
int _minOut = 20, _maxOut = 90;
|
||||
|
||||
// температура контура отопления в зависимости от наружной температуры
|
||||
datatype getResultN() {
|
||||
float a = (-0.21 * Kn) - 0.06; // a = -0,21k — 0,06
|
||||
@@ -56,9 +58,6 @@ public:
|
||||
|
||||
// Расчет поправки (ошибки) термостата
|
||||
datatype getResultT() {
|
||||
return (targetTemp - indoorTemp) * Kt;
|
||||
return constrain((targetTemp - indoorTemp), -2, 2) * Kt;
|
||||
}
|
||||
|
||||
private:
|
||||
int _minOut = 20, _maxOut = 90;
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
/*
|
||||
This file is needed by the Arduino IDE because the ino file needs to be named as the directory name.
|
||||
Don't worry, the Arduino compiler will "merge" all files, including src/main.cpp
|
||||
*/
|
||||
28
platformio.ini
Normal file
28
platformio.ini
Normal file
@@ -0,0 +1,28 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:d1_mini_pro]
|
||||
platform = espressif8266
|
||||
board = d1_mini_pro
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
nrwiersma/ESP8266Scheduler@^1.0
|
||||
arduino-libraries/NTPClient@^3.2.1
|
||||
bblanchon/ArduinoJson@^6.20.0
|
||||
ihormelnyk/OpenTherm Library@^1.1.4
|
||||
knolleary/PubSubClient@^2.8
|
||||
jandrassy/TelnetStream@^1.2.4
|
||||
gyverlibs/EEManager@^2.0
|
||||
gyverlibs/GyverPID@^3.3
|
||||
gyverlibs/microDS18B20@^3.10
|
||||
https://github.com/tzapu/WiFiManager.git#v2.0.16-rc.2
|
||||
build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,22 @@
|
||||
extern MqttTask* tMqtt;
|
||||
extern SensorsTask* tSensors;
|
||||
extern OpenThermTask* tOt;
|
||||
|
||||
class MainTask : public Task {
|
||||
class MainTask: public Task {
|
||||
public:
|
||||
MainTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {}
|
||||
MainTask(bool _enabled = false, unsigned long _interval = 0): Task(_enabled, _interval) {}
|
||||
|
||||
protected:
|
||||
unsigned long lastHeapInfo = 0;
|
||||
unsigned long firstFailConnect = 0;
|
||||
unsigned short minFreeHeapSize = 65535;
|
||||
|
||||
void setup() {
|
||||
pinMode(LED_STATUS_PIN, OUTPUT);
|
||||
//pinMode(LED_OT_RX_PIN, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static unsigned long lastHeapInfo = 0;
|
||||
static unsigned short minFreeHeapSize = 65535;
|
||||
|
||||
if (eeSettings.tick()) {
|
||||
INFO("Settings updated (EEPROM)");
|
||||
}
|
||||
@@ -20,12 +26,27 @@ protected:
|
||||
tMqtt->enable();
|
||||
}
|
||||
|
||||
if ( firstFailConnect != 0 ) {
|
||||
firstFailConnect = 0;
|
||||
}
|
||||
|
||||
vars.states.rssi = WiFi.RSSI();
|
||||
|
||||
} else {
|
||||
if (tMqtt->isEnabled()) {
|
||||
tMqtt->disable();
|
||||
}
|
||||
|
||||
if (settings.emergency.enable && !vars.states.emergency) {
|
||||
if (firstFailConnect == 0) {
|
||||
firstFailConnect = millis();
|
||||
}
|
||||
|
||||
if (millis() - firstFailConnect > EMERGENCY_TIME_TRESHOLD) {
|
||||
vars.states.emergency = true;
|
||||
INFO("Emergency mode enabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tSensors->isEnabled() && settings.outdoorTempSource == 2) {
|
||||
@@ -34,6 +55,12 @@ protected:
|
||||
tSensors->disable();
|
||||
}
|
||||
|
||||
if (!tOt->isEnabled() && settings.opentherm.inPin > 0 && settings.opentherm.outPin > 0 && settings.opentherm.inPin != settings.opentherm.outPin) {
|
||||
tOt->enable();
|
||||
}
|
||||
|
||||
ledStatus();
|
||||
|
||||
#ifdef USE_TELNET
|
||||
yield();
|
||||
|
||||
@@ -58,4 +85,57 @@ protected:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ledStatus() {
|
||||
static byte blinkLeft = 0;
|
||||
static bool ledOn = false;
|
||||
static unsigned long changeTime = 0;
|
||||
|
||||
byte errNo = 0;
|
||||
if (!vars.states.otStatus) {
|
||||
errNo = 1;
|
||||
} else if (vars.states.fault) {
|
||||
errNo = 2;
|
||||
} else if (vars.states.emergency) {
|
||||
errNo = 3;
|
||||
}
|
||||
|
||||
if (errNo == 0) {
|
||||
if (!ledOn) {
|
||||
digitalWrite(LED_STATUS_PIN, true);
|
||||
ledOn = true;
|
||||
}
|
||||
|
||||
if (blinkLeft > 0) {
|
||||
blinkLeft = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (blinkLeft == 0) {
|
||||
if (ledOn) {
|
||||
digitalWrite(LED_STATUS_PIN, false);
|
||||
ledOn = false;
|
||||
changeTime = millis();
|
||||
}
|
||||
|
||||
if (millis() - changeTime >= 3000) {
|
||||
blinkLeft = errNo;
|
||||
}
|
||||
}
|
||||
|
||||
if (blinkLeft > 0 && millis() - changeTime >= 500) {
|
||||
if (ledOn) {
|
||||
digitalWrite(LED_STATUS_PIN, false);
|
||||
ledOn = false;
|
||||
blinkLeft--;
|
||||
|
||||
} else {
|
||||
digitalWrite(LED_STATUS_PIN, true);
|
||||
ledOn = true;
|
||||
}
|
||||
|
||||
changeTime = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -8,15 +8,17 @@ PubSubClient client(espClient);
|
||||
HomeAssistantHelper haHelper;
|
||||
|
||||
|
||||
class MqttTask : public Task {
|
||||
class MqttTask: public Task {
|
||||
public:
|
||||
MqttTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {}
|
||||
MqttTask(bool _enabled = false, unsigned long _interval = 0): Task(_enabled, _interval) {}
|
||||
|
||||
protected:
|
||||
unsigned long lastReconnectAttempt = 0;
|
||||
unsigned short int reconnectAttempts = 0;
|
||||
unsigned long firstFailConnect = 0;
|
||||
|
||||
void setup() {
|
||||
DEBUG("[MQTT] Started");
|
||||
|
||||
client.setServer(settings.mqtt.server, settings.mqtt.port);
|
||||
client.setCallback(__callback);
|
||||
haHelper.setPrefix(settings.mqtt.prefix);
|
||||
@@ -38,16 +40,22 @@ protected:
|
||||
publishHaEntities();
|
||||
publishNonStaticHaEntities(true);
|
||||
|
||||
reconnectAttempts = 0;
|
||||
firstFailConnect = 0;
|
||||
lastReconnectAttempt = 0;
|
||||
|
||||
} else {
|
||||
INFO("Failed to connect to MQTT server\n");
|
||||
|
||||
if (!vars.states.emergency && ++reconnectAttempts >= EMERGENCY_TRESHOLD) {
|
||||
if (settings.emergency.enable && !vars.states.emergency) {
|
||||
if (firstFailConnect == 0) {
|
||||
firstFailConnect = millis();
|
||||
}
|
||||
|
||||
if (millis() - firstFailConnect > EMERGENCY_TIME_TRESHOLD) {
|
||||
vars.states.emergency = true;
|
||||
INFO("Emergency mode enabled");
|
||||
}
|
||||
}
|
||||
|
||||
forceARP();
|
||||
lastReconnectAttempt = millis();
|
||||
@@ -117,6 +125,11 @@ protected:
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (!doc["heating"]["turbo"].isNull() && doc["heating"]["turbo"].is<bool>()) {
|
||||
settings.heating.turbo = doc["heating"]["turbo"].as<bool>();
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (!doc["heating"]["target"].isNull() && (doc["heating"]["target"].is<float>() || doc["heating"]["target"].is<int>())) {
|
||||
settings.heating.target = round(doc["heating"]["target"].as<float>() * 10) / 10;
|
||||
flag = true;
|
||||
@@ -272,6 +285,7 @@ protected:
|
||||
|
||||
// heating
|
||||
haHelper.publishSwitchHeating(false);
|
||||
haHelper.publishSwitchHeatingTurbo();
|
||||
//haHelper.publishNumberHeatingTarget(false);
|
||||
haHelper.publishNumberHeatingHysteresis();
|
||||
haHelper.publishSensorHeatingSetpoint(false);
|
||||
@@ -305,6 +319,7 @@ protected:
|
||||
haHelper.publishBinSensorFault();
|
||||
haHelper.publishBinSensorDiagnostic();
|
||||
haHelper.publishSensorFaultCode();
|
||||
haHelper.publishSensorRssi();
|
||||
|
||||
// sensors
|
||||
haHelper.publishSensorModulation(false);
|
||||
@@ -383,6 +398,7 @@ protected:
|
||||
doc["emergency"]["useEquitherm"] = settings.emergency.useEquitherm;
|
||||
|
||||
doc["heating"]["enable"] = settings.heating.enable;
|
||||
doc["heating"]["turbo"] = settings.heating.turbo;
|
||||
doc["heating"]["target"] = settings.heating.target;
|
||||
doc["heating"]["hysteresis"] = settings.heating.hysteresis;
|
||||
|
||||
@@ -420,6 +436,7 @@ protected:
|
||||
doc["states"]["fault"] = vars.states.fault;
|
||||
doc["states"]["diagnostic"] = vars.states.diagnostic;
|
||||
doc["states"]["faultCode"] = vars.states.faultCode;
|
||||
doc["states"]["rssi"] = vars.states.rssi;
|
||||
|
||||
doc["sensors"]["modulation"] = vars.sensors.modulation;
|
||||
doc["sensors"]["pressure"] = vars.sensors.pressure;
|
||||
@@ -454,7 +471,7 @@ protected:
|
||||
|
||||
if (settings.debug) {
|
||||
DEBUG_F("MQTT received message\n\r Topic: %s\n\r Data: ", topic);
|
||||
for (int i = 0; i < length; i++) {
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
DEBUG_STREAM.print((char)payload[i]);
|
||||
}
|
||||
DEBUG_STREAM.print("\n");
|
||||
|
||||
@@ -1,107 +1,133 @@
|
||||
#include "lib/CustomOpenTherm.h"
|
||||
#include <new>
|
||||
#include <CustomOpenTherm.h>
|
||||
|
||||
CustomOpenTherm ot(OPENTHERM_IN_PIN, OPENTHERM_OUT_PIN);
|
||||
CustomOpenTherm* ot;
|
||||
|
||||
class OpenThermTask : public Task {
|
||||
class OpenThermTask: public Task {
|
||||
public:
|
||||
OpenThermTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {}
|
||||
OpenThermTask(bool _enabled = false, unsigned long _interval = 0): Task(_enabled, _interval) {}
|
||||
|
||||
protected:
|
||||
void setup() {
|
||||
ot.begin(handleInterrupt, responseCallback);
|
||||
ot.setHandleSendRequestCallback(sendRequestCallback);
|
||||
ot = new CustomOpenTherm(settings.opentherm.inPin, settings.opentherm.outPin);
|
||||
|
||||
ot->begin(handleInterrupt, responseCallback);
|
||||
ot->setHandleSendRequestCallback(sendRequestCallback);
|
||||
|
||||
#ifdef LED_OT_RX_PIN
|
||||
pinMode(LED_OT_RX_PIN, OUTPUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static byte currentHeatingTemp, currentDHWTemp = 0;
|
||||
byte newHeatingTemp, newDHWTemp = 0;
|
||||
unsigned long localResponse;
|
||||
|
||||
setMasterMemberIdCode();
|
||||
DEBUG_F("Slave member id code: %u \n", vars.parameters.slaveMemberIdCode);
|
||||
if ( setMasterMemberIdCode() ) {
|
||||
DEBUG_F("Slave member id code: %u\r\n", vars.parameters.slaveMemberIdCode);
|
||||
DEBUG_F("Master member id code: %u\r\n", settings.opentherm.memberIdCode > 0 ? settings.opentherm.memberIdCode : vars.parameters.slaveMemberIdCode);
|
||||
|
||||
localResponse = ot.setBoilerStatus(
|
||||
settings.heating.enable && pump,
|
||||
settings.dhw.enable
|
||||
} else {
|
||||
WARN("Slave member id failed");
|
||||
}
|
||||
|
||||
bool heatingEnable = (vars.states.emergency || settings.heating.enable) && pump && isReady();
|
||||
localResponse = ot->setBoilerStatus(
|
||||
heatingEnable,
|
||||
settings.dhw.enable,
|
||||
false, false, true, false, false
|
||||
);
|
||||
|
||||
if (!ot.isValidResponse(localResponse)) {
|
||||
if (!ot->isValidResponse(localResponse)) {
|
||||
WARN_F("Invalid response after setBoilerStatus: %s\r\n", ot->statusToString(ot->getLastResponseStatus()));
|
||||
return;
|
||||
}
|
||||
|
||||
vars.states.heating = ot.isCentralHeatingActive(localResponse);
|
||||
vars.states.dhw = ot.isHotWaterActive(localResponse);
|
||||
vars.states.flame = ot.isFlameOn(localResponse);
|
||||
vars.states.fault = ot.isFault(localResponse);
|
||||
vars.states.diagnostic = ot.isDiagnostic(localResponse);
|
||||
INFO_F("Heating enabled: %d\r\n", heatingEnable);
|
||||
setMaxModulationLevel(heatingEnable ? 100 : 0);
|
||||
|
||||
/*if (vars.dump_request.value)
|
||||
{
|
||||
testSupportedIDs();
|
||||
vars.dump_request.value = false;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
/*if ( ot.isValidResponse(localResponse) ) {
|
||||
vars.SlaveMemberIDcode.value = localResponse >> 0 & 0xFF;
|
||||
uint8_t flags = (localResponse & 0xFFFF) >> 8 & 0xFF;
|
||||
vars.dhw_present.value = flags & 0x01;
|
||||
vars.control_type.value = flags & 0x02;
|
||||
vars.cooling_present.value = flags & 0x04;
|
||||
vars.dhw_tank_present.value = flags & 0x08;
|
||||
vars.pump_control_present.value = flags & 0x10;
|
||||
vars.ch2_present.value = flags & 0x20;
|
||||
}*/
|
||||
vars.states.heating = ot->isCentralHeatingActive(localResponse);
|
||||
vars.states.dhw = ot->isHotWaterActive(localResponse);
|
||||
vars.states.flame = ot->isFlameOn(localResponse);
|
||||
vars.states.fault = ot->isFault(localResponse);
|
||||
vars.states.diagnostic = ot->isDiagnostic(localResponse);
|
||||
yield();
|
||||
|
||||
// Команды чтения данных котла
|
||||
if (millis() - prevUpdateNonEssentialVars > 30000) {
|
||||
if (millis() - prevUpdateNonEssentialVars > 60000) {
|
||||
updateSlaveParameters();
|
||||
updateMasterParameters();
|
||||
// crash?
|
||||
DEBUG_F("Master type: %u, version: %u \n", vars.parameters.masterType, vars.parameters.masterVersion);
|
||||
DEBUG_F("Slave type: %u, version: %u \n", vars.parameters.slaveType, vars.parameters.slaveVersion);
|
||||
|
||||
DEBUG_F("Master type: %u, version: %u\r\n", vars.parameters.masterType, vars.parameters.masterVersion);
|
||||
DEBUG_F("Slave type: %u, version: %u\r\n", vars.parameters.slaveType, vars.parameters.slaveVersion);
|
||||
|
||||
updateMinMaxDhwTemp();
|
||||
updateMinMaxHeatingTemp();
|
||||
|
||||
if (settings.outdoorTempSource == 0) {
|
||||
updateOutsideTemp();
|
||||
}
|
||||
if (vars.states.fault) {
|
||||
updateFaultCode();
|
||||
ot->sendBoilerReset();
|
||||
}
|
||||
|
||||
if ( vars.states.diagnostic ) {
|
||||
ot->sendServiceReset();
|
||||
}
|
||||
updatePressure();
|
||||
|
||||
prevUpdateNonEssentialVars = millis();
|
||||
yield();
|
||||
}
|
||||
updateHeatingTemp();
|
||||
updateDHWTemp();
|
||||
|
||||
updatePressure();
|
||||
if ( settings.dhw.enable || settings.heating.enable || heatingEnable ) {
|
||||
updateModulationLevel();
|
||||
}
|
||||
|
||||
if ( settings.dhw.enable ) {
|
||||
updateDHWTemp();
|
||||
} else {
|
||||
vars.temperatures.dhw = 0;
|
||||
}
|
||||
|
||||
if ( settings.heating.enable || heatingEnable ) {
|
||||
updateHeatingTemp();
|
||||
} else {
|
||||
vars.temperatures.heating = 0;
|
||||
}
|
||||
|
||||
yield();
|
||||
|
||||
//
|
||||
// Температура ГВС
|
||||
newDHWTemp = settings.dhw.target;
|
||||
if (newDHWTemp != currentDHWTemp) {
|
||||
byte newDHWTemp = settings.dhw.target;
|
||||
if (settings.dhw.enable && newDHWTemp != currentDHWTemp) {
|
||||
if (newDHWTemp < vars.parameters.dhwMinTemp || newDHWTemp > vars.parameters.dhwMaxTemp) {
|
||||
newDHWTemp = constrain(newDHWTemp, vars.parameters.dhwMinTemp, vars.parameters.dhwMaxTemp);
|
||||
}
|
||||
|
||||
INFO_F("Set DHW temp = %u \n", newDHWTemp);
|
||||
INFO_F("Set DHW temp = %u\r\n", newDHWTemp);
|
||||
|
||||
// Записываем заданную температуру ГВС
|
||||
if (ot.setDHWSetpoint(newDHWTemp)) {
|
||||
if (ot->setDHWSetpoint(newDHWTemp)) {
|
||||
currentDHWTemp = newDHWTemp;
|
||||
|
||||
} else {
|
||||
WARN("Failed set DHW temp");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Температура отопления
|
||||
if (fabs(vars.parameters.heatingSetpoint - currentHeatingTemp) > 0.0001) {
|
||||
INFO_F("Set heating temp = %u \n", vars.parameters.heatingSetpoint);
|
||||
if (heatingEnable && fabs(vars.parameters.heatingSetpoint - currentHeatingTemp) > 0.0001) {
|
||||
INFO_F("Setting heating temp = %u \n", vars.parameters.heatingSetpoint);
|
||||
|
||||
// Записываем заданную температуру
|
||||
if (ot.setBoilerTemperature(vars.parameters.heatingSetpoint)) {
|
||||
if (ot->setBoilerTemperature(vars.parameters.heatingSetpoint)) {
|
||||
currentHeatingTemp = vars.parameters.heatingSetpoint;
|
||||
|
||||
} else {
|
||||
WARN("Failed set heating temp");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,35 +137,51 @@ protected:
|
||||
float halfHyst = settings.heating.hysteresis / 2;
|
||||
if (pump && vars.temperatures.indoor - settings.heating.target + 0.0001 >= halfHyst) {
|
||||
pump = false;
|
||||
|
||||
} else if (!pump && vars.temperatures.indoor - settings.heating.target - 0.0001 <= -(halfHyst)) {
|
||||
pump = true;
|
||||
}
|
||||
|
||||
} else if (!pump) {
|
||||
pump = true;
|
||||
}
|
||||
}
|
||||
|
||||
void static IRAM_ATTR handleInterrupt() {
|
||||
ot.handleInterrupt();
|
||||
ot->handleInterrupt();
|
||||
}
|
||||
|
||||
void static sendRequestCallback(unsigned long request, unsigned long response, OpenThermResponseStatus status, byte attempt) {
|
||||
printRequestDetail(ot.getDataID(request), status, request, response, attempt);
|
||||
printRequestDetail(ot->getDataID(request), status, request, response, attempt);
|
||||
}
|
||||
|
||||
void static responseCallback(unsigned long result, OpenThermResponseStatus status) {
|
||||
static byte attempt = 0;
|
||||
|
||||
switch (status) {
|
||||
case OpenThermResponseStatus::TIMEOUT:
|
||||
if (++attempt > OPENTHERM_OFFLINE_TRESHOLD) {
|
||||
if (vars.states.otStatus && ++attempt > OPENTHERM_OFFLINE_TRESHOLD) {
|
||||
vars.states.otStatus = false;
|
||||
attempt = OPENTHERM_OFFLINE_TRESHOLD;
|
||||
}
|
||||
break;
|
||||
|
||||
case OpenThermResponseStatus::SUCCESS:
|
||||
attempt = 0;
|
||||
if (!vars.states.otStatus) {
|
||||
vars.states.otStatus = true;
|
||||
}
|
||||
|
||||
#ifdef LED_OT_RX_PIN
|
||||
{
|
||||
digitalWrite(LED_OT_RX_PIN, true);
|
||||
unsigned long ts = millis();
|
||||
while (millis() - ts < 2) {}
|
||||
digitalWrite(LED_OT_RX_PIN, false);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -148,9 +190,15 @@ protected:
|
||||
protected:
|
||||
bool pump = true;
|
||||
unsigned long prevUpdateNonEssentialVars = 0;
|
||||
unsigned long startupTime = millis();
|
||||
|
||||
|
||||
bool isReady() {
|
||||
return millis() - startupTime > 60000;
|
||||
}
|
||||
|
||||
void static printRequestDetail(OpenThermMessageID id, OpenThermResponseStatus status, unsigned long request, unsigned long response, byte attempt) {
|
||||
sprintf(buffer, "OT REQUEST ID: %4d Request: %8x Response: %8x Attempt: %2d Status: %s", id, request, response, attempt, ot.statusToString(status));
|
||||
sprintf(buffer, "OT REQUEST ID: %4d Request: %8lx Response: %8lx Attempt: %2d Status: %s", id, request, response, attempt, ot->statusToString(status));
|
||||
if (status != OpenThermResponseStatus::SUCCESS) {
|
||||
//WARN(buffer);
|
||||
DEBUG(buffer);
|
||||
@@ -159,267 +207,7 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool getBoilerTemp()
|
||||
{
|
||||
unsigned long response;
|
||||
return sendRequest(ot.buildGetBoilerTemperatureRequest(),response);
|
||||
}
|
||||
|
||||
bool getDHWTemp()
|
||||
{
|
||||
unsigned long response;
|
||||
unsigned long request = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Tdhw, 0);
|
||||
return sendRequest(request,response);
|
||||
}
|
||||
|
||||
bool getOutsideTemp()
|
||||
{
|
||||
unsigned long response;
|
||||
unsigned long request = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Toutside, 0);
|
||||
return sendRequest(request,response);
|
||||
}
|
||||
|
||||
bool setDHWTemp(float val)
|
||||
{
|
||||
unsigned long request = ot.buildRequest(OpenThermRequestType::WRITE, OpenThermMessageID::TdhwSet, ot.temperatureToData(val));
|
||||
unsigned long response;
|
||||
return sendRequest(request,response);
|
||||
}
|
||||
|
||||
bool getFaultCode()
|
||||
{
|
||||
unsigned long response;
|
||||
unsigned long request = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::ASFflags, 0);
|
||||
return sendRequest(request,response);
|
||||
}
|
||||
|
||||
bool getModulationLevel() {
|
||||
unsigned long response;
|
||||
unsigned long request = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::RelModLevel, 0);
|
||||
return sendRequest(request,response);
|
||||
}
|
||||
|
||||
bool getPressure() {
|
||||
unsigned long response;
|
||||
unsigned long request = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::CHPressure, 0);
|
||||
return sendRequest(request,response);
|
||||
}
|
||||
|
||||
bool sendRequest(unsigned long request, unsigned long& response)
|
||||
{
|
||||
send_newts = millis();
|
||||
if (send_newts - send_ts < 200) {
|
||||
// Преждем чем слать что то - надо подождать 100ms согласно специфиикации протокола ОТ
|
||||
delay(200 - (send_newts - send_ts));
|
||||
}
|
||||
|
||||
bool result = ot.sendRequestAync(request);
|
||||
if(!result) {
|
||||
WARN("Не могу отправить запрос");
|
||||
WARN("Шина " + ot.isReady() ? "готова" : "не готова");
|
||||
return false;
|
||||
}
|
||||
while (!ot.isReady())
|
||||
{
|
||||
ot.process();
|
||||
yield(); // This is local Task yield() call which allow us to switch to another task in scheduler
|
||||
}
|
||||
send_ts = millis();
|
||||
response = ot_response;
|
||||
//printRequestDetail(ot.getDataID(request), request, response);
|
||||
|
||||
return true; // Response is global variable
|
||||
}
|
||||
|
||||
void testSupportedIDs()
|
||||
{
|
||||
// Basic
|
||||
unsigned long request;
|
||||
unsigned long response;
|
||||
OpenThermMessageID id;
|
||||
//Command
|
||||
id = OpenThermMessageID::Command;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
//ASFlags
|
||||
id = OpenThermMessageID::ASFflags;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//TrOverride
|
||||
id = OpenThermMessageID::TrOverride;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//TSP
|
||||
id = OpenThermMessageID::TSP;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//TSPindexTSPvalue
|
||||
id = OpenThermMessageID::TSPindexTSPvalue;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//FHBsize
|
||||
id = OpenThermMessageID::FHBsize;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//FHBindexFHBvalue
|
||||
id = OpenThermMessageID::FHBindexFHBvalue;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//MaxCapacityMinModLevel
|
||||
id = OpenThermMessageID::MaxCapacityMinModLevel;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//TrSet
|
||||
id = OpenThermMessageID::TrSet;
|
||||
request = ot.buildRequest(OpenThermRequestType::WRITE, id, ot.temperatureToData(21));
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//RelModLevel
|
||||
id = OpenThermMessageID::RelModLevel;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//CHPressure
|
||||
id = OpenThermMessageID::CHPressure;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//DHWFlowRate
|
||||
id = OpenThermMessageID::DHWFlowRate;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//DayTime
|
||||
id = OpenThermMessageID::DayTime;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//Date
|
||||
id = OpenThermMessageID::Date;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//Year
|
||||
id = OpenThermMessageID::Year;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//TrSetCH2
|
||||
id = OpenThermMessageID::TrSetCH2;
|
||||
request = ot.buildRequest(OpenThermRequestType::WRITE, id, ot.temperatureToData(21));
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//Tr
|
||||
id = OpenThermMessageID::Tr;
|
||||
request = ot.buildRequest(OpenThermRequestType::WRITE, id, ot.temperatureToData(21));
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//Tret
|
||||
id = OpenThermMessageID::Tret;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//Texhaust
|
||||
id = OpenThermMessageID::Texhaust;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//Hcratio
|
||||
id = OpenThermMessageID::Hcratio;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//RemoteOverrideFunction
|
||||
id = OpenThermMessageID::RemoteOverrideFunction;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//OEMDiagnosticCode
|
||||
id = OpenThermMessageID::OEMDiagnosticCode;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//BurnerStarts
|
||||
id = OpenThermMessageID::BurnerStarts;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//CHPumpStarts
|
||||
id = OpenThermMessageID::CHPumpStarts;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//DHWPumpValveStarts
|
||||
id = OpenThermMessageID::DHWPumpValveStarts;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//DHWBurnerStarts
|
||||
id = OpenThermMessageID::DHWBurnerStarts;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//BurnerOperationHours
|
||||
id = OpenThermMessageID::BurnerOperationHours;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//CHPumpOperationHours
|
||||
id = OpenThermMessageID::CHPumpOperationHours;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//DHWPumpValveOperationHours
|
||||
id = OpenThermMessageID::DHWPumpValveOperationHours;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
|
||||
//DHWBurnerOperationHours
|
||||
id = OpenThermMessageID::DHWBurnerOperationHours;
|
||||
request = ot.buildRequest(OpenThermRequestType::READ, id, 0);
|
||||
if(sendRequest(request,response))
|
||||
printRequestDetail(id, ot.getLastResponseStatus(), request, response);
|
||||
}
|
||||
*/
|
||||
|
||||
void setMasterMemberIdCode() {
|
||||
bool setMasterMemberIdCode() {
|
||||
//=======================================================================================
|
||||
// Эта группа элементов данных определяет информацию о конфигурации как на ведомых, так
|
||||
// и на главных сторонах. Каждый из них имеет группу флагов конфигурации (8 бит)
|
||||
@@ -430,40 +218,88 @@ protected:
|
||||
// с "кодом идентификатора участника", который идентифицирует производителя устройства.
|
||||
//=======================================================================================
|
||||
|
||||
unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::SConfigSMemberIDcode, 0)); // 0xFFFF
|
||||
if (!ot.isValidResponse(response)) {
|
||||
return;
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::READ, OpenThermMessageID::SConfigSMemberIDcode, 0)); // 0xFFFF
|
||||
/*uint8_t flags = (response & 0xFFFF) >> 8;
|
||||
DEBUG_F(
|
||||
"MasterMemberIdCode:\r\n DHW present: %u\r\n Control type: %u\r\n Cooling configuration: %u\r\n DHW configuration: %u\r\n Pump control: %u\r\n CH2 present: %u\r\n Remote water filling function: %u\r\n Heat/cool mode control: %u\r\n Slave MemberID Code: %u\r\n",
|
||||
flags & 0x01,
|
||||
flags & 0x02,
|
||||
flags & 0x04,
|
||||
flags & 0x08,
|
||||
flags & 0x10,
|
||||
flags & 0x20,
|
||||
flags & 0x40,
|
||||
flags & 0x80,
|
||||
response & 0xFF
|
||||
);*/
|
||||
|
||||
if (ot->isValidResponse(response)) {
|
||||
vars.parameters.slaveMemberIdCode = response & 0xFF;
|
||||
|
||||
} else if ( settings.opentherm.memberIdCode <= 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vars.parameters.slaveMemberIdCode = response >> 0 & 0xFF;
|
||||
ot.sendRequest(ot.buildRequest(OpenThermRequestType::WRITE, OpenThermMessageID::MConfigMMemberIDcode, vars.parameters.slaveMemberIdCode));
|
||||
response = ot->sendRequest(ot->buildRequest(
|
||||
OpenThermRequestType::WRITE,
|
||||
OpenThermMessageID::MConfigMMemberIDcode,
|
||||
settings.opentherm.memberIdCode > 0 ? settings.opentherm.memberIdCode : vars.parameters.slaveMemberIdCode
|
||||
));
|
||||
|
||||
return ot->isValidResponse(response);
|
||||
}
|
||||
|
||||
void updateMasterParameters() {
|
||||
unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::WRITE, OpenThermMessageID::MasterVersion, 0x013F));
|
||||
if (!ot.isValidResponse(response)) {
|
||||
return;
|
||||
bool setMaxModulationLevel(byte value) {
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::WRITE, OpenThermMessageID::MaxRelModLevelSetting, (unsigned int)(value * 256)));
|
||||
|
||||
return ot->isValidResponse(response);
|
||||
}
|
||||
|
||||
bool setOpenThermVersionMaster() {
|
||||
unsigned long response;
|
||||
response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::READ, OpenThermMessageID::OpenThermVersionSlave, 0));
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
// INFO_F("Opentherm version slave: %f\n", ot->getFloat(response));
|
||||
|
||||
response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::WRITE_DATA, OpenThermMessageID::OpenThermVersionMaster, response));
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
// INFO_F("Opentherm version master: %f\n", ot->getFloat(response));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool updateMasterParameters() {
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::WRITE, OpenThermMessageID::MasterVersion, 0x013F));
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vars.parameters.masterType = (response & 0xFFFF) >> 8;
|
||||
vars.parameters.masterVersion = response & 0xFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateSlaveParameters() {
|
||||
unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::SlaveVersion, 0));
|
||||
if (!ot.isValidResponse(response)) {
|
||||
return;
|
||||
bool updateSlaveParameters() {
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::READ, OpenThermMessageID::SlaveVersion, 0));
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vars.parameters.slaveType = (response & 0xFFFF) >> 8;
|
||||
vars.parameters.slaveVersion = response & 0xFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateMinMaxDhwTemp() {
|
||||
unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::TdhwSetUBTdhwSetLB, 0));
|
||||
|
||||
if (!ot.isValidResponse(response)) {
|
||||
return;
|
||||
bool updateMinMaxDhwTemp() {
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::READ, OpenThermMessageID::TdhwSetUBTdhwSetLB, 0));
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte minTemp = response & 0xFF;
|
||||
@@ -472,14 +308,17 @@ protected:
|
||||
if (minTemp >= 0 && maxTemp > 0 && maxTemp > minTemp) {
|
||||
vars.parameters.dhwMinTemp = minTemp;
|
||||
vars.parameters.dhwMaxTemp = maxTemp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateMinMaxHeatingTemp() {
|
||||
unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::MaxTSetUBMaxTSetLB, 0));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ot.isValidResponse(response)) {
|
||||
return;
|
||||
bool updateMinMaxHeatingTemp() {
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::READ, OpenThermMessageID::MaxTSetUBMaxTSetLB, 0));
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte minTemp = response & 0xFF;
|
||||
@@ -488,55 +327,80 @@ protected:
|
||||
if (minTemp >= 0 && maxTemp > 0 && maxTemp > minTemp) {
|
||||
vars.parameters.heatingMinTemp = minTemp;
|
||||
vars.parameters.heatingMaxTemp = maxTemp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateOutsideTemp() {
|
||||
unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Toutside, 0));
|
||||
|
||||
if (ot.isValidResponse(response)) {
|
||||
vars.temperatures.outdoor = ot.getFloat(response);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void updateHeatingTemp() {
|
||||
unsigned long response = ot.sendRequest(ot.buildGetBoilerTemperatureRequest());
|
||||
|
||||
if (ot.isValidResponse(response)) {
|
||||
vars.temperatures.heating = ot.getFloat(response);
|
||||
bool updateOutsideTemp() {
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Toutside, 0));
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vars.temperatures.outdoor = ot->getFloat(response);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool updateHeatingTemp() {
|
||||
unsigned long response = ot->sendRequest(ot->buildGetBoilerTemperatureRequest());
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vars.temperatures.heating = ot->getFloat(response);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void updateDHWTemp() {
|
||||
unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Tdhw, 0));
|
||||
|
||||
if (ot.isValidResponse(response)) {
|
||||
vars.temperatures.dhw = ot.getFloat(response);
|
||||
}
|
||||
bool updateDHWTemp() {
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermMessageType::READ, OpenThermMessageID::Tdhw, 0));
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void updateFaultCode() {
|
||||
unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::ASFflags, 0));
|
||||
vars.temperatures.dhw = ot->getFloat(response);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool updateFaultCode() {
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::READ, OpenThermMessageID::ASFflags, 0));
|
||||
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ot.isValidResponse(response)) {
|
||||
vars.states.faultCode = response & 0xFF;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateModulationLevel() {
|
||||
unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::RelModLevel, 0));
|
||||
bool updateModulationLevel() {
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::READ, OpenThermMessageID::RelModLevel, 0));
|
||||
|
||||
if (ot.isValidResponse(response)) {
|
||||
vars.sensors.modulation = ot.getFloat(response);
|
||||
}
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void updatePressure() {
|
||||
unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::CHPressure, 0));
|
||||
|
||||
if (ot.isValidResponse(response)) {
|
||||
vars.sensors.pressure = ot.getFloat(response);
|
||||
float modulation = ot->f88(response);
|
||||
if (!vars.states.flame) {
|
||||
vars.sensors.modulation = 0;
|
||||
} else {
|
||||
vars.sensors.modulation = modulation;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool updatePressure() {
|
||||
unsigned long response = ot->sendRequest(ot->buildRequest(OpenThermRequestType::READ, OpenThermMessageID::CHPressure, 0));
|
||||
|
||||
if (!ot->isValidResponse(response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vars.sensors.pressure = ot->getFloat(response);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "lib/Equitherm.h"
|
||||
#include <Equitherm.h>
|
||||
#include <GyverPID.h>
|
||||
#include <PIDtuner.h>
|
||||
|
||||
@@ -6,9 +6,9 @@ Equitherm etRegulator;
|
||||
GyverPID pidRegulator(0, 0, 0, 10000);
|
||||
PIDtuner pidTuner;
|
||||
|
||||
class RegulatorTask : public LeanTask {
|
||||
class RegulatorTask: public LeanTask {
|
||||
public:
|
||||
RegulatorTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {}
|
||||
RegulatorTask(bool _enabled = false, unsigned long _interval = 0): LeanTask(_enabled, _interval) {}
|
||||
|
||||
protected:
|
||||
bool tunerInit = false;
|
||||
@@ -21,21 +21,39 @@ protected:
|
||||
|
||||
void setup() {}
|
||||
void loop() {
|
||||
byte newTemp;
|
||||
byte newTemp = vars.parameters.heatingSetpoint;
|
||||
|
||||
if (vars.states.emergency) {
|
||||
if (settings.heating.turbo) {
|
||||
settings.heating.turbo = false;
|
||||
|
||||
INFO("[REGULATOR] Turbo mode auto disabled");
|
||||
}
|
||||
|
||||
newTemp = getEmergencyModeTemp();
|
||||
|
||||
} else {
|
||||
if ( vars.tuning.enable || tunerInit ) {
|
||||
if (vars.tuning.enable || tunerInit) {
|
||||
if (settings.heating.turbo) {
|
||||
settings.heating.turbo = false;
|
||||
|
||||
INFO("[REGULATOR] Turbo mode auto disabled");
|
||||
}
|
||||
|
||||
newTemp = getTuningModeTemp();
|
||||
|
||||
if ( newTemp == 0 ) {
|
||||
if (newTemp == 0) {
|
||||
vars.tuning.enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !vars.tuning.enable ) {
|
||||
if (!vars.tuning.enable) {
|
||||
if (settings.heating.turbo && (fabs(settings.heating.target - vars.temperatures.indoor) < 1 || (settings.equitherm.enable && settings.pid.enable))) {
|
||||
settings.heating.turbo = false;
|
||||
|
||||
INFO("[REGULATOR] Turbo mode auto disabled");
|
||||
}
|
||||
|
||||
newTemp = getNormalModeTemp();
|
||||
}
|
||||
}
|
||||
@@ -56,13 +74,13 @@ protected:
|
||||
|
||||
// if use equitherm
|
||||
if (settings.emergency.useEquitherm && settings.outdoorTempSource != 1) {
|
||||
float etResult = getEquithermTemp();
|
||||
float etResult = getEquithermTemp(vars.parameters.heatingMinTemp, vars.parameters.heatingMaxTemp);
|
||||
|
||||
if (fabs(prevEtResult - etResult) + 0.0001 >= 0.5) {
|
||||
prevEtResult = etResult;
|
||||
newTemp += etResult;
|
||||
|
||||
INFO_F("[REGULATOR][EQUITHERM] New emergency result: %u (%f) \n", (byte) round(etResult), etResult);
|
||||
INFO_F("[REGULATOR][EQUITHERM] New emergency result: %u (%f) \n", (int)round(etResult), etResult);
|
||||
|
||||
} else {
|
||||
newTemp += prevEtResult;
|
||||
@@ -81,19 +99,23 @@ protected:
|
||||
|
||||
if (fabs(prevHeatingTarget - settings.heating.target) > 0.0001) {
|
||||
prevHeatingTarget = settings.heating.target;
|
||||
|
||||
INFO_F("[REGULATOR] New target: %f \n", settings.heating.target);
|
||||
|
||||
if (settings.equitherm.enable && settings.pid.enable) {
|
||||
pidRegulator.integral = 0;
|
||||
INFO_F("[REGULATOR][PID] Integral sum has been reset");
|
||||
}
|
||||
}
|
||||
|
||||
// if use equitherm
|
||||
if (settings.equitherm.enable) {
|
||||
float etResult = getEquithermTemp();
|
||||
float etResult = getEquithermTemp(vars.parameters.heatingMinTemp, vars.parameters.heatingMaxTemp);
|
||||
|
||||
if (fabs(prevEtResult - etResult) + 0.0001 >= 0.5) {
|
||||
prevEtResult = etResult;
|
||||
newTemp += etResult;
|
||||
|
||||
INFO_F("[REGULATOR][EQUITHERM] New result: %u (%f) \n", (byte) round(etResult), etResult);
|
||||
INFO_F("[REGULATOR][EQUITHERM] New result: %u (%f) \n", (int)round(etResult), etResult);
|
||||
|
||||
} else {
|
||||
newTemp += prevEtResult;
|
||||
@@ -102,13 +124,16 @@ protected:
|
||||
|
||||
// if use pid
|
||||
if (settings.pid.enable) {
|
||||
float pidResult = getPidTemp();
|
||||
float pidResult = getPidTemp(
|
||||
settings.equitherm.enable ? -30 : vars.parameters.heatingMinTemp,
|
||||
settings.equitherm.enable ? 30 : vars.parameters.heatingMaxTemp
|
||||
);
|
||||
|
||||
if (fabs(prevPidResult - pidResult) + 0.0001 >= 0.5) {
|
||||
prevPidResult = pidResult;
|
||||
newTemp += pidResult;
|
||||
|
||||
INFO_F("[REGULATOR][PID] New result: %u (%f) \n", (byte) round(pidResult), pidResult);
|
||||
INFO_F("[REGULATOR][PID] New result: %u (%f) \n", (int)round(pidResult), pidResult);
|
||||
|
||||
} else {
|
||||
newTemp += prevPidResult;
|
||||
@@ -124,8 +149,8 @@ protected:
|
||||
}
|
||||
|
||||
byte getTuningModeTemp() {
|
||||
if ( tunerInit && (!vars.tuning.enable || vars.tuning.regulator != tunerRegulator) ) {
|
||||
if ( tunerRegulator == 0 ) {
|
||||
if (tunerInit && (!vars.tuning.enable || vars.tuning.regulator != tunerRegulator)) {
|
||||
if (tunerRegulator == 0) {
|
||||
pidTuner.reset();
|
||||
}
|
||||
|
||||
@@ -135,19 +160,21 @@ protected:
|
||||
INFO(F("[REGULATOR][TUNING] Stopped"));
|
||||
}
|
||||
|
||||
if ( !vars.tuning.enable ) {
|
||||
if (!vars.tuning.enable) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if ( vars.tuning.regulator == 0 ) {
|
||||
if (vars.tuning.regulator == 0) {
|
||||
// @TODO дописать
|
||||
INFO(F("[REGULATOR][TUNING][EQUITHERM] Not implemented"));
|
||||
return 0;
|
||||
|
||||
} else if ( vars.tuning.regulator == 1 ) {
|
||||
} else if (vars.tuning.regulator == 1) {
|
||||
// PID tuner
|
||||
float defaultTemp = settings.equitherm.enable ? getEquithermTemp() : settings.heating.target;
|
||||
float defaultTemp = settings.equitherm.enable
|
||||
? getEquithermTemp(vars.parameters.heatingMinTemp, vars.parameters.heatingMaxTemp)
|
||||
: settings.heating.target;
|
||||
|
||||
if (tunerInit && pidTuner.getState() == 3) {
|
||||
INFO(F("[REGULATOR][TUNING][PID] Finished"));
|
||||
@@ -203,8 +230,8 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
float getEquithermTemp() {
|
||||
if ( vars.states.emergency ) {
|
||||
float getEquithermTemp(int minTemp, int maxTemp) {
|
||||
if (vars.states.emergency) {
|
||||
etRegulator.Kt = 0;
|
||||
etRegulator.indoorTemp = 0;
|
||||
etRegulator.outdoorTemp = vars.temperatures.outdoor;
|
||||
@@ -214,13 +241,17 @@ protected:
|
||||
etRegulator.indoorTemp = round(vars.temperatures.indoor);
|
||||
etRegulator.outdoorTemp = round(vars.temperatures.outdoor);
|
||||
|
||||
} else {
|
||||
if (settings.heating.turbo) {
|
||||
etRegulator.Kt = 10;
|
||||
} else {
|
||||
etRegulator.Kt = settings.equitherm.t_factor;
|
||||
}
|
||||
etRegulator.indoorTemp = vars.temperatures.indoor;
|
||||
etRegulator.outdoorTemp = vars.temperatures.outdoor;
|
||||
}
|
||||
|
||||
etRegulator.setLimits(vars.parameters.heatingMinTemp, vars.parameters.heatingMaxTemp);
|
||||
etRegulator.setLimits(minTemp, maxTemp);
|
||||
etRegulator.Kn = settings.equitherm.n_factor;
|
||||
// etRegulator.Kn = tuneEquithermN(etRegulator.Kn, vars.temperatures.indoor, settings.heating.target, 300, 1800, 0.01, 1);
|
||||
etRegulator.Kk = settings.equitherm.k_factor;
|
||||
@@ -229,12 +260,12 @@ protected:
|
||||
return etRegulator.getResult();
|
||||
}
|
||||
|
||||
float getPidTemp() {
|
||||
float getPidTemp(int minTemp, int maxTemp) {
|
||||
pidRegulator.Kp = settings.pid.p_factor;
|
||||
pidRegulator.Ki = settings.pid.i_factor;
|
||||
pidRegulator.Kd = settings.pid.d_factor;
|
||||
|
||||
pidRegulator.setLimits(vars.parameters.heatingMinTemp, vars.parameters.heatingMaxTemp);
|
||||
pidRegulator.setLimits(minTemp, maxTemp);
|
||||
pidRegulator.input = vars.temperatures.indoor;
|
||||
pidRegulator.setpoint = settings.heating.target;
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
MicroDS18B20<DS18B20_PIN> outdoorSensor;
|
||||
|
||||
class SensorsTask : public LeanTask {
|
||||
class SensorsTask: public LeanTask {
|
||||
public:
|
||||
SensorsTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {}
|
||||
SensorsTask(bool _enabled = false, unsigned long _interval = 0): LeanTask(_enabled, _interval) {}
|
||||
|
||||
protected:
|
||||
float filteredOutdoorTemp = 0;
|
||||
@@ -16,9 +16,9 @@ protected:
|
||||
if (outdoorSensor.online()) {
|
||||
if (outdoorSensor.readTemp()) {
|
||||
float rawTemp = outdoorSensor.getTemp();
|
||||
INFO_F("[SENSORS][DS18B20] Raw temp: %f \n", rawTemp);
|
||||
DEBUG_F("[SENSORS][DS18B20] Raw temp: %f \n", rawTemp);
|
||||
|
||||
if ( emptyOutdoorTemp ) {
|
||||
if (emptyOutdoorTemp) {
|
||||
filteredOutdoorTemp = rawTemp;
|
||||
emptyOutdoorTemp = false;
|
||||
|
||||
@@ -28,7 +28,7 @@ protected:
|
||||
|
||||
filteredOutdoorTemp = floor(filteredOutdoorTemp * 100) / 100;
|
||||
|
||||
if ( fabs(vars.temperatures.outdoor - filteredOutdoorTemp) > 0.099 ) {
|
||||
if (fabs(vars.temperatures.outdoor - filteredOutdoorTemp) > 0.099) {
|
||||
vars.temperatures.outdoor = filteredOutdoorTemp;
|
||||
INFO_F("[SENSORS][DS18B20] New temp: %f \n", filteredOutdoorTemp);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,12 @@ struct Settings {
|
||||
byte outdoorTempSource = 0;
|
||||
char hostname[80] = "opentherm";
|
||||
|
||||
struct {
|
||||
byte inPin = 5;
|
||||
byte outPin = 4;
|
||||
unsigned int memberIdCode = 4;
|
||||
} opentherm;
|
||||
|
||||
struct {
|
||||
char server[80];
|
||||
int port = 1883;
|
||||
@@ -21,6 +27,7 @@ struct Settings {
|
||||
|
||||
struct {
|
||||
bool enable = true;
|
||||
bool turbo = false;
|
||||
float target = 40.0f;
|
||||
float hysteresis = 0.5f;
|
||||
} heating;
|
||||
@@ -39,9 +46,9 @@ struct Settings {
|
||||
|
||||
struct {
|
||||
bool enable = false;
|
||||
float n_factor = 0.67f;
|
||||
float k_factor = 1.0f;
|
||||
float t_factor = 5.0f;
|
||||
float n_factor = 0.7f;
|
||||
float k_factor = 3.0f;
|
||||
float t_factor = 2.0f;
|
||||
} equitherm;
|
||||
|
||||
} settings;
|
||||
@@ -61,6 +68,7 @@ struct Variables {
|
||||
bool fault = false;
|
||||
bool diagnostic = false;
|
||||
byte faultCode = 0;
|
||||
int8_t rssi = 0;
|
||||
} states;
|
||||
|
||||
struct {
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
// #include <WiFiClient.h>
|
||||
#define WM_MDNS
|
||||
#include <WiFiManager.h>
|
||||
//#include <ESP8266mDNS.h>
|
||||
//#include <WiFiUdp.h>
|
||||
|
||||
// Wifimanager
|
||||
WiFiManager wm;
|
||||
WiFiManagerParameter *wmHostname;
|
||||
WiFiManagerParameter *wmMqttServer;
|
||||
WiFiManagerParameter *wmMqttPort;
|
||||
WiFiManagerParameter *wmMqttUser;
|
||||
WiFiManagerParameter *wmMqttPassword;
|
||||
WiFiManagerParameter *wmMqttPrefix;
|
||||
WiFiManagerParameter* wmHostname;
|
||||
WiFiManagerParameter* wmOtInPin;
|
||||
WiFiManagerParameter* wmOtOutPin;
|
||||
WiFiManagerParameter* wmOtMemberIdCode;
|
||||
WiFiManagerParameter* wmMqttServer;
|
||||
WiFiManagerParameter* wmMqttPort;
|
||||
WiFiManagerParameter* wmMqttUser;
|
||||
WiFiManagerParameter* wmMqttPassword;
|
||||
WiFiManagerParameter* wmMqttPrefix;
|
||||
|
||||
class WifiManagerTask : public Task {
|
||||
class WifiManagerTask: public Task {
|
||||
public:
|
||||
WifiManagerTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {}
|
||||
WifiManagerTask(bool _enabled = false, unsigned long _interval = 0): Task(_enabled, _interval) {}
|
||||
|
||||
protected:
|
||||
void setup() {
|
||||
@@ -25,6 +24,18 @@ protected:
|
||||
wmHostname = new WiFiManagerParameter("hostname", "Hostname", settings.hostname, 80);
|
||||
wm.addParameter(wmHostname);
|
||||
|
||||
sprintf(buffer, "%d", settings.opentherm.inPin);
|
||||
wmOtInPin = new WiFiManagerParameter("ot_in_pin", "Opentherm pin IN", buffer, 1);
|
||||
wm.addParameter(wmOtInPin);
|
||||
|
||||
sprintf(buffer, "%d", settings.opentherm.outPin);
|
||||
wmOtOutPin = new WiFiManagerParameter("ot_out_pin", "Opentherm pin OUT", buffer, 1);
|
||||
wm.addParameter(wmOtOutPin);
|
||||
|
||||
sprintf(buffer, "%d", settings.opentherm.memberIdCode);
|
||||
wmOtMemberIdCode = new WiFiManagerParameter("ot_member_id_code", "Opentherm member id code", buffer, 5);
|
||||
wm.addParameter(wmOtMemberIdCode);
|
||||
|
||||
wmMqttServer = new WiFiManagerParameter("mqtt_server", "MQTT server", settings.mqtt.server, 80);
|
||||
wm.addParameter(wmMqttServer);
|
||||
|
||||
@@ -46,15 +57,22 @@ protected:
|
||||
|
||||
wm.setHostname(settings.hostname);
|
||||
wm.setWiFiAutoReconnect(true);
|
||||
wm.setAPClientCheck(true);
|
||||
wm.setConfigPortalBlocking(false);
|
||||
wm.setSaveParamsCallback(saveParamsCallback);
|
||||
wm.setConfigPortalTimeout(300);
|
||||
wm.setDisableConfigPortal(false);
|
||||
wm.setConfigPortalTimeout(180);
|
||||
//wm.setDisableConfigPortal(false);
|
||||
|
||||
wm.autoConnect(AP_SSID);
|
||||
wm.autoConnect(AP_SSID, AP_PASSWORD);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static unsigned short prevCounterLiters = 0;
|
||||
|
||||
/*if (WiFi.status() != WL_CONNECTED && !wm.getWebPortalActive() && !wm.getConfigPortalActive()) {
|
||||
wm.autoConnect(AP_SSID);
|
||||
}*/
|
||||
|
||||
if (connected && WiFi.status() != WL_CONNECTED) {
|
||||
connected = false;
|
||||
INFO("[wifi] Disconnected");
|
||||
@@ -62,6 +80,10 @@ protected:
|
||||
} else if (!connected && WiFi.status() == WL_CONNECTED) {
|
||||
connected = true;
|
||||
|
||||
if (wm.getConfigPortalActive()) {
|
||||
wm.stopConfigPortal();
|
||||
}
|
||||
|
||||
INFO_F("[wifi] Connected. IP address: %s, RSSI: %d\n", WiFi.localIP().toString().c_str(), WiFi.RSSI());
|
||||
}
|
||||
|
||||
@@ -73,14 +95,34 @@ protected:
|
||||
}
|
||||
|
||||
void static saveParamsCallback() {
|
||||
strcpy(settings.hostname, (*wmHostname).getValue());
|
||||
strcpy(settings.mqtt.server, (*wmMqttServer).getValue());
|
||||
settings.mqtt.port = atoi((*wmMqttPort).getValue());
|
||||
strcpy(settings.mqtt.user, (*wmMqttUser).getValue());
|
||||
strcpy(settings.mqtt.password, (*wmMqttPassword).getValue());
|
||||
strcpy(settings.mqtt.prefix, (*wmMqttPrefix).getValue());
|
||||
strcpy(settings.hostname, wmHostname->getValue());
|
||||
settings.opentherm.inPin = atoi(wmOtInPin->getValue());
|
||||
settings.opentherm.outPin = atoi(wmOtOutPin->getValue());
|
||||
settings.opentherm.memberIdCode = atoi(wmOtMemberIdCode->getValue());
|
||||
strcpy(settings.mqtt.server, wmMqttServer->getValue());
|
||||
settings.mqtt.port = atoi(wmMqttPort->getValue());
|
||||
strcpy(settings.mqtt.user, wmMqttUser->getValue());
|
||||
strcpy(settings.mqtt.password, wmMqttPassword->getValue());
|
||||
strcpy(settings.mqtt.prefix, wmMqttPrefix->getValue());
|
||||
|
||||
INFO_F("Settings\nHostname: %s, Server: %s, port: %d, user: %s, pass: %s\n", settings.hostname, settings.mqtt.server, settings.mqtt.port, settings.mqtt.user, settings.mqtt.password);
|
||||
INFO_F(
|
||||
"New settings:\r\n"
|
||||
" Hostname: %s\r\n"
|
||||
" OT in pin: %d"
|
||||
" OT out pin: %d"
|
||||
" OT member id code: %d"
|
||||
" Mqtt server: %s:%d\r\n"
|
||||
" Mqtt user: %s\r\n"
|
||||
" Mqtt pass: %s\r\n",
|
||||
settings.hostname,
|
||||
settings.opentherm.inPin,
|
||||
settings.opentherm.outPin,
|
||||
settings.opentherm.memberIdCode,
|
||||
settings.mqtt.server,
|
||||
settings.mqtt.port,
|
||||
settings.mqtt.user,
|
||||
settings.mqtt.password
|
||||
);
|
||||
eeSettings.updateNow();
|
||||
INFO(F("Settings saved"));
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#define OT_GATEWAY_VERSION "1.0.7"
|
||||
#define OT_GATEWAY_VERSION "1.2.1"
|
||||
#define AP_SSID "OpenTherm Gateway"
|
||||
#define AP_PASSWORD "otgateway123456"
|
||||
#define USE_TELNET
|
||||
|
||||
#define EMERGENCY_TRESHOLD 10
|
||||
#define EMERGENCY_TIME_TRESHOLD 120000
|
||||
#define MQTT_RECONNECT_INTERVAL 5000
|
||||
#define MQTT_KEEPALIVE 30
|
||||
|
||||
#define OPENTHERM_IN_PIN 4
|
||||
#define OPENTHERM_OUT_PIN 5
|
||||
#define OPENTHERM_OFFLINE_TRESHOLD 10
|
||||
|
||||
#define DS18B20_PIN 2
|
||||
@@ -16,6 +15,9 @@
|
||||
#define DS_CHECK_CRC true
|
||||
#define DS_CRC_USE_TABLE true
|
||||
|
||||
#define LED_STATUS_PIN 13
|
||||
#define LED_OT_RX_PIN 15
|
||||
|
||||
#define CONFIG_URL "http://%s/"
|
||||
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <OpenTherm.h>
|
||||
|
||||
extern SchedulerClass Scheduler;
|
||||
|
||||
class CustomOpenTherm : public OpenTherm {
|
||||
private:
|
||||
unsigned long send_ts = millis();
|
||||
void(*handleSendRequestCallback)(unsigned long, unsigned long, OpenThermResponseStatus status, byte attempt);
|
||||
|
||||
public:
|
||||
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false) : OpenTherm(inPin, outPin, isSlave) {}
|
||||
void setHandleSendRequestCallback(void(*handleSendRequestCallback)(unsigned long, unsigned long, OpenThermResponseStatus status, byte attempt)) {
|
||||
this->handleSendRequestCallback = handleSendRequestCallback;
|
||||
}
|
||||
|
||||
unsigned long sendRequest(unsigned long request, byte attempts = 5, byte _attempt = 0) {
|
||||
_attempt++;
|
||||
while (send_ts > 0 && millis() - send_ts < 200) {
|
||||
Scheduler.yield();
|
||||
}
|
||||
|
||||
unsigned long _response;
|
||||
if (!sendRequestAync(request)) {
|
||||
_response = 0;
|
||||
} else {
|
||||
while (!isReady()) {
|
||||
Scheduler.yield();
|
||||
process();
|
||||
}
|
||||
|
||||
_response = getLastResponse();
|
||||
}
|
||||
|
||||
if (handleSendRequestCallback != NULL) {
|
||||
handleSendRequestCallback(request, _response, getLastResponseStatus(), _attempt);
|
||||
}
|
||||
|
||||
send_ts = millis();
|
||||
if (getLastResponseStatus() == OpenThermResponseStatus::SUCCESS || _attempt >= attempts) {
|
||||
return _response;
|
||||
} else {
|
||||
return sendRequest(request, attempts, _attempt);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <Arduino.h>
|
||||
#include "defines.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include <TelnetStream.h>
|
||||
@@ -52,7 +53,7 @@ void setup() {
|
||||
tMqtt = new MqttTask(false);
|
||||
Scheduler.start(tMqtt);
|
||||
|
||||
tOt = new OpenThermTask(true);
|
||||
tOt = new OpenThermTask(false);
|
||||
Scheduler.start(tOt);
|
||||
|
||||
tSensors = new SensorsTask(false, DS18B20_INTERVAL);
|
||||
|
||||
Reference in New Issue
Block a user