mirror of
https://github.com/Laxilef/OTGateway.git
synced 2025-12-24 00:53:36 +05:00
Compare commits
2 Commits
platformio
...
6bac4a3954
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bac4a3954 | ||
|
|
24342db40e |
@@ -72,7 +72,7 @@ All available information and instructions can be found in the wiki:
|
|||||||
* [Leds on board](https://github.com/Laxilef/OTGateway/wiki/OT-adapters#leds-on-board)
|
* [Leds on board](https://github.com/Laxilef/OTGateway/wiki/OT-adapters#leds-on-board)
|
||||||
|
|
||||||
## Gratitude
|
## Gratitude
|
||||||
* To the developers of the libraries used: [OpenTherm Library](https://github.com/ihormelnyk/opentherm_library), [ESP8266Scheduler](https://github.com/nrwiersma/ESP8266Scheduler), [ArduinoJson](https://github.com/bblanchon/ArduinoJson), [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino), [ArduinoMqttClient](https://github.com/arduino-libraries/ArduinoMqttClient), [ESPTelnet](https://github.com/LennartHennigs/ESPTelnet), [FileData](https://github.com/GyverLibs/FileData), [GyverPID](https://github.com/GyverLibs/GyverPID), [GyverBlinker](https://github.com/GyverLibs/GyverBlinker), [OneWireNg](https://github.com/pstolarz/OneWireNg) & [OneWire](https://github.com/PaulStoffregen/OneWire)
|
* To the developers of the libraries used: [OpenTherm Library](https://github.com/ihormelnyk/opentherm_library), [ESP8266Scheduler](https://github.com/nrwiersma/ESP8266Scheduler), [ArduinoJson](https://github.com/bblanchon/ArduinoJson), [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino), [ArduinoMqttClient](https://github.com/arduino-libraries/ArduinoMqttClient), [ESPTelnet](https://github.com/LennartHennigs/ESPTelnet), [FileData](https://github.com/GyverLibs/FileData), [GyverPID](https://github.com/GyverLibs/GyverPID), [GyverBlinker](https://github.com/GyverLibs/GyverBlinker), [FileData](https://github.com/GyverLibs/FileData), [OneWireNg](https://github.com/pstolarz/OneWireNg) & [OneWire](https://github.com/PaulStoffregen/OneWire)
|
||||||
* To the [PlatformIO](https://platformio.org/) Team
|
* To the [PlatformIO](https://platformio.org/) Team
|
||||||
* To the team and contributors of the [pioarduino](https://github.com/pioarduino/platform-espressif32) project
|
* To the team and contributors of the [pioarduino](https://github.com/pioarduino/platform-espressif32) project
|
||||||
* To the [BrowserStack](https://www.browserstack.com/) team. This project is tested with BrowserStack.
|
* To the [BrowserStack](https://www.browserstack.com/) team. This project is tested with BrowserStack.
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
class CustomOpenTherm : public OpenTherm {
|
class CustomOpenTherm : public OpenTherm {
|
||||||
public:
|
public:
|
||||||
typedef std::function<void(unsigned int)> DelayCallback;
|
typedef std::function<void(unsigned int)> DelayCallback;
|
||||||
typedef std::function<void(unsigned long, uint8_t)> BeforeSendRequestCallback;
|
typedef std::function<void(unsigned long, byte)> BeforeSendRequestCallback;
|
||||||
typedef std::function<void(unsigned long, unsigned long, OpenThermResponseStatus, uint8_t)> AfterSendRequestCallback;
|
typedef std::function<void(unsigned long, unsigned long, OpenThermResponseStatus, byte)> AfterSendRequestCallback;
|
||||||
|
|
||||||
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false, bool alwaysReceive = false) : OpenTherm(inPin, outPin, isSlave, alwaysReceive) {}
|
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false, bool alwaysReceive = false) : OpenTherm(inPin, outPin, isSlave, alwaysReceive) {}
|
||||||
~CustomOpenTherm() {}
|
~CustomOpenTherm() {}
|
||||||
@@ -106,14 +106,15 @@ public:
|
|||||||
return isValidResponse(response) && isValidResponseId(response, OpenThermMessageID::RemoteRequest);
|
return isValidResponse(response) && isValidResponseId(response, OpenThermMessageID::RemoteRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isCh2Active(unsigned long response) {
|
static bool isCh2Active(unsigned long response)
|
||||||
|
{
|
||||||
return response & 0x20;
|
return response & 0x20;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isValidResponseId(unsigned long response, OpenThermMessageID id) {
|
static bool isValidResponseId(unsigned long response, OpenThermMessageID id) {
|
||||||
uint8_t responseId = (response >> 16) & 0xFF;
|
byte responseId = (response >> 16) & 0xFF;
|
||||||
|
|
||||||
return (uint8_t)id == responseId;
|
return (byte)id == responseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t getResponseMessageTypeId(unsigned long response) {
|
static uint8_t getResponseMessageTypeId(unsigned long response) {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace NetworkUtils {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkMgr* setApCredentials(const char* ssid, const char* password = nullptr, uint8_t 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 NetworkUtils {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkMgr* setStaCredentials(const char* ssid = nullptr, const char* password = nullptr, uint8_t 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;
|
||||||
@@ -140,7 +140,7 @@ namespace NetworkUtils {
|
|||||||
return this->staPassword;
|
return this->staPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getStaChannel() {
|
byte getStaChannel() {
|
||||||
return this->staChannel;
|
return this->staChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +377,7 @@ namespace NetworkUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t rssiToSignalQuality(short int rssi) {
|
static byte rssiToSignalQuality(short int rssi) {
|
||||||
return constrain(map(rssi, -100, -50, 0, 100), 0, 100);
|
return constrain(map(rssi, -100, -50, 0, 100), 0, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,11 +397,11 @@ namespace NetworkUtils {
|
|||||||
const char* hostname = "esp";
|
const char* hostname = "esp";
|
||||||
const char* apName = "ESP";
|
const char* apName = "ESP";
|
||||||
const char* apPassword = nullptr;
|
const char* apPassword = nullptr;
|
||||||
uint8_t apChannel = 1;
|
byte apChannel = 1;
|
||||||
|
|
||||||
const char* staSsid = nullptr;
|
const char* staSsid = nullptr;
|
||||||
const char* staPassword = nullptr;
|
const char* staPassword = nullptr;
|
||||||
uint8_t staChannel = 0;
|
byte staChannel = 0;
|
||||||
|
|
||||||
bool useDhcp = true;
|
bool useDhcp = true;
|
||||||
IPAddress staticIp;
|
IPAddress staticIp;
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ core_dir = .pio
|
|||||||
version = 1.5.6
|
version = 1.5.6
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson@^7.4.2
|
bblanchon/ArduinoJson@^7.3.0
|
||||||
;ihormelnyk/OpenTherm Library@^1.1.5
|
;ihormelnyk/OpenTherm Library@^1.1.5
|
||||||
https://github.com/Laxilef/opentherm_library#esp32_timer
|
https://github.com/Laxilef/opentherm_library#esp32_timer
|
||||||
arduino-libraries/ArduinoMqttClient@^0.1.8
|
arduino-libraries/ArduinoMqttClient@^0.1.8
|
||||||
lennarthennigs/ESP Telnet@^2.2.3
|
lennarthennigs/ESP Telnet@^2.2
|
||||||
gyverlibs/FileData@^1.0.3
|
gyverlibs/FileData@^1.0.2
|
||||||
gyverlibs/GyverPID@^3.3.2
|
gyverlibs/GyverPID@^3.3.2
|
||||||
gyverlibs/GyverBlinker@^1.1.1
|
gyverlibs/GyverBlinker@^1.1.1
|
||||||
https://github.com/pstolarz/Arduino-Temperature-Control-Library.git#OneWireNg
|
https://github.com/pstolarz/Arduino-Temperature-Control-Library.git#OneWireNg
|
||||||
@@ -92,13 +92,13 @@ check_flags = ${env.check_flags}
|
|||||||
;platform_packages =
|
;platform_packages =
|
||||||
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5
|
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5
|
||||||
; framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip
|
; framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.31/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip
|
||||||
platform_packages = ${env.platform_packages}
|
platform_packages = ${env.platform_packages}
|
||||||
board_build.partitions = esp32_partitions.csv
|
board_build.partitions = esp32_partitions.csv
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
laxilef/ESP32Scheduler@^1.0.1
|
laxilef/ESP32Scheduler@^1.0.1
|
||||||
nimble_lib = h2zero/NimBLE-Arduino@2.3.6
|
nimble_lib = h2zero/NimBLE-Arduino@^2.1.0
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
post:tools/esp32.py
|
post:tools/esp32.py
|
||||||
@@ -294,10 +294,6 @@ build_flags =
|
|||||||
check_tool = ${esp32_defaults.check_tool}
|
check_tool = ${esp32_defaults.check_tool}
|
||||||
check_flags = ${esp32_defaults.check_flags}
|
check_flags = ${esp32_defaults.check_flags}
|
||||||
|
|
||||||
[env:nodemcu_32_160mhz]
|
|
||||||
extends = env:nodemcu_32
|
|
||||||
board_build.f_cpu = 160000000L ; set frequency to 160MHz
|
|
||||||
|
|
||||||
[env:d1_mini32]
|
[env:d1_mini32]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
platform_packages = ${esp32_defaults.platform_packages}
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
|
|||||||
334
src/HaHelper.h
334
src/HaHelper.h
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
class HaHelper : public HomeAssistantHelper {
|
class HaHelper : public HomeAssistantHelper {
|
||||||
public:
|
public:
|
||||||
static const uint8_t TEMP_SOURCE_HEATING = 0;
|
static const byte TEMP_SOURCE_HEATING = 0;
|
||||||
static const uint8_t TEMP_SOURCE_INDOOR = 1;
|
static const byte TEMP_SOURCE_INDOOR = 1;
|
||||||
static const char AVAILABILITY_OT_CONN[];
|
static const char AVAILABILITY_OT_CONN[];
|
||||||
static const char AVAILABILITY_SENSOR_CONN[];
|
static const char AVAILABILITY_SENSOR_CONN[];
|
||||||
|
|
||||||
@@ -418,25 +418,26 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
bool publishSwitchHeatingTurbo(bool enabledByDefault = true) {
|
bool publishSwitchHeatingTurbo(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
return publishSwitch(
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
F("heating_turbo"),
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
F("Turbo heating"),
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("heating_turbo"));
|
F("mdi:rocket-launch-outline"),
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)];
|
F("{{ value_json.heating.turbo }}"),
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG);
|
F("{\"heating\": {\"turbo\" : true}}"),
|
||||||
doc[FPSTR(HA_NAME)] = F("Turbo heating");
|
F("{\"heating\": {\"turbo\" : false}}"),
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:rocket-launch-outline");
|
enabledByDefault
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str();
|
);
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
}
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.turbo }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str();
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"heating\": {\"turbo\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"heating\": {\"turbo\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_SWITCH), F("heating_turbo")).c_str(), doc);
|
bool publishSwitchExtDevice(const String& caption, bool enabledByDefault = true) {
|
||||||
|
return publishSwitch(
|
||||||
|
F("extdev"),
|
||||||
|
caption,
|
||||||
|
F("mdi:toggle-switch-outline"),
|
||||||
|
F("{{ value_json.externalDev.state }}"),
|
||||||
|
F("{\"externalDev\": {\"state\" : true}}"),
|
||||||
|
F("{\"externalDev\": {\"state\" : false}}"),
|
||||||
|
enabledByDefault );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishInputHeatingHysteresis(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
bool publishInputHeatingHysteresis(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
@@ -634,26 +635,18 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
bool publishSwitchPid(bool enabledByDefault = true) {
|
bool publishSwitchPid(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("pid"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)];
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG);
|
|
||||||
doc[FPSTR(HA_NAME)] = F("PID");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:chart-bar-stacked");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str();
|
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.enabled }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str();
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"pid\": {\"enabled\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"pid\": {\"enabled\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_SWITCH), F("pid")).c_str(), doc);
|
return publishSwitch(
|
||||||
|
F("pid"),
|
||||||
|
F("PID"),
|
||||||
|
F("mdi:chart-bar-stacked"),
|
||||||
|
F("{{ value_json.pid.enabled }}"),
|
||||||
|
F("{\"pid\": {\"enabled\" : true}}"),
|
||||||
|
F("{\"pid\": {\"enabled\" : false}}"),
|
||||||
|
enabledByDefault
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool publishInputPidFactorP(bool enabledByDefault = true) {
|
bool publishInputPidFactorP(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
@@ -819,25 +812,16 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
bool publishSwitchEquitherm(bool enabledByDefault = true) {
|
bool publishSwitchEquitherm(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("equitherm"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)];
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG);
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Equitherm");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:sun-snowflake-variant");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str();
|
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.enabled }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str();
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"equitherm\": {\"enabled\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"equitherm\": {\"enabled\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_SWITCH), F("equitherm")).c_str(), doc);
|
return publishSwitch(
|
||||||
|
F("equitherm"),
|
||||||
|
F("Equitherm"),
|
||||||
|
F("mdi:sun-snowflake-variant"),
|
||||||
|
F("{{ value_json.equitherm.enabled }}"),
|
||||||
|
F("{\"equitherm\": {\"enabled\" : true}}"),
|
||||||
|
F("{\"equitherm\": {\"enabled\" : false}}"),
|
||||||
|
enabledByDefault
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishInputEquithermFactorN(bool enabledByDefault = true) {
|
bool publishInputEquithermFactorN(bool enabledByDefault = true) {
|
||||||
@@ -967,126 +951,87 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool publishHeatingState(bool enabledByDefault = true) {
|
bool publishHeatingState(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str();
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = JsonString(AVAILABILITY_OT_CONN, true);
|
|
||||||
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("heating"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)];
|
|
||||||
//doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC);
|
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("running");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Heating");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:radiator");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str();
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.heating.active, 'ON', 'OFF') }}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_BINARY_SENSOR), F("heating")).c_str(), doc);
|
return publishBinarySensorState(
|
||||||
|
F("heating"),
|
||||||
|
F("Heating"),
|
||||||
|
F("mdi:radiator"),
|
||||||
|
F("{{ iif(value_json.slave.heating.active, 'ON', 'OFF') }}"),
|
||||||
|
F("running"),
|
||||||
|
enabledByDefault
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishDhwState(bool enabledByDefault = true) {
|
bool publishDhwState(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str();
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = JsonString(AVAILABILITY_OT_CONN, true);
|
|
||||||
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("dhw"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)];
|
|
||||||
//doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC);
|
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("running");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("DHW");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:faucet");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str();
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.dhw.active, 'ON', 'OFF') }}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_BINARY_SENSOR), F("dhw")).c_str(), doc);
|
return publishBinarySensorState(
|
||||||
|
F("dhw"),
|
||||||
|
F("DHW"),
|
||||||
|
F("mdi:faucet"),
|
||||||
|
F("{{ iif(value_json.slave.dhw.active, 'ON', 'OFF') }}"),
|
||||||
|
F("running"),
|
||||||
|
enabledByDefault
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishFlameState(bool enabledByDefault = true) {
|
bool publishFlameState(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str();
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = JsonString(AVAILABILITY_OT_CONN, true);
|
|
||||||
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("flame"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)];
|
|
||||||
//doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC);
|
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("running");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Flame");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:gas-burner");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str();
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.flame, 'ON', 'OFF') }}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_BINARY_SENSOR), F("flame")).c_str(), doc);
|
return publishBinarySensorState(
|
||||||
|
F("flame"),
|
||||||
|
F("Flame"),
|
||||||
|
F("mdi:gas-burner"),
|
||||||
|
F("{{ iif(value_json.slave.flame, 'ON', 'OFF') }}"),
|
||||||
|
F("running"),
|
||||||
|
enabledByDefault
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishFaultState(bool enabledByDefault = true) {
|
bool publishFaultState(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str();
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = JsonString(AVAILABILITY_OT_CONN, true);
|
|
||||||
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("fault"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)];
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC);
|
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("problem");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Fault");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:alert-remove-outline");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str();
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.fault.active, 'ON', 'OFF') }}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_BINARY_SENSOR), F("fault")).c_str(), doc);
|
return publishBinarySensorState(
|
||||||
|
F("fault"),
|
||||||
|
F("Fault"),
|
||||||
|
F("mdi:alert-remove-outline"),
|
||||||
|
F("{{ iif(value_json.slave.fault.active, 'ON', 'OFF') }}"),
|
||||||
|
F("problem"),
|
||||||
|
enabledByDefault
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishDiagState(bool enabledByDefault = true) {
|
bool publishDiagState(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
return publishBinarySensorState(
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str();
|
F("diag"),
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = JsonString(AVAILABILITY_OT_CONN, true);
|
F("Diagnostic"),
|
||||||
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
|
F("mdi:account-wrench"),
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
F("{{ iif(value_json.slave.diag.active, 'ON', 'OFF') }}"),
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC));
|
F("problem"),
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)];
|
enabledByDefault
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC);
|
);
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("problem");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Diagnostic");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:account-wrench");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str();
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.diag.active, 'ON', 'OFF') }}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_BINARY_SENSOR), FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC)).c_str(), doc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishExternalPumpState(bool enabledByDefault = true) {
|
bool publishExternalPumpState(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("ext_pump"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)];
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC);
|
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("running");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("External pump");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:pump");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str();
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.master.externalPump.state, 'ON', 'OFF') }}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_BINARY_SENSOR), F("ext_pump")).c_str(), doc);
|
return publishBinarySensorState(
|
||||||
|
F("ext_pump"),
|
||||||
|
F("External pump"),
|
||||||
|
F("mdi:pump"),
|
||||||
|
F("{{ iif(value_json.master.externalPump.state, 'ON', 'OFF') }}"),
|
||||||
|
F("running"),
|
||||||
|
enabledByDefault
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool publishExtDevState(const String& caption, bool enabledByDefault = true) {
|
||||||
|
|
||||||
|
return publishBinarySensorState(
|
||||||
|
F("extdev"),
|
||||||
|
caption,
|
||||||
|
F("mdi:toggle-switch"),
|
||||||
|
F("{{ iif(value_json.master.externalDev.state, 'ON', 'OFF') }}"),
|
||||||
|
F("running"),
|
||||||
|
enabledByDefault
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishFaultCode(bool enabledByDefault = true) {
|
bool publishFaultCode(bool enabledByDefault = true) {
|
||||||
@@ -1170,7 +1115,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool publishClimateHeating(UnitSystem unit = UnitSystem::METRIC, uint8_t minTemp = 20, uint8_t maxTemp = 90, bool enabledByDefault = true) {
|
bool publishClimateHeating(UnitSystem unit = UnitSystem::METRIC, byte minTemp = 20, byte maxTemp = 90, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -1222,7 +1167,7 @@ public:
|
|||||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_CLIMATE), F("heating"), '_').c_str(), doc);
|
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_CLIMATE), F("heating"), '_').c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishClimateDhw(UnitSystem unit = UnitSystem::METRIC, uint8_t minTemp = 40, uint8_t maxTemp = 60, bool enabledByDefault = true) {
|
bool publishClimateDhw(UnitSystem unit = UnitSystem::METRIC, byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -1357,6 +1302,79 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
unsigned short expireAfter = 300u;
|
unsigned short expireAfter = 300u;
|
||||||
String statusTopic, stateTopic, setStateTopic, settingsTopic, setSettingsTopic;
|
String statusTopic, stateTopic, setStateTopic, settingsTopic, setSettingsTopic;
|
||||||
|
|
||||||
|
void initCommonDocFields(JsonDocument& doc,
|
||||||
|
const String& uniqueId,
|
||||||
|
const String& name,
|
||||||
|
const String& icon,
|
||||||
|
const String& stateTopic,
|
||||||
|
const String& entityCategory,
|
||||||
|
bool enabledByDefault) {
|
||||||
|
|
||||||
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
|
doc[FPSTR(HA_UNIQUE_ID)] = uniqueId;
|
||||||
|
doc[FPSTR(HA_OBJECT_ID)] = uniqueId;
|
||||||
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = entityCategory;
|
||||||
|
doc[FPSTR(HA_NAME)] = name;
|
||||||
|
doc[FPSTR(HA_ICON)] = icon;
|
||||||
|
doc[FPSTR(HA_STATE_TOPIC)] = stateTopic;
|
||||||
|
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool publishSwitch(const String& id,
|
||||||
|
const String& name,
|
||||||
|
const String& icon,
|
||||||
|
const String& valueTemplate,
|
||||||
|
const String& payloadOn,
|
||||||
|
const String& payloadOff,
|
||||||
|
bool enabledByDefault) {
|
||||||
|
JsonDocument doc;
|
||||||
|
initCommonDocFields(doc,
|
||||||
|
this->getObjectIdWithPrefix(id),
|
||||||
|
name,
|
||||||
|
icon,
|
||||||
|
this->settingsTopic.c_str(),
|
||||||
|
FPSTR(HA_ENTITY_CATEGORY_CONFIG),
|
||||||
|
enabledByDefault );
|
||||||
|
|
||||||
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
||||||
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str();
|
||||||
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = valueTemplate;
|
||||||
|
doc[FPSTR(HA_STATE_ON)] = true;
|
||||||
|
doc[FPSTR(HA_STATE_OFF)] = false;
|
||||||
|
doc[FPSTR(HA_PAYLOAD_ON)] = payloadOn;
|
||||||
|
doc[FPSTR(HA_PAYLOAD_OFF)] = payloadOff;
|
||||||
|
doc.shrinkToFit();
|
||||||
|
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_SWITCH), id).c_str(), doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool publishBinarySensorState(const String& id,
|
||||||
|
const String& name,
|
||||||
|
const String& icon,
|
||||||
|
const String& valueTemplate,
|
||||||
|
const String& deviceClass,
|
||||||
|
bool enabledByDefault) {
|
||||||
|
JsonDocument doc;
|
||||||
|
initCommonDocFields(doc,
|
||||||
|
this->getObjectIdWithPrefix(id),
|
||||||
|
name,
|
||||||
|
icon,
|
||||||
|
this->stateTopic.c_str(),
|
||||||
|
FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC),
|
||||||
|
enabledByDefault );
|
||||||
|
|
||||||
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str();
|
||||||
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str();
|
||||||
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = JsonString(AVAILABILITY_OT_CONN, true);
|
||||||
|
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
|
||||||
|
|
||||||
|
doc[FPSTR(HA_DEVICE_CLASS)] = deviceClass;
|
||||||
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = valueTemplate;
|
||||||
|
|
||||||
|
doc.shrinkToFit();
|
||||||
|
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_BINARY_SENSOR), id).c_str(), doc);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const char HaHelper::AVAILABILITY_OT_CONN[] = "{{ iif(value_json.slave.connected, 'online', 'offline') }}";
|
const char HaHelper::AVAILABILITY_OT_CONN[] = "{{ iif(value_json.slave.connected, 'online', 'offline') }}";
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ protected:
|
|||||||
this->emergency();
|
this->emergency();
|
||||||
this->cascadeControl();
|
this->cascadeControl();
|
||||||
this->externalPump();
|
this->externalPump();
|
||||||
|
this->externalDev();
|
||||||
this->miscRunned = millis();
|
this->miscRunned = millis();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -688,4 +689,46 @@ protected:
|
|||||||
Log.sinfoln(FPSTR(L_EXTPUMP), F("Enabled: anti stuck"));
|
Log.sinfoln(FPSTR(L_EXTPUMP), F("Enabled: anti stuck"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
void externalDev() {
|
||||||
|
static uint8_t configuredGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
|
||||||
|
if(!settings.externalDev.use) return;
|
||||||
|
|
||||||
|
// configure output
|
||||||
|
// if settings are different than the configured GPIO, update
|
||||||
|
if (settings.externalDev.gpio != configuredGpio) {
|
||||||
|
if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GPIO_IS_VALID(settings.externalDev.gpio)) {
|
||||||
|
configuredGpio = settings.externalDev.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.externalDev.state) {
|
||||||
|
vars.externalDev.state = false;
|
||||||
|
|
||||||
|
Log.sinfoln(FPSTR(L_EXTDEV), F("Disabled: use = off"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// output configured update relay if required
|
||||||
|
if(settings.externalDev.state != vars.externalDev.state ) {
|
||||||
|
digitalWrite(configuredGpio, settings.externalDev.state? HIGH:LOW );
|
||||||
|
vars.externalDev.state = settings.externalDev.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -506,6 +506,9 @@ protected:
|
|||||||
this->haHelper->publishInputEquithermFactorK(false);
|
this->haHelper->publishInputEquithermFactorK(false);
|
||||||
this->haHelper->publishInputEquithermFactorT(false);
|
this->haHelper->publishInputEquithermFactorT(false);
|
||||||
|
|
||||||
|
// ext device
|
||||||
|
this->haHelper->publishSwitchExtDevice(String(settings.externalDev.caption), false);
|
||||||
|
|
||||||
// states
|
// states
|
||||||
this->haHelper->publishStatusState();
|
this->haHelper->publishStatusState();
|
||||||
this->haHelper->publishEmergencyState();
|
this->haHelper->publishEmergencyState();
|
||||||
@@ -515,6 +518,8 @@ protected:
|
|||||||
this->haHelper->publishFaultState();
|
this->haHelper->publishFaultState();
|
||||||
this->haHelper->publishDiagState();
|
this->haHelper->publishDiagState();
|
||||||
this->haHelper->publishExternalPumpState(false);
|
this->haHelper->publishExternalPumpState(false);
|
||||||
|
this->haHelper->publishExtDevState(String(settings.externalDev.caption), false);
|
||||||
|
|
||||||
|
|
||||||
// sensors
|
// sensors
|
||||||
this->haHelper->publishFaultCode();
|
this->haHelper->publishFaultCode();
|
||||||
@@ -557,7 +562,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool publishNonStaticHaEntities(bool force = false) {
|
bool publishNonStaticHaEntities(bool force = false) {
|
||||||
static uint8_t _heatingMinTemp, _heatingMaxTemp, _dhwMinTemp, _dhwMaxTemp = 0;
|
static byte _heatingMinTemp, _heatingMaxTemp, _dhwMinTemp, _dhwMaxTemp = 0;
|
||||||
static bool _indoorTempControl, _dhwSupport = false;
|
static bool _indoorTempControl, _dhwSupport = false;
|
||||||
|
|
||||||
bool published = false;
|
bool published = false;
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ protected:
|
|||||||
|
|
||||||
CustomOpenTherm* instance = nullptr;
|
CustomOpenTherm* instance = nullptr;
|
||||||
unsigned long instanceCreatedTime = 0;
|
unsigned long instanceCreatedTime = 0;
|
||||||
uint8_t instanceInGpio = 0;
|
byte instanceInGpio = 0;
|
||||||
uint8_t instanceOutGpio = 0;
|
byte instanceOutGpio = 0;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
unsigned long connectedTime = 0;
|
unsigned long connectedTime = 0;
|
||||||
unsigned long disconnectedTime = 0;
|
unsigned long disconnectedTime = 0;
|
||||||
@@ -31,7 +31,7 @@ protected:
|
|||||||
unsigned long heatingSetTempTime = 0;
|
unsigned long heatingSetTempTime = 0;
|
||||||
unsigned long dhwSetTempTime = 0;
|
unsigned long dhwSetTempTime = 0;
|
||||||
unsigned long ch2SetTempTime = 0;
|
unsigned long ch2SetTempTime = 0;
|
||||||
uint8_t configuredRxLedGpio = GPIO_IS_NOT_CONFIGURED;
|
byte configuredRxLedGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
const char* getTaskName() override {
|
const char* getTaskName() override {
|
||||||
@@ -90,7 +90,7 @@ protected:
|
|||||||
|
|
||||||
Log.sinfoln(FPSTR(L_OT), F("Started. GPIO IN: %hhu, GPIO OUT: %hhu"), settings.opentherm.inGpio, settings.opentherm.outGpio);
|
Log.sinfoln(FPSTR(L_OT), F("Started. GPIO IN: %hhu, GPIO OUT: %hhu"), settings.opentherm.inGpio, settings.opentherm.outGpio);
|
||||||
|
|
||||||
this->instance->setAfterSendRequestCallback([this](unsigned long request, unsigned long response, OpenThermResponseStatus status, uint8_t attempt) {
|
this->instance->setAfterSendRequestCallback([this](unsigned long request, unsigned long response, OpenThermResponseStatus status, byte attempt) {
|
||||||
Log.sverboseln(
|
Log.sverboseln(
|
||||||
FPSTR(L_OT),
|
FPSTR(L_OT),
|
||||||
F("ID: %4d Request: %8lx Response: %8lx Msg type: %s Attempt: %2d Status: %s"),
|
F("ID: %4d Request: %8lx Response: %8lx Msg type: %s Attempt: %2d Status: %s"),
|
||||||
|
|||||||
@@ -213,8 +213,7 @@ protected:
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
float error = pidRegulator.setpoint - pidRegulator.input;
|
float error = pidRegulator.setpoint - pidRegulator.input;
|
||||||
bool hasDeadband = settings.pid.deadband.enabled
|
bool hasDeadband = (error > -(settings.pid.deadband.thresholdHigh))
|
||||||
&& (error > -(settings.pid.deadband.thresholdHigh))
|
|
||||||
&& (error < settings.pid.deadband.thresholdLow);
|
&& (error < settings.pid.deadband.thresholdLow);
|
||||||
|
|
||||||
if (hasDeadband) {
|
if (hasDeadband) {
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ public:
|
|||||||
|
|
||||||
uint8_t valueId = (uint8_t) valueType;
|
uint8_t valueId = (uint8_t) valueType;
|
||||||
if (!isValidValueId(valueId)) {
|
if (!isValidValueId(valueId)) {
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float value = 0.0f;
|
float value = 0.0f;
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ protected:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float sensorResistance = value > 1
|
const float sensorResistance = value > 0.001f
|
||||||
? DEFAULT_NTC_REF_RESISTANCE / (DEFAULT_NTC_VREF / (float) value - 1.0f)
|
? DEFAULT_NTC_REF_RESISTANCE / (DEFAULT_NTC_VREF / (float) value - 1.0f)
|
||||||
: 0.0f;
|
: 0.0f;
|
||||||
const float rawTemp = 1.0f / (
|
const float rawTemp = 1.0f / (
|
||||||
@@ -405,6 +405,7 @@ protected:
|
|||||||
|
|
||||||
#if USE_BLE
|
#if USE_BLE
|
||||||
void cleanBleInstances() {
|
void cleanBleInstances() {
|
||||||
|
#if USE_BLE
|
||||||
if (!NimBLEDevice::isInitialized()) {
|
if (!NimBLEDevice::isInitialized()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -441,13 +442,10 @@ protected:
|
|||||||
NimBLEDevice::deleteClient(client);
|
NimBLEDevice::deleteClient(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pollingBleSensors() {
|
void pollingBleSensors() {
|
||||||
if (!Sensors::getAmountByType(Sensors::Type::BLUETOOTH, true)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!NimBLEDevice::isInitialized() && millis() > 5000) {
|
if (!NimBLEDevice::isInitialized() && millis() > 5000) {
|
||||||
Log.sinfoln(FPSTR(L_SENSORS_BLE), F("Initialized"));
|
Log.sinfoln(FPSTR(L_SENSORS_BLE), F("Initialized"));
|
||||||
BLEDevice::init("");
|
BLEDevice::init("");
|
||||||
@@ -579,7 +577,7 @@ protected:
|
|||||||
|
|
||||||
bool subscribeToBleDevice(const uint8_t sensorId, NimBLEClient* pClient) {
|
bool subscribeToBleDevice(const uint8_t sensorId, NimBLEClient* pClient) {
|
||||||
auto& sSensor = Sensors::settings[sensorId];
|
auto& sSensor = Sensors::settings[sensorId];
|
||||||
auto pAddress = pClient->getPeerAddress().toString();
|
auto pAddress = pClient->getPeerAddress().toString().c_str();
|
||||||
|
|
||||||
NimBLERemoteService* pService = nullptr;
|
NimBLERemoteService* pService = nullptr;
|
||||||
NimBLERemoteCharacteristic* pChar = nullptr;
|
NimBLERemoteCharacteristic* pChar = nullptr;
|
||||||
@@ -590,13 +588,13 @@ protected:
|
|||||||
if (!pService) {
|
if (!pService) {
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to find env service (%s) on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to find env service (%s) on device %s"),
|
||||||
sensorId, sSensor.name, serviceUuid.toString().c_str(), pAddress.c_str()
|
sensorId, sSensor.name, serviceUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found env service (%s) on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found env service (%s) on device %s"),
|
||||||
sensorId, sSensor.name, serviceUuid.toString().c_str(), pAddress.c_str()
|
sensorId, sSensor.name, serviceUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
// 0x2A6E - Notify temperature x0.01C (pvvx)
|
// 0x2A6E - Notify temperature x0.01C (pvvx)
|
||||||
@@ -608,7 +606,7 @@ protected:
|
|||||||
if (pChar && (pChar->canNotify() || pChar->canIndicate())) {
|
if (pChar && (pChar->canNotify() || pChar->canIndicate())) {
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found temp char (%s) in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found temp char (%s) in env service on device %s"),
|
||||||
sensorId, sSensor.name, charUuid.toString().c_str(), pAddress.c_str()
|
sensorId, sSensor.name, charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
pChar->unsubscribe();
|
pChar->unsubscribe();
|
||||||
@@ -663,14 +661,14 @@ protected:
|
|||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': subscribed to temp char (%s) in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': subscribed to temp char (%s) in env service on device %s"),
|
||||||
sensorId, sSensor.name,
|
sensorId, sSensor.name,
|
||||||
charUuid.toString().c_str(), pAddress.c_str()
|
charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.swarningln(
|
Log.swarningln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to subscribe to temp char (%s) in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to subscribe to temp char (%s) in env service on device %s"),
|
||||||
sensorId, sSensor.name,
|
sensorId, sSensor.name,
|
||||||
charUuid.toString().c_str(), pAddress.c_str()
|
charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -685,7 +683,7 @@ protected:
|
|||||||
if (pChar && (pChar->canNotify() || pChar->canIndicate())) {
|
if (pChar && (pChar->canNotify() || pChar->canIndicate())) {
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found temp char (%s) in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found temp char (%s) in env service on device %s"),
|
||||||
sensorId, sSensor.name, charUuid.toString().c_str(), pAddress.c_str()
|
sensorId, sSensor.name, charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
pChar->unsubscribe();
|
pChar->unsubscribe();
|
||||||
@@ -740,14 +738,14 @@ protected:
|
|||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': subscribed to temp char (%s) in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': subscribed to temp char (%s) in env service on device %s"),
|
||||||
sensorId, sSensor.name,
|
sensorId, sSensor.name,
|
||||||
charUuid.toString().c_str(), pAddress.c_str()
|
charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.swarningln(
|
Log.swarningln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to subscribe to temp char (%s) in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to subscribe to temp char (%s) in env service on device %s"),
|
||||||
sensorId, sSensor.name,
|
sensorId, sSensor.name,
|
||||||
charUuid.toString().c_str(), pAddress.c_str()
|
charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -756,7 +754,7 @@ protected:
|
|||||||
if (!tempNotifyCreated) {
|
if (!tempNotifyCreated) {
|
||||||
Log.swarningln(
|
Log.swarningln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': not found supported temp chars in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': not found supported temp chars in env service on device %s"),
|
||||||
sensorId, sSensor.name, pAddress.c_str()
|
sensorId, sSensor.name, pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
pClient->disconnect();
|
pClient->disconnect();
|
||||||
@@ -774,7 +772,7 @@ protected:
|
|||||||
if (pChar && (pChar->canNotify() || pChar->canIndicate())) {
|
if (pChar && (pChar->canNotify() || pChar->canIndicate())) {
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found humidity char (%s) in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found humidity char (%s) in env service on device %s"),
|
||||||
sensorId, sSensor.name, charUuid.toString().c_str(), pAddress.c_str()
|
sensorId, sSensor.name, charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
pChar->unsubscribe();
|
pChar->unsubscribe();
|
||||||
@@ -829,14 +827,14 @@ protected:
|
|||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': subscribed to humidity char (%s) in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': subscribed to humidity char (%s) in env service on device %s"),
|
||||||
sensorId, sSensor.name,
|
sensorId, sSensor.name,
|
||||||
charUuid.toString().c_str(), pAddress.c_str()
|
charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.swarningln(
|
Log.swarningln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to subscribe to humidity char (%s) in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to subscribe to humidity char (%s) in env service on device %s"),
|
||||||
sensorId, sSensor.name,
|
sensorId, sSensor.name,
|
||||||
charUuid.toString().c_str(), pAddress.c_str()
|
charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -845,7 +843,7 @@ protected:
|
|||||||
if (!humidityNotifyCreated) {
|
if (!humidityNotifyCreated) {
|
||||||
Log.swarningln(
|
Log.swarningln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': not found supported humidity chars in env service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': not found supported humidity chars in env service on device %s"),
|
||||||
sensorId, sSensor.name, pAddress.c_str()
|
sensorId, sSensor.name, pAddress
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -859,13 +857,13 @@ protected:
|
|||||||
if (!pService) {
|
if (!pService) {
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to find battery service (%s) on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to find battery service (%s) on device %s"),
|
||||||
sensorId, sSensor.name, serviceUuid.toString().c_str(), pAddress.c_str()
|
sensorId, sSensor.name, serviceUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found battery service (%s) on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found battery service (%s) on device %s"),
|
||||||
sensorId, sSensor.name, serviceUuid.toString().c_str(), pAddress.c_str()
|
sensorId, sSensor.name, serviceUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
// 0x2A19 - Notify the battery charge level 0..99% (pvvx)
|
// 0x2A19 - Notify the battery charge level 0..99% (pvvx)
|
||||||
@@ -877,7 +875,7 @@ protected:
|
|||||||
if (pChar && (pChar->canNotify() || pChar->canIndicate())) {
|
if (pChar && (pChar->canNotify() || pChar->canIndicate())) {
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found battery char (%s) in battery service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': found battery char (%s) in battery service on device %s"),
|
||||||
sensorId, sSensor.name, charUuid.toString().c_str(), pAddress.c_str()
|
sensorId, sSensor.name, charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
pChar->unsubscribe();
|
pChar->unsubscribe();
|
||||||
@@ -932,14 +930,14 @@ protected:
|
|||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': subscribed to battery char (%s) in battery service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': subscribed to battery char (%s) in battery service on device %s"),
|
||||||
sensorId, sSensor.name,
|
sensorId, sSensor.name,
|
||||||
charUuid.toString().c_str(), pAddress.c_str()
|
charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.swarningln(
|
Log.swarningln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to subscribe to battery char (%s) in battery service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': failed to subscribe to battery char (%s) in battery service on device %s"),
|
||||||
sensorId, sSensor.name,
|
sensorId, sSensor.name,
|
||||||
charUuid.toString().c_str(), pAddress.c_str()
|
charUuid.toString().c_str(), pAddress
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -948,7 +946,7 @@ protected:
|
|||||||
if (!batteryNotifyCreated) {
|
if (!batteryNotifyCreated) {
|
||||||
Log.swarningln(
|
Log.swarningln(
|
||||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': not found supported battery chars in battery service on device %s"),
|
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu '%s': not found supported battery chars in battery service on device %s"),
|
||||||
sensorId, sSensor.name, pAddress.c_str()
|
sensorId, sSensor.name, pAddress
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ struct NetworkSettings {
|
|||||||
struct {
|
struct {
|
||||||
char ssid[33] = DEFAULT_AP_SSID;
|
char ssid[33] = DEFAULT_AP_SSID;
|
||||||
char password[65] = DEFAULT_AP_PASSWORD;
|
char password[65] = DEFAULT_AP_PASSWORD;
|
||||||
uint8_t channel = 6;
|
byte channel = 6;
|
||||||
} ap;
|
} ap;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
char ssid[33] = DEFAULT_STA_SSID;
|
char ssid[33] = DEFAULT_STA_SSID;
|
||||||
char password[65] = DEFAULT_STA_PASSWORD;
|
char password[65] = DEFAULT_STA_PASSWORD;
|
||||||
uint8_t channel = 0;
|
byte channel = 0;
|
||||||
} sta;
|
} sta;
|
||||||
} networkSettings;
|
} networkSettings;
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ struct Settings {
|
|||||||
} ntp;
|
} ntp;
|
||||||
|
|
||||||
UnitSystem unitSystem = UnitSystem::METRIC;
|
UnitSystem unitSystem = UnitSystem::METRIC;
|
||||||
uint8_t statusLedGpio = DEFAULT_STATUS_LED_GPIO;
|
byte statusLedGpio = DEFAULT_STATUS_LED_GPIO;
|
||||||
} system;
|
} system;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -54,9 +54,9 @@ struct Settings {
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
UnitSystem unitSystem = UnitSystem::METRIC;
|
UnitSystem unitSystem = UnitSystem::METRIC;
|
||||||
uint8_t inGpio = DEFAULT_OT_IN_GPIO;
|
byte inGpio = DEFAULT_OT_IN_GPIO;
|
||||||
uint8_t outGpio = DEFAULT_OT_OUT_GPIO;
|
byte outGpio = DEFAULT_OT_OUT_GPIO;
|
||||||
uint8_t rxLedGpio = DEFAULT_OT_RX_LED_GPIO;
|
byte rxLedGpio = DEFAULT_OT_RX_LED_GPIO;
|
||||||
uint8_t memberId = 0;
|
uint8_t memberId = 0;
|
||||||
uint8_t flags = 0;
|
uint8_t flags = 0;
|
||||||
float minPower = 0.0f;
|
float minPower = 0.0f;
|
||||||
@@ -105,8 +105,8 @@ struct Settings {
|
|||||||
float target = DEFAULT_HEATING_TARGET_TEMP;
|
float target = DEFAULT_HEATING_TARGET_TEMP;
|
||||||
float hysteresis = 0.5f;
|
float hysteresis = 0.5f;
|
||||||
float turboFactor = 7.5f;
|
float turboFactor = 7.5f;
|
||||||
uint8_t minTemp = DEFAULT_HEATING_MIN_TEMP;
|
byte minTemp = DEFAULT_HEATING_MIN_TEMP;
|
||||||
uint8_t maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
byte maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
||||||
uint8_t maxModulation = 100;
|
uint8_t maxModulation = 100;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -123,8 +123,8 @@ struct Settings {
|
|||||||
struct {
|
struct {
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
float target = DEFAULT_DHW_TARGET_TEMP;
|
float target = DEFAULT_DHW_TARGET_TEMP;
|
||||||
uint8_t minTemp = DEFAULT_DHW_MIN_TEMP;
|
byte minTemp = DEFAULT_DHW_MIN_TEMP;
|
||||||
uint8_t maxTemp = DEFAULT_DHW_MAX_TEMP;
|
byte maxTemp = DEFAULT_DHW_MAX_TEMP;
|
||||||
uint8_t maxModulation = 100;
|
uint8_t maxModulation = 100;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -161,24 +161,31 @@ struct Settings {
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool use = false;
|
bool use = false;
|
||||||
uint8_t gpio = DEFAULT_EXT_PUMP_GPIO;
|
byte gpio = DEFAULT_EXT_PUMP_GPIO;
|
||||||
unsigned short postCirculationTime = 600;
|
unsigned short postCirculationTime = 600;
|
||||||
unsigned int antiStuckInterval = 2592000;
|
unsigned int antiStuckInterval = 2592000;
|
||||||
unsigned short antiStuckTime = 300;
|
unsigned short antiStuckTime = 300;
|
||||||
} externalPump;
|
} externalPump;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool use = false;
|
||||||
|
byte gpio = DEFAULT_EXT_DEV_GPIO;
|
||||||
|
char caption[41] = DEFAULT_EXT_DEV_CAPTION;
|
||||||
|
bool state = false;
|
||||||
|
} externalDev;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct {
|
struct {
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
uint8_t gpio = GPIO_IS_NOT_CONFIGURED;
|
byte gpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
bool invertState = false;
|
byte invertState = false;
|
||||||
unsigned short thresholdTime = 60;
|
unsigned short thresholdTime = 60;
|
||||||
} input;
|
} input;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
uint8_t gpio = GPIO_IS_NOT_CONFIGURED;
|
byte gpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
bool invertState = false;
|
byte invertState = false;
|
||||||
unsigned short thresholdTime = 60;
|
unsigned short thresholdTime = 60;
|
||||||
bool onFault = true;
|
bool onFault = true;
|
||||||
bool onLossConnection = true;
|
bool onLossConnection = true;
|
||||||
@@ -279,6 +286,10 @@ struct Variables {
|
|||||||
unsigned long lastEnabledTime = 0;
|
unsigned long lastEnabledTime = 0;
|
||||||
} externalPump;
|
} externalPump;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool state = false;
|
||||||
|
} externalDev;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool input = false;
|
bool input = false;
|
||||||
bool output = false;
|
bool output = false;
|
||||||
|
|||||||
@@ -146,6 +146,14 @@
|
|||||||
#define DEFAULT_EXT_PUMP_GPIO GPIO_IS_NOT_CONFIGURED
|
#define DEFAULT_EXT_PUMP_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEFAULT_EXT_DEV_GPIO
|
||||||
|
#define DEFAULT_EXT_DEV_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEFAULT_EXT_DEV_CAPTION
|
||||||
|
#define DEFAULT_EXT_DEV_CAPTION "Device"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef PROGMEM
|
#ifndef PROGMEM
|
||||||
#define PROGMEM
|
#define PROGMEM
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ const char L_REGULATOR_EQUITHERM[] PROGMEM = "REGULATOR.EQUITHE
|
|||||||
const char L_CASCADE_INPUT[] PROGMEM = "CASCADE.INPUT";
|
const char L_CASCADE_INPUT[] PROGMEM = "CASCADE.INPUT";
|
||||||
const char L_CASCADE_OUTPUT[] PROGMEM = "CASCADE.OUTPUT";
|
const char L_CASCADE_OUTPUT[] PROGMEM = "CASCADE.OUTPUT";
|
||||||
const char L_EXTPUMP[] PROGMEM = "EXTPUMP";
|
const char L_EXTPUMP[] PROGMEM = "EXTPUMP";
|
||||||
|
const char L_EXTDEV[] PROGMEM = "EXTDEV";
|
||||||
|
|
||||||
|
|
||||||
const char S_ACTIONS[] PROGMEM = "actions";
|
const char S_ACTIONS[] PROGMEM = "actions";
|
||||||
@@ -82,6 +83,8 @@ const char S_ENV[] PROGMEM = "env";
|
|||||||
const char S_EPC[] PROGMEM = "epc";
|
const char S_EPC[] PROGMEM = "epc";
|
||||||
const char S_EQUITHERM[] PROGMEM = "equitherm";
|
const char S_EQUITHERM[] PROGMEM = "equitherm";
|
||||||
const char S_EXTERNAL_PUMP[] PROGMEM = "externalPump";
|
const char S_EXTERNAL_PUMP[] PROGMEM = "externalPump";
|
||||||
|
const char S_EXTERNAL_DEV[] PROGMEM = "externalDev";
|
||||||
|
const char S_EXTERNAL_DEV_CAPTION[] PROGMEM = "caption";
|
||||||
const char S_FACTOR[] PROGMEM = "factor";
|
const char S_FACTOR[] PROGMEM = "factor";
|
||||||
const char S_FAULT[] PROGMEM = "fault";
|
const char S_FAULT[] PROGMEM = "fault";
|
||||||
const char S_FREEZE_PROTECTION[] PROGMEM = "freezeProtection";
|
const char S_FREEZE_PROTECTION[] PROGMEM = "freezeProtection";
|
||||||
|
|||||||
63
src/utils.h
63
src/utils.h
@@ -72,7 +72,7 @@ time_t mkgmtime(const struct tm *ptm) {
|
|||||||
|
|
||||||
inline bool isDigit(const char* ptr) {
|
inline bool isDigit(const char* ptr) {
|
||||||
char* endPtr;
|
char* endPtr;
|
||||||
auto tmp = strtol(ptr, &endPtr, 10);
|
strtol(ptr, &endPtr, 10);
|
||||||
return *endPtr == 0;
|
return *endPtr == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,6 +561,15 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
|
|||||||
cascadeControlOutput[FPSTR(S_ON_LOSS_CONNECTION)] = src.cascadeControl.output.onLossConnection;
|
cascadeControlOutput[FPSTR(S_ON_LOSS_CONNECTION)] = src.cascadeControl.output.onLossConnection;
|
||||||
cascadeControlOutput[FPSTR(S_ON_ENABLED_HEATING)] = src.cascadeControl.output.onEnabledHeating;
|
cascadeControlOutput[FPSTR(S_ON_ENABLED_HEATING)] = src.cascadeControl.output.onEnabledHeating;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!safe ) {
|
||||||
|
dst[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_USE)] = src.externalDev.use;
|
||||||
|
dst[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_GPIO)] = src.externalDev.gpio;
|
||||||
|
dst[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_EXTERNAL_DEV_CAPTION)] = src.externalDev.caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(src.externalDev.use)
|
||||||
|
dst[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_STATE)] = src.externalDev.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void safeSettingsToJson(const Settings& src, JsonVariant dst) {
|
inline void safeSettingsToJson(const Settings& src, JsonVariant dst) {
|
||||||
@@ -1324,7 +1333,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
if (!src[FPSTR(S_HEATING)][FPSTR(S_MIN_TEMP)].isNull()) {
|
if (!src[FPSTR(S_HEATING)][FPSTR(S_MIN_TEMP)].isNull()) {
|
||||||
unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_MIN_TEMP)].as<unsigned char>();
|
unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_MIN_TEMP)].as<unsigned char>();
|
||||||
|
|
||||||
if (value != dst.heating.minTemp && value >= vars.slave.heating.minTemp && value < vars.slave.heating.maxTemp && value != dst.heating.maxTemp) {
|
if (value != dst.heating.minTemp && value >= vars.slave.heating.minTemp && value < vars.slave.heating.maxTemp && value != dst.heating.minTemp) {
|
||||||
dst.heating.minTemp = value;
|
dst.heating.minTemp = value;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
@@ -1333,7 +1342,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
if (!src[FPSTR(S_HEATING)][FPSTR(S_MAX_TEMP)].isNull()) {
|
if (!src[FPSTR(S_HEATING)][FPSTR(S_MAX_TEMP)].isNull()) {
|
||||||
unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_MAX_TEMP)].as<unsigned char>();
|
unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_MAX_TEMP)].as<unsigned char>();
|
||||||
|
|
||||||
if (value != dst.heating.maxTemp && value > vars.slave.heating.minTemp && value <= vars.slave.heating.maxTemp && value != dst.heating.minTemp) {
|
if (value != dst.heating.maxTemp && value > vars.slave.heating.minTemp && value <= vars.slave.heating.maxTemp && value != dst.heating.maxTemp) {
|
||||||
dst.heating.maxTemp = value;
|
dst.heating.maxTemp = value;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
@@ -1531,6 +1540,42 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// external device
|
||||||
|
if (src[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_USE)].is<bool>()) {
|
||||||
|
bool value = src[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_USE)].as<bool>();
|
||||||
|
|
||||||
|
if (value != dst.externalDev.use) {
|
||||||
|
dst.externalDev.use = value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_GPIO)].isNull()) {
|
||||||
|
if (src[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_GPIO)].is<JsonString>() &&
|
||||||
|
src[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_GPIO)].as<JsonString>().size() == 0) {
|
||||||
|
if (dst.externalDev.gpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
dst.externalDev.gpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
unsigned char value = src[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_GPIO)].as<unsigned char>();
|
||||||
|
|
||||||
|
if (GPIO_IS_VALID(value) && value != dst.externalDev.gpio) {
|
||||||
|
dst.externalDev.gpio = value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_EXTERNAL_DEV_CAPTION)].isNull()) {
|
||||||
|
String value = src[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_EXTERNAL_DEV_CAPTION)].as<String>();
|
||||||
|
|
||||||
|
if (value.length() < sizeof(dst.externalDev.caption) && !String(dst.externalDev.caption).equals(value)) {
|
||||||
|
strcpy(dst.externalDev.caption, value.c_str());
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// cascade control
|
// cascade control
|
||||||
if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_ENABLED)].is<bool>()) {
|
if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_ENABLED)].is<bool>()) {
|
||||||
@@ -1653,6 +1698,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dst.externalDev.use && src[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_STATE)].is<bool>()) {
|
||||||
|
bool value = src[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_STATE)].as<bool>();
|
||||||
|
|
||||||
|
if (value != dst.externalDev.state) {
|
||||||
|
dst.externalDev.state = value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// force check emergency target
|
// force check emergency target
|
||||||
{
|
{
|
||||||
float value = !src[FPSTR(S_EMERGENCY)][FPSTR(S_TARGET)].isNull() ? src[FPSTR(S_EMERGENCY)][FPSTR(S_TARGET)].as<float>() : dst.emergency.target;
|
float value = !src[FPSTR(S_EMERGENCY)][FPSTR(S_TARGET)].isNull() ? src[FPSTR(S_EMERGENCY)][FPSTR(S_TARGET)].as<float>() : dst.emergency.target;
|
||||||
@@ -1894,7 +1948,7 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se
|
|||||||
|
|
||||||
// gpio
|
// gpio
|
||||||
if (!src[FPSTR(S_GPIO)].isNull()) {
|
if (!src[FPSTR(S_GPIO)].isNull()) {
|
||||||
if (dst.type != Sensors::Type::DALLAS_TEMP && dst.type != Sensors::Type::NTC_10K_TEMP) {
|
if (dst.type != Sensors::Type::DALLAS_TEMP && dst.type == Sensors::Type::BLUETOOTH && dst.type == Sensors::Type::NTC_10K_TEMP) {
|
||||||
if (dst.gpio != GPIO_IS_NOT_CONFIGURED) {
|
if (dst.gpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
dst.gpio = GPIO_IS_NOT_CONFIGURED;
|
dst.gpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
changed = true;
|
changed = true;
|
||||||
@@ -2118,6 +2172,7 @@ void varsToJson(const Variables& src, JsonVariant dst) {
|
|||||||
master[FPSTR(S_MQTT)][FPSTR(S_CONNECTED)] = src.mqtt.connected;
|
master[FPSTR(S_MQTT)][FPSTR(S_CONNECTED)] = src.mqtt.connected;
|
||||||
master[FPSTR(S_EMERGENCY)][FPSTR(S_STATE)] = src.emergency.state;
|
master[FPSTR(S_EMERGENCY)][FPSTR(S_STATE)] = src.emergency.state;
|
||||||
master[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_STATE)] = src.externalPump.state;
|
master[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_STATE)] = src.externalPump.state;
|
||||||
|
master[FPSTR(S_EXTERNAL_DEV)][FPSTR(S_STATE)] = src.externalDev.state;
|
||||||
|
|
||||||
auto mCascadeControl = master[FPSTR(S_CASCADE_CONTROL)].to<JsonObject>();
|
auto mCascadeControl = master[FPSTR(S_CASCADE_CONTROL)].to<JsonObject>();
|
||||||
mCascadeControl[FPSTR(S_INPUT)] = src.cascadeControl.input;
|
mCascadeControl[FPSTR(S_INPUT)] = src.cascadeControl.input;
|
||||||
|
|||||||
@@ -104,6 +104,7 @@
|
|||||||
"mMqttConnected": "MQTT服务器连接状态",
|
"mMqttConnected": "MQTT服务器连接状态",
|
||||||
"mEmergencyState": "应急模式",
|
"mEmergencyState": "应急模式",
|
||||||
"mExtPumpState": "外置循环泵",
|
"mExtPumpState": "外置循环泵",
|
||||||
|
"mExtDevState": "外置设备",
|
||||||
"mCascadeControlInput": "Cascade 控制 (input)",
|
"mCascadeControlInput": "Cascade 控制 (input)",
|
||||||
"mCascadeControlOutput": "Cascade 控制 (output)",
|
"mCascadeControlOutput": "Cascade 控制 (output)",
|
||||||
|
|
||||||
@@ -289,6 +290,7 @@
|
|||||||
"ot": "OpenTherm协议设置",
|
"ot": "OpenTherm协议设置",
|
||||||
"mqtt": "MQTT 服务器设置",
|
"mqtt": "MQTT 服务器设置",
|
||||||
"extPump": "外置循环泵设置",
|
"extPump": "外置循环泵设置",
|
||||||
|
"extDev": "外置设备设置",
|
||||||
"cascadeControl": "Cascade 级联控制设置"
|
"cascadeControl": "Cascade 级联控制设置"
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -459,6 +461,13 @@
|
|||||||
"antiStuckTime": "防卡死运行时长<small>(分钟)</small>"
|
"antiStuckTime": "防卡死运行时长<small>(分钟)</small>"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"extDev": {
|
||||||
|
"use": "使用外置设备",
|
||||||
|
"gpio": "GPIO 继电器",
|
||||||
|
"state": "状态",
|
||||||
|
"caption": "说明"
|
||||||
|
},
|
||||||
|
|
||||||
"cascadeControl": {
|
"cascadeControl": {
|
||||||
"input": {
|
"input": {
|
||||||
"desc": "仅当另一台锅炉发生故障时启用本锅炉加热。另一台锅炉的控制器需在故障发生时切换GPIO输入状态以触发本功能。",
|
"desc": "仅当另一台锅炉发生故障时启用本锅炉加热。另一台锅炉的控制器需在故障发生时切换GPIO输入状态以触发本功能。",
|
||||||
|
|||||||
@@ -104,6 +104,7 @@
|
|||||||
"mMqttConnected": "MQTT connection",
|
"mMqttConnected": "MQTT connection",
|
||||||
"mEmergencyState": "Emergency mode",
|
"mEmergencyState": "Emergency mode",
|
||||||
"mExtPumpState": "External pump",
|
"mExtPumpState": "External pump",
|
||||||
|
"mExtDevState": "External device",
|
||||||
"mCascadeControlInput": "Cascade control (input)",
|
"mCascadeControlInput": "Cascade control (input)",
|
||||||
"mCascadeControlOutput": "Cascade control (output)",
|
"mCascadeControlOutput": "Cascade control (output)",
|
||||||
|
|
||||||
@@ -289,6 +290,7 @@
|
|||||||
"ot": "OpenTherm settings",
|
"ot": "OpenTherm settings",
|
||||||
"mqtt": "MQTT settings",
|
"mqtt": "MQTT settings",
|
||||||
"extPump": "External pump settings",
|
"extPump": "External pump settings",
|
||||||
|
"extDev": "External device settings",
|
||||||
"cascadeControl": "Cascade control settings"
|
"cascadeControl": "Cascade control settings"
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -458,6 +460,13 @@
|
|||||||
"antiStuckInterval": "Anti stuck interval <small>(days)</small>",
|
"antiStuckInterval": "Anti stuck interval <small>(days)</small>",
|
||||||
"antiStuckTime": "Anti stuck time <small>(min)</small>"
|
"antiStuckTime": "Anti stuck time <small>(min)</small>"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"extDev": {
|
||||||
|
"use": "Use external device",
|
||||||
|
"gpio": "Relay GPIO",
|
||||||
|
"state": "State",
|
||||||
|
"caption": "Caption"
|
||||||
|
},
|
||||||
|
|
||||||
"cascadeControl": {
|
"cascadeControl": {
|
||||||
"input": {
|
"input": {
|
||||||
|
|||||||
@@ -104,6 +104,7 @@
|
|||||||
"mMqttConnected": "Connessione MQTT",
|
"mMqttConnected": "Connessione MQTT",
|
||||||
"mEmergencyState": "Modo Emergenza",
|
"mEmergencyState": "Modo Emergenza",
|
||||||
"mExtPumpState": "Pompa esterna",
|
"mExtPumpState": "Pompa esterna",
|
||||||
|
"mExtDevState": "Dispositivo esterno",
|
||||||
"mCascadeControlInput": "Controllo a cascata (input)",
|
"mCascadeControlInput": "Controllo a cascata (input)",
|
||||||
"mCascadeControlOutput": "Controllo a cascata (output)",
|
"mCascadeControlOutput": "Controllo a cascata (output)",
|
||||||
|
|
||||||
@@ -289,6 +290,7 @@
|
|||||||
"ot": "Impostazioni OpenTherm",
|
"ot": "Impostazioni OpenTherm",
|
||||||
"mqtt": "Impostazioni MQTT",
|
"mqtt": "Impostazioni MQTT",
|
||||||
"extPump": "Impostazioni pompa esterna",
|
"extPump": "Impostazioni pompa esterna",
|
||||||
|
"extDev": "Impostazioni dispositivo esterno",
|
||||||
"cascadeControl": "Impostazioni controllo a cascata"
|
"cascadeControl": "Impostazioni controllo a cascata"
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -459,6 +461,13 @@
|
|||||||
"antiStuckTime": "Tempo antiblocco <small>(min)</small>"
|
"antiStuckTime": "Tempo antiblocco <small>(min)</small>"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"extDev": {
|
||||||
|
"use": "Usa dispositivo esterno",
|
||||||
|
"gpio": "GPIO relè",
|
||||||
|
"state": "Stato",
|
||||||
|
"caption": "Didascalia"
|
||||||
|
},
|
||||||
|
|
||||||
"cascadeControl": {
|
"cascadeControl": {
|
||||||
"input": {
|
"input": {
|
||||||
"desc": "Può essere attivata la caldaia se un'altra ha fallito. Il controllo dell'altra caldaia cambia lo stato dell'ingresso del GPIO in caso di errore.",
|
"desc": "Può essere attivata la caldaia se un'altra ha fallito. Il controllo dell'altra caldaia cambia lo stato dell'ingresso del GPIO in caso di errore.",
|
||||||
|
|||||||
@@ -104,6 +104,7 @@
|
|||||||
"mMqttConnected": "Подключение к MQTT",
|
"mMqttConnected": "Подключение к MQTT",
|
||||||
"mEmergencyState": "Аварийный режим",
|
"mEmergencyState": "Аварийный режим",
|
||||||
"mExtPumpState": "Внешний насос",
|
"mExtPumpState": "Внешний насос",
|
||||||
|
"mExtDevState": "Внешнее устройство",
|
||||||
"mCascadeControlInput": "Каскадное управление (вход)",
|
"mCascadeControlInput": "Каскадное управление (вход)",
|
||||||
"mCascadeControlOutput": "Каскадное управление (выход)",
|
"mCascadeControlOutput": "Каскадное управление (выход)",
|
||||||
|
|
||||||
@@ -289,6 +290,7 @@
|
|||||||
"ot": "Настройки OpenTherm",
|
"ot": "Настройки OpenTherm",
|
||||||
"mqtt": "Настройки MQTT",
|
"mqtt": "Настройки MQTT",
|
||||||
"extPump": "Настройки дополнительного насоса",
|
"extPump": "Настройки дополнительного насоса",
|
||||||
|
"extDev": "Настройки внешнего устройства",
|
||||||
"cascadeControl": "Настройки каскадного управления"
|
"cascadeControl": "Настройки каскадного управления"
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -459,6 +461,13 @@
|
|||||||
"antiStuckTime": "Время работы насоса <small>(в минутах)</small>"
|
"antiStuckTime": "Время работы насоса <small>(в минутах)</small>"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"extDev": {
|
||||||
|
"use": "Использовать внешнее устройство",
|
||||||
|
"gpio": "GPIO реле",
|
||||||
|
"state": "Состояние",
|
||||||
|
"caption": "Назначение"
|
||||||
|
},
|
||||||
|
|
||||||
"cascadeControl": {
|
"cascadeControl": {
|
||||||
"input": {
|
"input": {
|
||||||
"desc": "Может использоваться для включения отопления только при неисправности другого котла. Контроллер другого котла должен изменить состояние входа GPIO в случае неисправности.",
|
"desc": "Может использоваться для включения отопления только при неисправности другого котла. Контроллер другого котла должен изменить состояние входа GPIO в случае неисправности.",
|
||||||
|
|||||||
@@ -135,6 +135,10 @@
|
|||||||
<th scope="row" data-i18n>dashboard.states.mExtPumpState</th>
|
<th scope="row" data-i18n>dashboard.states.mExtPumpState</th>
|
||||||
<td><i class="mExtPumpState"></i></td>
|
<td><i class="mExtPumpState"></i></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row" data-i18n>dashboard.states.mExtDevState</th>
|
||||||
|
<td><i class="mExtDevState"></i></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row" data-i18n>dashboard.states.mCascadeControlInput</th>
|
<th scope="row" data-i18n>dashboard.states.mCascadeControlInput</th>
|
||||||
<td><i class="mCascadeControlInput"></i></td>
|
<td><i class="mCascadeControlInput"></i></td>
|
||||||
@@ -658,6 +662,7 @@
|
|||||||
result.master.emergency.state ? "red" : "green"
|
result.master.emergency.state ? "red" : "green"
|
||||||
);
|
);
|
||||||
setState('.mExtPumpState', result.master.externalPump.state);
|
setState('.mExtPumpState', result.master.externalPump.state);
|
||||||
|
setState('.mExtDevState', result.master.externalDev.state);
|
||||||
setState('.mCascadeControlInput', result.master.cascadeControl.input);
|
setState('.mCascadeControlInput', result.master.cascadeControl.input);
|
||||||
setState('.mCascadeControlOutput', result.master.cascadeControl.output);
|
setState('.mCascadeControlOutput', result.master.cascadeControl.output);
|
||||||
|
|
||||||
|
|||||||
@@ -763,6 +763,42 @@
|
|||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b data-i18n>settings.section.extDev</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="extdev-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="extdev-settings" class="hidden">
|
||||||
|
<fieldset>
|
||||||
|
<label for="extdev-use">
|
||||||
|
<input type="checkbox" id="extdev-use" name="externalDev[use]" value="false">
|
||||||
|
<span data-i18n>settings.extDev.use</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="extdev-state">
|
||||||
|
<input type="checkbox" id="extdev-state" name="externalDev[state]" value="false">
|
||||||
|
<span data-i18n>settings.extDev.state</span>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="extdev-gpio">
|
||||||
|
<span data-i18n>settings.extDev.gpio</span>
|
||||||
|
<input type="number" inputmode="numeric" id="extdev-gpio" name="externalDev[gpio]" min="0" max="254" step="1">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="extdev-caption">
|
||||||
|
<span data-i18n>settings.extDev.caption</span>
|
||||||
|
<input type="text" id="extdev-caption" name="externalDev[caption]" maxlength="40" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" data-i18n>button.save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><b data-i18n>settings.section.cascadeControl</b></summary>
|
<summary><b data-i18n>settings.section.cascadeControl</b></summary>
|
||||||
<div>
|
<div>
|
||||||
@@ -932,6 +968,13 @@
|
|||||||
setInputValue("[name='externalPump[antiStuckTime]']", data.externalPump.antiStuckTime);
|
setInputValue("[name='externalPump[antiStuckTime]']", data.externalPump.antiStuckTime);
|
||||||
setBusy('#extpump-settings-busy', '#extpump-settings', false);
|
setBusy('#extpump-settings-busy', '#extpump-settings', false);
|
||||||
|
|
||||||
|
// Extdev
|
||||||
|
setCheckboxValue('#extdev-use', data.externalDev.use);
|
||||||
|
setInputValue('#extdev-gpio', data.externalDev.gpio < 255 ? data.externalDev.gpio : '');
|
||||||
|
setInputValue('#extdev-caption', data.externalDev.caption);
|
||||||
|
setCheckboxValue('#extdev-state', data.externalDev.state);
|
||||||
|
setBusy('#extdev-settings-busy', '#extdev-settings', false);
|
||||||
|
|
||||||
// Cascade control
|
// Cascade control
|
||||||
setCheckboxValue("[name='cascadeControl[input][enabled]']", data.cascadeControl.input.enabled);
|
setCheckboxValue("[name='cascadeControl[input][enabled]']", data.cascadeControl.input.enabled);
|
||||||
setInputValue("[name='cascadeControl[input][gpio]']", data.cascadeControl.input.gpio < 255 ? data.cascadeControl.input.gpio : '');
|
setInputValue("[name='cascadeControl[input][gpio]']", data.cascadeControl.input.gpio < 255 ? data.cascadeControl.input.gpio : '');
|
||||||
@@ -1085,6 +1128,7 @@
|
|||||||
setupForm('#ot-settings', fillData);
|
setupForm('#ot-settings', fillData);
|
||||||
setupForm('#mqtt-settings', fillData, ['mqtt.user', 'mqtt.password', 'mqtt.prefix']);
|
setupForm('#mqtt-settings', fillData, ['mqtt.user', 'mqtt.password', 'mqtt.prefix']);
|
||||||
setupForm('#extpump-settings', fillData);
|
setupForm('#extpump-settings', fillData);
|
||||||
|
setupForm('#extdev-settings', fillData);
|
||||||
setupForm('#cc-settings', fillData);
|
setupForm('#cc-settings', fillData);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user