mirror of
https://github.com/Laxilef/OTGateway.git
synced 2025-12-25 17:43:35 +05:00
Compare commits
3 Commits
9dd5ee8da5
...
arduino_fr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
842b443723 | ||
|
|
3bf65aeaad | ||
|
|
1b004b25c7 |
@@ -7,7 +7,7 @@ public:
|
|||||||
typedef std::function<void(unsigned long, byte)> BeforeSendRequestCallback;
|
typedef std::function<void(unsigned long, byte)> BeforeSendRequestCallback;
|
||||||
typedef std::function<void(unsigned long, unsigned long, OpenThermResponseStatus, byte)> AfterSendRequestCallback;
|
typedef std::function<void(unsigned long, unsigned long, OpenThermResponseStatus, byte)> AfterSendRequestCallback;
|
||||||
|
|
||||||
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false, bool alwaysReceive = false) : OpenTherm(inPin, outPin, isSlave, alwaysReceive) {}
|
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false) : OpenTherm(inPin, outPin, isSlave) {}
|
||||||
~CustomOpenTherm() {}
|
~CustomOpenTherm() {}
|
||||||
|
|
||||||
CustomOpenTherm* setDelayCallback(DelayCallback callback = nullptr) {
|
CustomOpenTherm* setDelayCallback(DelayCallback callback = nullptr) {
|
||||||
@@ -28,8 +28,8 @@ public:
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long sendRequest(unsigned long request) override {
|
unsigned long sendRequest(unsigned long request, byte attempts = 5, byte _attempt = 0) {
|
||||||
this->sendRequestAttempt++;
|
_attempt++;
|
||||||
|
|
||||||
while (!this->isReady()) {
|
while (!this->isReady()) {
|
||||||
if (this->delayCallback) {
|
if (this->delayCallback) {
|
||||||
@@ -40,10 +40,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this->beforeSendRequestCallback) {
|
if (this->beforeSendRequestCallback) {
|
||||||
this->beforeSendRequestCallback(request, this->sendRequestAttempt);
|
this->beforeSendRequestCallback(request, _attempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->sendRequestAsync(request)) {
|
unsigned long _response;
|
||||||
|
OpenThermResponseStatus _responseStatus = OpenThermResponseStatus::NONE;
|
||||||
|
if (!this->sendRequestAsync(request)) {
|
||||||
|
_response = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
do {
|
do {
|
||||||
if (this->delayCallback) {
|
if (this->delayCallback) {
|
||||||
this->delayCallback(150);
|
this->delayCallback(150);
|
||||||
@@ -51,25 +56,42 @@ public:
|
|||||||
|
|
||||||
this->process();
|
this->process();
|
||||||
} while (this->status != OpenThermStatus::READY && this->status != OpenThermStatus::DELAY);
|
} while (this->status != OpenThermStatus::READY && this->status != OpenThermStatus::DELAY);
|
||||||
|
|
||||||
|
_response = this->getLastResponse();
|
||||||
|
_responseStatus = this->getLastResponseStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->afterSendRequestCallback) {
|
if (this->afterSendRequestCallback) {
|
||||||
this->afterSendRequestCallback(request, this->response, this->responseStatus, this->sendRequestAttempt);
|
this->afterSendRequestCallback(request, _response, _responseStatus, _attempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->responseStatus == OpenThermResponseStatus::SUCCESS || this->responseStatus == OpenThermResponseStatus::INVALID) {
|
if (_responseStatus == OpenThermResponseStatus::SUCCESS || _responseStatus == OpenThermResponseStatus::INVALID || _attempt >= attempts) {
|
||||||
this->sendRequestAttempt = 0;
|
return _response;
|
||||||
return this->response;
|
|
||||||
|
|
||||||
} else if (this->sendRequestAttempt >= this->sendRequestMaxAttempts) {
|
|
||||||
this->sendRequestAttempt = 0;
|
|
||||||
return this->response;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return this->sendRequest(request);
|
return this->sendRequest(request, attempts, _attempt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long setBoilerStatus(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2, bool summerWinterMode, bool dhwBlocking, uint8_t lb = 0) {
|
||||||
|
unsigned int data = enableCentralHeating
|
||||||
|
| (enableHotWater << 1)
|
||||||
|
| (enableCooling << 2)
|
||||||
|
| (enableOutsideTemperatureCompensation << 3)
|
||||||
|
| (enableCentralHeating2 << 4)
|
||||||
|
| (summerWinterMode << 5)
|
||||||
|
| (dhwBlocking << 6);
|
||||||
|
|
||||||
|
data <<= 8;
|
||||||
|
data |= lb;
|
||||||
|
|
||||||
|
return this->sendRequest(buildRequest(
|
||||||
|
OpenThermMessageType::READ_DATA,
|
||||||
|
OpenThermMessageID::Status,
|
||||||
|
data
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
bool sendBoilerReset() {
|
bool sendBoilerReset() {
|
||||||
unsigned int data = 1;
|
unsigned int data = 1;
|
||||||
data <<= 8;
|
data <<= 8;
|
||||||
@@ -108,31 +130,10 @@ public:
|
|||||||
|
|
||||||
static bool isValidResponseId(unsigned long response, OpenThermMessageID id) {
|
static bool isValidResponseId(unsigned long response, OpenThermMessageID id) {
|
||||||
byte responseId = (response >> 16) & 0xFF;
|
byte responseId = (response >> 16) & 0xFF;
|
||||||
|
|
||||||
return (byte)id == responseId;
|
return (byte)id == responseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t getResponseMessageTypeId(unsigned long response) {
|
|
||||||
return (response << 1) >> 29;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* getResponseMessageTypeString(unsigned long response) {
|
|
||||||
uint8_t msgType = getResponseMessageTypeId(response);
|
|
||||||
|
|
||||||
switch (msgType) {
|
|
||||||
case (uint8_t) OpenThermMessageType::READ_ACK:
|
|
||||||
case (uint8_t) OpenThermMessageType::WRITE_ACK:
|
|
||||||
case (uint8_t) OpenThermMessageType::DATA_INVALID:
|
|
||||||
case (uint8_t) OpenThermMessageType::UNKNOWN_DATA_ID:
|
|
||||||
return CustomOpenTherm::messageTypeToString(
|
|
||||||
static_cast<OpenThermMessageType>(msgType)
|
|
||||||
);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// converters
|
// converters
|
||||||
template <class T>
|
template <class T>
|
||||||
static unsigned int toFloat(const T val) {
|
static unsigned int toFloat(const T val) {
|
||||||
@@ -144,8 +145,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const uint8_t sendRequestMaxAttempts = 5;
|
|
||||||
uint8_t sendRequestAttempt = 0;
|
|
||||||
DelayCallback delayCallback;
|
DelayCallback delayCallback;
|
||||||
BeforeSendRequestCallback beforeSendRequestCallback;
|
BeforeSendRequestCallback beforeSendRequestCallback;
|
||||||
AfterSendRequestCallback afterSendRequestCallback;
|
AfterSendRequestCallback afterSendRequestCallback;
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ extra_configs = secrets.default.ini
|
|||||||
core_dir = .pio
|
core_dir = .pio
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
version = 1.5.4
|
version = 1.5.3
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson@^7.3.0
|
bblanchon/ArduinoJson@^7.3.0
|
||||||
;ihormelnyk/OpenTherm Library@^1.1.5
|
;ihormelnyk/OpenTherm Library@^1.1.5
|
||||||
https://github.com/Laxilef/opentherm_library#esp32_timer
|
https://github.com/ihormelnyk/opentherm_library#master
|
||||||
arduino-libraries/ArduinoMqttClient@^0.1.8
|
arduino-libraries/ArduinoMqttClient@^0.1.8
|
||||||
lennarthennigs/ESP Telnet@^2.2
|
lennarthennigs/ESP Telnet@^2.2
|
||||||
gyverlibs/FileData@^1.0.2
|
gyverlibs/FileData@^1.0.2
|
||||||
@@ -84,7 +84,7 @@ board_build.ldscript = eagle.flash.4m1m.ld
|
|||||||
;platform_packages =
|
;platform_packages =
|
||||||
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5
|
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5
|
||||||
; framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip
|
; framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip
|
||||||
platform_packages =
|
platform_packages =
|
||||||
board_build.partitions = esp32_partitions.csv
|
board_build.partitions = esp32_partitions.csv
|
||||||
lib_deps =
|
lib_deps =
|
||||||
|
|||||||
@@ -1215,7 +1215,7 @@ public:
|
|||||||
|
|
||||||
doc[FPSTR(HA_MIN_TEMP)] = minTemp;
|
doc[FPSTR(HA_MIN_TEMP)] = minTemp;
|
||||||
doc[FPSTR(HA_MAX_TEMP)] = maxTemp;
|
doc[FPSTR(HA_MAX_TEMP)] = maxTemp;
|
||||||
doc[FPSTR(HA_TEMP_STEP)] = 0.1f;
|
doc[FPSTR(HA_TEMP_STEP)] = 0.5f;
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
|||||||
@@ -196,7 +196,6 @@ protected:
|
|||||||
// critical heap
|
// critical heap
|
||||||
if (!vars.states.restarting && (freeHeap < 2048 || maxFreeBlockHeap < 2048)) {
|
if (!vars.states.restarting && (freeHeap < 2048 || maxFreeBlockHeap < 2048)) {
|
||||||
this->restartSignalReceivedTime = millis();
|
this->restartSignalReceivedTime = millis();
|
||||||
this->restartSignalReceived = true;
|
|
||||||
vars.states.restarting = true;
|
vars.states.restarting = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,13 +93,8 @@ protected:
|
|||||||
this->instance->setAfterSendRequestCallback([this](unsigned long request, unsigned long response, OpenThermResponseStatus status, byte attempt) {
|
this->instance->setAfterSendRequestCallback([this](unsigned long request, unsigned long response, OpenThermResponseStatus status, byte attempt) {
|
||||||
Log.sverboseln(
|
Log.sverboseln(
|
||||||
FPSTR(L_OT),
|
FPSTR(L_OT),
|
||||||
F("ID: %4d Request: %8lx Response: %8lx Msg type: %s Attempt: %2d Status: %s"),
|
F("ID: %4d Request: %8lx Response: %8lx Attempt: %2d Status: %s"),
|
||||||
CustomOpenTherm::getDataID(request),
|
CustomOpenTherm::getDataID(request), request, response, attempt, CustomOpenTherm::statusToString(status)
|
||||||
request,
|
|
||||||
response,
|
|
||||||
CustomOpenTherm::getResponseMessageTypeString(response),
|
|
||||||
attempt,
|
|
||||||
CustomOpenTherm::statusToString(status)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (status == OpenThermResponseStatus::SUCCESS) {
|
if (status == OpenThermResponseStatus::SUCCESS) {
|
||||||
@@ -143,12 +138,7 @@ protected:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
} else if (this->instance->status == OpenThermStatus::NOT_INITIALIZED) {
|
} else if (this->instance->status == OpenThermStatus::NOT_INITIALIZED) {
|
||||||
if (!this->instance->begin()) {
|
this->instance->begin();
|
||||||
Log.swarningln(FPSTR(L_OT), F("Failed begin"));
|
|
||||||
|
|
||||||
this->delay(5000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RX LED GPIO setup
|
// RX LED GPIO setup
|
||||||
@@ -222,20 +212,6 @@ protected:
|
|||||||
F("Failed receive boiler status: %s"),
|
F("Failed receive boiler status: %s"),
|
||||||
CustomOpenTherm::statusToString(this->instance->getLastResponseStatus())
|
CustomOpenTherm::statusToString(this->instance->getLastResponseStatus())
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
|
||||||
vars.slave.heating.active = CustomOpenTherm::isCentralHeatingActive(response);
|
|
||||||
vars.slave.dhw.active = settings.opentherm.options.dhwSupport ? CustomOpenTherm::isHotWaterActive(response) : false;
|
|
||||||
vars.slave.flame = CustomOpenTherm::isFlameOn(response);
|
|
||||||
vars.slave.cooling = CustomOpenTherm::isCoolingActive(response);
|
|
||||||
vars.slave.fault.active = CustomOpenTherm::isFault(response);
|
|
||||||
vars.slave.diag.active = CustomOpenTherm::isDiagnostic(response);
|
|
||||||
|
|
||||||
Log.snoticeln(
|
|
||||||
FPSTR(L_OT), F("Received boiler status. Heating: %hhu; DHW: %hhu; flame: %hhu; cooling: %hhu; fault: %hhu; diag: %hhu"),
|
|
||||||
vars.slave.heating.active, vars.slave.dhw.active,
|
|
||||||
vars.slave.flame, vars.slave.cooling, vars.slave.fault.active, vars.slave.diag.active
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5 request retries
|
// 5 request retries
|
||||||
@@ -334,6 +310,19 @@ protected:
|
|||||||
Log.sinfoln(FPSTR(L_OT_DHW), vars.master.dhw.enabled ? F("Enabled") : F("Disabled"));
|
Log.sinfoln(FPSTR(L_OT_DHW), vars.master.dhw.enabled ? F("Enabled") : F("Disabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vars.slave.heating.active = CustomOpenTherm::isCentralHeatingActive(response);
|
||||||
|
vars.slave.dhw.active = settings.opentherm.options.dhwSupport ? CustomOpenTherm::isHotWaterActive(response) : false;
|
||||||
|
vars.slave.flame = CustomOpenTherm::isFlameOn(response);
|
||||||
|
vars.slave.cooling = CustomOpenTherm::isCoolingActive(response);
|
||||||
|
vars.slave.fault.active = CustomOpenTherm::isFault(response);
|
||||||
|
vars.slave.diag.active = CustomOpenTherm::isDiagnostic(response);
|
||||||
|
|
||||||
|
Log.snoticeln(
|
||||||
|
FPSTR(L_OT), F("Received boiler status. Heating: %hhu; DHW: %hhu; flame: %hhu; cooling: %hhu; fault: %hhu; diag: %hhu"),
|
||||||
|
vars.slave.heating.active, vars.slave.dhw.active,
|
||||||
|
vars.slave.flame, vars.slave.cooling, vars.slave.fault.active, vars.slave.diag.active
|
||||||
|
);
|
||||||
|
|
||||||
// These parameters will be updated every minute
|
// These parameters will be updated every minute
|
||||||
if (millis() - this->prevUpdateNonEssentialVars > 60000) {
|
if (millis() - this->prevUpdateNonEssentialVars > 60000) {
|
||||||
if (this->updateMinModulationLevel()) {
|
if (this->updateMinModulationLevel()) {
|
||||||
@@ -1190,17 +1179,17 @@ protected:
|
|||||||
|
|
||||||
bool needSetDhwTemp(const float target) {
|
bool needSetDhwTemp(const float target) {
|
||||||
return millis() - this->dhwSetTempTime > this->dhwSetTempInterval
|
return millis() - this->dhwSetTempTime > this->dhwSetTempInterval
|
||||||
|| fabsf(target - vars.slave.dhw.targetTemp) > 0.05f;
|
|| fabsf(target - vars.slave.dhw.targetTemp) > 0.001f;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needSetHeatingTemp(const float target) {
|
bool needSetHeatingTemp(const float target) {
|
||||||
return millis() - this->heatingSetTempTime > this->heatingSetTempInterval
|
return millis() - this->heatingSetTempTime > this->heatingSetTempInterval
|
||||||
|| fabsf(target - vars.slave.heating.targetTemp) > 0.05f;
|
|| fabsf(target - vars.slave.heating.targetTemp) > 0.001f;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needSetCh2Temp(const float target) {
|
bool needSetCh2Temp(const float target) {
|
||||||
return millis() - this->ch2SetTempTime > this->ch2SetTempInterval
|
return millis() - this->ch2SetTempTime > this->ch2SetTempInterval
|
||||||
|| fabsf(target - vars.slave.ch2.targetTemp) > 0.05f;
|
|| fabsf(target - vars.slave.ch2.targetTemp) > 0.001f;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool updateSlaveConfig() {
|
bool updateSlaveConfig() {
|
||||||
@@ -1361,7 +1350,7 @@ protected:
|
|||||||
return CustomOpenTherm::getUInt(response) == request;
|
return CustomOpenTherm::getUInt(response) == request;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setMaxHeatingTemp(const float temperature) {
|
bool setMaxHeatingTemp(const uint8_t temperature) {
|
||||||
const unsigned int request = CustomOpenTherm::temperatureToData(temperature);
|
const unsigned int request = CustomOpenTherm::temperatureToData(temperature);
|
||||||
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
|
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
|
||||||
OpenThermMessageType::WRITE_DATA,
|
OpenThermMessageType::WRITE_DATA,
|
||||||
|
|||||||
@@ -60,11 +60,11 @@ protected:
|
|||||||
this->hysteresis();
|
this->hysteresis();
|
||||||
|
|
||||||
vars.master.heating.targetTemp = settings.heating.target;
|
vars.master.heating.targetTemp = settings.heating.target;
|
||||||
vars.master.heating.setpointTemp = roundf(constrain(
|
vars.master.heating.setpointTemp = constrain(
|
||||||
this->getHeatingSetpointTemp(),
|
this->getHeatingSetpointTemp(),
|
||||||
this->getHeatingMinSetpointTemp(),
|
this->getHeatingMinSetpointTemp(),
|
||||||
this->getHeatingMaxSetpointTemp()
|
this->getHeatingMaxSetpointTemp()
|
||||||
), 0);
|
);
|
||||||
|
|
||||||
Sensors::setValueByType(
|
Sensors::setValueByType(
|
||||||
Sensors::Type::HEATING_SETPOINT_TEMP, vars.master.heating.setpointTemp,
|
Sensors::Type::HEATING_SETPOINT_TEMP, vars.master.heating.setpointTemp,
|
||||||
|
|||||||
@@ -496,8 +496,9 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark connected
|
if (!rSensor.connected) {
|
||||||
Sensors::setConnectionStatusById(sensorId, true, true);
|
rSensor.connected = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this->bleLastSetDtTime[sensorId] || millis() - this->bleLastSetDtTime[sensorId] > this->bleSetDtInterval) {
|
if (!this->bleLastSetDtTime[sensorId] || millis() - this->bleLastSetDtTime[sensorId] > this->bleSetDtInterval) {
|
||||||
struct tm ti;
|
struct tm ti;
|
||||||
@@ -520,6 +521,7 @@ protected:
|
|||||||
|
|
||||||
this->bleLastSetDtTime[sensorId] = millis();
|
this->bleLastSetDtTime[sensorId] = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -979,16 +981,16 @@ protected:
|
|||||||
auto& rSensor = Sensors::results[sensorId];
|
auto& rSensor = Sensors::results[sensorId];
|
||||||
|
|
||||||
if (rSensor.connected && !sSensor.enabled) {
|
if (rSensor.connected && !sSensor.enabled) {
|
||||||
Sensors::setConnectionStatusById(sensorId, false, false);
|
rSensor.connected = false;
|
||||||
|
|
||||||
} else if (rSensor.connected && sSensor.type == Sensors::Type::NOT_CONFIGURED) {
|
} else if (rSensor.connected && sSensor.type == Sensors::Type::NOT_CONFIGURED) {
|
||||||
Sensors::setConnectionStatusById(sensorId, false, false);
|
rSensor.connected = false;
|
||||||
|
|
||||||
} else if (rSensor.connected && sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
} else if (rSensor.connected && sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
||||||
Sensors::setConnectionStatusById(sensorId, false, false);
|
rSensor.connected = false;
|
||||||
|
|
||||||
} else if (sSensor.type != Sensors::Type::MANUAL && rSensor.connected && (millis() - rSensor.activityTime) > this->disconnectedTimeout) {
|
} else if (sSensor.type != Sensors::Type::MANUAL && rSensor.connected && (millis() - rSensor.activityTime) > this->disconnectedTimeout) {
|
||||||
Sensors::setConnectionStatusById(sensorId, false, false);
|
rSensor.connected = false;
|
||||||
|
|
||||||
}/* else if (!rSensor.connected) {
|
}/* else if (!rSensor.connected) {
|
||||||
rSensor.connected = true;
|
rSensor.connected = true;
|
||||||
|
|||||||
@@ -41,18 +41,14 @@
|
|||||||
<details open>
|
<details open>
|
||||||
<summary><b data-i18n>dashboard.section.control</b></summary>
|
<summary><b data-i18n>dashboard.section.control</b></summary>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="thermostat tHeat" data-purpose="heating" data-min="0" data-max="100" data-step="0.1" data-big-step="1">
|
<div class="thermostat" id="thermostat-heating">
|
||||||
<div class="thermostat-header" data-i18n>dashboard.thermostat.heating</div>
|
<div class="thermostat-header" data-i18n>dashboard.thermostat.heating</div>
|
||||||
<div class="thermostat-temp">
|
<div class="thermostat-temp">
|
||||||
<div class="thermostat-temp-target"><span class="targetTemp"></span> <span class="tempUnit"></span></div>
|
<div class="thermostat-temp-target"><span id="tHeatTargetTemp"></span> <span class="tempUnit"></span></div>
|
||||||
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.temp.current</span>: <span id="tHeatCurrentTemp"></span> <span class="tempUnit"></span></div>
|
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.temp.current</span>: <span id="tHeatCurrentTemp"></span> <span class="tempUnit"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="thermostat-minus">
|
<div class="thermostat-minus"><button id="tHeatActionMinus" class="outline"><i class="icons-down"></i></button></div>
|
||||||
<button class="tAction outline" data-action="decrement"><i class="icons-down"></i></button>
|
<div class="thermostat-plus"><button id="tHeatActionPlus" class="outline"><i class="icons-up"></i></button></div>
|
||||||
</div>
|
|
||||||
<div class="thermostat-plus">
|
|
||||||
<button class="tAction outline" data-action="increment"><i class="icons-up"></i></button>
|
|
||||||
</div>
|
|
||||||
<div class="thermostat-control">
|
<div class="thermostat-control">
|
||||||
<input type="checkbox" role="switch" id="tHeatEnabled" value="true">
|
<input type="checkbox" role="switch" id="tHeatEnabled" value="true">
|
||||||
<label htmlFor="tHeatEnabled" data-i18n>dashboard.thermostat.enable</label>
|
<label htmlFor="tHeatEnabled" data-i18n>dashboard.thermostat.enable</label>
|
||||||
@@ -62,25 +58,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="thermostat tDhw" data-purpose="dhw" data-min="0" data-max="100" data-step="1" data-big-step="5">
|
<div class="thermostat" id="thermostat-dhw">
|
||||||
<div class="thermostat-header" data-i18n>dashboard.thermostat.dhw</div>
|
<div class="thermostat-header" data-i18n>dashboard.thermostat.dhw</div>
|
||||||
<div class="thermostat-temp">
|
<div class="thermostat-temp">
|
||||||
<div class="thermostat-temp-target"><span class="targetTemp"></span> <span class="tempUnit"></span></div>
|
<div class="thermostat-temp-target"><span id="tDhwTargetTemp"></span> <span class="tempUnit"></span></div>
|
||||||
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.temp.current</span>: <span id="tDhwCurrentTemp"></span> <span class="tempUnit"></span></div>
|
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.temp.current</span>: <span id="tDhwCurrentTemp"></span> <span class="tempUnit"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="thermostat-minus">
|
<div class="thermostat-minus"><button class="outline" id="tDhwActionMinus"><i class="icons-down"></i></button></div>
|
||||||
<button class="tAction outline" data-action="decrement"><i class="icons-down"></i></button>
|
<div class="thermostat-plus"><button class="outline" id="tDhwActionPlus"><i class="icons-up"></i></button></div>
|
||||||
</div>
|
|
||||||
<div class="thermostat-plus">
|
|
||||||
<button class="tAction outline" data-action="increment"><i class="icons-up"></i></button>
|
|
||||||
</div>
|
|
||||||
<div class="thermostat-control">
|
<div class="thermostat-control">
|
||||||
<input type="checkbox" role="switch" id="tDhwEnabled" value="true">
|
<input type="checkbox" role="switch" id="tDhwEnabled" value="true">
|
||||||
<label htmlFor="tDhwEnabled" data-i18n>dashboard.thermostat.enable</label>
|
<label htmlFor="tDhwEnabled" data-i18n>dashboard.thermostat.enable</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="notify notify-error notify-fault hidden">
|
<div class="notify notify-error notify-fault hidden">
|
||||||
<div class="notify-icon">
|
<div class="notify-icon">
|
||||||
<i class="icons-error"></i>
|
<i class="icons-error"></i>
|
||||||
@@ -290,6 +282,7 @@
|
|||||||
<script src="/static/app.js?{BUILD_TIME}"></script>
|
<script src="/static/app.js?{BUILD_TIME}"></script>
|
||||||
<script>
|
<script>
|
||||||
let modifiedTime = null;
|
let modifiedTime = null;
|
||||||
|
let noRegulators;
|
||||||
let prevSettings;
|
let prevSettings;
|
||||||
let newSettings = {
|
let newSettings = {
|
||||||
heating: {
|
heating: {
|
||||||
@@ -307,69 +300,78 @@
|
|||||||
const lang = new Lang(document.getElementById('lang'));
|
const lang = new Lang(document.getElementById('lang'));
|
||||||
lang.build();
|
lang.build();
|
||||||
|
|
||||||
let actionTimer = null;
|
document.querySelector('#tHeatActionMinus').addEventListener('click', (event) => {
|
||||||
let actionLongPress = false;
|
if (!prevSettings) {
|
||||||
document.querySelectorAll('.tAction').forEach((item) => {
|
return;
|
||||||
const action = item.dataset.action;
|
|
||||||
const tContainer = item.parentNode.parentNode;
|
|
||||||
|
|
||||||
for (const eName of ['pointerup', 'pointercancel']) {
|
|
||||||
item.addEventListener(eName, (event) => {
|
|
||||||
clearInterval(actionTimer);
|
|
||||||
|
|
||||||
const purpose = tContainer.dataset.purpose;
|
|
||||||
const minTemp = parseFloat(tContainer.dataset.min);
|
|
||||||
const maxTemp = parseFloat(tContainer.dataset.max);
|
|
||||||
const step = parseFloat(tContainer.dataset.step);
|
|
||||||
const bigStep = parseFloat(tContainer.dataset.bigStep);
|
|
||||||
|
|
||||||
if (!actionLongPress && prevSettings) {
|
|
||||||
let value = 0;
|
|
||||||
if (action == 'increment') {
|
|
||||||
value = step;
|
|
||||||
|
|
||||||
} else if (action == 'decrement') {
|
|
||||||
value = -(step);
|
|
||||||
}
|
|
||||||
|
|
||||||
newSettings[purpose].target = parseFloat(constrain(newSettings[purpose].target + value, minTemp, maxTemp).toFixed(2));
|
|
||||||
modifiedTime = Date.now();
|
|
||||||
setValue('.targetTemp', newSettings[purpose].target, tContainer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
item.addEventListener('pointerdown', (event) => {
|
newSettings.heating.target -= 0.5;
|
||||||
if (!prevSettings) {
|
modifiedTime = Date.now();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const purpose = tContainer.dataset.purpose;
|
let minTemp;
|
||||||
const minTemp = parseFloat(tContainer.dataset.min);
|
if (noRegulators) {
|
||||||
const maxTemp = parseFloat(tContainer.dataset.max);
|
minTemp = prevSettings.heating.minTemp;
|
||||||
const step = parseFloat(tContainer.dataset.step);
|
} else {
|
||||||
const bigStep = parseFloat(tContainer.dataset.bigStep);
|
minTemp = prevSettings.system.unitSystem == 0 ? 5 : 41;
|
||||||
|
}
|
||||||
|
|
||||||
actionLongPress = false;
|
if (prevSettings && newSettings.heating.target < minTemp) {
|
||||||
actionTimer = setInterval(() => {
|
newSettings.heating.target = minTemp;
|
||||||
if (!actionLongPress) {
|
}
|
||||||
actionLongPress = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let value = 0;
|
setValue('#tHeatTargetTemp', newSettings.heating.target);
|
||||||
if (action == 'increment') {
|
});
|
||||||
value = bigStep;
|
|
||||||
|
|
||||||
} else if (action == 'decrement') {
|
document.querySelector('#tHeatActionPlus').addEventListener('click', (event) => {
|
||||||
value = -(bigStep);
|
if (!prevSettings) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
newSettings[purpose].target = parseFloat(constrain(newSettings[purpose].target + value, minTemp, maxTemp).toFixed(2));
|
newSettings.heating.target += 0.5;
|
||||||
modifiedTime = Date.now();
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
setValue('.targetTemp', newSettings[purpose].target, tContainer);
|
let maxTemp;
|
||||||
}, 500);
|
if (noRegulators) {
|
||||||
});
|
maxTemp = prevSettings.heating.maxTemp;
|
||||||
|
} else {
|
||||||
|
maxTemp = prevSettings.system.unitSystem == 0 ? 30 : 86;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevSettings && newSettings.heating.target > maxTemp) {
|
||||||
|
newSettings.heating.target = maxTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue('#tHeatTargetTemp', newSettings.heating.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector('#tDhwActionMinus').addEventListener('click', (event) => {
|
||||||
|
if (!prevSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newSettings.dhw.target -= 1.0;
|
||||||
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
|
if (newSettings.dhw.target < prevSettings.dhw.minTemp) {
|
||||||
|
newSettings.dhw.target = prevSettings.dhw.minTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue('#tDhwTargetTemp', newSettings.dhw.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector('#tDhwActionPlus').addEventListener('click', (event) => {
|
||||||
|
if (!prevSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newSettings.dhw.target += 1.0;
|
||||||
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
|
if (newSettings.dhw.target > prevSettings.dhw.maxTemp) {
|
||||||
|
newSettings.dhw.target = prevSettings.dhw.maxTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue('#tDhwTargetTemp', newSettings.dhw.target);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('#tHeatEnabled').addEventListener('change', (event) => {
|
document.querySelector('#tHeatEnabled').addEventListener('change', (event) => {
|
||||||
@@ -484,6 +486,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
noRegulators = !result.opentherm.options.nativeHeatingControl && !result.equitherm.enabled && !result.pid.enabled;
|
||||||
prevSettings = result;
|
prevSettings = result;
|
||||||
unitSystem = result.system.unitSystem;
|
unitSystem = result.system.unitSystem;
|
||||||
newSettings.heating.enabled = result.heating.enabled;
|
newSettings.heating.enabled = result.heating.enabled;
|
||||||
@@ -493,17 +496,17 @@
|
|||||||
newSettings.dhw.target = result.dhw.target;
|
newSettings.dhw.target = result.dhw.target;
|
||||||
|
|
||||||
if (result.opentherm.options.dhwSupport) {
|
if (result.opentherm.options.dhwSupport) {
|
||||||
show('.tDhw');
|
show('#thermostat-dhw');
|
||||||
} else {
|
} else {
|
||||||
hide('.tDhw');
|
hide('#thermostat-dhw');
|
||||||
}
|
}
|
||||||
|
|
||||||
setCheckboxValue('#tHeatEnabled', result.heating.enabled);
|
setCheckboxValue('#tHeatEnabled', result.heating.enabled);
|
||||||
setCheckboxValue('#tHeatTurbo', result.heating.turbo);
|
setCheckboxValue('#tHeatTurbo', result.heating.turbo);
|
||||||
setValue('.tHeat .targetTemp', result.heating.target);
|
setValue('#tHeatTargetTemp', result.heating.target);
|
||||||
|
|
||||||
setCheckboxValue('#tDhwEnabled', result.dhw.enabled);
|
setCheckboxValue('#tDhwEnabled', result.dhw.enabled);
|
||||||
setValue('.tDhw .targetTemp', result.dhw.target);
|
setValue('#tDhwTargetTemp', result.dhw.target);
|
||||||
|
|
||||||
setValue('.tempUnit', temperatureUnit(unitSystem));
|
setValue('.tempUnit', temperatureUnit(unitSystem));
|
||||||
setValue('.pressureUnit', pressureUnit(unitSystem));
|
setValue('.pressureUnit', pressureUnit(unitSystem));
|
||||||
@@ -520,20 +523,20 @@
|
|||||||
cache: "no-cache",
|
cache: "no-cache",
|
||||||
credentials: "include"
|
credentials: "include"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Response not valid');
|
throw new Error('Response not valid');
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
// Graph
|
// Graph
|
||||||
setValue('#tHeatCurrentTemp', result.master.heating.indoorTempControl
|
setValue('#tHeatCurrentTemp', result.master.heating.indoorTempControl
|
||||||
? result.master.heating.indoorTemp
|
? result.master.heating.indoorTemp
|
||||||
: result.master.heating.currentTemp
|
: result.master.heating.currentTemp
|
||||||
);
|
);
|
||||||
setValue('#tDhwCurrentTemp', result.master.dhw.currentTemp);
|
setValue('#tDhwCurrentTemp', result.master.dhw.currentTemp);
|
||||||
|
|
||||||
|
|
||||||
// SLAVE
|
// SLAVE
|
||||||
setValue('.sMemberId', result.slave.memberId);
|
setValue('.sMemberId', result.slave.memberId);
|
||||||
@@ -643,14 +646,6 @@
|
|||||||
setState('.mCascadeControlInput', result.master.cascadeControl.input);
|
setState('.mCascadeControlInput', result.master.cascadeControl.input);
|
||||||
setState('.mCascadeControlOutput', result.master.cascadeControl.output);
|
setState('.mCascadeControlOutput', result.master.cascadeControl.output);
|
||||||
|
|
||||||
const tHeat = document.querySelector('.tHeat');
|
|
||||||
tHeat.dataset.min = result.master.heating.minTemp;
|
|
||||||
tHeat.dataset.max = result.master.heating.maxTemp;
|
|
||||||
|
|
||||||
const tDhw = document.querySelector('.tDhw');
|
|
||||||
tDhw.dataset.min = result.master.dhw.minTemp;
|
|
||||||
tDhw.dataset.max = result.master.dhw.maxTemp;
|
|
||||||
|
|
||||||
setBusy('#dashboard-busy', '#dashboard-container', false);
|
setBusy('#dashboard-busy', '#dashboard-container', false);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -663,7 +658,7 @@
|
|||||||
cache: "no-cache",
|
cache: "no-cache",
|
||||||
credentials: "include"
|
credentials: "include"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Response not valid");
|
throw new Error("Response not valid");
|
||||||
}
|
}
|
||||||
@@ -689,7 +684,7 @@
|
|||||||
if (!sensorNode) {
|
if (!sensorNode) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sData = result[sensorId];
|
const sData = result[sensorId];
|
||||||
if (!sData.enabled || sData.purpose == 255) {
|
if (!sData.enabled || sData.purpose == 255) {
|
||||||
sensorNode.classList.toggle("hidden", true);
|
sensorNode.classList.toggle("hidden", true);
|
||||||
|
|||||||
@@ -849,8 +849,4 @@ function dec2hex(i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return hex.toUpperCase();
|
return hex.toUpperCase();
|
||||||
}
|
|
||||||
|
|
||||||
function constrain(amt, low, high) {
|
|
||||||
return ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)));
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user