mirror of
https://github.com/Laxilef/OTGateway.git
synced 2025-12-12 11:14:28 +05:00
Compare commits
35 Commits
1.4.0-rc.2
...
1.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b631b496cb | ||
|
|
36328a1db5 | ||
|
|
a28c7f67b5 | ||
|
|
bb9b6a5f4c | ||
|
|
ce7bd7e23b | ||
|
|
249d32ce35 | ||
|
|
baf8adfb02 | ||
|
|
018a1c5188 | ||
|
|
b600c130f0 | ||
|
|
59eb05726a | ||
|
|
f245f37dfd | ||
|
|
a825412f37 | ||
|
|
935f8bd0a8 | ||
|
|
f78d2f38b8 | ||
|
|
ef083991e3 | ||
|
|
3c0f846335 | ||
|
|
85011ce4ea | ||
|
|
8687e122ca | ||
|
|
d35ea81080 | ||
|
|
cca8ec58b4 | ||
|
|
301b14bbd4 | ||
|
|
41ce9b268e | ||
|
|
646939179e | ||
|
|
73dddd18f0 | ||
|
|
f069de0415 | ||
|
|
f4a4afeb29 | ||
|
|
f9824337dc | ||
|
|
1cd8c6a336 | ||
|
|
63228baebd | ||
|
|
6bb261dfd7 | ||
|
|
a026a962f0 | ||
|
|
db2faad741 | ||
|
|
fbc43dc535 | ||
|
|
31dfc21d69 | ||
|
|
96289cb0f7 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
.pio
|
.pio
|
||||||
.vscode
|
.vscode
|
||||||
build/*.bin
|
build/*.bin
|
||||||
|
data/**/*.gz
|
||||||
secrets.ini
|
secrets.ini
|
||||||
!.gitkeep
|
!.gitkeep
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
- The current temperature of the heat carrier (usually the return heat carrier)
|
- The current temperature of the heat carrier (usually the return heat carrier)
|
||||||
- Set heat carrier temperature (depending on the selected mode)
|
- Set heat carrier temperature (depending on the selected mode)
|
||||||
- Current hot water temperature
|
- Current hot water temperature
|
||||||
- Auto tuning of PID and Equitherm parameters *(in development)*
|
|
||||||
- [Home Assistant](https://www.home-assistant.io/) integration via MQTT. The ability to create any automation for the boiler!
|
- [Home Assistant](https://www.home-assistant.io/) integration via MQTT. The ability to create any automation for the boiler!
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
0
data/.gitkeep
Normal file
0
data/.gitkeep
Normal file
0
data/static/.gitkeep
Normal file
0
data/static/.gitkeep
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -126,6 +126,36 @@ public:
|
|||||||
return isValidResponse(response);
|
return isValidResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool setRoomSetpoint(float temperature) {
|
||||||
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
|
OpenThermMessageType::WRITE_DATA,
|
||||||
|
OpenThermMessageID::TrSet,
|
||||||
|
temperatureToData(temperature)
|
||||||
|
));
|
||||||
|
|
||||||
|
return isValidResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setRoomSetpointCh2(float temperature) {
|
||||||
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
|
OpenThermMessageType::WRITE_DATA,
|
||||||
|
OpenThermMessageID::TrSetCH2,
|
||||||
|
temperatureToData(temperature)
|
||||||
|
));
|
||||||
|
|
||||||
|
return isValidResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setRoomTemp(float temperature) {
|
||||||
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
|
OpenThermMessageType::WRITE_DATA,
|
||||||
|
OpenThermMessageID::Tr,
|
||||||
|
temperatureToData(temperature)
|
||||||
|
));
|
||||||
|
|
||||||
|
return isValidResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
bool sendBoilerReset() {
|
bool sendBoilerReset() {
|
||||||
unsigned int data = 1;
|
unsigned int data = 1;
|
||||||
data <<= 8;
|
data <<= 8;
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
#include "NetworkConnection.h"
|
#include "NetworkConnection.h"
|
||||||
using namespace Network;
|
using namespace NetworkUtils;
|
||||||
|
|
||||||
void Connection::setup(bool useDhcp) {
|
void NetworkConnection::setup(bool useDhcp) {
|
||||||
setUseDhcp(useDhcp);
|
setUseDhcp(useDhcp);
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP8266)
|
#if defined(ARDUINO_ARCH_ESP8266)
|
||||||
wifi_set_event_handler_cb(Connection::onEvent);
|
wifi_set_event_handler_cb(NetworkConnection::onEvent);
|
||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
WiFi.onEvent(Connection::onEvent);
|
WiFi.onEvent(NetworkConnection::onEvent);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::reset() {
|
void NetworkConnection::reset() {
|
||||||
status = Status::NONE;
|
status = Status::NONE;
|
||||||
disconnectReason = DisconnectReason::NONE;
|
disconnectReason = DisconnectReason::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::setUseDhcp(bool value) {
|
void NetworkConnection::setUseDhcp(bool value) {
|
||||||
useDhcp = value;
|
useDhcp = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::Status Connection::getStatus() {
|
NetworkConnection::Status NetworkConnection::getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::DisconnectReason Connection::getDisconnectReason() {
|
NetworkConnection::DisconnectReason NetworkConnection::getDisconnectReason() {
|
||||||
return disconnectReason;
|
return disconnectReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP8266)
|
#if defined(ARDUINO_ARCH_ESP8266)
|
||||||
void Connection::onEvent(System_Event_t *event) {
|
void NetworkConnection::onEvent(System_Event_t *event) {
|
||||||
switch (event->event) {
|
switch (event->event) {
|
||||||
case EVENT_STAMODE_CONNECTED:
|
case EVENT_STAMODE_CONNECTED:
|
||||||
status = useDhcp ? Status::CONNECTING : Status::CONNECTED;
|
status = useDhcp ? Status::CONNECTING : Status::CONNECTED;
|
||||||
@@ -75,7 +75,7 @@ void Connection::onEvent(System_Event_t *event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
void Connection::onEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
void NetworkConnection::onEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||||
status = useDhcp ? Status::CONNECTING : Status::CONNECTED;
|
status = useDhcp ? Status::CONNECTING : Status::CONNECTED;
|
||||||
@@ -106,7 +106,7 @@ void Connection::onEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Connection::DisconnectReason Connection::convertDisconnectReason(uint8_t reason) {
|
NetworkConnection::DisconnectReason NetworkConnection::convertDisconnectReason(uint8_t reason) {
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
#if defined(ARDUINO_ARCH_ESP8266)
|
#if defined(ARDUINO_ARCH_ESP8266)
|
||||||
case REASON_BEACON_TIMEOUT:
|
case REASON_BEACON_TIMEOUT:
|
||||||
@@ -145,6 +145,6 @@ Connection::DisconnectReason Connection::convertDisconnectReason(uint8_t reason)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Connection::useDhcp = false;
|
bool NetworkConnection::useDhcp = false;
|
||||||
Connection::Status Connection::status = Status::NONE;
|
NetworkConnection::Status NetworkConnection::status = Status::NONE;
|
||||||
Connection::DisconnectReason Connection::disconnectReason = DisconnectReason::NONE;
|
NetworkConnection::DisconnectReason NetworkConnection::disconnectReason = DisconnectReason::NONE;
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Network {
|
namespace NetworkUtils {
|
||||||
struct Connection {
|
struct NetworkConnection {
|
||||||
enum class Status {
|
enum class Status {
|
||||||
CONNECTED,
|
CONNECTED,
|
||||||
CONNECTING,
|
CONNECTING,
|
||||||
@@ -7,35 +7,35 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <NetworkConnection.h>
|
#include <NetworkConnection.h>
|
||||||
|
|
||||||
namespace Network {
|
namespace NetworkUtils {
|
||||||
class Manager {
|
class NetworkMgr {
|
||||||
public:
|
public:
|
||||||
typedef std::function<void()> YieldCallback;
|
typedef std::function<void()> YieldCallback;
|
||||||
typedef std::function<void(unsigned int)> DelayCallback;
|
typedef std::function<void(unsigned int)> DelayCallback;
|
||||||
|
|
||||||
Manager() {
|
NetworkMgr() {
|
||||||
Connection::setup(this->useDhcp);
|
NetworkConnection::setup(this->useDhcp);
|
||||||
this->resetWifi();
|
this->resetWifi();
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setYieldCallback(YieldCallback callback = nullptr) {
|
NetworkMgr* setYieldCallback(YieldCallback callback = nullptr) {
|
||||||
this->yieldCallback = callback;
|
this->yieldCallback = callback;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setDelayCallback(DelayCallback callback = nullptr) {
|
NetworkMgr* setDelayCallback(DelayCallback callback = nullptr) {
|
||||||
this->delayCallback = callback;
|
this->delayCallback = callback;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setHostname(const char* value) {
|
NetworkMgr* setHostname(const char* value) {
|
||||||
this->hostname = value;
|
this->hostname = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setApCredentials(const char* ssid, const char* password = nullptr, byte channel = 0) {
|
NetworkMgr* setApCredentials(const char* ssid, const char* password = nullptr, byte channel = 0) {
|
||||||
this->apName = ssid;
|
this->apName = ssid;
|
||||||
this->apPassword = password;
|
this->apPassword = password;
|
||||||
this->apChannel = channel;
|
this->apChannel = channel;
|
||||||
@@ -43,7 +43,7 @@ namespace Network {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setStaCredentials(const char* ssid = nullptr, const char* password = nullptr, byte channel = 0) {
|
NetworkMgr* setStaCredentials(const char* ssid = nullptr, const char* password = nullptr, byte channel = 0) {
|
||||||
this->staSsid = ssid;
|
this->staSsid = ssid;
|
||||||
this->staPassword = password;
|
this->staPassword = password;
|
||||||
this->staChannel = channel;
|
this->staChannel = channel;
|
||||||
@@ -51,14 +51,14 @@ namespace Network {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setUseDhcp(bool value) {
|
NetworkMgr* setUseDhcp(bool value) {
|
||||||
this->useDhcp = value;
|
this->useDhcp = value;
|
||||||
Connection::setup(this->useDhcp);
|
NetworkConnection::setup(this->useDhcp);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setStaticConfig(const char* ip, const char* gateway, const char* subnet, const char* dns) {
|
NetworkMgr* setStaticConfig(const char* ip, const char* gateway, const char* subnet, const char* dns) {
|
||||||
this->staticIp.fromString(ip);
|
this->staticIp.fromString(ip);
|
||||||
this->staticGateway.fromString(gateway);
|
this->staticGateway.fromString(gateway);
|
||||||
this->staticSubnet.fromString(subnet);
|
this->staticSubnet.fromString(subnet);
|
||||||
@@ -67,7 +67,7 @@ namespace Network {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setStaticConfig(IPAddress& ip, IPAddress& gateway, IPAddress& subnet, IPAddress& dns) {
|
NetworkMgr* setStaticConfig(IPAddress& ip, IPAddress& gateway, IPAddress& subnet, IPAddress& dns) {
|
||||||
this->staticIp = ip;
|
this->staticIp = ip;
|
||||||
this->staticGateway = gateway;
|
this->staticGateway = gateway;
|
||||||
this->staticSubnet = subnet;
|
this->staticSubnet = subnet;
|
||||||
@@ -81,11 +81,11 @@ namespace Network {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isConnected() {
|
bool isConnected() {
|
||||||
return this->isStaEnabled() && Connection::getStatus() == Connection::Status::CONNECTED;
|
return this->isStaEnabled() && NetworkConnection::getStatus() == NetworkConnection::Status::CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isConnecting() {
|
bool isConnecting() {
|
||||||
return this->isStaEnabled() && Connection::getStatus() == Connection::Status::CONNECTING;
|
return this->isStaEnabled() && NetworkConnection::getStatus() == NetworkConnection::Status::CONNECTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isStaEnabled() {
|
bool isStaEnabled() {
|
||||||
@@ -147,16 +147,19 @@ namespace Network {
|
|||||||
bool resetWifi() {
|
bool resetWifi() {
|
||||||
// set policy manual for work 13 ch
|
// set policy manual for work 13 ch
|
||||||
{
|
{
|
||||||
wifi_country_t country = {"CN", 1, 13, WIFI_COUNTRY_POLICY_MANUAL};
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
wifi_country_t country = {"CN", 1, 13, WIFI_COUNTRY_POLICY_AUTO};
|
||||||
wifi_set_country(&country);
|
wifi_set_country(&country);
|
||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const wifi_country_t country = {"CN", 1, 13, CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER, WIFI_COUNTRY_POLICY_AUTO};
|
||||||
esp_wifi_set_country(&country);
|
esp_wifi_set_country(&country);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
WiFi.persistent(false);
|
WiFi.persistent(false);
|
||||||
|
#if !defined(ESP_ARDUINO_VERSION_MAJOR) || ESP_ARDUINO_VERSION_MAJOR < 3
|
||||||
WiFi.setAutoConnect(false);
|
WiFi.setAutoConnect(false);
|
||||||
|
#endif
|
||||||
WiFi.setAutoReconnect(false);
|
WiFi.setAutoReconnect(false);
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
@@ -181,8 +184,8 @@ namespace Network {
|
|||||||
wifi_station_dhcpc_set_maxtry(5);
|
wifi_station_dhcpc_set_maxtry(5);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#if defined(ARDUINO_ARCH_ESP32) && ESP_ARDUINO_VERSION_MAJOR < 3
|
||||||
// Nothing. Because memory leaks when turn off WiFi on ESP32, bug?
|
// Nothing. Because memory leaks when turn off WiFi on ESP32 SDK < 3.0.0
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
return WiFi.mode(WIFI_OFF);
|
return WiFi.mode(WIFI_OFF);
|
||||||
@@ -200,6 +203,7 @@ namespace Network {
|
|||||||
|
|
||||||
if (force && !this->isApEnabled()) {
|
if (force && !this->isApEnabled()) {
|
||||||
this->resetWifi();
|
this->resetWifi();
|
||||||
|
NetworkConnection::reset();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/*#ifdef ARDUINO_ARCH_ESP8266
|
/*#ifdef ARDUINO_ARCH_ESP8266
|
||||||
@@ -215,7 +219,7 @@ namespace Network {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->delayCallback(200);
|
this->delayCallback(250);
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
if (this->setWifiHostname(this->hostname)) {
|
if (this->setWifiHostname(this->hostname)) {
|
||||||
@@ -230,7 +234,7 @@ namespace Network {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->delayCallback(200);
|
this->delayCallback(250);
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
if (this->setWifiHostname(this->hostname)) {
|
if (this->setWifiHostname(this->hostname)) {
|
||||||
@@ -240,7 +244,7 @@ namespace Network {
|
|||||||
Log.serrorln(FPSTR(L_NETWORK), F("Set hostname '%s': fail"), this->hostname);
|
Log.serrorln(FPSTR(L_NETWORK), F("Set hostname '%s': fail"), this->hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->delayCallback(200);
|
this->delayCallback(250);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!this->useDhcp) {
|
if (!this->useDhcp) {
|
||||||
@@ -253,9 +257,9 @@ namespace Network {
|
|||||||
while (millis() - beginConnectionTime < timeout) {
|
while (millis() - beginConnectionTime < timeout) {
|
||||||
this->delayCallback(100);
|
this->delayCallback(100);
|
||||||
|
|
||||||
Connection::Status status = Connection::getStatus();
|
NetworkConnection::Status status = NetworkConnection::getStatus();
|
||||||
if (status != Connection::Status::CONNECTING && status != Connection::Status::NONE) {
|
if (status != NetworkConnection::Status::CONNECTING && status != NetworkConnection::Status::NONE) {
|
||||||
return status == Connection::Status::CONNECTED;
|
return status == NetworkConnection::Status::CONNECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,13 +267,22 @@ namespace Network {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (this->isConnected() && !this->hasStaCredentials()) {
|
if (this->reconnectFlag) {
|
||||||
|
this->delayCallback(5000);
|
||||||
|
|
||||||
|
Log.sinfoln(FPSTR(L_NETWORK), F("Reconnecting..."));
|
||||||
|
this->reconnectFlag = false;
|
||||||
|
this->resetWifi();
|
||||||
|
NetworkConnection::reset();
|
||||||
|
this->delayCallback(1000);
|
||||||
|
|
||||||
|
} else if (this->isConnected() && !this->hasStaCredentials()) {
|
||||||
Log.sinfoln(FPSTR(L_NETWORK), F("Reset"));
|
Log.sinfoln(FPSTR(L_NETWORK), F("Reset"));
|
||||||
this->resetWifi();
|
this->resetWifi();
|
||||||
Connection::reset();
|
NetworkConnection::reset();
|
||||||
this->delayCallback(200);
|
this->delayCallback(1000);
|
||||||
|
|
||||||
} else if (this->isConnected() && !this->reconnectFlag) {
|
} else if (this->isConnected()) {
|
||||||
if (!this->connected) {
|
if (!this->connected) {
|
||||||
this->connectedTime = millis();
|
this->connectedTime = millis();
|
||||||
this->connected = true;
|
this->connected = true;
|
||||||
@@ -305,7 +318,7 @@ namespace Network {
|
|||||||
Log.sinfoln(
|
Log.sinfoln(
|
||||||
FPSTR(L_NETWORK),
|
FPSTR(L_NETWORK),
|
||||||
F("Disconnected, reason: %d, uptime: %lu s."),
|
F("Disconnected, reason: %d, uptime: %lu s."),
|
||||||
Connection::getDisconnectReason(),
|
NetworkConnection::getDisconnectReason(),
|
||||||
(millis() - this->connectedTime) / 1000
|
(millis() - this->connectedTime) / 1000
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -327,16 +340,15 @@ namespace Network {
|
|||||||
} else if (this->isConnecting() && millis() - this->prevReconnectingTime > this->resetConnectionTimeout) {
|
} else if (this->isConnecting() && millis() - this->prevReconnectingTime > this->resetConnectionTimeout) {
|
||||||
Log.swarningln(FPSTR(L_NETWORK), F("Connection timeout, reset wifi..."));
|
Log.swarningln(FPSTR(L_NETWORK), F("Connection timeout, reset wifi..."));
|
||||||
this->resetWifi();
|
this->resetWifi();
|
||||||
Connection::reset();
|
NetworkConnection::reset();
|
||||||
this->delayCallback(200);
|
this->delayCallback(250);
|
||||||
|
|
||||||
} else if (!this->isConnecting() && this->hasStaCredentials() && (!this->prevReconnectingTime || millis() - this->prevReconnectingTime > this->reconnectInterval)) {
|
} else if (!this->isConnecting() && this->hasStaCredentials() && (!this->prevReconnectingTime || millis() - this->prevReconnectingTime > this->reconnectInterval)) {
|
||||||
Log.sinfoln(FPSTR(L_NETWORK), F("Try connect..."));
|
Log.sinfoln(FPSTR(L_NETWORK), F("Try connect..."));
|
||||||
|
|
||||||
this->reconnectFlag = false;
|
NetworkConnection::reset();
|
||||||
Connection::reset();
|
|
||||||
if (!this->connect(true, this->connectionTimeout)) {
|
if (!this->connect(true, this->connectionTimeout)) {
|
||||||
Log.straceln(FPSTR(L_NETWORK), F("Connection failed. Status: %d, reason: %d"), Connection::getStatus(), Connection::getDisconnectReason());
|
Log.straceln(FPSTR(L_NETWORK), F("Connection failed. Status: %d, reason: %d"), NetworkConnection::getStatus(), NetworkConnection::getDisconnectReason());
|
||||||
}
|
}
|
||||||
|
|
||||||
this->prevReconnectingTime = millis();
|
this->prevReconnectingTime = millis();
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
|
#include <detail/mimetable.h>
|
||||||
|
|
||||||
|
using namespace mime;
|
||||||
|
|
||||||
class StaticPage : public RequestHandler {
|
class StaticPage : public RequestHandler {
|
||||||
public:
|
public:
|
||||||
@@ -61,6 +64,14 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!this->path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !this->fs->exists(path)) {
|
||||||
|
String pathWithGz = this->path + FPSTR(mimeTable[gz].endsWith);
|
||||||
|
|
||||||
|
if (this->fs->exists(pathWithGz)) {
|
||||||
|
this->path += FPSTR(mimeTable[gz].endsWith);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
File file = this->fs->open(this->path, "r");
|
File file = this->fs->open(this->path, "r");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return false;
|
return false;
|
||||||
@@ -93,6 +104,6 @@ protected:
|
|||||||
BeforeSendCallback beforeSendCallback;
|
BeforeSendCallback beforeSendCallback;
|
||||||
String eTag;
|
String eTag;
|
||||||
const char* uri = nullptr;
|
const char* uri = nullptr;
|
||||||
const char* path = nullptr;
|
String path;
|
||||||
const char* cacheHeader = nullptr;
|
const char* cacheHeader = nullptr;
|
||||||
};
|
};
|
||||||
@@ -17,16 +17,18 @@ framework = arduino
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson@^7.0.4
|
bblanchon/ArduinoJson@^7.0.4
|
||||||
;ihormelnyk/OpenTherm Library@^1.1.5
|
;ihormelnyk/OpenTherm Library@^1.1.5
|
||||||
https://github.com/Laxilef/opentherm_library/archive/refs/heads/fix_lambda.zip
|
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
|
||||||
gyverlibs/GyverPID@^3.3.2
|
gyverlibs/GyverPID@^3.3.2
|
||||||
gyverlibs/GyverBlinker@^1.0
|
gyverlibs/GyverBlinker@^1.0
|
||||||
|
https://github.com/PaulStoffregen/OneWire#master
|
||||||
milesburton/DallasTemperature@^3.11.0
|
milesburton/DallasTemperature@^3.11.0
|
||||||
laxilef/TinyLogger@^1.1.0
|
laxilef/TinyLogger@^1.1.0
|
||||||
build_flags =
|
build_flags =
|
||||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
||||||
|
;-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||||
-D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
|
-D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
|
||||||
-mtext-section-literals
|
-mtext-section-literals
|
||||||
-D MQTT_CLIENT_STD_FUNCTION_CALLBACK=1
|
-D MQTT_CLIENT_STD_FUNCTION_CALLBACK=1
|
||||||
@@ -51,11 +53,11 @@ monitor_speed = 115200
|
|||||||
monitor_filters = direct
|
monitor_filters = direct
|
||||||
board_build.flash_mode = dio
|
board_build.flash_mode = dio
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
version = 1.4.0-rc.21
|
version = 1.4.1
|
||||||
|
|
||||||
; Defaults
|
; Defaults
|
||||||
[esp8266_defaults]
|
[esp8266_defaults]
|
||||||
platform = espressif8266
|
platform = espressif8266@^4.2.1
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
nrwiersma/ESP8266Scheduler@^1.2
|
nrwiersma/ESP8266Scheduler@^1.2
|
||||||
@@ -66,7 +68,12 @@ build_flags = ${env.build_flags}
|
|||||||
board_build.ldscript = eagle.flash.4m1m.ld
|
board_build.ldscript = eagle.flash.4m1m.ld
|
||||||
|
|
||||||
[esp32_defaults]
|
[esp32_defaults]
|
||||||
platform = espressif32@^6.6
|
;platform = espressif32@^6.7
|
||||||
|
platform = https://github.com/platformio/platform-espressif32.git
|
||||||
|
platform_packages =
|
||||||
|
;platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32/archive/refs/tags/2.0.17.zip
|
||||||
|
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||||
|
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||||
board_build.partitions = esp32_partitions.csv
|
board_build.partitions = esp32_partitions.csv
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
@@ -94,8 +101,8 @@ build_flags =
|
|||||||
-D DEFAULT_OT_OUT_GPIO=5
|
-D DEFAULT_OT_OUT_GPIO=5
|
||||||
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
||||||
-D DEFAULT_SENSOR_INDOOR_GPIO=14
|
-D DEFAULT_SENSOR_INDOOR_GPIO=14
|
||||||
-D LED_STATUS_GPIO=13
|
-D DEFAULT_STATUS_LED_GPIO=13
|
||||||
-D LED_OT_RX_GPIO=15
|
-D DEFAULT_OT_RX_LED_GPIO=15
|
||||||
|
|
||||||
[env:d1_mini_lite]
|
[env:d1_mini_lite]
|
||||||
platform = ${esp8266_defaults.platform}
|
platform = ${esp8266_defaults.platform}
|
||||||
@@ -110,8 +117,8 @@ build_flags =
|
|||||||
-D DEFAULT_OT_OUT_GPIO=5
|
-D DEFAULT_OT_OUT_GPIO=5
|
||||||
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
||||||
-D DEFAULT_SENSOR_INDOOR_GPIO=14
|
-D DEFAULT_SENSOR_INDOOR_GPIO=14
|
||||||
-D LED_STATUS_GPIO=13
|
-D DEFAULT_STATUS_LED_GPIO=13
|
||||||
-D LED_OT_RX_GPIO=15
|
-D DEFAULT_OT_RX_LED_GPIO=15
|
||||||
|
|
||||||
[env:d1_mini_pro]
|
[env:d1_mini_pro]
|
||||||
platform = ${esp8266_defaults.platform}
|
platform = ${esp8266_defaults.platform}
|
||||||
@@ -126,27 +133,33 @@ build_flags =
|
|||||||
-D DEFAULT_OT_OUT_GPIO=5
|
-D DEFAULT_OT_OUT_GPIO=5
|
||||||
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
||||||
-D DEFAULT_SENSOR_INDOOR_GPIO=14
|
-D DEFAULT_SENSOR_INDOOR_GPIO=14
|
||||||
-D LED_STATUS_GPIO=13
|
-D DEFAULT_STATUS_LED_GPIO=13
|
||||||
-D LED_OT_RX_GPIO=15
|
-D DEFAULT_OT_RX_LED_GPIO=15
|
||||||
|
|
||||||
[env:s2_mini]
|
[env:s2_mini]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = lolin_s2_mini
|
board = lolin_s2_mini
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps = ${esp32_defaults.lib_deps}
|
lib_deps = ${esp32_defaults.lib_deps}
|
||||||
lib_ignore = ${esp32_defaults.lib_ignore}
|
lib_ignore = ${esp32_defaults.lib_ignore}
|
||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
|
build_unflags =
|
||||||
|
-DARDUINO_USB_MODE=1
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
|
-D ARDUINO_USB_MODE=0
|
||||||
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-D DEFAULT_OT_IN_GPIO=33
|
-D DEFAULT_OT_IN_GPIO=33
|
||||||
-D DEFAULT_OT_OUT_GPIO=35
|
-D DEFAULT_OT_OUT_GPIO=35
|
||||||
-D DEFAULT_SENSOR_OUTDOOR_GPIO=9
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=9
|
||||||
-D DEFAULT_SENSOR_INDOOR_GPIO=7
|
-D DEFAULT_SENSOR_INDOOR_GPIO=7
|
||||||
-D LED_STATUS_GPIO=11
|
-D DEFAULT_STATUS_LED_GPIO=11
|
||||||
-D LED_OT_RX_GPIO=12
|
-D DEFAULT_OT_RX_LED_GPIO=12
|
||||||
|
|
||||||
[env:s3_mini]
|
[env:s3_mini]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = lolin_s3_mini
|
board = lolin_s3_mini
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@@ -154,18 +167,23 @@ lib_deps =
|
|||||||
h2zero/NimBLE-Arduino@^1.4.1
|
h2zero/NimBLE-Arduino@^1.4.1
|
||||||
lib_ignore = ${esp32_defaults.lib_ignore}
|
lib_ignore = ${esp32_defaults.lib_ignore}
|
||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
|
build_unflags =
|
||||||
|
-DARDUINO_USB_MODE=1
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
|
-D ARDUINO_USB_MODE=0
|
||||||
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-D USE_BLE=1
|
-D USE_BLE=1
|
||||||
-D DEFAULT_OT_IN_GPIO=35
|
-D DEFAULT_OT_IN_GPIO=35
|
||||||
-D DEFAULT_OT_OUT_GPIO=36
|
-D DEFAULT_OT_OUT_GPIO=36
|
||||||
-D DEFAULT_SENSOR_OUTDOOR_GPIO=13
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=13
|
||||||
-D DEFAULT_SENSOR_INDOOR_GPIO=12
|
-D DEFAULT_SENSOR_INDOOR_GPIO=12
|
||||||
-D LED_STATUS_GPIO=11
|
-D DEFAULT_STATUS_LED_GPIO=11
|
||||||
-D LED_OT_RX_GPIO=10
|
-D DEFAULT_OT_RX_LED_GPIO=10
|
||||||
|
|
||||||
[env:c3_mini]
|
[env:c3_mini]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = lolin_c3_mini
|
board = lolin_c3_mini
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@@ -182,11 +200,12 @@ build_flags =
|
|||||||
-D DEFAULT_OT_OUT_GPIO=10
|
-D DEFAULT_OT_OUT_GPIO=10
|
||||||
-D DEFAULT_SENSOR_OUTDOOR_GPIO=0
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=0
|
||||||
-D DEFAULT_SENSOR_INDOOR_GPIO=1
|
-D DEFAULT_SENSOR_INDOOR_GPIO=1
|
||||||
-D LED_STATUS_GPIO=4
|
-D DEFAULT_STATUS_LED_GPIO=4
|
||||||
-D LED_OT_RX_GPIO=5
|
-D DEFAULT_OT_RX_LED_GPIO=5
|
||||||
|
|
||||||
[env:nodemcu_32s]
|
[env:nodemcu_32s]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = nodemcu-32s
|
board = nodemcu-32s
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@@ -201,12 +220,13 @@ build_flags =
|
|||||||
-D DEFAULT_OT_OUT_GPIO=22
|
-D DEFAULT_OT_OUT_GPIO=22
|
||||||
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
||||||
-D DEFAULT_SENSOR_INDOOR_GPIO=13
|
-D DEFAULT_SENSOR_INDOOR_GPIO=13
|
||||||
-D LED_STATUS_GPIO=2 ; 18
|
-D DEFAULT_STATUS_LED_GPIO=2 ; 18
|
||||||
-D LED_OT_RX_GPIO=19
|
-D DEFAULT_OT_RX_LED_GPIO=19
|
||||||
;-D WOKWI=1
|
;-D WOKWI=1
|
||||||
|
|
||||||
[env:d1_mini32]
|
[env:d1_mini32]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = wemos_d1_mini32
|
board = wemos_d1_mini32
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@@ -221,5 +241,5 @@ build_flags =
|
|||||||
-D DEFAULT_OT_OUT_GPIO=22
|
-D DEFAULT_OT_OUT_GPIO=22
|
||||||
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
||||||
-D DEFAULT_SENSOR_INDOOR_GPIO=18
|
-D DEFAULT_SENSOR_INDOOR_GPIO=18
|
||||||
-D LED_STATUS_GPIO=2
|
-D DEFAULT_STATUS_LED_GPIO=2
|
||||||
-D LED_OT_RX_GPIO=19
|
-D DEFAULT_OT_RX_LED_GPIO=19
|
||||||
|
|||||||
175
src/HaHelper.h
175
src/HaHelper.h
@@ -6,107 +6,6 @@ public:
|
|||||||
static const byte TEMP_SOURCE_HEATING = 0;
|
static const byte TEMP_SOURCE_HEATING = 0;
|
||||||
static const byte TEMP_SOURCE_INDOOR = 1;
|
static const byte TEMP_SOURCE_INDOOR = 1;
|
||||||
|
|
||||||
bool publishSwitchEmergency(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("emergency"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("emergency"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Use emergency");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:sun-snowflake-variant");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.enable }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"emergency\": {\"enable\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"emergency\": {\"enable\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("emergency")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool publishNumberEmergencyTarget(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("emergency_target"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("emergency_target"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
|
||||||
|
|
||||||
if (unit == UnitSystem::METRIC) {
|
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
|
||||||
doc[FPSTR(HA_MIN)] = 5;
|
|
||||||
doc[FPSTR(HA_MAX)] = 50;
|
|
||||||
|
|
||||||
} else if (unit == UnitSystem::IMPERIAL) {
|
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
|
||||||
doc[FPSTR(HA_MIN)] = 41;
|
|
||||||
doc[FPSTR(HA_MAX)] = 122;
|
|
||||||
}
|
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Emergency target temp");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-alert");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.target|float(0)|round(1) }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"emergency\": {\"target\" : {{ value }}}}");
|
|
||||||
doc[FPSTR(HA_STEP)] = 0.5;
|
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("emergency_target")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool publishSwitchEmergencyUseEquitherm(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.sensors.outdoor.type != 1, 'online', 'offline') }}");
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("emergency_use_equitherm"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("emergency_use_equitherm"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Use equitherm in emergency");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:snowflake-alert");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.useEquitherm }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"emergency\": {\"useEquitherm\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"emergency\": {\"useEquitherm\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("emergency_use_equitherm")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool publishSwitchEmergencyUsePid(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.sensors.indoor.type != 1, 'online', 'offline') }}");
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("emergency_use_pid"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("emergency_use_pid"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Use PID in emergency");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:snowflake-alert");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.usePid }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"emergency\": {\"usePid\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"emergency\": {\"usePid\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("emergency_use_pid")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool publishSwitchHeating(bool enabledByDefault = true) {
|
bool publishSwitchHeating(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
@@ -175,7 +74,7 @@ public:
|
|||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"target\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"target\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = minTemp;
|
doc[FPSTR(HA_MIN)] = minTemp;
|
||||||
doc[FPSTR(HA_MAX)] = maxTemp;
|
doc[FPSTR(HA_MAX)] = maxTemp;
|
||||||
doc[FPSTR(HA_STEP)] = 0.5;
|
doc[FPSTR(HA_STEP)] = 0.5f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -206,7 +105,7 @@ public:
|
|||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"hysteresis\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"hysteresis\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
doc[FPSTR(HA_MAX)] = 5;
|
doc[FPSTR(HA_MAX)] = 5;
|
||||||
doc[FPSTR(HA_STEP)] = 0.1;
|
doc[FPSTR(HA_STEP)] = 0.1f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -234,7 +133,7 @@ public:
|
|||||||
doc[FPSTR(HA_NAME)] = F("Heating setpoint");
|
doc[FPSTR(HA_NAME)] = F("Heating setpoint");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:coolant-temperature");
|
doc[FPSTR(HA_ICON)] = F("mdi:coolant-temperature");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.heatingSetpoint|int(0) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.heatingSetpoint|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
@@ -433,7 +332,7 @@ public:
|
|||||||
doc[FPSTR(HA_NAME)] = F("DHW target");
|
doc[FPSTR(HA_NAME)] = F("DHW target");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:water-pump");
|
doc[FPSTR(HA_ICON)] = F("mdi:water-pump");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.target|int(0) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.target|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = minTemp;
|
doc[FPSTR(HA_MIN)] = minTemp;
|
||||||
@@ -605,9 +504,9 @@ public:
|
|||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.p_factor|float(0)|round(3) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.p_factor|float(0)|round(3) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"p_factor\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"p_factor\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0.1;
|
doc[FPSTR(HA_MIN)] = 0.1f;
|
||||||
doc[FPSTR(HA_MAX)] = 1000;
|
doc[FPSTR(HA_MAX)] = 1000;
|
||||||
doc[FPSTR(HA_STEP)] = 0.1;
|
doc[FPSTR(HA_STEP)] = 0.1f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -623,12 +522,12 @@ public:
|
|||||||
doc[FPSTR(HA_NAME)] = F("PID factor I");
|
doc[FPSTR(HA_NAME)] = F("PID factor I");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:alpha-i-circle-outline");
|
doc[FPSTR(HA_ICON)] = F("mdi:alpha-i-circle-outline");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.i_factor|float(0)|round(3) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.i_factor|float(0)|round(4) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"i_factor\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"i_factor\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
doc[FPSTR(HA_MAX)] = 100;
|
doc[FPSTR(HA_MAX)] = 100;
|
||||||
doc[FPSTR(HA_STEP)] = 0.001;
|
doc[FPSTR(HA_STEP)] = 0.001f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -779,9 +678,9 @@ public:
|
|||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.n_factor|float(0)|round(3) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.n_factor|float(0)|round(3) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"n_factor\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"n_factor\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0.001;
|
doc[FPSTR(HA_MIN)] = 0.001f;
|
||||||
doc[FPSTR(HA_MAX)] = 10;
|
doc[FPSTR(HA_MAX)] = 10;
|
||||||
doc[FPSTR(HA_STEP)] = 0.001;
|
doc[FPSTR(HA_STEP)] = 0.001f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -802,7 +701,7 @@ public:
|
|||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"k_factor\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"k_factor\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
doc[FPSTR(HA_MAX)] = 10;
|
doc[FPSTR(HA_MAX)] = 10;
|
||||||
doc[FPSTR(HA_STEP)] = 0.01;
|
doc[FPSTR(HA_STEP)] = 0.01f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -825,7 +724,7 @@ public:
|
|||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"t_factor\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"t_factor\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
doc[FPSTR(HA_MAX)] = 10;
|
doc[FPSTR(HA_MAX)] = 10;
|
||||||
doc[FPSTR(HA_STEP)] = 0.01;
|
doc[FPSTR(HA_STEP)] = 0.01f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -834,48 +733,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool publishSwitchTuning(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("tuning"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("tuning"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Tuning");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:tune-vertical");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.tuning.enable }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"tuning\": {\"enable\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"tuning\": {\"enable\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("tuning")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool publishSelectTuningRegulator(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"tuning\": {\"regulator\": {% if value == 'Equitherm' %}0{% elif value == 'PID' %}1{% endif %}}}");
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("tuning_regulator"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("tuning_regulator"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Tuning regulator");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{% if value_json.tuning.regulator == 0 %}Equitherm{% elif value_json.tuning.regulator == 1 %}PID{% endif %}");
|
|
||||||
doc[FPSTR(HA_OPTIONS)][0] = F("Equitherm");
|
|
||||||
doc[FPSTR(HA_OPTIONS)][1] = F("PID");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SELECT), F("tuning_regulator")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool publishBinSensorStatus(bool enabledByDefault = true) {
|
bool publishBinSensorStatus(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -1184,7 +1041,7 @@ public:
|
|||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.indoor|float(0)|round(1) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.indoor|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"temperatures\": {\"indoor\":{{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"temperatures\": {\"indoor\":{{ value }}}}");
|
||||||
doc[FPSTR(HA_STEP)] = 0.01;
|
doc[FPSTR(HA_STEP)] = 0.01f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -1243,7 +1100,7 @@ public:
|
|||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.outdoor|float(0)|round(1) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.outdoor|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"temperatures\": {\"outdoor\":{{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"temperatures\": {\"outdoor\":{{ value }}}}");
|
||||||
doc[FPSTR(HA_STEP)] = 0.01;
|
doc[FPSTR(HA_STEP)] = 0.01f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -1452,7 +1309,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.5;
|
doc[FPSTR(HA_TEMP_STEP)] = 0.5f;
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
@@ -1475,7 +1332,7 @@ public:
|
|||||||
doc[FPSTR(HA_TEMPERATURE_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}");
|
doc[FPSTR(HA_TEMPERATURE_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}");
|
||||||
|
|
||||||
doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_TEMPERATURE_STATE_TEMPLATE)] = F("{{ value_json.dhw.target|int(0) }}");
|
doc[FPSTR(HA_TEMPERATURE_STATE_TEMPLATE)] = F("{{ value_json.dhw.target|float(0)|round(1) }}");
|
||||||
|
|
||||||
if (unit == UnitSystem::METRIC) {
|
if (unit == UnitSystem::METRIC) {
|
||||||
doc[FPSTR(HA_TEMPERATURE_UNIT)] = "C";
|
doc[FPSTR(HA_TEMPERATURE_UNIT)] = "C";
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include <Blinker.h>
|
#include <Blinker.h>
|
||||||
|
|
||||||
extern Network::Manager* network;
|
using namespace NetworkUtils;
|
||||||
|
|
||||||
|
extern NetworkMgr* network;
|
||||||
extern MqttTask* tMqtt;
|
extern MqttTask* tMqtt;
|
||||||
extern OpenThermTask* tOt;
|
extern OpenThermTask* tOt;
|
||||||
extern FileData fsSettings, fsNetworkSettings;
|
extern FileData fsSettings, fsNetworkSettings;
|
||||||
@@ -27,7 +29,6 @@ protected:
|
|||||||
enum class PumpStartReason {NONE, HEATING, ANTISTUCK};
|
enum class PumpStartReason {NONE, HEATING, ANTISTUCK};
|
||||||
|
|
||||||
Blinker* blinker = nullptr;
|
Blinker* blinker = nullptr;
|
||||||
bool blinkerInitialized = false;
|
|
||||||
unsigned long firstFailConnect = 0;
|
unsigned long firstFailConnect = 0;
|
||||||
unsigned long lastHeapInfo = 0;
|
unsigned long lastHeapInfo = 0;
|
||||||
unsigned int minFreeHeap = 0;
|
unsigned int minFreeHeap = 0;
|
||||||
@@ -39,29 +40,21 @@ protected:
|
|||||||
unsigned long externalPumpStartTime = 0;
|
unsigned long externalPumpStartTime = 0;
|
||||||
bool telnetStarted = false;
|
bool telnetStarted = false;
|
||||||
|
|
||||||
const char* getTaskName() {
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const char* getTaskName() override {
|
||||||
return "Main";
|
return "Main";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int getTaskCore() {
|
/*BaseType_t getTaskCore() override {
|
||||||
return 1;
|
return 1;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
|
||||||
#ifdef LED_STATUS_GPIO
|
|
||||||
pinMode(LED_STATUS_GPIO, OUTPUT);
|
|
||||||
digitalWrite(LED_STATUS_GPIO, LOW);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (GPIO_IS_VALID(settings.externalPump.gpio)) {
|
void setup() {}
|
||||||
pinMode(settings.externalPump.gpio, OUTPUT);
|
|
||||||
digitalWrite(settings.externalPump.gpio, LOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
network->loop();
|
network->loop();
|
||||||
@@ -142,7 +135,7 @@ protected:
|
|||||||
this->firstFailConnect = millis();
|
this->firstFailConnect = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (millis() - this->firstFailConnect > EMERGENCY_TIME_TRESHOLD) {
|
if (millis() - this->firstFailConnect > (settings.emergency.tresholdTime * 1000)) {
|
||||||
vars.states.emergency = true;
|
vars.states.emergency = true;
|
||||||
Log.sinfoln(FPSTR(L_MAIN), F("Emergency mode enabled"));
|
Log.sinfoln(FPSTR(L_MAIN), F("Emergency mode enabled"));
|
||||||
}
|
}
|
||||||
@@ -151,9 +144,7 @@ protected:
|
|||||||
this->yield();
|
this->yield();
|
||||||
|
|
||||||
|
|
||||||
#ifdef LED_STATUS_GPIO
|
this->ledStatus();
|
||||||
this->ledStatus(LED_STATUS_GPIO);
|
|
||||||
#endif
|
|
||||||
this->externalPump();
|
this->externalPump();
|
||||||
this->yield();
|
this->yield();
|
||||||
|
|
||||||
@@ -222,16 +213,32 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ledStatus(uint8_t gpio) {
|
void ledStatus() {
|
||||||
uint8_t errors[4];
|
uint8_t errors[4];
|
||||||
uint8_t errCount = 0;
|
uint8_t errCount = 0;
|
||||||
static uint8_t errPos = 0;
|
static uint8_t errPos = 0;
|
||||||
static unsigned long endBlinkTime = 0;
|
static unsigned long endBlinkTime = 0;
|
||||||
static bool ledOn = false;
|
static bool ledOn = false;
|
||||||
|
static uint8_t configuredGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
|
||||||
if (!this->blinkerInitialized) {
|
if (settings.system.statusLedGpio != configuredGpio) {
|
||||||
this->blinker->init(gpio);
|
if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
this->blinkerInitialized = true;
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GPIO_IS_VALID(settings.system.statusLedGpio)) {
|
||||||
|
configuredGpio = settings.system.statusLedGpio;
|
||||||
|
pinMode(configuredGpio, OUTPUT);
|
||||||
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
this->blinker->init(configuredGpio);
|
||||||
|
|
||||||
|
} else if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
configuredGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuredGpio == GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!network->isConnected()) {
|
if (!network->isConnected()) {
|
||||||
@@ -258,14 +265,14 @@ protected:
|
|||||||
if (!this->blinker->running() && millis() - endBlinkTime >= 5000) {
|
if (!this->blinker->running() && millis() - endBlinkTime >= 5000) {
|
||||||
if (errCount == 0) {
|
if (errCount == 0) {
|
||||||
if (!ledOn) {
|
if (!ledOn) {
|
||||||
digitalWrite(gpio, HIGH);
|
digitalWrite(configuredGpio, HIGH);
|
||||||
ledOn = true;
|
ledOn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else if (ledOn) {
|
} else if (ledOn) {
|
||||||
digitalWrite(gpio, LOW);
|
digitalWrite(configuredGpio, LOW);
|
||||||
ledOn = false;
|
ledOn = false;
|
||||||
endBlinkTime = millis();
|
endBlinkTime = millis();
|
||||||
return;
|
return;
|
||||||
@@ -286,6 +293,34 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void externalPump() {
|
void externalPump() {
|
||||||
|
static uint8_t configuredGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
|
||||||
|
if (settings.externalPump.gpio != configuredGpio) {
|
||||||
|
if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GPIO_IS_VALID(settings.externalPump.gpio)) {
|
||||||
|
configuredGpio = settings.externalPump.gpio;
|
||||||
|
pinMode(configuredGpio, OUTPUT);
|
||||||
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
|
||||||
|
} else if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
configuredGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuredGpio == GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
if (vars.states.externalPump) {
|
||||||
|
vars.states.externalPump = false;
|
||||||
|
vars.parameters.extPumpLastEnableTime = millis();
|
||||||
|
|
||||||
|
Log.sinfoln("EXTPUMP", F("Disabled: use = off"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!vars.states.heating && this->heatingEnabled) {
|
if (!vars.states.heating && this->heatingEnabled) {
|
||||||
this->heatingEnabled = false;
|
this->heatingEnabled = false;
|
||||||
this->heatingDisabledTime = millis();
|
this->heatingDisabledTime = millis();
|
||||||
@@ -294,11 +329,9 @@ protected:
|
|||||||
this->heatingEnabled = true;
|
this->heatingEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!settings.externalPump.use || !GPIO_IS_VALID(settings.externalPump.gpio)) {
|
if (!settings.externalPump.use) {
|
||||||
if (vars.states.externalPump) {
|
if (vars.states.externalPump) {
|
||||||
if (GPIO_IS_VALID(settings.externalPump.gpio)) {
|
digitalWrite(configuredGpio, LOW);
|
||||||
digitalWrite(settings.externalPump.gpio, LOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
vars.states.externalPump = false;
|
vars.states.externalPump = false;
|
||||||
vars.parameters.extPumpLastEnableTime = millis();
|
vars.parameters.extPumpLastEnableTime = millis();
|
||||||
@@ -311,7 +344,7 @@ protected:
|
|||||||
|
|
||||||
if (vars.states.externalPump && !this->heatingEnabled) {
|
if (vars.states.externalPump && !this->heatingEnabled) {
|
||||||
if (this->extPumpStartReason == MainTask::PumpStartReason::HEATING && millis() - this->heatingDisabledTime > (settings.externalPump.postCirculationTime * 1000u)) {
|
if (this->extPumpStartReason == MainTask::PumpStartReason::HEATING && millis() - this->heatingDisabledTime > (settings.externalPump.postCirculationTime * 1000u)) {
|
||||||
digitalWrite(settings.externalPump.gpio, LOW);
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
|
||||||
vars.states.externalPump = false;
|
vars.states.externalPump = false;
|
||||||
vars.parameters.extPumpLastEnableTime = millis();
|
vars.parameters.extPumpLastEnableTime = millis();
|
||||||
@@ -319,7 +352,7 @@ protected:
|
|||||||
Log.sinfoln("EXTPUMP", F("Disabled: expired post circulation time"));
|
Log.sinfoln("EXTPUMP", F("Disabled: expired post circulation time"));
|
||||||
|
|
||||||
} else if (this->extPumpStartReason == MainTask::PumpStartReason::ANTISTUCK && millis() - this->externalPumpStartTime >= (settings.externalPump.antiStuckTime * 1000u)) {
|
} else if (this->extPumpStartReason == MainTask::PumpStartReason::ANTISTUCK && millis() - this->externalPumpStartTime >= (settings.externalPump.antiStuckTime * 1000u)) {
|
||||||
digitalWrite(settings.externalPump.gpio, LOW);
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
|
||||||
vars.states.externalPump = false;
|
vars.states.externalPump = false;
|
||||||
vars.parameters.extPumpLastEnableTime = millis();
|
vars.parameters.extPumpLastEnableTime = millis();
|
||||||
@@ -335,7 +368,7 @@ protected:
|
|||||||
this->externalPumpStartTime = millis();
|
this->externalPumpStartTime = millis();
|
||||||
this->extPumpStartReason = MainTask::PumpStartReason::HEATING;
|
this->extPumpStartReason = MainTask::PumpStartReason::HEATING;
|
||||||
|
|
||||||
digitalWrite(settings.externalPump.gpio, HIGH);
|
digitalWrite(configuredGpio, HIGH);
|
||||||
|
|
||||||
Log.sinfoln("EXTPUMP", F("Enabled: heating on"));
|
Log.sinfoln("EXTPUMP", F("Enabled: heating on"));
|
||||||
|
|
||||||
@@ -344,7 +377,7 @@ protected:
|
|||||||
this->externalPumpStartTime = millis();
|
this->externalPumpStartTime = millis();
|
||||||
this->extPumpStartReason = MainTask::PumpStartReason::ANTISTUCK;
|
this->extPumpStartReason = MainTask::PumpStartReason::ANTISTUCK;
|
||||||
|
|
||||||
digitalWrite(settings.externalPump.gpio, HIGH);
|
digitalWrite(configuredGpio, HIGH);
|
||||||
|
|
||||||
Log.sinfoln("EXTPUMP", F("Enabled: anti stuck"));
|
Log.sinfoln("EXTPUMP", F("Enabled: anti stuck"));
|
||||||
}
|
}
|
||||||
|
|||||||
117
src/MqttTask.h
117
src/MqttTask.h
@@ -53,16 +53,25 @@ public:
|
|||||||
Log.sinfoln(FPSTR(L_MQTT), F("Enabled"));
|
Log.sinfoln(FPSTR(L_MQTT), F("Enabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isConnected() {
|
inline bool isConnected() {
|
||||||
return this->connected;
|
return this->connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void resetPublishedSettingsTime() {
|
||||||
|
this->prevPubSettingsTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void resetPublishedVarsTime() {
|
||||||
|
this->prevPubVarsTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MqttWiFiClient* wifiClient = nullptr;
|
MqttWiFiClient* wifiClient = nullptr;
|
||||||
MqttClient* client = nullptr;
|
MqttClient* client = nullptr;
|
||||||
HaHelper* haHelper = nullptr;
|
HaHelper* haHelper = nullptr;
|
||||||
MqttWriter* writer = nullptr;
|
MqttWriter* writer = nullptr;
|
||||||
UnitSystem currentUnitSystem = UnitSystem::METRIC;
|
UnitSystem currentUnitSystem = UnitSystem::METRIC;
|
||||||
|
bool currentHomeAssistantDiscovery = false;
|
||||||
unsigned short readyForSendTime = 15000;
|
unsigned short readyForSendTime = 15000;
|
||||||
unsigned long lastReconnectTime = 0;
|
unsigned long lastReconnectTime = 0;
|
||||||
unsigned long connectedTime = 0;
|
unsigned long connectedTime = 0;
|
||||||
@@ -72,19 +81,21 @@ protected:
|
|||||||
bool connected = false;
|
bool connected = false;
|
||||||
bool newConnection = false;
|
bool newConnection = false;
|
||||||
|
|
||||||
const char* getTaskName() {
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const char* getTaskName() override {
|
||||||
return "Mqtt";
|
return "Mqtt";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int getTaskCore() {
|
/*BaseType_t getTaskCore() override {
|
||||||
return 1;
|
return 1;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool isReadyForSend() {
|
inline bool isReadyForSend() {
|
||||||
return millis() - this->connectedTime > this->readyForSendTime;
|
return millis() - this->connectedTime > this->readyForSendTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +199,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (settings.emergency.enable && settings.emergency.onMqttFault) {
|
if (settings.emergency.enable && settings.emergency.onMqttFault) {
|
||||||
if (!this->connected && !vars.states.emergency && millis() - this->disconnectedTime > EMERGENCY_TIME_TRESHOLD) {
|
if (!this->connected && !vars.states.emergency && millis() - this->disconnectedTime > (settings.emergency.tresholdTime * 1000)) {
|
||||||
vars.states.emergency = true;
|
vars.states.emergency = true;
|
||||||
Log.sinfoln(FPSTR(L_MQTT), F("Emergency mode enabled"));
|
Log.sinfoln(FPSTR(L_MQTT), F("Emergency mode enabled"));
|
||||||
|
|
||||||
@@ -227,16 +238,25 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// publish ha entities if not published
|
// publish ha entities if not published
|
||||||
if (this->newConnection || this->currentUnitSystem != settings.system.unitSystem) {
|
if (settings.mqtt.homeAssistantDiscovery) {
|
||||||
|
if (this->newConnection || !this->currentHomeAssistantDiscovery || this->currentUnitSystem != settings.system.unitSystem) {
|
||||||
this->publishHaEntities();
|
this->publishHaEntities();
|
||||||
this->publishNonStaticHaEntities(true);
|
this->publishNonStaticHaEntities(true);
|
||||||
this->newConnection = false;
|
this->currentHomeAssistantDiscovery = true;
|
||||||
this->currentUnitSystem = settings.system.unitSystem;
|
this->currentUnitSystem = settings.system.unitSystem;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// publish non static ha entities
|
// publish non static ha entities
|
||||||
this->publishNonStaticHaEntities();
|
this->publishNonStaticHaEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (this->currentHomeAssistantDiscovery) {
|
||||||
|
this->currentHomeAssistantDiscovery = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->newConnection) {
|
||||||
|
this->newConnection = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onConnect() {
|
void onConnect() {
|
||||||
@@ -291,52 +311,26 @@ protected:
|
|||||||
Log.swarningln(FPSTR(L_MQTT_MSG), F("Not valid json"));
|
Log.swarningln(FPSTR(L_MQTT_MSG), F("Not valid json"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
if (this->haHelper->getDeviceTopic("state/set").equals(topic)) {
|
if (this->haHelper->getDeviceTopic("state/set").equals(topic)) {
|
||||||
this->writer->publish(this->haHelper->getDeviceTopic("state/set").c_str(), nullptr, 0, true);
|
this->writer->publish(this->haHelper->getDeviceTopic("state/set").c_str(), nullptr, 0, true);
|
||||||
this->updateVariables(doc);
|
|
||||||
|
if (jsonToVars(doc, vars)) {
|
||||||
|
this->resetPublishedVarsTime();
|
||||||
|
}
|
||||||
|
|
||||||
} else if (this->haHelper->getDeviceTopic("settings/set").equals(topic)) {
|
} else if (this->haHelper->getDeviceTopic("settings/set").equals(topic)) {
|
||||||
this->writer->publish(this->haHelper->getDeviceTopic("settings/set").c_str(), nullptr, 0, true);
|
this->writer->publish(this->haHelper->getDeviceTopic("settings/set").c_str(), nullptr, 0, true);
|
||||||
this->updateSettings(doc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (safeJsonToSettings(doc, settings)) {
|
||||||
bool updateSettings(JsonDocument& doc) {
|
this->resetPublishedSettingsTime();
|
||||||
bool changed = safeJsonToSettings(doc, settings);
|
|
||||||
doc.clear();
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
this->prevPubSettingsTime = 0;
|
|
||||||
fsSettings.update();
|
fsSettings.update();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool updateVariables(JsonDocument& doc) {
|
|
||||||
bool changed = jsonToVars(doc, vars);
|
|
||||||
doc.clear();
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
this->prevPubVarsTime = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void publishHaEntities() {
|
void publishHaEntities() {
|
||||||
// emergency
|
|
||||||
this->haHelper->publishSwitchEmergency();
|
|
||||||
this->haHelper->publishNumberEmergencyTarget(settings.system.unitSystem);
|
|
||||||
this->haHelper->publishSwitchEmergencyUseEquitherm();
|
|
||||||
this->haHelper->publishSwitchEmergencyUsePid();
|
|
||||||
|
|
||||||
// heating
|
// heating
|
||||||
this->haHelper->publishSwitchHeating(false);
|
this->haHelper->publishSwitchHeating(false);
|
||||||
this->haHelper->publishSwitchHeatingTurbo();
|
this->haHelper->publishSwitchHeatingTurbo();
|
||||||
@@ -363,10 +357,6 @@ protected:
|
|||||||
this->haHelper->publishNumberEquithermFactorK();
|
this->haHelper->publishNumberEquithermFactorK();
|
||||||
this->haHelper->publishNumberEquithermFactorT();
|
this->haHelper->publishNumberEquithermFactorT();
|
||||||
|
|
||||||
// tuning
|
|
||||||
this->haHelper->publishSwitchTuning();
|
|
||||||
this->haHelper->publishSelectTuningRegulator();
|
|
||||||
|
|
||||||
// states
|
// states
|
||||||
this->haHelper->publishBinSensorStatus();
|
this->haHelper->publishBinSensorStatus();
|
||||||
this->haHelper->publishBinSensorOtStatus();
|
this->haHelper->publishBinSensorOtStatus();
|
||||||
@@ -396,26 +386,22 @@ protected:
|
|||||||
|
|
||||||
bool publishNonStaticHaEntities(bool force = false) {
|
bool publishNonStaticHaEntities(bool force = false) {
|
||||||
static byte _heatingMinTemp, _heatingMaxTemp, _dhwMinTemp, _dhwMaxTemp = 0;
|
static byte _heatingMinTemp, _heatingMaxTemp, _dhwMinTemp, _dhwMaxTemp = 0;
|
||||||
static bool _isStupidMode, _editableOutdoorTemp, _editableIndoorTemp, _dhwPresent = false;
|
static bool _noRegulators, _editableOutdoorTemp, _editableIndoorTemp, _dhwPresent = false;
|
||||||
|
|
||||||
bool published = false;
|
bool published = false;
|
||||||
bool isStupidMode = !settings.pid.enable && !settings.equitherm.enable;
|
bool noRegulators = !settings.opentherm.nativeHeatingControl && !settings.pid.enable && !settings.equitherm.enable;
|
||||||
byte heatingMinTemp = 0;
|
byte heatingMinTemp = 0;
|
||||||
byte heatingMaxTemp = 0;
|
byte heatingMaxTemp = 0;
|
||||||
bool editableOutdoorTemp = settings.sensors.outdoor.type == SensorType::MANUAL;
|
bool editableOutdoorTemp = settings.sensors.outdoor.type == SensorType::MANUAL;
|
||||||
bool editableIndoorTemp = settings.sensors.indoor.type == SensorType::MANUAL;
|
bool editableIndoorTemp = settings.sensors.indoor.type == SensorType::MANUAL;
|
||||||
|
|
||||||
if (isStupidMode) {
|
if (noRegulators) {
|
||||||
heatingMinTemp = settings.heating.minTemp;
|
heatingMinTemp = settings.heating.minTemp;
|
||||||
heatingMaxTemp = settings.heating.maxTemp;
|
heatingMaxTemp = settings.heating.maxTemp;
|
||||||
|
|
||||||
} else if (settings.system.unitSystem == UnitSystem::METRIC) {
|
} else {
|
||||||
heatingMinTemp = 5;
|
heatingMinTemp = convertTemp(THERMOSTAT_INDOOR_MIN_TEMP, UnitSystem::METRIC, settings.system.unitSystem);
|
||||||
heatingMaxTemp = 30;
|
heatingMaxTemp = convertTemp(THERMOSTAT_INDOOR_MAX_TEMP, UnitSystem::METRIC, settings.system.unitSystem);
|
||||||
|
|
||||||
} else if (settings.system.unitSystem == UnitSystem::IMPERIAL) {
|
|
||||||
heatingMinTemp = 41;
|
|
||||||
heatingMaxTemp = 86;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (force || _dhwPresent != settings.opentherm.dhwPresent) {
|
if (force || _dhwPresent != settings.opentherm.dhwPresent) {
|
||||||
@@ -447,32 +433,17 @@ protected:
|
|||||||
published = true;
|
published = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (force || _heatingMinTemp != heatingMinTemp || _heatingMaxTemp != heatingMaxTemp) {
|
if (force || _noRegulators != noRegulators || _heatingMinTemp != heatingMinTemp || _heatingMaxTemp != heatingMaxTemp) {
|
||||||
if (settings.heating.target < heatingMinTemp || settings.heating.target > heatingMaxTemp) {
|
|
||||||
settings.heating.target = constrain(settings.heating.target, heatingMinTemp, heatingMaxTemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
_heatingMinTemp = heatingMinTemp;
|
_heatingMinTemp = heatingMinTemp;
|
||||||
_heatingMaxTemp = heatingMaxTemp;
|
_heatingMaxTemp = heatingMaxTemp;
|
||||||
_isStupidMode = isStupidMode;
|
_noRegulators = noRegulators;
|
||||||
|
|
||||||
this->haHelper->publishNumberHeatingTarget(settings.system.unitSystem, heatingMinTemp, heatingMaxTemp, false);
|
this->haHelper->publishNumberHeatingTarget(settings.system.unitSystem, heatingMinTemp, heatingMaxTemp, false);
|
||||||
this->haHelper->publishClimateHeating(
|
this->haHelper->publishClimateHeating(
|
||||||
settings.system.unitSystem,
|
settings.system.unitSystem,
|
||||||
heatingMinTemp,
|
heatingMinTemp,
|
||||||
heatingMaxTemp,
|
heatingMaxTemp,
|
||||||
isStupidMode ? HaHelper::TEMP_SOURCE_HEATING : HaHelper::TEMP_SOURCE_INDOOR
|
noRegulators ? HaHelper::TEMP_SOURCE_HEATING : HaHelper::TEMP_SOURCE_INDOOR
|
||||||
);
|
|
||||||
|
|
||||||
published = true;
|
|
||||||
|
|
||||||
} else if (_isStupidMode != isStupidMode) {
|
|
||||||
_isStupidMode = isStupidMode;
|
|
||||||
this->haHelper->publishClimateHeating(
|
|
||||||
settings.system.unitSystem,
|
|
||||||
heatingMinTemp,
|
|
||||||
heatingMaxTemp,
|
|
||||||
isStupidMode ? HaHelper::TEMP_SOURCE_HEATING : HaHelper::TEMP_SOURCE_INDOOR
|
|
||||||
);
|
);
|
||||||
|
|
||||||
published = true;
|
published = true;
|
||||||
|
|||||||
@@ -29,19 +29,23 @@ protected:
|
|||||||
unsigned long prevUpdateNonEssentialVars = 0;
|
unsigned long prevUpdateNonEssentialVars = 0;
|
||||||
unsigned long dhwSetTempTime = 0;
|
unsigned long dhwSetTempTime = 0;
|
||||||
unsigned long heatingSetTempTime = 0;
|
unsigned long heatingSetTempTime = 0;
|
||||||
|
byte configuredRxLedGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
byte configuredFaultStateGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
bool faultState = false;
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
const char* getTaskName() {
|
const char* getTaskName() override {
|
||||||
return "OpenTherm";
|
return "OpenTherm";
|
||||||
}
|
}
|
||||||
|
|
||||||
int getTaskCore() {
|
BaseType_t getTaskCore() override {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
if (settings.system.unitSystem != UnitSystem::METRIC) {
|
if (settings.system.unitSystem != UnitSystem::METRIC) {
|
||||||
@@ -51,11 +55,6 @@ protected:
|
|||||||
vars.parameters.dhwMaxTemp = convertTemp(vars.parameters.dhwMaxTemp, UnitSystem::METRIC, settings.system.unitSystem);
|
vars.parameters.dhwMaxTemp = convertTemp(vars.parameters.dhwMaxTemp, UnitSystem::METRIC, settings.system.unitSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LED_OT_RX_GPIO
|
|
||||||
pinMode(LED_OT_RX_GPIO, OUTPUT);
|
|
||||||
digitalWrite(LED_OT_RX_GPIO, LOW);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// delete instance
|
// delete instance
|
||||||
if (this->instance != nullptr) {
|
if (this->instance != nullptr) {
|
||||||
delete this->instance;
|
delete this->instance;
|
||||||
@@ -89,13 +88,11 @@ protected:
|
|||||||
if (status == OpenThermResponseStatus::SUCCESS) {
|
if (status == OpenThermResponseStatus::SUCCESS) {
|
||||||
this->lastSuccessResponse = millis();
|
this->lastSuccessResponse = millis();
|
||||||
|
|
||||||
#ifdef LED_OT_RX_GPIO
|
if (this->configuredRxLedGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
{
|
digitalWrite(this->configuredRxLedGpio, HIGH);
|
||||||
digitalWrite(LED_OT_RX_GPIO, HIGH);
|
|
||||||
delayMicroseconds(2000);
|
delayMicroseconds(2000);
|
||||||
digitalWrite(LED_OT_RX_GPIO, LOW);
|
digitalWrite(this->configuredRxLedGpio, LOW);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -107,7 +104,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
static byte currentHeatingTemp, currentDhwTemp = 0;
|
static float currentHeatingTemp = 0.0f;
|
||||||
|
static float currentDhwTemp = 0.0f;
|
||||||
|
|
||||||
if (this->instanceInGpio != settings.opentherm.inGpio || this->instanceOutGpio != settings.opentherm.outGpio) {
|
if (this->instanceInGpio != settings.opentherm.inGpio || this->instanceOutGpio != settings.opentherm.outGpio) {
|
||||||
this->setup();
|
this->setup();
|
||||||
@@ -121,6 +119,43 @@ protected:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RX LED GPIO setup
|
||||||
|
if (settings.opentherm.rxLedGpio != this->configuredRxLedGpio) {
|
||||||
|
if (this->configuredRxLedGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
digitalWrite(this->configuredRxLedGpio, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GPIO_IS_VALID(settings.opentherm.rxLedGpio)) {
|
||||||
|
this->configuredRxLedGpio = settings.opentherm.rxLedGpio;
|
||||||
|
pinMode(this->configuredRxLedGpio, OUTPUT);
|
||||||
|
digitalWrite(this->configuredRxLedGpio, LOW);
|
||||||
|
|
||||||
|
} else if (this->configuredRxLedGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
this->configuredRxLedGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fault state setup
|
||||||
|
if (settings.opentherm.faultStateGpio != this->configuredFaultStateGpio) {
|
||||||
|
if (this->configuredFaultStateGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
digitalWrite(this->configuredFaultStateGpio, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GPIO_IS_VALID(settings.opentherm.faultStateGpio)) {
|
||||||
|
this->configuredFaultStateGpio = settings.opentherm.faultStateGpio;
|
||||||
|
this->faultState = false ^ settings.opentherm.invertFaultState ? HIGH : LOW;
|
||||||
|
|
||||||
|
pinMode(this->configuredFaultStateGpio, OUTPUT);
|
||||||
|
digitalWrite(
|
||||||
|
this->configuredFaultStateGpio,
|
||||||
|
this->faultState
|
||||||
|
);
|
||||||
|
|
||||||
|
} else if (this->configuredFaultStateGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
this->configuredFaultStateGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool heatingEnabled = (vars.states.emergency || settings.heating.enable) && this->pump && this->isReady();
|
bool heatingEnabled = (vars.states.emergency || settings.heating.enable) && this->pump && this->isReady();
|
||||||
bool heatingCh2Enabled = settings.opentherm.heatingCh2Enabled;
|
bool heatingCh2Enabled = settings.opentherm.heatingCh2Enabled;
|
||||||
if (settings.opentherm.heatingCh1ToCh2) {
|
if (settings.opentherm.heatingCh1ToCh2) {
|
||||||
@@ -134,7 +169,7 @@ protected:
|
|||||||
heatingEnabled,
|
heatingEnabled,
|
||||||
settings.opentherm.dhwPresent && settings.dhw.enable,
|
settings.opentherm.dhwPresent && settings.dhw.enable,
|
||||||
false,
|
false,
|
||||||
false,
|
settings.opentherm.nativeHeatingControl,
|
||||||
heatingCh2Enabled,
|
heatingCh2Enabled,
|
||||||
settings.opentherm.summerWinterMode,
|
settings.opentherm.summerWinterMode,
|
||||||
settings.opentherm.dhwBlocking
|
settings.opentherm.dhwBlocking
|
||||||
@@ -164,6 +199,16 @@ protected:
|
|||||||
vars.states.fault = false;
|
vars.states.fault = false;
|
||||||
vars.states.diagnostic = false;
|
vars.states.diagnostic = false;
|
||||||
|
|
||||||
|
// Force fault state = on
|
||||||
|
if (this->configuredFaultStateGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
bool fState = true ^ settings.opentherm.invertFaultState ? HIGH : LOW;
|
||||||
|
|
||||||
|
if (fState != this->faultState) {
|
||||||
|
this->faultState = fState;
|
||||||
|
digitalWrite(this->configuredFaultStateGpio, this->faultState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +234,16 @@ protected:
|
|||||||
vars.states.fault = CustomOpenTherm::isFault(response);
|
vars.states.fault = CustomOpenTherm::isFault(response);
|
||||||
vars.states.diagnostic = CustomOpenTherm::isDiagnostic(response);
|
vars.states.diagnostic = CustomOpenTherm::isDiagnostic(response);
|
||||||
|
|
||||||
|
// Fault state
|
||||||
|
if (this->configuredFaultStateGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
bool fState = vars.states.fault ^ settings.opentherm.invertFaultState ? HIGH : LOW;
|
||||||
|
|
||||||
|
if (fState != this->faultState) {
|
||||||
|
this->faultState = fState;
|
||||||
|
digitalWrite(this->configuredFaultStateGpio, this->faultState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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 (!heatingEnabled && settings.opentherm.modulationSyncWithHeating) {
|
if (!heatingEnabled && settings.opentherm.modulationSyncWithHeating) {
|
||||||
@@ -276,6 +331,9 @@ protected:
|
|||||||
// Get fault code (if necessary)
|
// Get fault code (if necessary)
|
||||||
if (vars.states.fault) {
|
if (vars.states.fault) {
|
||||||
updateFaultCode();
|
updateFaultCode();
|
||||||
|
|
||||||
|
} else if (vars.sensors.faultCode != 0) {
|
||||||
|
vars.sensors.faultCode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePressure();
|
updatePressure();
|
||||||
@@ -342,18 +400,13 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
// Update DHW temp
|
// Update DHW temp
|
||||||
byte newDhwTemp = settings.dhw.target;
|
if (settings.opentherm.dhwPresent && settings.dhw.enable && (this->needSetDhwTemp() || fabs(settings.dhw.target - currentDhwTemp) > 0.0001f)) {
|
||||||
if (settings.opentherm.dhwPresent && settings.dhw.enable && (this->needSetDhwTemp() || newDhwTemp != currentDhwTemp)) {
|
float convertedTemp = convertTemp(settings.dhw.target, settings.system.unitSystem, settings.opentherm.unitSystem);
|
||||||
if (newDhwTemp < settings.dhw.minTemp || newDhwTemp > settings.dhw.maxTemp) {
|
Log.sinfoln(FPSTR(L_OT_DHW), F("Set temp: %.2f (converted: %.2f)"), settings.dhw.target, convertedTemp);
|
||||||
newDhwTemp = constrain(newDhwTemp, settings.dhw.minTemp, settings.dhw.maxTemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
float convertedTemp = convertTemp(newDhwTemp, settings.system.unitSystem, settings.opentherm.unitSystem);
|
|
||||||
Log.sinfoln(FPSTR(L_OT_DHW), F("Set temp: %u (converted: %.2f)"), newDhwTemp, convertedTemp);
|
|
||||||
|
|
||||||
// Set DHW temp
|
// Set DHW temp
|
||||||
if (this->instance->setDhwTemp(convertedTemp)) {
|
if (this->instance->setDhwTemp(convertedTemp)) {
|
||||||
currentDhwTemp = newDhwTemp;
|
currentDhwTemp = settings.dhw.target;
|
||||||
this->dhwSetTempTime = millis();
|
this->dhwSetTempTime = millis();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -363,30 +416,82 @@ protected:
|
|||||||
// Set DHW temp to CH2
|
// Set DHW temp to CH2
|
||||||
if (settings.opentherm.dhwToCh2) {
|
if (settings.opentherm.dhwToCh2) {
|
||||||
if (!this->instance->setHeatingCh2Temp(convertedTemp)) {
|
if (!this->instance->setHeatingCh2Temp(convertedTemp)) {
|
||||||
Log.swarningln(FPSTR(L_OT_DHW), F("Failed set ch2 temp"));
|
Log.swarningln(FPSTR(L_OT_DHW), F("Failed set CH2 temp"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Update heating temp
|
// Native heating control
|
||||||
if (heatingEnabled && (this->needSetHeatingTemp() || fabs(vars.parameters.heatingSetpoint - currentHeatingTemp) > 0.0001)) {
|
if (settings.opentherm.nativeHeatingControl) {
|
||||||
float convertedTemp = convertTemp(vars.parameters.heatingSetpoint, settings.system.unitSystem, settings.opentherm.unitSystem);
|
// Set current indoor temp
|
||||||
Log.sinfoln(FPSTR(L_OT_HEATING), F("Set temp: %u (converted: %.2f)"), vars.parameters.heatingSetpoint, convertedTemp);
|
float indoorTemp = 0.0f;
|
||||||
|
float convertedTemp = 0.0f;
|
||||||
|
|
||||||
// Set heating temp
|
if (!vars.states.emergency || settings.sensors.indoor.type != SensorType::MANUAL) {
|
||||||
if (this->instance->setHeatingCh1Temp(convertedTemp) || this->setMaxHeatingTemp(convertedTemp)) {
|
indoorTemp = vars.temperatures.indoor;
|
||||||
|
convertedTemp = convertTemp(indoorTemp, settings.system.unitSystem, settings.opentherm.unitSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.sinfoln(FPSTR(L_OT_HEATING), F("Set current indoor temp: %.2f (converted: %.2f)"), indoorTemp, convertedTemp);
|
||||||
|
if (!this->instance->setRoomTemp(convertedTemp)) {
|
||||||
|
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set current indoor temp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set target indoor temp
|
||||||
|
if (this->needSetHeatingTemp() || fabs(vars.parameters.heatingSetpoint - currentHeatingTemp) > 0.0001f) {
|
||||||
|
convertedTemp = convertTemp(vars.parameters.heatingSetpoint, settings.system.unitSystem, settings.opentherm.unitSystem);
|
||||||
|
Log.sinfoln(FPSTR(L_OT_HEATING), F("Set target indoor temp: %.2f (converted: %.2f)"), vars.parameters.heatingSetpoint, convertedTemp);
|
||||||
|
|
||||||
|
if (this->instance->setRoomSetpoint(convertedTemp)) {
|
||||||
currentHeatingTemp = vars.parameters.heatingSetpoint;
|
currentHeatingTemp = vars.parameters.heatingSetpoint;
|
||||||
this->heatingSetTempTime = millis();
|
this->heatingSetTempTime = millis();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set temp"));
|
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set target indoor temp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set target temp to CH2
|
||||||
|
if (settings.opentherm.heatingCh1ToCh2) {
|
||||||
|
if (!this->instance->setRoomSetpointCh2(convertedTemp)) {
|
||||||
|
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set target indoor temp to CH2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// force enable pump
|
||||||
|
if (!this->pump) {
|
||||||
|
this->pump = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Update heating temp
|
||||||
|
if (heatingEnabled && (this->needSetHeatingTemp() || fabs(vars.parameters.heatingSetpoint - currentHeatingTemp) > 0.0001f)) {
|
||||||
|
float convertedTemp = convertTemp(vars.parameters.heatingSetpoint, settings.system.unitSystem, settings.opentherm.unitSystem);
|
||||||
|
Log.sinfoln(FPSTR(L_OT_HEATING), F("Set temp: %.2f (converted: %.2f)"), vars.parameters.heatingSetpoint, convertedTemp);
|
||||||
|
|
||||||
|
// Set max heating temp
|
||||||
|
if (this->setMaxHeatingTemp(convertedTemp)) {
|
||||||
|
currentHeatingTemp = vars.parameters.heatingSetpoint;
|
||||||
|
this->heatingSetTempTime = millis();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set max heating temp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set heating temp
|
||||||
|
if (this->instance->setHeatingCh1Temp(convertedTemp)) {
|
||||||
|
currentHeatingTemp = vars.parameters.heatingSetpoint;
|
||||||
|
this->heatingSetTempTime = millis();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set CH1 temp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set heating temp to CH2
|
// Set heating temp to CH2
|
||||||
if (settings.opentherm.heatingCh1ToCh2) {
|
if (settings.opentherm.heatingCh1ToCh2) {
|
||||||
if (!this->instance->setHeatingCh2Temp(convertedTemp)) {
|
if (!this->instance->setHeatingCh2Temp(convertedTemp)) {
|
||||||
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set ch2 temp"));
|
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set CH2 temp"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -396,10 +501,10 @@ protected:
|
|||||||
// Only if enabled PID or/and Equitherm
|
// Only if enabled PID or/and Equitherm
|
||||||
if (settings.heating.hysteresis > 0 && (!vars.states.emergency || settings.emergency.usePid) && (settings.equitherm.enable || settings.pid.enable)) {
|
if (settings.heating.hysteresis > 0 && (!vars.states.emergency || settings.emergency.usePid) && (settings.equitherm.enable || settings.pid.enable)) {
|
||||||
float halfHyst = settings.heating.hysteresis / 2;
|
float halfHyst = settings.heating.hysteresis / 2;
|
||||||
if (this->pump && vars.temperatures.indoor - settings.heating.target + 0.0001 >= halfHyst) {
|
if (this->pump && vars.temperatures.indoor - settings.heating.target + 0.0001f >= halfHyst) {
|
||||||
this->pump = false;
|
this->pump = false;
|
||||||
|
|
||||||
} else if (!this->pump && vars.temperatures.indoor - settings.heating.target - 0.0001 <= -(halfHyst)) {
|
} else if (!this->pump && vars.temperatures.indoor - settings.heating.target - 0.0001f <= -(halfHyst)) {
|
||||||
this->pump = true;
|
this->pump = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,6 +512,7 @@ protected:
|
|||||||
this->pump = true;
|
this->pump = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void initialize() {
|
void initialize() {
|
||||||
// Not all boilers support these, only try once when the boiler becomes connected
|
// Not all boilers support these, only try once when the boiler becomes connected
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ using WebServer = ESP8266WebServer;
|
|||||||
#include <UpgradeHandler.h>
|
#include <UpgradeHandler.h>
|
||||||
#include <DNSServer.h>
|
#include <DNSServer.h>
|
||||||
|
|
||||||
extern Network::Manager* network;
|
using namespace NetworkUtils;
|
||||||
|
|
||||||
|
extern NetworkMgr* network;
|
||||||
extern FileData fsSettings, fsNetworkSettings;
|
extern FileData fsSettings, fsNetworkSettings;
|
||||||
extern MqttTask* tMqtt;
|
extern MqttTask* tMqtt;
|
||||||
|
|
||||||
@@ -53,17 +55,19 @@ protected:
|
|||||||
unsigned long webServerChangeState = 0;
|
unsigned long webServerChangeState = 0;
|
||||||
unsigned long dnsServerChangeState = 0;
|
unsigned long dnsServerChangeState = 0;
|
||||||
|
|
||||||
const char* getTaskName() {
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const char* getTaskName() override {
|
||||||
return "Portal";
|
return "Portal";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int getTaskCore() {
|
/*BaseType_t getTaskCore() override {
|
||||||
return 1;
|
return 1;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
this->dnsServer->setTTL(0);
|
this->dnsServer->setTTL(0);
|
||||||
@@ -344,7 +348,11 @@ protected:
|
|||||||
auto apCount = WiFi.scanComplete();
|
auto apCount = WiFi.scanComplete();
|
||||||
if (apCount <= 0) {
|
if (apCount <= 0) {
|
||||||
if (apCount != WIFI_SCAN_RUNNING) {
|
if (apCount != WIFI_SCAN_RUNNING) {
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
WiFi.scanNetworks(true, true);
|
WiFi.scanNetworks(true, true);
|
||||||
|
#else
|
||||||
|
WiFi.scanNetworks(true, true, true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
this->webServer->send(404);
|
this->webServer->send(404);
|
||||||
@@ -355,10 +363,16 @@ protected:
|
|||||||
for (short int i = 0; i < apCount; i++) {
|
for (short int i = 0; i < apCount; i++) {
|
||||||
String ssid = WiFi.SSID(i);
|
String ssid = WiFi.SSID(i);
|
||||||
doc[i]["ssid"] = ssid;
|
doc[i]["ssid"] = ssid;
|
||||||
doc[i]["signalQuality"] = Network::Manager::rssiToSignalQuality(WiFi.RSSI(i));
|
doc[i]["bssid"] = WiFi.BSSIDstr(i);
|
||||||
|
doc[i]["signalQuality"] = NetworkMgr::rssiToSignalQuality(WiFi.RSSI(i));
|
||||||
doc[i]["channel"] = WiFi.channel(i);
|
doc[i]["channel"] = WiFi.channel(i);
|
||||||
doc[i]["hidden"] = !ssid.length();
|
doc[i]["hidden"] = !ssid.length();
|
||||||
doc[i]["encryptionType"] = WiFi.encryptionType(i);
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
const bss_info* info = WiFi.getScanInfoByIndex(i);
|
||||||
|
doc[i]["auth"] = info->authmode;
|
||||||
|
#else
|
||||||
|
doc[i]["auth"] = WiFi.encryptionType(i);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
@@ -423,7 +437,9 @@ protected:
|
|||||||
if (changed) {
|
if (changed) {
|
||||||
doc.clear();
|
doc.clear();
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
fsSettings.update();
|
fsSettings.update();
|
||||||
|
tMqtt->resetPublishedSettingsTime();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -473,6 +489,13 @@ protected:
|
|||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
this->bufferedWebServer->send(changed ? 201 : 200, "application/json", doc);
|
this->bufferedWebServer->send(changed ? 201 : 200, "application/json", doc);
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
doc.clear();
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
tMqtt->resetPublishedVarsTime();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this->webServer->on("/api/info", HTTP_GET, [this]() {
|
this->webServer->on("/api/info", HTTP_GET, [this]() {
|
||||||
@@ -483,7 +506,7 @@ protected:
|
|||||||
doc["network"]["mac"] = network->getStaMac();
|
doc["network"]["mac"] = network->getStaMac();
|
||||||
doc["network"]["connected"] = isConnected;
|
doc["network"]["connected"] = isConnected;
|
||||||
doc["network"]["ssid"] = network->getStaSsid();
|
doc["network"]["ssid"] = network->getStaSsid();
|
||||||
doc["network"]["signalQuality"] = isConnected ? Network::Manager::rssiToSignalQuality(network->getRssi()) : 0;
|
doc["network"]["signalQuality"] = isConnected ? NetworkMgr::rssiToSignalQuality(network->getRssi()) : 0;
|
||||||
doc["network"]["channel"] = isConnected ? network->getStaChannel() : 0;
|
doc["network"]["channel"] = isConnected ? network->getStaChannel() : 0;
|
||||||
doc["network"]["ip"] = isConnected ? network->getStaIp().toString() : "";
|
doc["network"]["ip"] = isConnected ? network->getStaIp().toString() : "";
|
||||||
doc["network"]["subnet"] = isConnected ? network->getStaSubnet().toString() : "";
|
doc["network"]["subnet"] = isConnected ? network->getStaSubnet().toString() : "";
|
||||||
@@ -499,6 +522,34 @@ protected:
|
|||||||
doc["system"]["maxFreeBlockHeap"] = getMaxFreeBlockHeap();
|
doc["system"]["maxFreeBlockHeap"] = getMaxFreeBlockHeap();
|
||||||
doc["system"]["minMaxFreeBlockHeap"] = getMaxFreeBlockHeap(true);
|
doc["system"]["minMaxFreeBlockHeap"] = getMaxFreeBlockHeap(true);
|
||||||
doc["system"]["resetReason"] = getResetReason();
|
doc["system"]["resetReason"] = getResetReason();
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
doc["system"]["chipModel"] = esp_is_8285() ? "ESP8285" : "ESP8266";
|
||||||
|
doc["system"]["chipRevision"] = 0;
|
||||||
|
doc["system"]["chipCores"] = 1;
|
||||||
|
doc["system"]["cpuFreq"] = ESP.getCpuFreqMHz();
|
||||||
|
doc["system"]["coreVersion"] = ESP.getCoreVersion();
|
||||||
|
doc["system"]["flashSize"] = ESP.getFlashChipSize();
|
||||||
|
doc["system"]["flashRealSize"] = ESP.getFlashChipRealSize();
|
||||||
|
#elif ARDUINO_ARCH_ESP32
|
||||||
|
doc["system"]["chipModel"] = ESP.getChipModel();
|
||||||
|
doc["system"]["chipRevision"] = ESP.getChipRevision();
|
||||||
|
doc["system"]["chipCores"] = ESP.getChipCores();
|
||||||
|
doc["system"]["cpuFreq"] = ESP.getCpuFreqMHz();
|
||||||
|
doc["system"]["coreVersion"] = ESP.getSdkVersion();
|
||||||
|
doc["system"]["flashSize"] = ESP.getFlashChipSize();
|
||||||
|
doc["system"]["flashRealSize"] = doc["system"]["flashSize"];
|
||||||
|
#else
|
||||||
|
doc["system"]["chipModel"] = 0;
|
||||||
|
doc["system"]["chipRevision"] = 0;
|
||||||
|
doc["system"]["chipCores"] = 0;
|
||||||
|
doc["system"]["cpuFreq"] = 0;
|
||||||
|
doc["system"]["coreVersion"] = 0;
|
||||||
|
doc["system"]["flashSize"] = 0;
|
||||||
|
doc["system"]["flashRealSize"] = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
this->bufferedWebServer->send(200, "application/json", doc);
|
this->bufferedWebServer->send(200, "application/json", doc);
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
#include <Equitherm.h>
|
#include <Equitherm.h>
|
||||||
#include <GyverPID.h>
|
#include <GyverPID.h>
|
||||||
#include <PIDtuner.h>
|
|
||||||
|
|
||||||
Equitherm etRegulator;
|
Equitherm etRegulator;
|
||||||
GyverPID pidRegulator(0, 0, 0);
|
GyverPID pidRegulator(0, 0, 0);
|
||||||
PIDtuner pidTuner;
|
|
||||||
|
|
||||||
|
|
||||||
class RegulatorTask : public LeanTask {
|
class RegulatorTask : public LeanTask {
|
||||||
@@ -12,27 +10,26 @@ public:
|
|||||||
RegulatorTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {}
|
RegulatorTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool tunerInit = false;
|
|
||||||
byte tunerState = 0;
|
|
||||||
byte tunerRegulator = 0;
|
|
||||||
float prevHeatingTarget = 0;
|
float prevHeatingTarget = 0;
|
||||||
float prevEtResult = 0;
|
float prevEtResult = 0;
|
||||||
float prevPidResult = 0;
|
float prevPidResult = 0;
|
||||||
|
|
||||||
const char* getTaskName() {
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const char* getTaskName() override {
|
||||||
return "Regulator";
|
return "Regulator";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int getTaskCore() {
|
/*BaseType_t getTaskCore() override {
|
||||||
return 1;
|
return 1;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
byte newTemp = vars.parameters.heatingSetpoint;
|
float newTemp = vars.parameters.heatingSetpoint;
|
||||||
|
|
||||||
if (vars.states.emergency) {
|
if (vars.states.emergency) {
|
||||||
if (settings.heating.turbo) {
|
if (settings.heating.turbo) {
|
||||||
@@ -41,74 +38,60 @@ protected:
|
|||||||
Log.sinfoln(FPSTR(L_REGULATOR), F("Turbo mode auto disabled"));
|
Log.sinfoln(FPSTR(L_REGULATOR), F("Turbo mode auto disabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
newTemp = getEmergencyModeTemp();
|
newTemp = this->getEmergencyModeTemp();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (vars.tuning.enable || tunerInit) {
|
|
||||||
if (settings.heating.turbo) {
|
|
||||||
settings.heating.turbo = false;
|
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR), F("Turbo mode auto disabled"));
|
|
||||||
}
|
|
||||||
|
|
||||||
newTemp = getTuningModeTemp();
|
|
||||||
|
|
||||||
if (newTemp == 0) {
|
|
||||||
vars.tuning.enable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vars.tuning.enable) {
|
|
||||||
if (settings.heating.turbo && (fabs(settings.heating.target - vars.temperatures.indoor) < 1 || !settings.heating.enable || (settings.equitherm.enable && settings.pid.enable))) {
|
if (settings.heating.turbo && (fabs(settings.heating.target - vars.temperatures.indoor) < 1 || !settings.heating.enable || (settings.equitherm.enable && settings.pid.enable))) {
|
||||||
settings.heating.turbo = false;
|
settings.heating.turbo = false;
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR), F("Turbo mode auto disabled"));
|
Log.sinfoln(FPSTR(L_REGULATOR), F("Turbo mode auto disabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
newTemp = getNormalModeTemp();
|
newTemp = this->getNormalModeTemp();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limits
|
// Limits
|
||||||
if (newTemp < settings.heating.minTemp || newTemp > settings.heating.maxTemp) {
|
newTemp = constrain(
|
||||||
newTemp = constrain(newTemp, settings.heating.minTemp, settings.heating.maxTemp);
|
newTemp,
|
||||||
}
|
!settings.opentherm.nativeHeatingControl ? settings.heating.minTemp : THERMOSTAT_INDOOR_MIN_TEMP,
|
||||||
|
!settings.opentherm.nativeHeatingControl ? settings.heating.maxTemp : THERMOSTAT_INDOOR_MAX_TEMP
|
||||||
|
);
|
||||||
|
|
||||||
if (abs(vars.parameters.heatingSetpoint - newTemp) + 0.0001 >= 1) {
|
if (fabs(vars.parameters.heatingSetpoint - newTemp) > 0.4999f) {
|
||||||
vars.parameters.heatingSetpoint = newTemp;
|
vars.parameters.heatingSetpoint = newTemp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
byte getEmergencyModeTemp() {
|
float getEmergencyModeTemp() {
|
||||||
float newTemp = 0;
|
float newTemp = 0;
|
||||||
|
|
||||||
// if use equitherm
|
// if use equitherm
|
||||||
if (settings.emergency.useEquitherm && settings.sensors.outdoor.type != SensorType::MANUAL) {
|
if (settings.emergency.useEquitherm) {
|
||||||
float etResult = getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp);
|
float etResult = getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp);
|
||||||
|
|
||||||
if (fabs(prevEtResult - etResult) + 0.0001 >= 0.5) {
|
if (fabs(prevEtResult - etResult) > 0.4999f) {
|
||||||
prevEtResult = etResult;
|
prevEtResult = etResult;
|
||||||
newTemp += etResult;
|
newTemp += etResult;
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR_EQUITHERM), F("New emergency result: %hhu (%.2f)"), (uint8_t) round(etResult), etResult);
|
Log.sinfoln(FPSTR(L_REGULATOR_EQUITHERM), F("New emergency result: %.2f"), etResult);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newTemp += prevEtResult;
|
newTemp += prevEtResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(settings.emergency.usePid && settings.sensors.indoor.type != SensorType::MANUAL) {
|
} else if(settings.emergency.usePid) {
|
||||||
if (vars.parameters.heatingEnabled) {
|
if (vars.parameters.heatingEnabled) {
|
||||||
float pidResult = getPidTemp(
|
float pidResult = getPidTemp(
|
||||||
settings.heating.minTemp,
|
settings.heating.minTemp,
|
||||||
settings.heating.maxTemp
|
settings.heating.maxTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
if (fabs(prevPidResult - pidResult) + 0.0001 >= 0.5) {
|
if (fabs(prevPidResult - pidResult) > 0.4999f) {
|
||||||
prevPidResult = pidResult;
|
prevPidResult = pidResult;
|
||||||
newTemp += pidResult;
|
newTemp += pidResult;
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("New emergency result: %hhu (%.2f)"), (uint8_t) round(pidResult), pidResult);
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("New emergency result: %.2f"), pidResult);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newTemp += prevPidResult;
|
newTemp += prevPidResult;
|
||||||
@@ -123,17 +106,17 @@ protected:
|
|||||||
newTemp = settings.emergency.target;
|
newTemp = settings.emergency.target;
|
||||||
}
|
}
|
||||||
|
|
||||||
return round(newTemp);
|
return newTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte getNormalModeTemp() {
|
float getNormalModeTemp() {
|
||||||
float newTemp = 0;
|
float newTemp = 0;
|
||||||
|
|
||||||
if (fabs(prevHeatingTarget - settings.heating.target) > 0.0001) {
|
if (fabs(prevHeatingTarget - settings.heating.target) > 0.0001f) {
|
||||||
prevHeatingTarget = settings.heating.target;
|
prevHeatingTarget = settings.heating.target;
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR), F("New target: %.2f"), settings.heating.target);
|
Log.sinfoln(FPSTR(L_REGULATOR), F("New target: %.2f"), settings.heating.target);
|
||||||
|
|
||||||
if (settings.equitherm.enable && settings.pid.enable) {
|
if (/*settings.equitherm.enable && */settings.pid.enable) {
|
||||||
pidRegulator.integral = 0;
|
pidRegulator.integral = 0;
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
||||||
}
|
}
|
||||||
@@ -143,11 +126,11 @@ protected:
|
|||||||
if (settings.equitherm.enable) {
|
if (settings.equitherm.enable) {
|
||||||
float etResult = getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp);
|
float etResult = getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp);
|
||||||
|
|
||||||
if (fabs(prevEtResult - etResult) + 0.0001 >= 0.5) {
|
if (fabs(prevEtResult - etResult) > 0.4999f) {
|
||||||
prevEtResult = etResult;
|
prevEtResult = etResult;
|
||||||
newTemp += etResult;
|
newTemp += etResult;
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR_EQUITHERM), F("New result: %hhu (%.2f)"), (uint8_t) round(etResult), etResult);
|
Log.sinfoln(FPSTR(L_REGULATOR_EQUITHERM), F("New result: %.2f"), etResult);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newTemp += prevEtResult;
|
newTemp += prevEtResult;
|
||||||
@@ -162,11 +145,12 @@ protected:
|
|||||||
settings.pid.maxTemp
|
settings.pid.maxTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
if (fabs(prevPidResult - pidResult) + 0.0001 >= 0.5) {
|
if (fabs(prevPidResult - pidResult) > 0.4999f) {
|
||||||
prevPidResult = pidResult;
|
prevPidResult = pidResult;
|
||||||
newTemp += pidResult;
|
newTemp += pidResult;
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("New result: %hhd (%.2f)"), (int8_t) round(pidResult), pidResult);
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("New result: %.2f"), pidResult);
|
||||||
|
Log.straceln(FPSTR(L_REGULATOR_PID), F("Integral: %.2f"), pidRegulator.integral);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newTemp += prevPidResult;
|
newTemp += prevPidResult;
|
||||||
@@ -174,6 +158,10 @@ protected:
|
|||||||
} else {
|
} else {
|
||||||
newTemp += prevPidResult;
|
newTemp += prevPidResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (fabs(pidRegulator.integral) > 0.0001f) {
|
||||||
|
pidRegulator.integral = 0;
|
||||||
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// default temp, manual mode
|
// default temp, manual mode
|
||||||
@@ -181,97 +169,9 @@ protected:
|
|||||||
newTemp = settings.heating.target;
|
newTemp = settings.heating.target;
|
||||||
}
|
}
|
||||||
|
|
||||||
newTemp = round(newTemp);
|
|
||||||
return newTemp;
|
return newTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte getTuningModeTemp() {
|
|
||||||
if (tunerInit && (!vars.tuning.enable || vars.tuning.regulator != tunerRegulator)) {
|
|
||||||
if (tunerRegulator == 0) {
|
|
||||||
pidTuner.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
tunerInit = false;
|
|
||||||
tunerRegulator = 0;
|
|
||||||
tunerState = 0;
|
|
||||||
Log.sinfoln("REGULATOR.TUNING", F("Stopped"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vars.tuning.enable) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (vars.tuning.regulator == 0) {
|
|
||||||
// @TODO дописать
|
|
||||||
Log.sinfoln("REGULATOR.TUNING.EQUITHERM", F("Not implemented"));
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
} else if (vars.tuning.regulator == 1) {
|
|
||||||
// PID tuner
|
|
||||||
float defaultTemp = settings.equitherm.enable
|
|
||||||
? getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp)
|
|
||||||
: settings.heating.target;
|
|
||||||
|
|
||||||
if (tunerInit && pidTuner.getState() == 3) {
|
|
||||||
Log.sinfoln("REGULATOR.TUNING.PID", F("Finished"));
|
|
||||||
for (Stream* stream : Log.getStreams()) {
|
|
||||||
pidTuner.debugText(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
pidTuner.reset();
|
|
||||||
tunerInit = false;
|
|
||||||
tunerRegulator = 0;
|
|
||||||
tunerState = 0;
|
|
||||||
|
|
||||||
if (pidTuner.getAccuracy() < 90) {
|
|
||||||
Log.swarningln("REGULATOR.TUNING.PID", F("Bad result, try again..."));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
settings.pid.p_factor = pidTuner.getPID_p();
|
|
||||||
settings.pid.i_factor = pidTuner.getPID_i();
|
|
||||||
settings.pid.d_factor = pidTuner.getPID_d();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tunerInit) {
|
|
||||||
Log.sinfoln("REGULATOR.TUNING.PID", F("Start..."));
|
|
||||||
|
|
||||||
float step;
|
|
||||||
if (vars.temperatures.indoor - vars.temperatures.outdoor > 10) {
|
|
||||||
step = ceil(vars.parameters.heatingSetpoint / vars.temperatures.indoor * 2);
|
|
||||||
} else {
|
|
||||||
step = 5.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float startTemp = step;
|
|
||||||
Log.sinfoln("REGULATOR.TUNING.PID", F("Started. Start value: %f, step: %f"), startTemp, step);
|
|
||||||
pidTuner.setParameters(NORMAL, startTemp, step, 20 * 60 * 1000, 0.15, 60 * 1000, 10000);
|
|
||||||
tunerInit = true;
|
|
||||||
tunerRegulator = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pidTuner.setInput(vars.temperatures.indoor);
|
|
||||||
pidTuner.compute();
|
|
||||||
|
|
||||||
if (tunerState > 0 && pidTuner.getState() != tunerState) {
|
|
||||||
Log.sinfoln("REGULATOR.TUNING.PID", F("Log:"));
|
|
||||||
for (Stream* stream : Log.getStreams()) {
|
|
||||||
pidTuner.debugText(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
tunerState = pidTuner.getState();
|
|
||||||
}
|
|
||||||
|
|
||||||
return round(defaultTemp + pidTuner.getOutput());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the Equitherm Temp
|
* @brief Get the Equitherm Temp
|
||||||
* Calculations in degrees C, conversion occurs when using F
|
* Calculations in degrees C, conversion occurs when using F
|
||||||
@@ -294,8 +194,15 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vars.states.emergency) {
|
if (vars.states.emergency) {
|
||||||
|
if (settings.sensors.indoor.type == SensorType::MANUAL) {
|
||||||
etRegulator.Kt = 0;
|
etRegulator.Kt = 0;
|
||||||
etRegulator.indoorTemp = 0;
|
etRegulator.indoorTemp = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
etRegulator.Kt = settings.equitherm.t_factor;
|
||||||
|
etRegulator.indoorTemp = indoorTemp;
|
||||||
|
}
|
||||||
|
|
||||||
etRegulator.outdoorTemp = outdoorTemp;
|
etRegulator.outdoorTemp = outdoorTemp;
|
||||||
|
|
||||||
} else if (settings.pid.enable) {
|
} else if (settings.pid.enable) {
|
||||||
@@ -327,9 +234,23 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
float getPidTemp(int minTemp, int maxTemp) {
|
float getPidTemp(int minTemp, int maxTemp) {
|
||||||
|
if (fabs(pidRegulator.Kp - settings.pid.p_factor) >= 0.0001f) {
|
||||||
pidRegulator.Kp = settings.pid.p_factor;
|
pidRegulator.Kp = settings.pid.p_factor;
|
||||||
|
pidRegulator.integral = 0;
|
||||||
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fabs(pidRegulator.Ki - settings.pid.i_factor) >= 0.0001f) {
|
||||||
pidRegulator.Ki = settings.pid.i_factor;
|
pidRegulator.Ki = settings.pid.i_factor;
|
||||||
|
pidRegulator.integral = 0;
|
||||||
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fabs(pidRegulator.Kd - settings.pid.d_factor) >= 0.0001f) {
|
||||||
pidRegulator.Kd = settings.pid.d_factor;
|
pidRegulator.Kd = settings.pid.d_factor;
|
||||||
|
pidRegulator.integral = 0;
|
||||||
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
||||||
|
}
|
||||||
|
|
||||||
pidRegulator.setLimits(minTemp, maxTemp);
|
pidRegulator.setLimits(minTemp, maxTemp);
|
||||||
pidRegulator.setDt(settings.pid.dt * 1000u);
|
pidRegulator.setDt(settings.pid.dt * 1000u);
|
||||||
@@ -338,32 +259,4 @@ protected:
|
|||||||
|
|
||||||
return pidRegulator.getResultTimer();
|
return pidRegulator.getResultTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
float tuneEquithermN(float ratio, float currentTemp, float setTemp, unsigned int dirtyInterval = 60, unsigned int accurateInterval = 1800, float accurateStep = 0.01, float accurateStepAfter = 1) {
|
|
||||||
static uint32_t _prevIteration = millis();
|
|
||||||
|
|
||||||
if (abs(currentTemp - setTemp) < accurateStepAfter) {
|
|
||||||
if (millis() - _prevIteration < (accurateInterval * 1000)) {
|
|
||||||
return ratio;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentTemp - setTemp > 0.1f) {
|
|
||||||
ratio -= accurateStep;
|
|
||||||
|
|
||||||
} else if (currentTemp - setTemp < -0.1f) {
|
|
||||||
ratio += accurateStep;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (millis() - _prevIteration < (dirtyInterval * 1000)) {
|
|
||||||
return ratio;
|
|
||||||
}
|
|
||||||
|
|
||||||
ratio = ratio * (setTemp / currentTemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
_prevIteration = millis();
|
|
||||||
return ratio;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,38 +32,47 @@ protected:
|
|||||||
DallasTemperature* indoorSensor = nullptr;
|
DallasTemperature* indoorSensor = nullptr;
|
||||||
|
|
||||||
bool initOutdoorSensor = false;
|
bool initOutdoorSensor = false;
|
||||||
|
unsigned long initOutdoorSensorTime = 0;
|
||||||
unsigned long startOutdoorConversionTime = 0;
|
unsigned long startOutdoorConversionTime = 0;
|
||||||
float filteredOutdoorTemp = 0;
|
float filteredOutdoorTemp = 0;
|
||||||
bool emptyOutdoorTemp = true;
|
bool emptyOutdoorTemp = true;
|
||||||
|
|
||||||
bool initIndoorSensor = false;
|
bool initIndoorSensor = false;
|
||||||
|
unsigned long initIndoorSensorTime = 0;
|
||||||
unsigned long startIndoorConversionTime = 0;
|
unsigned long startIndoorConversionTime = 0;
|
||||||
float filteredIndoorTemp = 0;
|
float filteredIndoorTemp = 0;
|
||||||
bool emptyIndoorTemp = true;
|
bool emptyIndoorTemp = true;
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
#if USE_BLE
|
#if USE_BLE
|
||||||
BLEClient* pBleClient = nullptr;
|
BLEClient* pBleClient = nullptr;
|
||||||
bool initBleSensor = false;
|
bool initBleSensor = false;
|
||||||
bool initBleNotify = false;
|
bool initBleNotify = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* getTaskName() {
|
const char* getTaskName() override {
|
||||||
return "Sensors";
|
return "Sensors";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int getTaskCore() {
|
BaseType_t getTaskCore() override {
|
||||||
return 1;
|
// https://github.com/h2zero/NimBLE-Arduino/issues/676
|
||||||
}*/
|
#if USE_BLE && defined(CONFIG_BT_NIMBLE_PINNED_TO_CORE)
|
||||||
|
return CONFIG_BT_NIMBLE_PINNED_TO_CORE;
|
||||||
|
#else
|
||||||
|
return tskNO_AFFINITY;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
bool indoorTempUpdated = false;
|
bool indoorTempUpdated = false;
|
||||||
bool outdoorTempUpdated = false;
|
bool outdoorTempUpdated = false;
|
||||||
|
|
||||||
if (settings.sensors.outdoor.type == SensorType::DS18B20 && GPIO_IS_VALID(settings.sensors.indoor.gpio)) {
|
if (settings.sensors.outdoor.type == SensorType::DS18B20 && GPIO_IS_VALID(settings.sensors.outdoor.gpio)) {
|
||||||
outdoorTemperatureSensor();
|
outdoorTemperatureSensor();
|
||||||
outdoorTempUpdated = true;
|
outdoorTempUpdated = true;
|
||||||
}
|
}
|
||||||
@@ -88,7 +97,7 @@ protected:
|
|||||||
newTemp += c2f(this->filteredOutdoorTemp);
|
newTemp += c2f(this->filteredOutdoorTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fabs(vars.temperatures.outdoor - newTemp) > 0.099) {
|
if (fabs(vars.temperatures.outdoor - newTemp) > 0.099f) {
|
||||||
vars.temperatures.outdoor = newTemp;
|
vars.temperatures.outdoor = newTemp;
|
||||||
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("New temp: %f"), vars.temperatures.outdoor);
|
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("New temp: %f"), vars.temperatures.outdoor);
|
||||||
}
|
}
|
||||||
@@ -103,7 +112,7 @@ protected:
|
|||||||
newTemp += c2f(this->filteredIndoorTemp);
|
newTemp += c2f(this->filteredIndoorTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fabs(vars.temperatures.indoor - newTemp) > 0.099) {
|
if (fabs(vars.temperatures.indoor - newTemp) > 0.099f) {
|
||||||
vars.temperatures.indoor = newTemp;
|
vars.temperatures.indoor = newTemp;
|
||||||
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("New temp: %f"), vars.temperatures.indoor);
|
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("New temp: %f"), vars.temperatures.indoor);
|
||||||
}
|
}
|
||||||
@@ -161,7 +170,7 @@ protected:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float rawTemp = ((pData[0] | (pData[1] << 8)) * 0.01);
|
float rawTemp = ((pData[0] | (pData[1] << 8)) * 0.01f);
|
||||||
Log.straceln(FPSTR(L_SENSORS_INDOOR), F("Raw temp: %f"), rawTemp);
|
Log.straceln(FPSTR(L_SENSORS_INDOOR), F("Raw temp: %f"), rawTemp);
|
||||||
|
|
||||||
if (this->emptyIndoorTemp) {
|
if (this->emptyIndoorTemp) {
|
||||||
@@ -229,10 +238,16 @@ protected:
|
|||||||
|
|
||||||
void outdoorTemperatureSensor() {
|
void outdoorTemperatureSensor() {
|
||||||
if (!this->initOutdoorSensor) {
|
if (!this->initOutdoorSensor) {
|
||||||
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("Starting on gpio %hhu..."), settings.sensors.outdoor.gpio);
|
if (this->initOutdoorSensorTime && millis() - this->initOutdoorSensorTime < EXT_SENSORS_INTERVAL * 10) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("Starting on GPIO %hhu..."), settings.sensors.outdoor.gpio);
|
||||||
|
|
||||||
this->oneWireOutdoorSensor->begin(settings.sensors.outdoor.gpio);
|
this->oneWireOutdoorSensor->begin(settings.sensors.outdoor.gpio);
|
||||||
|
this->oneWireOutdoorSensor->reset();
|
||||||
this->outdoorSensor->begin();
|
this->outdoorSensor->begin();
|
||||||
|
this->initOutdoorSensorTime = millis();
|
||||||
|
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_OUTDOOR),
|
FPSTR(L_SENSORS_OUTDOOR),
|
||||||
@@ -295,10 +310,16 @@ protected:
|
|||||||
|
|
||||||
void indoorTemperatureSensor() {
|
void indoorTemperatureSensor() {
|
||||||
if (!this->initIndoorSensor) {
|
if (!this->initIndoorSensor) {
|
||||||
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("Starting on gpio %hhu..."), settings.sensors.indoor.gpio);
|
if (this->initIndoorSensorTime && millis() - this->initIndoorSensorTime < EXT_SENSORS_INTERVAL * 10) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("Starting on GPIO %hhu..."), settings.sensors.indoor.gpio);
|
||||||
|
|
||||||
this->oneWireIndoorSensor->begin(settings.sensors.indoor.gpio);
|
this->oneWireIndoorSensor->begin(settings.sensors.indoor.gpio);
|
||||||
|
this->oneWireIndoorSensor->reset();
|
||||||
this->indoorSensor->begin();
|
this->indoorSensor->begin();
|
||||||
|
this->initIndoorSensorTime = millis();
|
||||||
|
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_INDOOR),
|
FPSTR(L_SENSORS_INDOOR),
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ struct Settings {
|
|||||||
} telnet;
|
} telnet;
|
||||||
|
|
||||||
UnitSystem unitSystem = UnitSystem::METRIC;
|
UnitSystem unitSystem = UnitSystem::METRIC;
|
||||||
|
byte statusLedGpio = DEFAULT_STATUS_LED_GPIO;
|
||||||
} system;
|
} system;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -49,6 +50,9 @@ struct Settings {
|
|||||||
UnitSystem unitSystem = UnitSystem::METRIC;
|
UnitSystem unitSystem = UnitSystem::METRIC;
|
||||||
byte inGpio = DEFAULT_OT_IN_GPIO;
|
byte inGpio = DEFAULT_OT_IN_GPIO;
|
||||||
byte outGpio = DEFAULT_OT_OUT_GPIO;
|
byte outGpio = DEFAULT_OT_OUT_GPIO;
|
||||||
|
byte rxLedGpio = DEFAULT_OT_RX_LED_GPIO;
|
||||||
|
byte faultStateGpio = DEFAULT_OT_FAULT_STATE_GPIO;
|
||||||
|
byte invertFaultState = false;
|
||||||
unsigned int memberIdCode = 0;
|
unsigned int memberIdCode = 0;
|
||||||
bool dhwPresent = true;
|
bool dhwPresent = true;
|
||||||
bool summerWinterMode = false;
|
bool summerWinterMode = false;
|
||||||
@@ -58,6 +62,7 @@ struct Settings {
|
|||||||
bool dhwBlocking = false;
|
bool dhwBlocking = false;
|
||||||
bool modulationSyncWithHeating = false;
|
bool modulationSyncWithHeating = false;
|
||||||
bool getMinMaxTemp = true;
|
bool getMinMaxTemp = true;
|
||||||
|
bool nativeHeatingControl = false;
|
||||||
} opentherm;
|
} opentherm;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -68,11 +73,13 @@ struct Settings {
|
|||||||
char password[33] = DEFAULT_MQTT_PASSWORD;
|
char password[33] = DEFAULT_MQTT_PASSWORD;
|
||||||
char prefix[33] = DEFAULT_MQTT_PREFIX;
|
char prefix[33] = DEFAULT_MQTT_PREFIX;
|
||||||
unsigned short interval = 5;
|
unsigned short interval = 5;
|
||||||
|
bool homeAssistantDiscovery = true;
|
||||||
} mqtt;
|
} mqtt;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enable = true;
|
bool enable = true;
|
||||||
float target = 40.0f;
|
float target = DEFAULT_HEATING_TARGET_TEMP;
|
||||||
|
unsigned short tresholdTime = 120;
|
||||||
bool useEquitherm = false;
|
bool useEquitherm = false;
|
||||||
bool usePid = false;
|
bool usePid = false;
|
||||||
bool onNetworkFault = true;
|
bool onNetworkFault = true;
|
||||||
@@ -82,7 +89,7 @@ struct Settings {
|
|||||||
struct {
|
struct {
|
||||||
bool enable = true;
|
bool enable = true;
|
||||||
bool turbo = false;
|
bool turbo = false;
|
||||||
float target = 40.0f;
|
float target = DEFAULT_HEATING_TARGET_TEMP;
|
||||||
float hysteresis = 0.5f;
|
float hysteresis = 0.5f;
|
||||||
byte minTemp = DEFAULT_HEATING_MIN_TEMP;
|
byte minTemp = DEFAULT_HEATING_MIN_TEMP;
|
||||||
byte maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
byte maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
||||||
@@ -91,16 +98,16 @@ struct Settings {
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enable = true;
|
bool enable = true;
|
||||||
byte target = 40;
|
float target = DEFAULT_DHW_TARGET_TEMP;
|
||||||
byte minTemp = DEFAULT_DHW_MIN_TEMP;
|
byte minTemp = DEFAULT_DHW_MIN_TEMP;
|
||||||
byte maxTemp = DEFAULT_DHW_MAX_TEMP;
|
byte maxTemp = DEFAULT_DHW_MAX_TEMP;
|
||||||
} dhw;
|
} dhw;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enable = false;
|
bool enable = false;
|
||||||
float p_factor = 50;
|
float p_factor = 2;
|
||||||
float i_factor = 0.006f;
|
float i_factor = 0.0055f;
|
||||||
float d_factor = 10000;
|
float d_factor = 0;
|
||||||
unsigned short dt = 180;
|
unsigned short dt = 180;
|
||||||
byte minTemp = 0;
|
byte minTemp = 0;
|
||||||
byte maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
byte maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
||||||
@@ -140,11 +147,6 @@ struct Settings {
|
|||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
struct Variables {
|
struct Variables {
|
||||||
struct {
|
|
||||||
bool enable = false;
|
|
||||||
byte regulator = 0;
|
|
||||||
} tuning;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool otStatus = false;
|
bool otStatus = false;
|
||||||
bool emergency = false;
|
bool emergency = false;
|
||||||
@@ -178,7 +180,7 @@ struct Variables {
|
|||||||
bool heatingEnabled = false;
|
bool heatingEnabled = false;
|
||||||
byte heatingMinTemp = DEFAULT_HEATING_MIN_TEMP;
|
byte heatingMinTemp = DEFAULT_HEATING_MIN_TEMP;
|
||||||
byte heatingMaxTemp = DEFAULT_HEATING_MAX_TEMP;
|
byte heatingMaxTemp = DEFAULT_HEATING_MAX_TEMP;
|
||||||
byte heatingSetpoint = 0;
|
float heatingSetpoint = 0;
|
||||||
unsigned long extPumpLastEnableTime = 0;
|
unsigned long extPumpLastEnableTime = 0;
|
||||||
byte dhwMinTemp = DEFAULT_DHW_MIN_TEMP;
|
byte dhwMinTemp = DEFAULT_DHW_MIN_TEMP;
|
||||||
byte dhwMaxTemp = DEFAULT_DHW_MAX_TEMP;
|
byte dhwMaxTemp = DEFAULT_DHW_MAX_TEMP;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#define PROJECT_NAME "OpenTherm Gateway"
|
#define PROJECT_NAME "OpenTherm Gateway"
|
||||||
#define PROJECT_VERSION "1.4.0-rc.21"
|
#define PROJECT_VERSION "1.4.1"
|
||||||
#define PROJECT_REPO "https://github.com/Laxilef/OTGateway"
|
#define PROJECT_REPO "https://github.com/Laxilef/OTGateway"
|
||||||
|
|
||||||
#define EMERGENCY_TIME_TRESHOLD 120000
|
|
||||||
#define MQTT_RECONNECT_INTERVAL 15000
|
#define MQTT_RECONNECT_INTERVAL 15000
|
||||||
|
|
||||||
#define EXT_SENSORS_INTERVAL 5000
|
#define EXT_SENSORS_INTERVAL 5000
|
||||||
@@ -10,13 +9,20 @@
|
|||||||
|
|
||||||
#define CONFIG_URL "http://%s/"
|
#define CONFIG_URL "http://%s/"
|
||||||
#define SETTINGS_VALID_VALUE "stvalid" // only 8 chars!
|
#define SETTINGS_VALID_VALUE "stvalid" // only 8 chars!
|
||||||
|
|
||||||
#define GPIO_IS_NOT_CONFIGURED 0xff
|
#define GPIO_IS_NOT_CONFIGURED 0xff
|
||||||
|
|
||||||
|
#define DEFAULT_HEATING_TARGET_TEMP 40
|
||||||
#define DEFAULT_HEATING_MIN_TEMP 20
|
#define DEFAULT_HEATING_MIN_TEMP 20
|
||||||
#define DEFAULT_HEATING_MAX_TEMP 90
|
#define DEFAULT_HEATING_MAX_TEMP 90
|
||||||
|
|
||||||
|
#define DEFAULT_DHW_TARGET_TEMP 40
|
||||||
#define DEFAULT_DHW_MIN_TEMP 30
|
#define DEFAULT_DHW_MIN_TEMP 30
|
||||||
#define DEFAULT_DHW_MAX_TEMP 60
|
#define DEFAULT_DHW_MAX_TEMP 60
|
||||||
|
|
||||||
|
#define THERMOSTAT_INDOOR_DEFAULT_TEMP 20
|
||||||
|
#define THERMOSTAT_INDOOR_MIN_TEMP 5
|
||||||
|
#define THERMOSTAT_INDOOR_MAX_TEMP 30
|
||||||
|
|
||||||
#ifndef USE_SERIAL
|
#ifndef USE_SERIAL
|
||||||
#define USE_SERIAL true
|
#define USE_SERIAL true
|
||||||
#endif
|
#endif
|
||||||
@@ -53,6 +59,10 @@
|
|||||||
#define DEBUG_BY_DEFAULT false
|
#define DEBUG_BY_DEFAULT false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEFAULT_STATUS_LED_GPIO
|
||||||
|
#define DEFAULT_STATUS_LED_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef DEFAULT_PORTAL_LOGIN
|
#ifndef DEFAULT_PORTAL_LOGIN
|
||||||
#define DEFAULT_PORTAL_LOGIN ""
|
#define DEFAULT_PORTAL_LOGIN ""
|
||||||
#endif
|
#endif
|
||||||
@@ -89,6 +99,14 @@
|
|||||||
#define DEFAULT_OT_OUT_GPIO GPIO_IS_NOT_CONFIGURED
|
#define DEFAULT_OT_OUT_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEFAULT_OT_RX_LED_GPIO
|
||||||
|
#define DEFAULT_OT_RX_LED_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEFAULT_OT_FAULT_STATE_GPIO
|
||||||
|
#define DEFAULT_OT_FAULT_STATE_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef DEFAULT_SENSOR_OUTDOOR_GPIO
|
#ifndef DEFAULT_SENSOR_OUTDOOR_GPIO
|
||||||
#define DEFAULT_SENSOR_OUTDOOR_GPIO GPIO_IS_NOT_CONFIGURED
|
#define DEFAULT_SENSOR_OUTDOOR_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
#endif
|
#endif
|
||||||
@@ -105,7 +123,9 @@
|
|||||||
#define PROGMEM
|
#define PROGMEM
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef GPIO_IS_VALID_GPIO
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
#include <driver/gpio.h>
|
||||||
|
#elif !defined(GPIO_IS_VALID_GPIO)
|
||||||
#define GPIO_IS_VALID_GPIO(gpioNum) (gpioNum >= 0 && gpioNum <= 16)
|
#define GPIO_IS_VALID_GPIO(gpioNum) (gpioNum >= 0 && gpioNum <= 16)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
23
src/main.cpp
23
src/main.cpp
@@ -4,11 +4,11 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <FileData.h>
|
#include <FileData.h>
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
#include "ESPTelnetStream.h"
|
#include <ESPTelnetStream.h>
|
||||||
#include <TinyLogger.h>
|
#include <TinyLogger.h>
|
||||||
#include <NetworkManager.h>
|
#include <NetworkMgr.h>
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include <utils.h>
|
#include "utils.h"
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
#include <ESP32Scheduler.h>
|
#include <ESP32Scheduler.h>
|
||||||
@@ -27,11 +27,13 @@
|
|||||||
#include "PortalTask.h"
|
#include "PortalTask.h"
|
||||||
#include "MainTask.h"
|
#include "MainTask.h"
|
||||||
|
|
||||||
|
using namespace NetworkUtils;
|
||||||
|
|
||||||
// Vars
|
// Vars
|
||||||
FileData fsNetworkSettings(&LittleFS, "/network.conf", 'n', &networkSettings, sizeof(networkSettings), 1000);
|
FileData fsNetworkSettings(&LittleFS, "/network.conf", 'n', &networkSettings, sizeof(networkSettings), 1000);
|
||||||
FileData fsSettings(&LittleFS, "/settings.conf", 's', &settings, sizeof(settings), 60000);
|
FileData fsSettings(&LittleFS, "/settings.conf", 's', &settings, sizeof(settings), 60000);
|
||||||
ESPTelnetStream* telnetStream = nullptr;
|
ESPTelnetStream* telnetStream = nullptr;
|
||||||
Network::Manager* network = nullptr;
|
NetworkMgr* network = nullptr;
|
||||||
|
|
||||||
// Tasks
|
// Tasks
|
||||||
MqttTask* tMqtt;
|
MqttTask* tMqtt;
|
||||||
@@ -59,7 +61,7 @@ void setup() {
|
|||||||
return tm{sec, min, hour};
|
return tm{sec, min, hour};
|
||||||
});
|
});
|
||||||
|
|
||||||
Serial.begin(settings.system.serial.baudrate);
|
Serial.begin(115200);
|
||||||
Log.addStream(&Serial);
|
Log.addStream(&Serial);
|
||||||
Log.print("\n\n\r");
|
Log.print("\n\n\r");
|
||||||
|
|
||||||
@@ -110,8 +112,15 @@ void setup() {
|
|||||||
|
|
||||||
// logs
|
// logs
|
||||||
if (!settings.system.serial.enable) {
|
if (!settings.system.serial.enable) {
|
||||||
Log.clearStreams();
|
|
||||||
Serial.end();
|
Serial.end();
|
||||||
|
Log.clearStreams();
|
||||||
|
|
||||||
|
} else if (settings.system.serial.baudrate != 115200) {
|
||||||
|
Serial.end();
|
||||||
|
Log.clearStreams();
|
||||||
|
|
||||||
|
Serial.begin(settings.system.serial.baudrate);
|
||||||
|
Log.addStream(&Serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.system.telnet.enable) {
|
if (settings.system.telnet.enable) {
|
||||||
@@ -123,7 +132,7 @@ void setup() {
|
|||||||
Log.setLevel(settings.system.debug ? TinyLogger::Level::VERBOSE : TinyLogger::Level::INFO);
|
Log.setLevel(settings.system.debug ? TinyLogger::Level::VERBOSE : TinyLogger::Level::INFO);
|
||||||
|
|
||||||
// network
|
// network
|
||||||
network = (new Network::Manager)
|
network = (new NetworkMgr)
|
||||||
->setHostname(networkSettings.hostname)
|
->setHostname(networkSettings.hostname)
|
||||||
->setStaCredentials(
|
->setStaCredentials(
|
||||||
#ifdef WOKWI
|
#ifdef WOKWI
|
||||||
|
|||||||
560
src/utils.h
560
src/utils.h
File diff suppressed because it is too large
Load Diff
@@ -38,8 +38,8 @@
|
|||||||
<div class="thermostat-temp-target"><span id="thermostat-heating-target"></span> <span class="temp-unit"></span></div>
|
<div class="thermostat-temp-target"><span id="thermostat-heating-target"></span> <span class="temp-unit"></span></div>
|
||||||
<div class="thermostat-temp-current">Current: <span id="thermostat-heating-current"></span> <span class="temp-unit"></span></div>
|
<div class="thermostat-temp-current">Current: <span id="thermostat-heating-current"></span> <span class="temp-unit"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="thermostat-minus"><button id="thermostat-heating-minus" class="outline"><b>-</b></button></div>
|
<div class="thermostat-minus"><button id="thermostat-heating-minus" class="outline"><i class="icons-down"></i></button></div>
|
||||||
<div class="thermostat-plus"><button id="thermostat-heating-plus" class="outline"><b>+</b></button></div>
|
<div class="thermostat-plus"><button id="thermostat-heating-plus" class="outline"><i class="icons-up"></i></button></div>
|
||||||
<div class="thermostat-control">
|
<div class="thermostat-control">
|
||||||
<input type="checkbox" role="switch" id="thermostat-heating-enabled" value="true">
|
<input type="checkbox" role="switch" id="thermostat-heating-enabled" value="true">
|
||||||
<label htmlFor="thermostat-heating-enabled">Enable</label>
|
<label htmlFor="thermostat-heating-enabled">Enable</label>
|
||||||
@@ -55,8 +55,8 @@
|
|||||||
<div class="thermostat-temp-target"><span id="thermostat-dhw-target"></span> <span class="temp-unit"></span></div>
|
<div class="thermostat-temp-target"><span id="thermostat-dhw-target"></span> <span class="temp-unit"></span></div>
|
||||||
<div class="thermostat-temp-current">Current: <span id="thermostat-dhw-current"></span> <span class="temp-unit"></span></div>
|
<div class="thermostat-temp-current">Current: <span id="thermostat-dhw-current"></span> <span class="temp-unit"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="thermostat-minus"><button class="outline" id="thermostat-dhw-minus"><b>-</b></button></div>
|
<div class="thermostat-minus"><button class="outline" id="thermostat-dhw-minus"><i class="icons-down"></i></button></div>
|
||||||
<div class="thermostat-plus"><button class="outline" id="thermostat-dhw-plus"><b>+</b></button></div>
|
<div class="thermostat-plus"><button class="outline" id="thermostat-dhw-plus"><i class="icons-up"></i></button></div>
|
||||||
<div class="thermostat-control">
|
<div class="thermostat-control">
|
||||||
<input type="checkbox" role="switch" id="thermostat-dhw-enabled" value="true">
|
<input type="checkbox" role="switch" id="thermostat-dhw-enabled" value="true">
|
||||||
<label htmlFor="thermostat-dhw-enabled">Enable</label>
|
<label htmlFor="thermostat-dhw-enabled">Enable</label>
|
||||||
@@ -202,10 +202,20 @@
|
|||||||
|
|
||||||
window.onload = async function () {
|
window.onload = async function () {
|
||||||
document.querySelector('#thermostat-heating-minus').addEventListener('click', (event) => {
|
document.querySelector('#thermostat-heating-minus').addEventListener('click', (event) => {
|
||||||
|
if (!prevSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
newSettings.heating.target -= 0.5;
|
newSettings.heating.target -= 0.5;
|
||||||
modifiedTime = Date.now();
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
const minTemp = noRegulators ? prevSettings.heating.minTemp : 5;
|
let minTemp;
|
||||||
|
if (noRegulators) {
|
||||||
|
minTemp = prevSettings.heating.minTemp;
|
||||||
|
} else {
|
||||||
|
minTemp = prevSettings.system.unitSystem == 0 ? 5 : 41;
|
||||||
|
}
|
||||||
|
|
||||||
if (prevSettings && newSettings.heating.target < minTemp) {
|
if (prevSettings && newSettings.heating.target < minTemp) {
|
||||||
newSettings.heating.target = minTemp;
|
newSettings.heating.target = minTemp;
|
||||||
}
|
}
|
||||||
@@ -214,10 +224,20 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('#thermostat-heating-plus').addEventListener('click', (event) => {
|
document.querySelector('#thermostat-heating-plus').addEventListener('click', (event) => {
|
||||||
|
if (!prevSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
newSettings.heating.target += 0.5;
|
newSettings.heating.target += 0.5;
|
||||||
modifiedTime = Date.now();
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
const maxTemp = noRegulators ? prevSettings.heating.maxTemp : 30;
|
let maxTemp;
|
||||||
|
if (noRegulators) {
|
||||||
|
maxTemp = prevSettings.heating.maxTemp;
|
||||||
|
} else {
|
||||||
|
maxTemp = prevSettings.system.unitSystem == 0 ? 30 : 86;
|
||||||
|
}
|
||||||
|
|
||||||
if (prevSettings && newSettings.heating.target > maxTemp) {
|
if (prevSettings && newSettings.heating.target > maxTemp) {
|
||||||
newSettings.heating.target = maxTemp;
|
newSettings.heating.target = maxTemp;
|
||||||
}
|
}
|
||||||
@@ -226,10 +246,14 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('#thermostat-dhw-minus').addEventListener('click', (event) => {
|
document.querySelector('#thermostat-dhw-minus').addEventListener('click', (event) => {
|
||||||
newSettings.dhw.target -= 1;
|
if (!prevSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newSettings.dhw.target -= 1.0;
|
||||||
modifiedTime = Date.now();
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
if (prevSettings && newSettings.dhw.target < prevSettings.dhw.minTemp) {
|
if (newSettings.dhw.target < prevSettings.dhw.minTemp) {
|
||||||
newSettings.dhw.target = prevSettings.dhw.minTemp;
|
newSettings.dhw.target = prevSettings.dhw.minTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,10 +261,14 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('#thermostat-dhw-plus').addEventListener('click', (event) => {
|
document.querySelector('#thermostat-dhw-plus').addEventListener('click', (event) => {
|
||||||
newSettings.dhw.target += 1;
|
if (!prevSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newSettings.dhw.target += 1.0;
|
||||||
modifiedTime = Date.now();
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
if (prevSettings && newSettings.dhw.target > prevSettings.dhw.maxTemp) {
|
if (newSettings.dhw.target > prevSettings.dhw.maxTemp) {
|
||||||
newSettings.dhw.target = prevSettings.dhw.maxTemp;
|
newSettings.dhw.target = prevSettings.dhw.maxTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +287,7 @@
|
|||||||
|
|
||||||
document.querySelector('#thermostat-dhw-enabled').addEventListener('change', (event) => {
|
document.querySelector('#thermostat-dhw-enabled').addEventListener('change', (event) => {
|
||||||
modifiedTime = Date.now();
|
modifiedTime = Date.now();
|
||||||
newSettings.heating.dhw = event.currentTarget.checked;
|
newSettings.dhw.enable = event.currentTarget.checked;
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(async function onLoadPage() {
|
setTimeout(async function onLoadPage() {
|
||||||
@@ -298,7 +326,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
noRegulators = !result.equitherm.enable && !result.pid.enable;
|
noRegulators = !result.opentherm.nativeHeatingControl && !result.equitherm.enable && !result.pid.enable;
|
||||||
prevSettings = result;
|
prevSettings = result;
|
||||||
newSettings.heating.enable = result.heating.enable;
|
newSettings.heating.enable = result.heating.enable;
|
||||||
newSettings.heating.turbo = result.heating.turbo;
|
newSettings.heating.turbo = result.heating.turbo;
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Version:</th>
|
<th scope="row">Version:</th>
|
||||||
<td><b id="version"></b></td>
|
<td><b id="version"></b>, core/sdk: <b id="core-version"></b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Build date:</th>
|
<th scope="row">Build date:</th>
|
||||||
@@ -101,6 +101,10 @@
|
|||||||
<th scope="row">Free memory:</th>
|
<th scope="row">Free memory:</th>
|
||||||
<td><b id="free-heap"></b> of <b id="total-heap"></b> bytes (min: <b id="min-free-heap"></b> bytes)<br />max free block: <b id="max-free-block-heap"></b> bytes (min: <b id="min-max-free-block-heap"></b> bytes)</td>
|
<td><b id="free-heap"></b> of <b id="total-heap"></b> bytes (min: <b id="min-free-heap"></b> bytes)<br />max free block: <b id="max-free-block-heap"></b> bytes (min: <b id="min-max-free-block-heap"></b> bytes)</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Board:</th>
|
||||||
|
<td>Chip <b id="chip-model"></b> (rev. <span id="chip-revision"></span>)<br />Cores: <b id="chip-cores"></b>, frequency: <b id="cpu-freq"></b> mHz<br />Flash size: <b id="flash-size"></b> MB (real: <b id="flash-real-size"></b> MB)</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Last reset reason:</th>
|
<th scope="row">Last reset reason:</th>
|
||||||
<td><b id="reset-reason"></b></td>
|
<td><b id="reset-reason"></b></td>
|
||||||
@@ -164,6 +168,15 @@
|
|||||||
setValue('#max-free-block-heap', result.system.maxFreeBlockHeap);
|
setValue('#max-free-block-heap', result.system.maxFreeBlockHeap);
|
||||||
setValue('#min-max-free-block-heap', result.system.minMaxFreeBlockHeap);
|
setValue('#min-max-free-block-heap', result.system.minMaxFreeBlockHeap);
|
||||||
setValue('#reset-reason', result.system.resetReason);
|
setValue('#reset-reason', result.system.resetReason);
|
||||||
|
|
||||||
|
setValue('#chip-model', result.system.chipModel);
|
||||||
|
setValue('#chip-revision', result.system.chipRevision);
|
||||||
|
setValue('#chip-cores', result.system.chipCores);
|
||||||
|
setValue('#cpu-freq', result.system.cpuFreq);
|
||||||
|
setValue('#core-version', result.system.coreVersion);
|
||||||
|
setValue('#flash-size', result.system.flashSize / 1024 / 1024);
|
||||||
|
setValue('#flash-real-size', result.system.flashRealSize / 1024 / 1024);
|
||||||
|
|
||||||
setBusy('#system-busy', '#system-table', false);
|
setBusy('#system-busy', '#system-table', false);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -76,18 +76,18 @@
|
|||||||
</hgroup>
|
</hgroup>
|
||||||
|
|
||||||
<form action="/api/network/scan" id="network-scan">
|
<form action="/api/network/scan" id="network-scan">
|
||||||
<figure style="max-height: 25em;">
|
<div style="max-height: 25rem;" class="overflow-auto">
|
||||||
<table id="networks" role="grid">
|
<table id="networks" role="grid">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">#</th>
|
<th scope="col">#</th>
|
||||||
<th scope="col">SSID</th>
|
<th scope="col">SSID</th>
|
||||||
<th scope="col">Signal</th>
|
<th scope="col">Info</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
</table>
|
</table>
|
||||||
</figure>
|
</div>
|
||||||
|
|
||||||
<button type="submit">Refresh</button>
|
<button type="submit">Refresh</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -167,6 +167,26 @@
|
|||||||
<script src="/static/app.js"></script>
|
<script src="/static/app.js"></script>
|
||||||
<script>
|
<script>
|
||||||
window.onload = async function () {
|
window.onload = async function () {
|
||||||
|
const fillData = (data) => {
|
||||||
|
setInputValue('#network-hostname', data.hostname);
|
||||||
|
setCheckboxValue('#network-use-dhcp', data.useDhcp);
|
||||||
|
setInputValue('#network-static-ip', data.staticConfig.ip);
|
||||||
|
setInputValue('#network-static-gateway', data.staticConfig.gateway);
|
||||||
|
setInputValue('#network-static-subnet', data.staticConfig.subnet);
|
||||||
|
setInputValue('#network-static-dns', data.staticConfig.dns);
|
||||||
|
setBusy('#network-settings-busy', '#network-settings', false);
|
||||||
|
|
||||||
|
setInputValue('#sta-ssid', data.sta.ssid);
|
||||||
|
setInputValue('#sta-password', data.sta.password);
|
||||||
|
setInputValue('#sta-channel', data.sta.channel);
|
||||||
|
setBusy('#sta-settings-busy', '#sta-settings', false);
|
||||||
|
|
||||||
|
setInputValue('#ap-ssid', data.ap.ssid);
|
||||||
|
setInputValue('#ap-password', data.ap.password);
|
||||||
|
setInputValue('#ap-channel', data.ap.channel);
|
||||||
|
setBusy('#ap-settings-busy', '#ap-settings', false);
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/network/settings', { cache: 'no-cache' });
|
const response = await fetch('/api/network/settings', { cache: 'no-cache' });
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -174,32 +194,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
setInputValue('#network-hostname', result.hostname);
|
fillData(result);
|
||||||
setCheckboxValue('#network-use-dhcp', result.useDhcp);
|
|
||||||
setInputValue('#network-static-ip', result.staticConfig.ip);
|
|
||||||
setInputValue('#network-static-gateway', result.staticConfig.gateway);
|
|
||||||
setInputValue('#network-static-subnet', result.staticConfig.subnet);
|
|
||||||
setInputValue('#network-static-dns', result.staticConfig.dns);
|
|
||||||
setBusy('#network-settings-busy', '#network-settings', false);
|
|
||||||
|
|
||||||
setInputValue('#sta-ssid', result.sta.ssid);
|
setupForm('#network-settings', fillData, ['hostname']);
|
||||||
setInputValue('#sta-password', result.sta.password);
|
setupNetworkScanForm('#network-scan', '#networks');
|
||||||
setInputValue('#sta-channel', result.sta.channel);
|
setupForm('#sta-settings', fillData, ['sta.ssid', 'sta.password']);
|
||||||
setBusy('#sta-settings-busy', '#sta-settings', false);
|
setupForm('#ap-settings', fillData, ['ap.ssid', 'ap.password']);
|
||||||
|
|
||||||
setInputValue('#ap-ssid', result.ap.ssid);
|
|
||||||
setInputValue('#ap-password', result.ap.password);
|
|
||||||
setInputValue('#ap-channel', result.ap.channel);
|
|
||||||
setBusy('#ap-settings-busy', '#ap-settings', false);
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
setupForm('#network-settings');
|
|
||||||
setupNetworkScanForm('#network-scan', '#networks');
|
|
||||||
setupForm('#sta-settings');
|
|
||||||
setupForm('#ap-settings');
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
@@ -67,53 +67,56 @@
|
|||||||
<legend>Unit system</legend>
|
<legend>Unit system</legend>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" id="system-unit-system" name="system[unitSystem]" value="0" />
|
<input type="radio" class="system-unit-system" name="system[unitSystem]" value="0" />
|
||||||
Metric (celsius, liters, bar)
|
Metric (celsius, liters, bar)
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" id="system-unit-system" name="system[unitSystem]" value="1" />
|
<input type="radio" class="system-unit-system" name="system[unitSystem]" value="1" />
|
||||||
Imperial (fahrenheit, gallons, psi)
|
Imperial (fahrenheit, gallons, psi)
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Serial</legend>
|
<label for="system-status-led-gpio">
|
||||||
|
Status LED GPIO
|
||||||
<label for="system-serial-enable">
|
<input type="number" inputmode="numeric" id="system-status-led-gpio" name="system[statusLedGpio]" min="0" max="254" step="1">
|
||||||
<input type="checkbox" id="system-serial-enable" name="system[serial][enable]" value="true">
|
<small>blank - not use</small>
|
||||||
Enable
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label for="system-serial-baudrate">
|
|
||||||
Baud rate
|
|
||||||
<input type="number" inputmode="numeric" id="system-serial-baudrate" name="system[serial][baudrate]" min="9600" max="115200" step="1" required>
|
|
||||||
<small>(Available: 9600, 19200, 38400, 57600, 74880, 115200)</small>
|
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Telnet</legend>
|
<legend>Diagnostic</legend>
|
||||||
|
|
||||||
<label for="system-telnet-enable">
|
|
||||||
<input type="checkbox" id="system-telnet-enable" name="system[telnet][enable]" value="true">
|
|
||||||
Enable
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label for="system-telnet-port">
|
|
||||||
Port
|
|
||||||
<input type="number" inputmode="numeric" id="system-telnet-port" name="system[telnet][port]" min="1" max="65535" step="1" required>
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<label for="system-debug">
|
<label for="system-debug">
|
||||||
<input type="checkbox" id="system-debug" name="system[debug]" value="true">
|
<input type="checkbox" id="system-debug" name="system[debug]" value="true">
|
||||||
Debug mode
|
Debug mode
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
<label for="system-serial-enable">
|
||||||
|
<input type="checkbox" id="system-serial-enable" name="system[serial][enable]" value="true">
|
||||||
|
Enable Serial port
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="system-telnet-enable">
|
||||||
|
<input type="checkbox" id="system-telnet-enable" name="system[telnet][enable]" value="true">
|
||||||
|
Enable Telnet
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="system-serial-baudrate">
|
||||||
|
Serial port baud rate
|
||||||
|
<input type="number" inputmode="numeric" id="system-serial-baudrate" name="system[serial][baudrate]" min="9600" max="115200" step="1" required>
|
||||||
|
<small>Available: 9600, 19200, 38400, 57600, 74880, 115200</small>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="system-telnet-port">
|
||||||
|
Telnet port
|
||||||
|
<input type="number" inputmode="numeric" id="system-telnet-port" name="system[telnet][port]" min="1" max="65535" step="1" required>
|
||||||
|
<small>Default: 23</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<mark>After changing this settings, the ESP must be restarted for the changes to take effect.</mark>
|
<mark>After changing this settings, the ESP must be restarted for the changes to take effect.</mark>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
@@ -195,9 +198,13 @@
|
|||||||
<input type="checkbox" id="emergency-enable" name="emergency[enable]" value="true">
|
<input type="checkbox" id="emergency-enable" name="emergency[enable]" value="true">
|
||||||
Enable
|
Enable
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<small>
|
||||||
|
<b>!</b> Emergency mode can be useful <u>only</u> when using Equitherm and/or PID (when normal work) and when reporting indoor/outdoor temperature via MQTT or API. In this mode, sensor values that are reported via MQTT/API are not used.
|
||||||
|
</small>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<div class="grid">
|
||||||
<label for="emergency-target">
|
<label for="emergency-target">
|
||||||
Target temperature
|
Target temperature
|
||||||
<input type="number" inputmode="numeric" id="emergency-target" name="emergency[target]" min="0" max="0" step="1" required>
|
<input type="number" inputmode="numeric" id="emergency-target" name="emergency[target]" min="0" max="0" step="1" required>
|
||||||
@@ -206,7 +213,12 @@
|
|||||||
<u>Heat carrier temperature</u> if Equitherm and PID <b>is disabled</b>
|
<u>Heat carrier temperature</u> if Equitherm and PID <b>is disabled</b>
|
||||||
</small>
|
</small>
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
|
||||||
|
<label for="emergency-treshold-time">
|
||||||
|
Treshold time <small>(sec)</small>
|
||||||
|
<input type="number" inputmode="numeric" id="emergency-treshold-time" name="emergency[tresholdTime]" min="60" max="1800" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Events</legend>
|
<legend>Events</legend>
|
||||||
@@ -223,15 +235,19 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Regulators</legend>
|
<legend>Using regulators</legend>
|
||||||
|
|
||||||
<label for="emergency-use-equitherm">
|
<label for="emergency-use-equitherm">
|
||||||
<input type="checkbox" id="emergency-use-equitherm" name="emergency[useEquitherm]" value="true">
|
<input type="checkbox" id="emergency-use-equitherm" name="emergency[useEquitherm]" value="true">
|
||||||
Use Equitherm
|
<span>
|
||||||
|
Equitherm <small>(requires at least an external/boiler <u>outdoor</u> sensor)</small>
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<label for="emergency-use-pid">
|
<label for="emergency-use-pid">
|
||||||
<input type="checkbox" id="emergency-use-pid" name="emergency[usePid]" value="true">
|
<input type="checkbox" id="emergency-use-pid" name="emergency[usePid]" value="true">
|
||||||
Use PID
|
<span>
|
||||||
|
PID <small>(requires at least an external/BLE <u>indoor</u> sensor)</small>
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
@@ -299,7 +315,7 @@
|
|||||||
|
|
||||||
<label for="pid-i-factor">
|
<label for="pid-i-factor">
|
||||||
I factor
|
I factor
|
||||||
<input type="number" inputmode="numeric" id="pid-i-factor" name="pid[i_factor]" min="0" max="100" step="0.001" required>
|
<input type="number" inputmode="numeric" id="pid-i-factor" name="pid[i_factor]" min="0" max="100" step="0.0001" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="pid-d-factor">
|
<label for="pid-d-factor">
|
||||||
@@ -343,12 +359,12 @@
|
|||||||
<legend>Unit system</legend>
|
<legend>Unit system</legend>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" id="opentherm-unit-system" name="opentherm[unitSystem]" value="0" />
|
<input type="radio" class="opentherm-unit-system" name="opentherm[unitSystem]" value="0" />
|
||||||
Metric (celsius)
|
Metric (celsius)
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" id="opentherm-unit-system" name="opentherm[unitSystem]" value="1" />
|
<input type="radio" class="opentherm-unit-system" name="opentherm[unitSystem]" value="1" />
|
||||||
Imperial (fahrenheit)
|
Imperial (fahrenheit)
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -363,6 +379,14 @@
|
|||||||
Out GPIO
|
Out GPIO
|
||||||
<input type="number" inputmode="numeric" id="opentherm-out-gpio" name="opentherm[outGpio]" min="0" max="254" step="1">
|
<input type="number" inputmode="numeric" id="opentherm-out-gpio" name="opentherm[outGpio]" min="0" max="254" step="1">
|
||||||
</label>
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="opentherm-rx-led-gpio">
|
||||||
|
RX LED GPIO
|
||||||
|
<input type="number" inputmode="numeric" id="opentherm-rx-led-gpio" name="opentherm[rxLedGpio]" min="0" max="254" step="1">
|
||||||
|
<small>blank - not use</small>
|
||||||
|
</label>
|
||||||
|
|
||||||
<label for="opentherm-member-id-code">
|
<label for="opentherm-member-id-code">
|
||||||
Master MemberID code
|
Master MemberID code
|
||||||
@@ -411,6 +435,27 @@
|
|||||||
<input type="checkbox" id="opentherm-get-min-max-temp" name="opentherm[getMinMaxTemp]" value="true">
|
<input type="checkbox" id="opentherm-get-min-max-temp" name="opentherm[getMinMaxTemp]" value="true">
|
||||||
Get min/max temp from boiler
|
Get min/max temp from boiler
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<fieldset>
|
||||||
|
<label for="opentherm-fault-state-gpio">
|
||||||
|
Fault state GPIO
|
||||||
|
<input type="number" inputmode="numeric" id="opentherm-fault-state-gpio" name="opentherm[faultStateGpio]" min="0" max="254" step="1">
|
||||||
|
<small>Can be useful to switch on another boiler <u>via relay</u>. Blank - not use.</small>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-invert-fault-state">
|
||||||
|
<input type="checkbox" id="opentherm-invert-fault-state" name="opentherm[invertFaultState]" value="true">
|
||||||
|
Invert fault state
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<label for="opentherm-native-heating-control">
|
||||||
|
<input type="checkbox" id="opentherm-native-heating-control" name="opentherm[nativeHeatingControl]" value="true">
|
||||||
|
Native heating control (boiler)<br />
|
||||||
|
<small>Works <u>ONLY</u> if the boiler requires the desired room temperature and regulates the temperature of the coolant itself. Not compatible with PID and Equitherm regulators and hysteresis in firmware.</small>
|
||||||
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<button type="submit">Save</button>
|
<button type="submit">Save</button>
|
||||||
@@ -430,6 +475,11 @@
|
|||||||
<input type="checkbox" id="mqtt-enable" name="mqtt[enable]" value="true">
|
<input type="checkbox" id="mqtt-enable" name="mqtt[enable]" value="true">
|
||||||
Enable
|
Enable
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<label for="mqtt-ha-discovery">
|
||||||
|
<input type="checkbox" id="mqtt-ha-discovery" name="mqtt[homeAssistantDiscovery]" value="true">
|
||||||
|
Home Assistant Discovery
|
||||||
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
@@ -484,17 +534,17 @@
|
|||||||
<legend>Source type</legend>
|
<legend>Source type</legend>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" id="outdoor-sensor-type" name="sensors[outdoor][type]" value="0" />
|
<input type="radio" class="outdoor-sensor-type" name="sensors[outdoor][type]" value="0" />
|
||||||
From boiler via OpenTherm
|
From boiler via OpenTherm
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" id="outdoor-sensor-type" name="sensors[outdoor][type]" value="1" />
|
<input type="radio" class="outdoor-sensor-type" name="sensors[outdoor][type]" value="1" />
|
||||||
Manual via MQTT/API
|
Manual via MQTT/API
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" id="outdoor-sensor-type" name="sensors[outdoor][type]" value="2" />
|
<input type="radio" class="outdoor-sensor-type" name="sensors[outdoor][type]" value="2" />
|
||||||
External (DS18B20)
|
External (DS18B20)
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -525,17 +575,17 @@
|
|||||||
<legend>Source type</legend>
|
<legend>Source type</legend>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" id="indoor-sensor-type" name="sensors[indoor][type]" value="1" />
|
<input type="radio" class="indoor-sensor-type" name="sensors[indoor][type]" value="1" />
|
||||||
Manual via MQTT/API
|
Manual via MQTT/API
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" id="indoor-sensor-type" name="sensors[indoor][type]" value="2" />
|
<input type="radio" class="indoor-sensor-type" name="sensors[indoor][type]" value="2" />
|
||||||
External (DS18B20)
|
External (DS18B20)
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" id="indoor-sensor-type" name="sensors[indoor][type]" value="3" />
|
<input type="radio" class="indoor-sensor-type" name="sensors[indoor][type]" value="3" />
|
||||||
BLE device <i>(ONLY for some ESP32 which support BLE)</i>
|
BLE device <i>(ONLY for some ESP32 which support BLE)</i>
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -629,7 +679,8 @@
|
|||||||
setInputValue('#system-serial-baudrate', data.system.serial.baudrate);
|
setInputValue('#system-serial-baudrate', data.system.serial.baudrate);
|
||||||
setCheckboxValue('#system-telnet-enable', data.system.telnet.enable);
|
setCheckboxValue('#system-telnet-enable', data.system.telnet.enable);
|
||||||
setInputValue('#system-telnet-port', data.system.telnet.port);
|
setInputValue('#system-telnet-port', data.system.telnet.port);
|
||||||
setRadioValue('#system-unit-system', data.system.unitSystem);
|
setRadioValue('.system-unit-system', data.system.unitSystem);
|
||||||
|
setInputValue('#system-status-led-gpio', data.system.statusLedGpio < 255 ? data.system.statusLedGpio : '');
|
||||||
setBusy('#system-settings-busy', '#system-settings', false);
|
setBusy('#system-settings-busy', '#system-settings', false);
|
||||||
|
|
||||||
// Portal
|
// Portal
|
||||||
@@ -639,9 +690,12 @@
|
|||||||
setBusy('#portal-settings-busy', '#portal-settings', false);
|
setBusy('#portal-settings-busy', '#portal-settings', false);
|
||||||
|
|
||||||
// Opentherm
|
// Opentherm
|
||||||
setRadioValue('#opentherm-unit-system', data.opentherm.unitSystem);
|
setRadioValue('.opentherm-unit-system', data.opentherm.unitSystem);
|
||||||
setInputValue('#opentherm-in-gpio', data.opentherm.inGpio < 255 ? data.opentherm.inGpio : '');
|
setInputValue('#opentherm-in-gpio', data.opentherm.inGpio < 255 ? data.opentherm.inGpio : '');
|
||||||
setInputValue('#opentherm-out-gpio', data.opentherm.outGpio < 255 ? data.opentherm.outGpio : '');
|
setInputValue('#opentherm-out-gpio', data.opentherm.outGpio < 255 ? data.opentherm.outGpio : '');
|
||||||
|
setInputValue('#opentherm-rx-led-gpio', data.opentherm.rxLedGpio < 255 ? data.opentherm.rxLedGpio : '');
|
||||||
|
setInputValue('#opentherm-fault-state-gpio', data.opentherm.faultStateGpio < 255 ? data.opentherm.faultStateGpio : '');
|
||||||
|
setCheckboxValue('#opentherm-invert-fault-state', data.opentherm.invertFaultState);
|
||||||
setInputValue('#opentherm-member-id-code', data.opentherm.memberIdCode);
|
setInputValue('#opentherm-member-id-code', data.opentherm.memberIdCode);
|
||||||
setCheckboxValue('#opentherm-dhw-present', data.opentherm.dhwPresent);
|
setCheckboxValue('#opentherm-dhw-present', data.opentherm.dhwPresent);
|
||||||
setCheckboxValue('#opentherm-sw-mode', data.opentherm.summerWinterMode);
|
setCheckboxValue('#opentherm-sw-mode', data.opentherm.summerWinterMode);
|
||||||
@@ -651,10 +705,12 @@
|
|||||||
setCheckboxValue('#opentherm-dhw-blocking', data.opentherm.dhwBlocking);
|
setCheckboxValue('#opentherm-dhw-blocking', data.opentherm.dhwBlocking);
|
||||||
setCheckboxValue('#opentherm-sync-modulation-with-heating', data.opentherm.modulationSyncWithHeating);
|
setCheckboxValue('#opentherm-sync-modulation-with-heating', data.opentherm.modulationSyncWithHeating);
|
||||||
setCheckboxValue('#opentherm-get-min-max-temp', data.opentherm.getMinMaxTemp);
|
setCheckboxValue('#opentherm-get-min-max-temp', data.opentherm.getMinMaxTemp);
|
||||||
|
setCheckboxValue('#opentherm-native-heating-control', data.opentherm.nativeHeatingControl);
|
||||||
setBusy('#opentherm-settings-busy', '#opentherm-settings', false);
|
setBusy('#opentherm-settings-busy', '#opentherm-settings', false);
|
||||||
|
|
||||||
// MQTT
|
// MQTT
|
||||||
setCheckboxValue('#mqtt-enable', data.mqtt.enable);
|
setCheckboxValue('#mqtt-enable', data.mqtt.enable);
|
||||||
|
setCheckboxValue('#mqtt-ha-discovery', data.mqtt.homeAssistantDiscovery);
|
||||||
setInputValue('#mqtt-server', data.mqtt.server);
|
setInputValue('#mqtt-server', data.mqtt.server);
|
||||||
setInputValue('#mqtt-port', data.mqtt.port);
|
setInputValue('#mqtt-port', data.mqtt.port);
|
||||||
setInputValue('#mqtt-user', data.mqtt.user);
|
setInputValue('#mqtt-user', data.mqtt.user);
|
||||||
@@ -664,13 +720,13 @@
|
|||||||
setBusy('#mqtt-settings-busy', '#mqtt-settings', false);
|
setBusy('#mqtt-settings-busy', '#mqtt-settings', false);
|
||||||
|
|
||||||
// Outdoor sensor
|
// Outdoor sensor
|
||||||
setRadioValue('#outdoor-sensor-type', data.sensors.outdoor.type);
|
setRadioValue('.outdoor-sensor-type', data.sensors.outdoor.type);
|
||||||
setInputValue('#outdoor-sensor-gpio', data.sensors.outdoor.gpio < 255 ? data.sensors.outdoor.gpio : '');
|
setInputValue('#outdoor-sensor-gpio', data.sensors.outdoor.gpio < 255 ? data.sensors.outdoor.gpio : '');
|
||||||
setInputValue('#outdoor-sensor-offset', data.sensors.outdoor.offset);
|
setInputValue('#outdoor-sensor-offset', data.sensors.outdoor.offset);
|
||||||
setBusy('#outdoor-sensor-settings-busy', '#outdoor-sensor-settings', false);
|
setBusy('#outdoor-sensor-settings-busy', '#outdoor-sensor-settings', false);
|
||||||
|
|
||||||
// Indoor sensor
|
// Indoor sensor
|
||||||
setRadioValue('#indoor-sensor-type', data.sensors.indoor.type);
|
setRadioValue('.indoor-sensor-type', data.sensors.indoor.type);
|
||||||
setInputValue('#indoor-sensor-gpio', data.sensors.indoor.gpio < 255 ? data.sensors.indoor.gpio : '');
|
setInputValue('#indoor-sensor-gpio', data.sensors.indoor.gpio < 255 ? data.sensors.indoor.gpio : '');
|
||||||
setInputValue('#indoor-sensor-offset', data.sensors.indoor.offset);
|
setInputValue('#indoor-sensor-offset', data.sensors.indoor.offset);
|
||||||
setInputValue('#indoor-sensor-ble-addresss', data.sensors.indoor.bleAddresss);
|
setInputValue('#indoor-sensor-ble-addresss', data.sensors.indoor.bleAddresss);
|
||||||
@@ -710,6 +766,7 @@
|
|||||||
|
|
||||||
// Emergency mode
|
// Emergency mode
|
||||||
setCheckboxValue('#emergency-enable', data.emergency.enable);
|
setCheckboxValue('#emergency-enable', data.emergency.enable);
|
||||||
|
setInputValue('#emergency-treshold-time', data.emergency.tresholdTime);
|
||||||
setCheckboxValue('#emergency-use-equitherm', data.emergency.useEquitherm);
|
setCheckboxValue('#emergency-use-equitherm', data.emergency.useEquitherm);
|
||||||
setCheckboxValue('#emergency-use-pid', data.emergency.usePid);
|
setCheckboxValue('#emergency-use-pid', data.emergency.usePid);
|
||||||
setCheckboxValue('#emergency-on-network-fault', data.emergency.onNetworkFault);
|
setCheckboxValue('#emergency-on-network-fault', data.emergency.onNetworkFault);
|
||||||
@@ -752,7 +809,8 @@
|
|||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
fillData(result);
|
fillData(result);
|
||||||
setupForm('#portal-settings', fillData);
|
|
||||||
|
setupForm('#portal-settings', fillData, ['portal.login', 'portal.password']);
|
||||||
setupForm('#system-settings', fillData);
|
setupForm('#system-settings', fillData);
|
||||||
setupForm('#heating-settings', fillData);
|
setupForm('#heating-settings', fillData);
|
||||||
setupForm('#dhw-settings', fillData);
|
setupForm('#dhw-settings', fillData);
|
||||||
@@ -760,9 +818,9 @@
|
|||||||
setupForm('#equitherm-settings', fillData);
|
setupForm('#equitherm-settings', fillData);
|
||||||
setupForm('#pid-settings', fillData);
|
setupForm('#pid-settings', fillData);
|
||||||
setupForm('#opentherm-settings', fillData);
|
setupForm('#opentherm-settings', fillData);
|
||||||
setupForm('#mqtt-settings', fillData);
|
setupForm('#mqtt-settings', fillData, ['mqtt.user', 'mqtt.password', 'mqtt.prefix']);
|
||||||
setupForm('#outdoor-sensor-settings', fillData);
|
setupForm('#outdoor-sensor-settings', fillData);
|
||||||
setupForm('#indoor-sensor-settings', fillData);
|
setupForm('#indoor-sensor-settings', fillData, ['sensors.indoor.bleAddresss']);
|
||||||
setupForm('#extpump-settings', fillData);
|
setupForm('#extpump-settings', fillData);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -86,18 +86,6 @@ tr.network:hover {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.greatSignal {
|
|
||||||
background-color: var(--pico-form-element-valid-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.normalSignal {
|
|
||||||
background-color: #e48500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.badSignal {
|
|
||||||
background-color: var(--pico-form-element-invalid-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
.primary {
|
||||||
border: 0.25rem solid var(--pico-form-element-invalid-border-color);
|
border: 0.25rem solid var(--pico-form-element-invalid-border-color);
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
@@ -194,3 +182,13 @@ tr.network:hover {
|
|||||||
|
|
||||||
margin: 1.25rem 0;
|
margin: 1.25rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[class*=" icons-"],[class=icons],[class^=icons-] {font-size: 1.35rem; }
|
||||||
|
*:has(> [class*=" icons-"], > [class=icons], > [class^=icons-]):has(+ * > [class*=" icons-"], + * > [class=icons], + * > [class^=icons-]) { margin: 0 0.5rem 0 0; }
|
||||||
|
[data-tooltip]:has(> [class*=" icons-"], > [class=icons], > [class^=icons-]) { border: 0!important; }
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Icons icon font. Generated by Iconly: https://iconly.io/
|
||||||
|
*/
|
||||||
|
@font-face{font-display:auto;font-family:"Icons";font-style:normal;font-weight:400;src:url(./fonts/iconly.eot?1717885802370);src:url(./fonts/iconly.eot?#iefix) format("embedded-opentype"),url(./fonts/iconly.woff2?1717885802370) format("woff2"),url(./fonts/iconly.woff?1717885802370) format("woff"),url(./fonts/iconly.ttf?1717885802370) format("truetype")}[class*=" icons-"],[class=icons],[class^=icons-]{display:inline-block;font-family:"Icons"!important;font-weight:400;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}.icons-plus:before{content:"\e000"}.icons-minus:before{content:"\e001"}.icons-unlocked:before{content:"\e002"}.icons-locked:before{content:"\e003"}.icons-wifi-strength-1:before{content:"\e004"}.icons-wifi-strength-0:before{content:"\e005"}.icons-wifi-strength-2:before{content:"\e006"}.icons-wifi-strength-3:before{content:"\e008"}.icons-down:before{content:"\e009"}.icons-wifi-strength-4:before{content:"\e00a"}.icons-up:before{content:"\e00c"}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
function setupForm(formSelector, onResultCallback = null) {
|
function setupForm(formSelector, onResultCallback = null, noCastItems = []) {
|
||||||
const form = document.querySelector(formSelector);
|
const form = document.querySelector(formSelector);
|
||||||
if (!form) {
|
if (!form) {
|
||||||
return;
|
return;
|
||||||
@@ -68,7 +68,7 @@ function setupForm(formSelector, onResultCallback = null) {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: form2json(fd)
|
body: form2json(fd, noCastItems)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -139,7 +139,7 @@ function setupNetworkScanForm(formSelector, tableSelector) {
|
|||||||
row.classList.add("network");
|
row.classList.add("network");
|
||||||
row.setAttribute('data-ssid', result[i].hidden ? '' : result[i].ssid);
|
row.setAttribute('data-ssid', result[i].hidden ? '' : result[i].ssid);
|
||||||
row.onclick = function () {
|
row.onclick = function () {
|
||||||
const input = document.querySelector('input.sta-ssid');
|
const input = document.querySelector('input#sta-ssid');
|
||||||
const ssid = this.getAttribute('data-ssid');
|
const ssid = this.getAttribute('data-ssid');
|
||||||
if (!input || !ssid) {
|
if (!input || !ssid) {
|
||||||
return;
|
return;
|
||||||
@@ -150,19 +150,56 @@ function setupNetworkScanForm(formSelector, tableSelector) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
row.insertCell().textContent = "#" + (i + 1);
|
row.insertCell().textContent = "#" + (i + 1);
|
||||||
row.insertCell().innerHTML = result[i].hidden ? '<i>Hidden</i>' : result[i].ssid;
|
row.insertCell().innerHTML = result[i].hidden ? ("<i>" + result[i].bssid + "</i>") : result[i].ssid;
|
||||||
|
|
||||||
const signalCell = row.insertCell();
|
// info cell
|
||||||
const signalElement = document.createElement("kbd");
|
let infoCell = row.insertCell();
|
||||||
signalElement.textContent = result[i].signalQuality + "%";
|
|
||||||
if (result[i].signalQuality > 60) {
|
// signal quality
|
||||||
signalElement.classList.add('greatSignal');
|
let signalQualityIcon = document.createElement("i");
|
||||||
|
if (result[i].signalQuality > 80) {
|
||||||
|
signalQualityIcon.classList.add('icons-wifi-strength-4');
|
||||||
|
} else if (result[i].signalQuality > 60) {
|
||||||
|
signalQualityIcon.classList.add('icons-wifi-strength-3');
|
||||||
} else if (result[i].signalQuality > 40) {
|
} else if (result[i].signalQuality > 40) {
|
||||||
signalElement.classList.add('normalSignal');
|
signalQualityIcon.classList.add('icons-wifi-strength-2');
|
||||||
|
} else if (result[i].signalQuality > 20) {
|
||||||
|
signalQualityIcon.classList.add('icons-wifi-strength-1');
|
||||||
} else {
|
} else {
|
||||||
signalElement.classList.add('badSignal');
|
signalQualityIcon.classList.add('icons-wifi-strength-0');
|
||||||
}
|
}
|
||||||
signalCell.appendChild(signalElement);
|
|
||||||
|
let signalQualityContainer = document.createElement("span");
|
||||||
|
signalQualityContainer.setAttribute('data-tooltip', result[i].signalQuality + "%");
|
||||||
|
signalQualityContainer.appendChild(signalQualityIcon);
|
||||||
|
infoCell.appendChild(signalQualityContainer);
|
||||||
|
|
||||||
|
// auth
|
||||||
|
const authList = {
|
||||||
|
0: "Open",
|
||||||
|
1: "WEP",
|
||||||
|
2: "WPA",
|
||||||
|
3: "WPA2",
|
||||||
|
4: "WPA/WPA2",
|
||||||
|
5: "WPA/WPA2 Enterprise",
|
||||||
|
6: "WPA3",
|
||||||
|
7: "WPA2/WPA3",
|
||||||
|
8: "WAPI",
|
||||||
|
9: "OWE",
|
||||||
|
10: "WPA3 Enterprise"
|
||||||
|
};
|
||||||
|
let authIcon = document.createElement("i");
|
||||||
|
|
||||||
|
if (result[i].auth == 0) {
|
||||||
|
authIcon.classList.add('icons-unlocked');
|
||||||
|
} else {
|
||||||
|
authIcon.classList.add('icons-locked');
|
||||||
|
}
|
||||||
|
|
||||||
|
let authContainer = document.createElement("span");
|
||||||
|
authContainer.setAttribute('data-tooltip', (result[i].auth in authList) ? authList[result[i].auth] : "unknown");
|
||||||
|
authContainer.appendChild(authIcon);
|
||||||
|
infoCell.appendChild(authContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (button) {
|
if (button) {
|
||||||
@@ -584,6 +621,7 @@ function memberIdToVendor(memberId) {
|
|||||||
27: "Baxi",
|
27: "Baxi",
|
||||||
29: "Itho Daalderop",
|
29: "Itho Daalderop",
|
||||||
33: "Viessmann",
|
33: "Viessmann",
|
||||||
|
41: "Italtherm",
|
||||||
56: "Baxi Luna Duo-Tec",
|
56: "Baxi Luna Duo-Tec",
|
||||||
131: "Nefit",
|
131: "Nefit",
|
||||||
148: "Navien",
|
148: "Navien",
|
||||||
@@ -597,16 +635,20 @@ function memberIdToVendor(memberId) {
|
|||||||
: "unknown vendor";
|
: "unknown vendor";
|
||||||
}
|
}
|
||||||
|
|
||||||
function form2json(data) {
|
function form2json(data, noCastItems = []) {
|
||||||
let method = function (object, pair) {
|
let method = function (object, pair) {
|
||||||
let keys = pair[0].replace(/\]/g, '').split('[');
|
let keys = pair[0].replace(/\]/g, '').split('[');
|
||||||
let key = keys[0];
|
let key = keys[0];
|
||||||
let value = pair[1];
|
let value = pair[1];
|
||||||
|
|
||||||
|
if (!noCastItems.includes(keys.join('.'))) {
|
||||||
if (value === 'true' || value === 'false') {
|
if (value === 'true' || value === 'false') {
|
||||||
value = value === 'true';
|
value = value === 'true';
|
||||||
|
|
||||||
} else if (typeof (value) === 'string' && value.trim() !== '' && !isNaN(value)) {
|
} else if (typeof (value) === 'string' && value.trim() !== '' && !isNaN(value)) {
|
||||||
value = parseFloat(value);
|
value = parseFloat(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (keys.length > 1) {
|
if (keys.length > 1) {
|
||||||
let i, x, segment;
|
let i, x, segment;
|
||||||
|
|||||||
BIN
src_data/static/fonts/iconly.eot
Normal file
BIN
src_data/static/fonts/iconly.eot
Normal file
Binary file not shown.
BIN
src_data/static/fonts/iconly.ttf
Normal file
BIN
src_data/static/fonts/iconly.ttf
Normal file
Binary file not shown.
BIN
src_data/static/fonts/iconly.woff
Normal file
BIN
src_data/static/fonts/iconly.woff
Normal file
Binary file not shown.
BIN
src_data/static/fonts/iconly.woff2
Normal file
BIN
src_data/static/fonts/iconly.woff2
Normal file
Binary file not shown.
@@ -1,4 +1,5 @@
|
|||||||
import shutil
|
import shutil
|
||||||
|
import gzip
|
||||||
import os
|
import os
|
||||||
Import("env")
|
Import("env")
|
||||||
|
|
||||||
@@ -12,6 +13,26 @@ def post_build(source, target, env):
|
|||||||
env.Execute("pio run --target buildfs --environment %s" % env["PIOENV"]);
|
env.Execute("pio run --target buildfs --environment %s" % env["PIOENV"]);
|
||||||
|
|
||||||
|
|
||||||
|
def before_buildfs(source, target, env):
|
||||||
|
src = os.path.join(env["PROJECT_DIR"], "src_data")
|
||||||
|
dst = os.path.join(env["PROJECT_DIR"], "data")
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(src, topdown=False):
|
||||||
|
for name in files:
|
||||||
|
src_path = os.path.join(root, name)
|
||||||
|
|
||||||
|
with open(src_path, 'rb') as f_in:
|
||||||
|
dst_name = name + ".gz"
|
||||||
|
dst_path = os.path.join(dst, os.path.relpath(root, src), dst_name)
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(dst, os.path.relpath(root, src))) == False:
|
||||||
|
os.mkdir(os.path.join(dst, os.path.relpath(root, src)))
|
||||||
|
|
||||||
|
with gzip.open(dst_path, 'wb', 9) as f_out:
|
||||||
|
shutil.copyfileobj(f_in, f_out)
|
||||||
|
|
||||||
|
print("Compressed '%s' to '%s'" % (src_path, dst_path))
|
||||||
|
|
||||||
def after_buildfs(source, target, env):
|
def after_buildfs(source, target, env):
|
||||||
copy_to_build_dir({
|
copy_to_build_dir({
|
||||||
source[0].get_abspath(): "filesystem_%s_%s.bin" % (env["PIOENV"], env.GetProjectOption("version")),
|
source[0].get_abspath(): "filesystem_%s_%s.bin" % (env["PIOENV"], env.GetProjectOption("version")),
|
||||||
@@ -31,4 +52,6 @@ def copy_to_build_dir(files, build_dir):
|
|||||||
|
|
||||||
|
|
||||||
env.AddPostAction("buildprog", post_build)
|
env.AddPostAction("buildprog", post_build)
|
||||||
|
env.AddPreAction("$BUILD_DIR/spiffs.bin", before_buildfs)
|
||||||
|
env.AddPreAction("$BUILD_DIR/littlefs.bin", before_buildfs)
|
||||||
env.AddPostAction("buildfs", after_buildfs)
|
env.AddPostAction("buildfs", after_buildfs)
|
||||||
Reference in New Issue
Block a user