Compare commits

..

19 Commits

Author SHA1 Message Date
Yurii 67adb3b9cf Merge branch 'async' into passive_ble 2026-01-26 02:23:19 +03:00
Yurii aae53d605a fix: move OpenThermTask to 0 core 2026-01-25 22:44:58 +03:00
Yurii de9276d04e refactor: cosmetic changes 2026-01-25 22:42:48 +03:00
Yurii cb8cd7c26e feat: added support BTHome v2 format for BLE sensors #215 2026-01-25 22:25:58 +03:00
Yurii 74e321cc1e Merge branch 'async' into passive_ble 2026-01-23 00:26:24 +03:00
Yurii 1e83f284cb chore: dependencies fixed 2026-01-19 22:03:04 +03:00
Yurii 27baf675e5 chore: reformat platformio.ini 2026-01-19 21:44:18 +03:00
Yurii 1fdc06fce6 Merge branch 'async' into passive_ble 2026-01-19 21:38:12 +03:00
Yurii c39eeee9cf Merge branch 'master' into passive_ble 2025-11-17 13:26:51 +03:00
Yurii f2fe6036c2 chore: fix dependencies 2025-11-17 13:24:43 +03:00
Yurii 40dc863530 refactor: improved OTA upgrade
https://github.com/ESP32Async/ESPAsyncWebServer/pull/329
2025-11-03 03:19:50 +03:00
Yurii a40413aeac style: formatting 2025-11-02 23:34:46 +03:00
Yurii 9a045bfc40 Merge branch 'async' into passive_ble 2025-11-02 11:45:06 +03:00
Yurii c78d2d0c0b refactor: reduced tasks stack size 2025-11-01 19:12:03 +03:00
Yurii b7825111bb refactor: active + passive BLE scanning 2025-10-22 20:37:36 +03:00
Yurii d5691ef8f7 refactor: decreased interval and window for scanning BLE 2025-10-22 17:22:02 +03:00
Yurii 0213582464 fix: build for nodemcu32, c3, c6 boards; formatting `platformio.ini` 2025-10-21 13:43:41 +03:00
Yurii 396dc7f7e3 refactor: increased disconnected timeout for sensors 2025-10-20 18:37:35 +03:00
Yurii 9d38525251 refactor: passive scan instead of connecting to BLE devices 2025-10-20 17:59:52 +03:00
31 changed files with 413 additions and 741 deletions
+1 -1
View File
@@ -1,5 +1,4 @@
.pio
.dummy
.vscode
.PVS-Studio
build/*
@@ -11,4 +10,5 @@ package-lock.json
*.lock
sdkconfig.*
CMakeLists.txt
!sdkconfig.defaults
!.gitkeep
+1 -10
View File
@@ -2,7 +2,6 @@
[![GitHub version](https://img.shields.io/github/release/Laxilef/OTGateway.svg?include_prereleases)](https://github.com/Laxilef/OTGateway/releases)
[![GitHub download](https://img.shields.io/github/downloads/Laxilef/OTGateway/total.svg)](https://github.com/Laxilef/OTGateway/releases/latest)
[![Translations](https://hosted.weblate.org/widget/otgateway/svg-badge.svg)](https://hosted.weblate.org/engage/otgateway/)
[![License](https://img.shields.io/github/license/Laxilef/OTGateway.svg)](LICENSE.txt)
[![Telegram](https://img.shields.io/badge/Telegram-Channel-33A8E3)](https://t.me/otgateway)
@@ -72,18 +71,10 @@ All available information and instructions can be found in the wiki:
* [Connection](https://github.com/Laxilef/OTGateway/wiki/OT-adapters#connection)
* [Leds on board](https://github.com/Laxilef/OTGateway/wiki/OT-adapters#leds-on-board)
## Translations
The project uses [Weblate](https://hosted.weblate.org/new-lang/otgateway/) to manage translations of the interface.<br />
Anyone is welcome to add their native language as a [new localization](https://hosted.weblate.org/new-lang/otgateway/portal/). All contributions are welcome!
<a href="https://hosted.weblate.org/engage/otgateway/">
<img src="https://hosted.weblate.org/widget/otgateway/multi-auto.svg" alt="Translation status" />
</a>
## 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 [PlatformIO](https://platformio.org/) Team
* 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 [PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.
* And of course to the contributors for their contribution to the development of the project!
* And of course to the contributors for their contribution to the development of the project!
+3 -3
View File
@@ -4,12 +4,12 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"cssnano": "^8.0.0",
"cssnano-preset-advanced": "^8.0.0",
"cssnano": "^7.0.2",
"cssnano-preset-advanced": "^7.0.2",
"gulp": "^5.0.0",
"gulp-concat": "^2.6.1",
"gulp-gzip": "^1.4.2",
"gulp-html-minifier-terser": "^8.0.0",
"gulp-html-minifier-terser": "^7.1.0",
"gulp-jsonminify": "^1.1.0",
"gulp-postcss": "^10.0.0",
"gulp-terser": "^2.1.0",
+13 -24
View File
@@ -4,12 +4,12 @@ extra_configs = secrets.default.ini
core_dir = .pio
[env]
version = 1.6.0-async
version = 1.6.0-passiveble
framework = arduino
lib_deps = ESP32Async/AsyncTCP@^3.4.10
ESP32Async/ESPAsyncWebServer@^3.11.0
mathieucarbou/MycilaWebSerial@^8.2.3
bblanchon/ArduinoJson@^7.4.3
ESP32Async/ESPAsyncWebServer@^3.9.4
mathieucarbou/MycilaWebSerial@^8.2.0
bblanchon/ArduinoJson@^7.4.2
;ihormelnyk/OpenTherm Library@^1.1.5
https://github.com/Laxilef/opentherm_library#esp32_timer
arduino-libraries/ArduinoMqttClient@^0.1.8
@@ -17,14 +17,13 @@ lib_deps = ESP32Async/AsyncTCP@^3.4.10
gyverlibs/GyverPID@^3.3.2
gyverlibs/GyverBlinker@^1.1.1
pstolarz/OneWireNg@^0.14.1
milesburton/DallasTemperature@^4.0.6
https://github.com/Laxilef/esp32DHT#idf5
;milesburton/DallasTemperature@^4.0.5
https://github.com/Laxilef/Arduino-Temperature-Control-Library#fix_85c
;laxilef/TinyLogger@^1.1.1
https://github.com/Laxilef/TinyLogger#custom_handlers
lib_ignore = OneWire
lib_ignore = paulstoffregen/OneWire
build_type = ${secrets.build_type}
build_flags = ;-mtext-section-literals
-O2
build_flags = -mtext-section-literals
-Wno-deprecated-declarations
-D MQTT_CLIENT_STD_FUNCTION_CALLBACK=1
;-D DEBUG_ESP_CORE -D DEBUG_ESP_WIFI -D DEBUG_ESP_HTTP_SERVER -D DEBUG_ESP_PORT=Serial
@@ -34,7 +33,6 @@ build_flags = ;-mtext-section-literals
-D ARDUINOJSON_USE_DOUBLE=0
-D ARDUINOJSON_USE_LONG_LONG=0
-D TINYLOGGER_GLOBAL
-D DHT_TASK_STACK_SIZE=4096
-D DEFAULT_SERIAL_ENABLED=${secrets.serial_enabled}
-D DEFAULT_SERIAL_BAUD=${secrets.serial_baud}
-D DEFAULT_WEBSERIAL_ENABLED=${secrets.webserial_enabled}
@@ -63,7 +61,7 @@ check_flags = ;pvs-studio: --analysis-mode=4 --exclude-path=./.pio/l
; Defaults
[esp32_defaults]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.37/platform-espressif32.zip
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.36/platform-espressif32.zip
platform_packages = ${env.platform_packages}
board_build.partitions = esp32_partitions.csv
lib_deps = ${env.lib_deps}
@@ -98,14 +96,10 @@ custom_component_remove = espressif/esp_hosted
espressif/esp-zboss-lib
espressif/esp-zigbee-lib
chmorgan/esp-libhelix-mp3
extra_scripts = pre:tools/add_build_commit.py
post:tools/esp32.py
extra_scripts = post:tools/esp32.py
post:tools/build.py
build_type = ${env.build_type}
build_flags = ${env.build_flags}
-D MYNEWT_VAL_BLE_MAX_CONNECTIONS=1
-D MYNEWT_VAL_BLE_STORE_MAX_BONDS=1
-D MYNEWT_VAL_BLE_ROLE_CENTRAL=0
-D CORE_DEBUG_LEVEL=0
-Wl,--wrap=esp_panic_handler
check_tool = ${env.check_tool}
@@ -150,7 +144,7 @@ extends = esp32_defaults
board = lolin_c3_mini
lib_deps = ${esp32_defaults.lib_deps}
${esp32_defaults.nimble_lib}
;build_unflags = -mtext-section-literals
build_unflags = -mtext-section-literals
build_flags = ${esp32_defaults.build_flags}
-D MYNEWT_VAL_BLE_EXT_ADV=1
-D USE_BLE=1
@@ -198,7 +192,7 @@ extends = esp32_defaults
board = esp32-c6-devkitc-1
lib_deps = ${esp32_defaults.lib_deps}
${esp32_defaults.nimble_lib}
;build_unflags = -mtext-section-literals
build_unflags = -mtext-section-literals
build_flags = ${esp32_defaults.build_flags}
-D USE_BLE=1
-D DEFAULT_OT_IN_GPIO=15
@@ -207,18 +201,13 @@ build_flags = ${esp32_defaults.build_flags}
-D DEFAULT_SENSOR_INDOOR_GPIO=0
-D DEFAULT_STATUS_LED_GPIO=11
-D DEFAULT_OT_RX_LED_GPIO=10
custom_sdkconfig = '# CONFIG_OPENTHREAD_ENABLED is not set'
'# CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT is not set'
'# CONFIG_LWIP_IPV6 is not set'
'# CONFIG_LWIP_IPV6_AUTOCONFIG is not set'
'# CONFIG_LWIP_PPP_SUPPORT is not set'
[env:otthing]
extends = esp32_defaults
board = lolin_c3_mini
lib_deps = ${esp32_defaults.lib_deps}
${esp32_defaults.nimble_lib}
;build_unflags = -mtext-section-literals
build_unflags = -mtext-section-literals
build_flags = ${esp32_defaults.build_flags}
-D MYNEWT_VAL_BLE_EXT_ADV=1
-D USE_BLE=1
+33
View File
@@ -0,0 +1,33 @@
# Source:
# https://github.com/pioarduino/platform-espressif32/tree/main/examples/espidf-arduino-h2zero-BLE_scan
CONFIG_FREERTOS_HZ=1000
CONFIG_MBEDTLS_PSK_MODES=y
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
#
# BT config
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
CONFIG_BTDM_CTRL_MODE_BTDM=n
CONFIG_BT_BLUEDROID_ENABLED=n
CONFIG_BT_NIMBLE_ENABLED=y
#
# Arduino Configuration
CONFIG_AUTOSTART_ARDUINO=y
CONFIG_ARDUINO_SELECTIVE_COMPILATION=y
CONFIG_ARDUINO_SELECTIVE_Zigbee=n
CONFIG_ARDUINO_SELECTIVE_Matter=n
CONFIG_ARDUINO_SELECTIVE_WiFiProv=n
CONFIG_ARDUINO_SELECTIVE_BLE=n
CONFIG_ARDUINO_SELECTIVE_BluetoothSerial=n
CONFIG_ARDUINO_SELECTIVE_SimpleBLE=n
CONFIG_ARDUINO_SELECTIVE_RainMaker=n
CONFIG_ARDUINO_SELECTIVE_OpenThread=n
CONFIG_ARDUINO_SELECTIVE_Insights=n
+2 -3
View File
@@ -176,10 +176,9 @@ public:
objId.c_str()
);
// set device class, name, value template for Bluetooth/DHT sensors
// set device class, name, value template for bluetooth sensors
// or name & value template for another sensors
if (sSensor.type == Sensors::Type::BLUETOOTH ||
sSensor.type == Sensors::Type::DHT11 || sSensor.type == Sensors::Type::DHT22) {
if (sSensor.type == Sensors::Type::BLUETOOTH) {
// available state topic
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = doc[FPSTR(HA_STATE_TOPIC)];
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = JsonString(AVAILABILITY_SENSOR_CONN, true);
+22 -31
View File
@@ -41,6 +41,8 @@ protected:
bool ntpStarted = false;
bool emergencyDetected = false;
unsigned long emergencyFlipTime = 0;
bool freezeDetected = false;
unsigned long freezeDetectedTime = 0;
#if defined(ARDUINO_ARCH_ESP32)
const char* getTaskName() override {
@@ -220,12 +222,12 @@ protected:
void heating() {
// freeze protection
{
if (!settings.heating.enabled) {
float lowTemp = 255.0f;
uint8_t availableSensors = 0;
if (Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::INDOOR_TEMP)) {
auto value = Sensors::getMeanValueByPurpose(Sensors::Purpose::INDOOR_TEMP, Sensors::ValueType::PRIMARY, settings.heating.indoorTempAvgType);
auto value = Sensors::getMeanValueByPurpose(Sensors::Purpose::INDOOR_TEMP, Sensors::ValueType::PRIMARY);
if (value < lowTemp) {
lowTemp = value;
}
@@ -251,40 +253,29 @@ protected:
availableSensors++;
}
if (availableSensors) {
if (vars.master.heating.freezing) {
if (lowTemp - (float) settings.heating.freezeProtection.highTemp + 0.0001f >= 0.0f) {
vars.master.heating.freezing = false;
if (availableSensors && lowTemp <= settings.heating.freezeProtection.lowTemp) {
if (!this->freezeDetected) {
this->freezeDetected = true;
this->freezeDetectedTime = millis();
Log.sinfoln(
FPSTR(L_MAIN),
F("No freezing detected. Current low temp: %.2f, threshold (high): %hhu"),
lowTemp, settings.heating.freezeProtection.highTemp
);
}
} else if (millis() - this->freezeDetectedTime > (settings.heating.freezeProtection.thresholdTime * 1000)) {
this->freezeDetected = false;
settings.heating.enabled = true;
fsSettings.update();
} else {
if ((float) settings.heating.freezeProtection.lowTemp - lowTemp + 0.0001f >= 0.0f) {
vars.master.heating.freezing = true;
if (!settings.heating.enabled) {
settings.heating.enabled = true;
fsSettings.update();
}
Log.sinfoln(
FPSTR(L_MAIN),
F("Freezing detected! Current low temp: %.2f, threshold (low): %hhu"),
lowTemp, settings.heating.freezeProtection.lowTemp
);
}
Log.sinfoln(
FPSTR(L_MAIN),
F("Heating turned on by freeze protection, current low temp: %.2f, threshold: %hhu"),
lowTemp, settings.heating.freezeProtection.lowTemp
);
}
} else if (vars.master.heating.freezing) {
vars.master.heating.freezing = false;
Log.sinfoln(FPSTR(L_MAIN), F("No sensors available, freeze protection unavailable!"));
} else if (this->freezeDetected) {
this->freezeDetected = false;
}
} else if (this->freezeDetected) {
this->freezeDetected = false;
}
}
-16
View File
@@ -292,14 +292,6 @@ protected:
this->haHelper->deleteDynamicSensor(prevSettings, Sensors::ValueType::RSSI);
break;
case Sensors::Type::DHT11:
case Sensors::Type::DHT22:
this->haHelper->deleteConnectionDynamicSensor(prevSettings);
this->haHelper->deleteSignalQualityDynamicSensor(prevSettings);
this->haHelper->deleteDynamicSensor(prevSettings, Sensors::ValueType::TEMPERATURE);
this->haHelper->deleteDynamicSensor(prevSettings, Sensors::ValueType::HUMIDITY);
break;
case Sensors::Type::DALLAS_TEMP:
this->haHelper->deleteConnectionDynamicSensor(prevSettings);
this->haHelper->deleteSignalQualityDynamicSensor(prevSettings);
@@ -327,14 +319,6 @@ protected:
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::RSSI, settings.system.unitSystem, false);
break;
case Sensors::Type::DHT11:
case Sensors::Type::DHT22:
this->haHelper->publishConnectionDynamicSensor(sSettings);
this->haHelper->publishSignalQualityDynamicSensor(sSettings, false);
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::TEMPERATURE, settings.system.unitSystem);
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::HUMIDITY, settings.system.unitSystem);
break;
case Sensors::Type::DALLAS_TEMP:
this->haHelper->publishConnectionDynamicSensor(sSettings);
this->haHelper->publishSignalQualityDynamicSensor(sSettings, false);
+2 -1
View File
@@ -174,7 +174,8 @@ protected:
// Heating settings
vars.master.heating.enabled = this->isReady()
&& settings.heating.enabled
&& (vars.master.heating.freezing || (vars.cascadeControl.input && !vars.master.heating.blocking))
&& vars.cascadeControl.input
&& !vars.master.heating.blocking
&& !vars.master.heating.overheat;
// DHW settings
-2
View File
@@ -552,7 +552,6 @@ protected:
auto docBuild = doc[FPSTR(S_BUILD)].to<JsonObject>();
docBuild[FPSTR(S_VERSION)] = BUILD_VERSION;
docBuild[FPSTR(S_COMMIT)] = BUILD_COMMIT;
docBuild[FPSTR(S_DATE)] = __DATE__ " " __TIME__;
docBuild[FPSTR(S_ENV)] = BUILD_ENV;
docBuild[FPSTR(S_CORE)] = ESP.getCoreVersion();
@@ -593,7 +592,6 @@ protected:
auto docBuild = doc[FPSTR(S_BUILD)].to<JsonObject>();
docBuild[FPSTR(S_VERSION)] = BUILD_VERSION;
docBuild[FPSTR(S_COMMIT)] = BUILD_COMMIT;
docBuild[FPSTR(S_DATE)] = __DATE__ " " __TIME__;
docBuild[FPSTR(S_ENV)] = BUILD_ENV;
docBuild[FPSTR(S_CORE)] = ESP.getCoreVersion();
+3 -8
View File
@@ -32,7 +32,7 @@ protected:
return 4;
}
#endif
void loop() {
if (vars.states.restarting || vars.states.upgrading) {
return;
@@ -159,7 +159,7 @@ protected:
);
float etResult = settings.heating.target + settings.equitherm.shift + sf * (
tempDelta >= 0
? pow(tempDelta, 1.0f / settings.equitherm.exponent)
? pow(tempDelta, 1.0f / settings.equitherm.exponent)
: -(pow(-(tempDelta), 1.0f / settings.equitherm.exponent))
);
@@ -208,7 +208,7 @@ protected:
}*/
float error = pidRegulator.setpoint - pidRegulator.input;
bool hasDeadband = settings.pid.deadband.enabled
bool hasDeadband = settings.pid.deadband.enabled
&& (error > -(settings.pid.deadband.thresholdHigh))
&& (error < settings.pid.deadband.thresholdLow);
@@ -244,11 +244,6 @@ protected:
) * settings.heating.turboFactor;
}
// If freezing, set temperature to no lower than low temp provided by freeze protection
if (vars.master.heating.freezing && fabsf(settings.heating.freezeProtection.lowTemp - newTemp) < 0.0001f) {
newTemp = settings.heating.freezeProtection.lowTemp;
}
return newTemp;
}
};
+18 -49
View File
@@ -39,8 +39,6 @@ public:
NTC_10K_TEMP = 50,
DALLAS_TEMP = 51,
BLUETOOTH = 52,
DHT11 = 53,
DHT22 = 54,
HEATING_SETPOINT_TEMP = 253,
MANUAL = 254,
@@ -77,12 +75,6 @@ public:
RSSI = 3
};
enum class AverageType : uint8_t {
MEAN = 0,
MINIMUM = 1,
MAXIMUM = 2
};
typedef struct {
bool enabled = false;
char name[33];
@@ -336,61 +328,38 @@ public:
return updated;
}
static float getMeanValueByPurpose(Purpose purpose, const ValueType valueType, const AverageType avgType = AverageType::MEAN, const bool onlyConnected = true, const float defaultValue = NAN) {
static float getMeanValueByPurpose(Purpose purpose, const ValueType valueType, bool onlyConnected = true) {
if (settings == nullptr || results == nullptr) {
return defaultValue;
return 0.0f;
}
uint8_t valueId = (uint8_t) valueType;
if (!isValidValueId(valueId)) {
return defaultValue;
return 0.0f;
}
float value = 0.0f;
uint8_t amount = 0;
if (avgType == AverageType::MEAN) {
float sum = 0.0f;
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
auto& sSensor = settings[id];
auto& rSensor = results[id];
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
auto& sSensor = settings[id];
auto& rSensor = results[id];
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
sum += rSensor.values[valueId];
amount++;
}
}
value = amount == 1 ? sum : (sum / amount);
} else if (avgType == AverageType::MINIMUM) {
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
auto& sSensor = settings[id];
auto& rSensor = results[id];
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
if (amount == 0 || rSensor.values[valueId] < value) {
value = rSensor.values[valueId];
amount++;
}
}
}
} else if (avgType == AverageType::MAXIMUM) {
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
auto& sSensor = settings[id];
auto& rSensor = results[id];
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
if (amount == 0 || rSensor.values[valueId] > value) {
value = rSensor.values[valueId];
amount++;
}
}
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
value += rSensor.values[valueId];
amount++;
}
}
return amount > 0 ? value : defaultValue;
if (!amount) {
return 0.0f;
} else if (amount == 1) {
return value;
} else {
return value / amount;
}
}
static bool existsConnectedSensorsByPurpose(Purpose purpose) {
+14 -155
View File
@@ -1,7 +1,6 @@
#include <unordered_map>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <esp32DHT.h>
#if USE_BLE
#include <NimBLEDevice.h>
@@ -305,13 +304,11 @@ public:
class SensorsTask : public LeanTask {
public:
SensorsTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {
this->gpioLastPollingTime.reserve(2);
// OneWire
this->owInstances.reserve(2);
this->dallasInstances.reserve(2);
this->dallasSearchTime.reserve(2);
this->dallasPolling.reserve(2);
this->dallasLastPollingTime.reserve(2);
#if USE_BLE
this->pBLEScanCallbacks = new BluetoothScanCallbacks();
@@ -319,13 +316,11 @@ public:
}
~SensorsTask() {
this->gpioLastPollingTime.clear();
// OneWire
this->dallasInstances.clear();
this->owInstances.clear();
this->dallasSearchTime.clear();
this->dallasPolling.clear();
this->dallasLastPollingTime.clear();
#if USE_BLE
delete this->pBLEScanCallbacks;
@@ -337,21 +332,13 @@ protected:
const unsigned int wirelessDisconnectTimeout = 600000u;
const unsigned short dallasSearchInterval = 60000u;
const unsigned short dallasPollingInterval = 10000u;
const unsigned short dhtPollingInterval = 15000;
const unsigned short globalPollingInterval = 15000u;
std::unordered_map<uint8_t, unsigned long> gpioLastPollingTime;
// OneWire
std::unordered_map<uint8_t, OneWire> owInstances;
std::unordered_map<uint8_t, DallasTemperature> dallasInstances;
std::unordered_map<uint8_t, unsigned long> dallasSearchTime;
std::unordered_map<uint8_t, bool> dallasPolling;
// DHT
DHT dhtInstance;
bool dhtIsPolling = false;
std::unordered_map<uint8_t, unsigned long> dallasLastPollingTime;
#if USE_BLE
NimBLEScan* pBLEScan = nullptr;
BluetoothScanCallbacks* pBLEScanCallbacks = nullptr;
@@ -392,9 +379,6 @@ protected:
this->yield();
}
pollingDhtSensors();
this->yield();
if (millis() - this->globalLastPollingTime > this->globalPollingInterval) {
cleanDallasInstances();
makeDallasInstances();
@@ -423,50 +407,14 @@ protected:
}
void updateMasterValues() {
vars.master.heating.indoorTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::INDOOR_TEMP,
Sensors::ValueType::PRIMARY,
settings.heating.indoorTempAvgType,
true,
0.0f
);
vars.master.heating.outdoorTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::OUTDOOR_TEMP,
Sensors::ValueType::PRIMARY,
settings.heating.outdoorTempAvgType,
true,
0.0f
);
vars.master.heating.outdoorTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::OUTDOOR_TEMP, Sensors::ValueType::PRIMARY);
vars.master.heating.indoorTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::INDOOR_TEMP, Sensors::ValueType::PRIMARY);
vars.master.heating.currentTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::HEATING_TEMP,
Sensors::ValueType::PRIMARY,
Sensors::AverageType::MEAN,
true,
0.0f
);
vars.master.heating.returnTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::HEATING_RETURN_TEMP,
Sensors::ValueType::PRIMARY,
Sensors::AverageType::MEAN,
true,
0.0f
);
vars.master.heating.currentTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::HEATING_TEMP, Sensors::ValueType::PRIMARY);
vars.master.heating.returnTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::HEATING_RETURN_TEMP, Sensors::ValueType::PRIMARY);
vars.master.dhw.currentTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::DHW_TEMP,
Sensors::ValueType::PRIMARY,
Sensors::AverageType::MEAN,
true,
0.0f
);
vars.master.dhw.returnTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::DHW_RETURN_TEMP,
Sensors::ValueType::PRIMARY,
Sensors::AverageType::MEAN,
true,
0.0f
);
vars.master.dhw.currentTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::DHW_TEMP, Sensors::ValueType::PRIMARY);
vars.master.dhw.returnTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::DHW_RETURN_TEMP, Sensors::ValueType::PRIMARY);
}
void makeDallasInstances() {
@@ -487,7 +435,7 @@ protected:
this->dallasSearchTime[sSensor.gpio] = 0;
this->dallasPolling[sSensor.gpio] = false;
this->gpioLastPollingTime[sSensor.gpio] = 0;
this->dallasLastPollingTime[sSensor.gpio] = 0;
auto& instance = this->dallasInstances[sSensor.gpio];
instance.setOneWire(&owInstance);
@@ -522,7 +470,7 @@ protected:
this->owInstances.erase(gpio);
this->dallasSearchTime.erase(gpio);
this->dallasPolling.erase(gpio);
this->gpioLastPollingTime.erase(gpio);
this->dallasLastPollingTime.erase(gpio);
Log.sinfoln(FPSTR(L_SENSORS_DALLAS), F("Stopped on GPIO %hhu"), gpio);
continue;
@@ -643,7 +591,7 @@ protected:
if (this->dallasPolling[gpio]) {
unsigned long minPollingTime = instance.millisToWaitForConversion(12) * 2;
unsigned long estimatePollingTime = ts - this->gpioLastPollingTime[gpio];
unsigned long estimatePollingTime = ts - this->dallasLastPollingTime[gpio];
// check conversion time
// isConversionComplete does not work with chinese clones!
@@ -695,7 +643,7 @@ protected:
this->dallasPolling[gpio] = false;
} else if (newPolling) {
auto estimateLastPollingTime = ts - this->gpioLastPollingTime[gpio];
auto estimateLastPollingTime = ts - this->dallasLastPollingTime[gpio];
// check last polling time
if (estimateLastPollingTime < this->dallasPollingInterval) {
@@ -706,102 +654,13 @@ protected:
instance.setResolution(12);
instance.requestTemperatures();
this->dallasPolling[gpio] = true;
this->gpioLastPollingTime[gpio] = ts;
this->dallasLastPollingTime[gpio] = ts;
Log.straceln(FPSTR(L_SENSORS_DALLAS), F("GPIO %hhu, polling..."), gpio);
}
}
}
void pollingDhtSensors() {
if (this->dhtIsPolling) {
// busy
return;
}
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
auto& sSensor = Sensors::settings[sensorId];
if (!sSensor.enabled || sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
continue;
}
if (sSensor.type != Sensors::Type::DHT11 && sSensor.type != Sensors::Type::DHT22) {
continue;
}
if (this->gpioLastPollingTime.count(sSensor.gpio) && millis() - this->gpioLastPollingTime[sSensor.gpio] < this->dhtPollingInterval) {
continue;
}
const auto sensorGpio = static_cast<gpio_num_t>(sSensor.gpio);
if (this->dhtInstance.getGpio() != sensorGpio) {
this->dhtInstance.reset();
this->dhtInstance.onData([this, sensorId](float humidity, float temperature) {
auto& sSensor = Sensors::settings[sensorId];
Log.straceln(
FPSTR(L_SENSORS_DHT), F("GPIO %hhu, sensor #%hhu '%s', temp: %.2f, humidity: %.2f%%"),
sSensor.gpio, sensorId, sSensor.name, temperature, humidity
);
// set temperature
Sensors::setValueById(sensorId, temperature, Sensors::ValueType::TEMPERATURE, true, true);
// set humidity
Sensors::setValueById(sensorId, humidity, Sensors::ValueType::HUMIDITY, true, true);
auto& rSensor = Sensors::results[sensorId];
if (rSensor.signalQuality < 100) {
rSensor.signalQuality++;
}
this->gpioLastPollingTime[sSensor.gpio] = millis();
this->dhtIsPolling = false;
});
this->dhtInstance.onError([this, sensorId](DHT::Status status) {
auto& sSensor = Sensors::settings[sensorId];
Log.swarningln(
FPSTR(L_SENSORS_DHT), F("GPIO %hhu, sensor #%hhu '%s': failed receiving data (err: %s)"),
sSensor.gpio, sensorId, sSensor.name, DHT::statusToString(this->dhtInstance.getStatus())
);
auto& rSensor = Sensors::results[sensorId];
if (rSensor.signalQuality > 0) {
rSensor.signalQuality--;
}
this->gpioLastPollingTime[sSensor.gpio] = millis();
this->dhtIsPolling = false;
});
DHT::Type sType = DHT::Type::DHT22;
if (sSensor.type == Sensors::Type::DHT11) {
sType = DHT::Type::DHT11;
} else if (sSensor.type == Sensors::Type::DHT22) {
sType = DHT::Type::DHT22;
}
if (this->dhtInstance.setup(sensorGpio, sType)) {
Log.sinfoln(FPSTR(L_SENSORS_DHT), F("Started on GPIO %hhu"), sSensor.gpio);
} else {
Log.swarningln(
FPSTR(L_SENSORS_DHT), F("Failed to start on GPIO %hhu (err: %s)"),
sSensor.gpio, DHT::statusToString(this->dhtInstance.getStatus())
);
}
}
this->dhtIsPolling = this->dhtInstance.poll();
break;
}
}
void pollingNtcSensors() {
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
auto& sSensor = Sensors::settings[sensorId];
+1 -4
View File
@@ -107,8 +107,6 @@ struct Settings {
uint8_t minTemp = DEFAULT_HEATING_MIN_TEMP;
uint8_t maxTemp = DEFAULT_HEATING_MAX_TEMP;
uint8_t maxModulation = 100;
Sensors::AverageType indoorTempAvgType = Sensors::AverageType::MEAN;
Sensors::AverageType outdoorTempAvgType = Sensors::AverageType::MEAN;
struct {
bool enabled = true;
@@ -122,8 +120,8 @@ struct Settings {
} overheatProtection;
struct {
uint8_t highTemp = 15;
uint8_t lowTemp = 10;
unsigned short thresholdTime = 600;
} freezeProtection;
} heating;
@@ -305,7 +303,6 @@ struct Variables {
bool enabled = false;
bool indoorTempControl = false;
bool overheat = false;
bool freezing = false;
float setpointTemp = 0.0f;
float targetTemp = 0.0f;
float currentTemp = 0.0f;
-4
View File
@@ -30,10 +30,6 @@
#define BUILD_VERSION "0.0.0"
#endif
#ifndef BUILD_COMMIT
#define BUILD_COMMIT "undefined"
#endif
#ifndef BUILD_ENV
#define BUILD_ENV "undefined"
#endif
+3
View File
@@ -0,0 +1,3 @@
dependencies:
idf: ">=5.3.2"
h2zero/esp-nimble-cpp: ">=2.2.1"
-5
View File
@@ -24,7 +24,6 @@ const char L_OT_CH2[] PROGMEM = "OT.CH2";
const char L_SENSORS[] PROGMEM = "SENSORS";
const char L_SENSORS_SETTINGS[] PROGMEM = "SENSORS.SETTINGS";
const char L_SENSORS_DALLAS[] PROGMEM = "SENSORS.DALLAS";
const char L_SENSORS_DHT[] PROGMEM = "SENSORS.DHT";
const char L_SENSORS_NTC[] PROGMEM = "SENSORS.NTC";
const char L_SENSORS_BLE[] PROGMEM = "SENSORS.BLE";
const char L_REGULATOR[] PROGMEM = "REGULATOR";
@@ -57,7 +56,6 @@ const char S_CHANNEL[] PROGMEM = "channel";
const char S_CH2_ALWAYS_ENABLED[] PROGMEM = "ch2AlwaysEnabled";
const char S_CHIP[] PROGMEM = "chip";
const char S_CODE[] PROGMEM = "code";
const char S_COMMIT[] PROGMEM = "commit";
const char S_CONNECTED[] PROGMEM = "connected";
const char S_CONTINUES[] PROGMEM = "continues";
const char S_COOLING[] PROGMEM = "cooling";
@@ -89,7 +87,6 @@ const char S_EXTERNAL_PUMP[] PROGMEM = "externalPump";
const char S_FACTOR[] PROGMEM = "factor";
const char S_FAULT[] PROGMEM = "fault";
const char S_FREEZE_PROTECTION[] PROGMEM = "freezeProtection";
const char S_FREEZING[] PROGMEM = "freezing";
const char S_FILTERING[] PROGMEM = "filtering";
const char S_FILTERING_FACTOR[] PROGMEM = "filteringFactor";
const char S_FLAGS[] PROGMEM = "flags";
@@ -115,7 +112,6 @@ const char S_IGNORE_DIAG_STATE[] PROGMEM = "ignoreDiagState";
const char S_IMMERGAS_FIX[] PROGMEM = "immergasFix";
const char S_ALWAYS_SEND_INDOOR_TEMP[] PROGMEM = "alwaysSendIndoorTemp";
const char S_INDOOR_TEMP[] PROGMEM = "indoorTemp";
const char S_INDOOR_TEMP_AVG_TYPE[] PROGMEM = "indoorTempAvgType";
const char S_INDOOR_TEMP_CONTROL[] PROGMEM = "indoorTempControl";
const char S_IN_GPIO[] PROGMEM = "inGpio";
const char S_INPUT[] PROGMEM = "input";
@@ -156,7 +152,6 @@ const char S_ON_LOSS_CONNECTION[] PROGMEM = "onLossConnection"
const char S_OPENTHERM[] PROGMEM = "opentherm";
const char S_OPTIONS[] PROGMEM = "options";
const char S_OUTDOOR_TEMP[] PROGMEM = "outdoorTemp";
const char S_OUTDOOR_TEMP_AVG_TYPE[] PROGMEM = "outdoorTempAvgType";
const char S_OUT_GPIO[] PROGMEM = "outGpio";
const char S_OUTPUT[] PROGMEM = "output";
const char S_OVERHEAT[] PROGMEM = "overheat";
+11 -60
View File
@@ -498,16 +498,14 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
heating[FPSTR(S_MIN_TEMP)] = src.heating.minTemp;
heating[FPSTR(S_MAX_TEMP)] = src.heating.maxTemp;
heating[FPSTR(S_MAX_MODULATION)] = src.heating.maxModulation;
heating[FPSTR(S_INDOOR_TEMP_AVG_TYPE)] = static_cast<uint8_t>(src.heating.indoorTempAvgType);
heating[FPSTR(S_OUTDOOR_TEMP_AVG_TYPE)] = static_cast<uint8_t>(src.heating.outdoorTempAvgType);
auto heatingOverheatProtection = heating[FPSTR(S_OVERHEAT_PROTECTION)].to<JsonObject>();
heatingOverheatProtection[FPSTR(S_HIGH_TEMP)] = src.heating.overheatProtection.highTemp;
heatingOverheatProtection[FPSTR(S_LOW_TEMP)] = src.heating.overheatProtection.lowTemp;
auto freezeProtection = heating[FPSTR(S_FREEZE_PROTECTION)].to<JsonObject>();
freezeProtection[FPSTR(S_HIGH_TEMP)] = src.heating.freezeProtection.highTemp;
freezeProtection[FPSTR(S_LOW_TEMP)] = src.heating.freezeProtection.lowTemp;
freezeProtection[FPSTR(S_THRESHOLD_TIME)] = src.heating.freezeProtection.thresholdTime;
auto dhw = dst[FPSTR(S_DHW)].to<JsonObject>();
dhw[FPSTR(S_ENABLED)] = src.dhw.enabled;
@@ -1395,42 +1393,6 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
}
}
if (!src[FPSTR(S_HEATING)][FPSTR(S_INDOOR_TEMP_AVG_TYPE)].isNull()) {
uint8_t value = src[FPSTR(S_HEATING)][FPSTR(S_INDOOR_TEMP_AVG_TYPE)].as<uint8_t>();
switch (value) {
case static_cast<uint8_t>(Sensors::AverageType::MEAN):
case static_cast<uint8_t>(Sensors::AverageType::MINIMUM):
case static_cast<uint8_t>(Sensors::AverageType::MAXIMUM):
if (static_cast<uint8_t>(dst.heating.indoorTempAvgType) != value) {
dst.heating.indoorTempAvgType = static_cast<Sensors::AverageType>(value);
changed = true;
}
break;
default:
break;
}
}
if (!src[FPSTR(S_HEATING)][FPSTR(S_OUTDOOR_TEMP_AVG_TYPE)].isNull()) {
uint8_t value = src[FPSTR(S_HEATING)][FPSTR(S_OUTDOOR_TEMP_AVG_TYPE)].as<uint8_t>();
switch (value) {
case static_cast<uint8_t>(Sensors::AverageType::MEAN):
case static_cast<uint8_t>(Sensors::AverageType::MINIMUM):
case static_cast<uint8_t>(Sensors::AverageType::MAXIMUM):
if (static_cast<uint8_t>(dst.heating.outdoorTempAvgType) != value) {
dst.heating.outdoorTempAvgType = static_cast<Sensors::AverageType>(value);
changed = true;
}
break;
default:
break;
}
}
if (!src[FPSTR(S_HEATING)][FPSTR(S_OVERHEAT_PROTECTION)][FPSTR(S_HIGH_TEMP)].isNull()) {
unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_OVERHEAT_PROTECTION)][FPSTR(S_HIGH_TEMP)].as<unsigned char>();
@@ -1454,15 +1416,6 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
changed = true;
}
if (!src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_HIGH_TEMP)].isNull()) {
unsigned short value = src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_HIGH_TEMP)].as<uint8_t>();
if (isValidTemp(value, dst.system.unitSystem, 1, 50) && value != dst.heating.freezeProtection.highTemp) {
dst.heating.freezeProtection.highTemp = value;
changed = true;
}
}
if (!src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_LOW_TEMP)].isNull()) {
unsigned short value = src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_LOW_TEMP)].as<uint8_t>();
@@ -1472,9 +1425,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
}
}
if (dst.heating.freezeProtection.highTemp < dst.heating.freezeProtection.lowTemp) {
dst.heating.freezeProtection.highTemp = dst.heating.freezeProtection.lowTemp;
changed = true;
if (!src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_THRESHOLD_TIME)].isNull()) {
unsigned short value = src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_THRESHOLD_TIME)].as<unsigned short>();
if (value >= 30 && value <= 1800) {
if (value != dst.heating.freezeProtection.thresholdTime) {
dst.heating.freezeProtection.thresholdTime = value;
changed = true;
}
}
}
@@ -1968,8 +1927,6 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se
case static_cast<uint8_t>(Sensors::Type::NTC_10K_TEMP):
case static_cast<uint8_t>(Sensors::Type::DALLAS_TEMP):
case static_cast<uint8_t>(Sensors::Type::BLUETOOTH):
case static_cast<uint8_t>(Sensors::Type::DHT11):
case static_cast<uint8_t>(Sensors::Type::DHT22):
case static_cast<uint8_t>(Sensors::Type::HEATING_SETPOINT_TEMP):
case static_cast<uint8_t>(Sensors::Type::MANUAL):
case static_cast<uint8_t>(Sensors::Type::NOT_CONFIGURED):
@@ -1986,8 +1943,7 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se
// gpio
if (!src[FPSTR(S_GPIO)].isNull()) {
if (dst.type != Sensors::Type::DALLAS_TEMP && dst.type != Sensors::Type::NTC_10K_TEMP &&
dst.type != Sensors::Type::DHT11 && dst.type != Sensors::Type::DHT22) {
if (dst.type != Sensors::Type::DALLAS_TEMP && dst.type != Sensors::Type::NTC_10K_TEMP) {
if (dst.gpio != GPIO_IS_NOT_CONFIGURED) {
dst.gpio = GPIO_IS_NOT_CONFIGURED;
changed = true;
@@ -2128,10 +2084,6 @@ void sensorResultToJson(const uint8_t sensorId, JsonVariant dst) {
dst[FPSTR(S_BATTERY)] = roundf(rSensor.values[static_cast<uint8_t>(Sensors::ValueType::BATTERY)], 1);
dst[FPSTR(S_RSSI)] = roundf(rSensor.values[static_cast<uint8_t>(Sensors::ValueType::RSSI)], 0);
} else if (sSensor.type == Sensors::Type::DHT11 || sSensor.type == Sensors::Type::DHT22) {
dst[FPSTR(S_TEMPERATURE)] = roundf(rSensor.values[static_cast<uint8_t>(Sensors::ValueType::TEMPERATURE)], 3);
dst[FPSTR(S_HUMIDITY)] = roundf(rSensor.values[static_cast<uint8_t>(Sensors::ValueType::HUMIDITY)], 3);
} else {
dst[FPSTR(S_VALUE)] = roundf(rSensor.values[static_cast<uint8_t>(Sensors::ValueType::PRIMARY)], 3);
}
@@ -2208,7 +2160,6 @@ void varsToJson(const Variables& src, JsonVariant dst) {
mHeating[FPSTR(S_BLOCKING)] = src.master.heating.blocking;
mHeating[FPSTR(S_INDOOR_TEMP_CONTROL)] = src.master.heating.indoorTempControl;
mHeating[FPSTR(S_OVERHEAT)] = src.master.heating.overheat;
mHeating[FPSTR(S_FREEZING)] = src.master.heating.freezing;
mHeating[FPSTR(S_SETPOINT_TEMP)] = roundf(src.master.heating.setpointTemp, 2);
mHeating[FPSTR(S_TARGET_TEMP)] = roundf(src.master.heating.targetTemp, 2);
mHeating[FPSTR(S_CURRENT_TEMP)] = roundf(src.master.heating.currentTemp, 2);
+60 -52
View File
@@ -8,19 +8,15 @@
"issues": "问题与反馈",
"releases": "发行版"
},
"units": {
"dbm": "dBm",
"kw": "kW",
"time": {
"days": "天",
"hours": "小时",
"min": "分",
"sec": "秒",
"dbm": "dBm",
"mhz": "MHz",
"kw": "kW",
"rpm": "RPM",
"ppm": "ppm",
"byte": "byte",
"mbyte": "MB"
"sec": "秒"
},
"button": {
"upgrade": "固件升级",
"restart": "重启",
@@ -35,25 +31,26 @@
"success": "成功",
"error": "错误"
},
"index": {
"title": "OpenTherm Gateway",
"section": {
"network": "网络",
"system": "系统"
},
"system": {
"build": {
"title": "Build",
"version": "固件版本",
"commit": "Commit",
"date": "日期",
"core": "内核版本",
"sdk": "SDK"
},
"uptime": "运行时间",
"memory": {
"heap": "内存 (heap)",
"psram": "内存 (PSRAM)",
"title": "可用内存",
"maxFreeBlock": "max free block",
"min": "min"
},
@@ -70,22 +67,26 @@
"lastResetReason": "上次重置原因"
}
},
"dashboard": {
"name": "仪表盘",
"title": "仪表盘 - OpenTherm Gateway",
"section": {
"control": "调节",
"states": "状态",
"sensors": "传感器",
"diag": "OpenTherm 诊断"
},
"thermostat": {
"heating": "供暖",
"dhw": "生活热水",
"currentTemp": "当前温度",
"temp.current": "当前温度",
"enable": "启用",
"turbo": "Turbo 模式"
},
"notify": {
"fault": {
"title": "锅炉报警状态已激活!",
@@ -97,6 +98,7 @@
},
"reset": "点击复位"
},
"states": {
"mNetworkConnected": "网络连接状态",
"mMqttConnected": "MQTT服务器连接状态",
@@ -104,6 +106,7 @@
"mExtPumpState": "外置循环泵",
"mCascadeControlInput": "Cascade 控制 (input)",
"mCascadeControlOutput": "Cascade 控制 (output)",
"sConnected": "OpenTherm 通讯状态",
"sFlame": "火焰",
"sCoolingActive": "制冷",
@@ -112,10 +115,10 @@
"sFaultCode": "报警代码",
"sDiagActive": "诊断状态",
"sDiagCode": "诊断代码",
"mHeatEnabled": "供暖功能已启用",
"mHeatBlocking": "供暖",
"mHeatOverheat": "供暖超热保护",
"mHeatFreezing": "防冻保护",
"sHeatActive": "供暖激活状态",
"mHeatSetpointTemp": "供暖供水设定温度",
"mHeatTargetTemp": "供暖供水目标温度",
@@ -123,6 +126,7 @@
"mHeatRetTemp": "供暖回水温度",
"mHeatIndoorTemp": "供暖,室内温度",
"mHeatOutdoorTemp": "供暖,室外温度",
"mDhwEnabled": "生活热水功能已启用",
"mDhwOverheat": "生活热水超热保护",
"sDhwActive": "生活热水激活",
@@ -130,6 +134,7 @@
"mDhwCurrTemp": "生活热水当前出水温度",
"mDhwRetTemp": "生活热水回水温度"
},
"sensors": {
"values": {
"temp": "温度",
@@ -139,19 +144,23 @@
}
}
},
"network": {
"title": "网络 - OpenTherm Gateway",
"name": "网络设置",
"section": {
"static": "静态设置",
"availableNetworks": "可用网络",
"staSettings": "WiFi 设置",
"apSettings": "AP 设置"
},
"scan": {
"pos": "#",
"info": "Info"
},
"wifi": {
"ssid": "SSID",
"password": "密码",
@@ -159,6 +168,7 @@
"signal": "信号强度",
"connected": "已连接"
},
"params": {
"hostname": "Hostname",
"dhcp": "自动 (DHCP)",
@@ -168,15 +178,16 @@
"gateway": "网关",
"dns": "DNS 服务器"
},
"sta": {
"channel": {
"note": "自动选择设置为0"
}
"channel.note": "自动选择设置为0"
}
},
"sensors": {
"title": "传感器设置 - OpenTherm Gateway",
"name": "传感器设置",
"enabled": "启用",
"sensorName": {
"title": "传感器名称",
@@ -233,11 +244,10 @@
"otHeatingPumpHours": "OpenTherm, number of pump operating hours (heating)",
"otDhwPumpHours": "OpenTherm, number of pump operating hours (DHW)",
"otCoolingHours": "OpenTherm, number of cooling hours",
"ntcTemp": "NTC 传感器",
"dallasTemp": "DALLAS 传感器",
"bluetooth": "BLE 传感器",
"dht11": "DHT11 传感器",
"dht22": "DHT22 传感器",
"heatSetpointTemp": "Heating, setpoint temp",
"manual": "通过 MQTT/API 手动配置",
"notConfigured": "未配置"
@@ -264,9 +274,11 @@
}
}
},
"settings": {
"title": "设置 - OpenTherm Gateway",
"name": "设置",
"section": {
"portal": "Portal 设置",
"system": "系统设置",
@@ -281,21 +293,18 @@
"extPump": "外置循环泵设置",
"cascadeControl": "Cascade 级联控制设置"
},
"enable": "启用",
"note": {
"restart": "更改这些设置后,必须重启设备以使变更生效",
"blankNotUse": "空白 - 未使用",
"bleDevice": "BLE设备仅支持搭载BLE功能的特定ESP32开发板使用!"
},
"temp": {
"min": "最低温度",
"max": "最高温度"
},
"avgType": {
"mean": "平均温度",
"min": "最低温度",
"max": "最高温度"
},
"maxModulation": "最大调制范围",
"ohProtection": {
"title": "超温保护",
@@ -311,22 +320,18 @@
},
"freezeProtection": {
"title": "防冻保护",
"desc": "如果热载体或室内温度低于 <b>低温</b>,加热将被强制开启。",
"highTemp": {
"title": "高温阈值",
"note": "防冻保护激活后系统恢复正常模式的阈值"
},
"lowTemp": {
"title": "低温阈值",
"note": "强制开启加热的阈值"
}
"desc": "当热媒或室内温度在<b>等待时间</b> 内降至<b>低温阈值</b>以下时,系统将强制启动加热功能。",
"lowTemp": "低温阈值",
"thresholdTime": "等待时间<small>(秒)</small>"
},
"portal": {
"login": "登录",
"password": "密码",
"auth": "需身份验证",
"mdns": "使用 mDNS"
},
"system": {
"unit": "单位",
"metric": "公制 <small>(摄氏度、升、巴)</small>",
@@ -346,6 +351,7 @@
"timezonePresets": "选择预设配置..."
}
},
"heating": {
"hyst": {
"title": "滞回",
@@ -357,24 +363,19 @@
"set0target": "设置空目标"
}
},
"turboFactor": "Turbo 模式系数",
"indoorTempAvgType": {
"title": "室内温度平均类型",
"desc": "使用两个或更多室内温度传感器时可能有用(使用 «Equitherm» 和/或 «PID» 时)。"
},
"outdoorTempAvgType": {
"title": "室外温度平均类型",
"desc": "使用两个或更多室外温度传感器时可能有用(使用 «Equitherm» 时)。"
}
"turboFactor": "Turbo 模式系数"
},
"emergency": {
"desc": "紧急模式会在以下情况自动激活(当PID或气候补偿无法计算热媒设定值时):<br />启用气候补偿但室外温度传感器断开连接;<br />启用PID或 OpenTherm 选项中启用<i>原生供暖控制</i>但室内温度传感器断开连接。<br /><b>注意:</b> 网络故障或MQTT 服务器连接故障时,类型为<i>通过MQTT/API手动控制</i>的传感器将显示为断开连接状态。",
"desc": "紧急模式会在以下情况自动激活(当PID或气候补偿无法计算热媒设定值时):<br />启用气候补偿但室外温度传感器断开连接;<br />启用PID或 OpenTherm 选项中启用<i>原生供暖控制</i>但室内温度传感器断开连接。<br /><b>注意:</b> 网络故障或MQTT 服务器连接故障时,类型为<i>通过MQTT/API手动控制<i>的传感器将显示为断开连接状态。",
"target": {
"title": "目标温度",
"note": "<b>重要提示:</b> 若启用OpenTherm选项 <i>«原生供暖控制»</i>,此处设定值为<u>目标室内温度</u><br />其他所有情况下,此处设定值为 <u>目标热媒出水温度</u>."
},
"treshold": "阈值时间 <small>(秒)</small>"
},
"equitherm": {
"slope": {
"title": "斜率",
@@ -398,6 +399,7 @@
"outdoorTemp": "室外温度"
}
},
"pid": {
"p": "P 系数",
"i": "I 系数",
@@ -417,6 +419,7 @@
"thresholdLow": "Threshold low"
}
},
"ot": {
"advanced": "高级设置",
"inGpio": "In GPIO",
@@ -430,8 +433,9 @@
},
"maxPower": {
"title": "最大锅炉功率 <small>(kW)</small>",
"note": "<b>0</b> - 自动检测,通常在锅炉参数设置中的\"最大有效热输出\"。"
"note": "<b>0</b> - 自动检测,通常在锅炉参数设置中的\"最大有效热输出\"。 "
},
"options": {
"title": "选项(附加设置)",
"desc": "附加设置选项可调整锅炉的运行逻辑。由于协议未完整记录所有选项,同一选项在不同锅炉上可能产生不同效果。<br /><b>注意:</b>若系统运行正常,无需修改设置。",
@@ -453,11 +457,13 @@
"immergasFix": "针对Immergas锅炉的兼容性修复",
"alwaysSendIndoorTemp": "向锅炉发送当前室内温度"
},
"nativeOTC": {
"title": "原生热载体温度计算模式",
"note": "仅在锅炉处于 OTC 模式时<u>才</u>工作:需要并接受目标室内温度,并基于内置曲线模式自行调节热载体温度。与 PID 和 Equitherm 不兼容。"
}
},
"mqtt": {
"homeAssistantDiscovery": "Home Assistant 自动发现",
"server": "服务器地址",
@@ -467,6 +473,7 @@
"prefix": "Prefix 前缀",
"interval": "发布间隔 <small>(秒)</small>"
},
"extPump": {
"use": "使用外置循环泵",
"gpio": "继电器 GPIO引脚",
@@ -475,6 +482,7 @@
"antiStuckInterval": "防卡死间隔时间<small>(天)</small>",
"antiStuckTime": "防卡死运行时长<small>(分钟)</small>"
},
"cascadeControl": {
"input": {
"desc": "仅当另一台锅炉发生故障时启用本锅炉加热。另一台锅炉的控制器需在故障发生时切换GPIO输入状态以触发本功能。",
@@ -498,23 +506,23 @@
}
}
},
"upgrade": {
"title": "固件升级 - OpenTherm Gateway",
"name": "固件升级",
"section": {
"backupAndRestore": {
"title": "备份恢复",
"desc": "本功能支持备份和恢复全部设置"
},
"upgrade": {
"title": "升级",
"desc": "本模块支持升级设备的固件与系统文件。<br />可从以下地址下载最新版本 <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Releases page</a> 。"
}
"backupAndRestore": "备份与恢复",
"backupAndRestore.desc": "本功能支持备份恢复全部设置",
"upgrade": "升级",
"upgrade.desc": "本模块支持升级设备的固件与系统文件。<br />可从以下地址下载最新版本 <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Releases page</a> 。"
},
"note": {
"disclaimer1": "升级系统文件成功后,所有设置将恢复为默认值!升级前请务必备份配置。",
"disclaimer2": "升级成功后,设备将在15秒后自动重启。"
},
"settingsFile": "设置文件",
"fw": "Firmware",
"fs": "Filesystem"
+59 -51
View File
@@ -8,19 +8,15 @@
"issues": "Issues & questions",
"releases": "Releases"
},
"units": {
"dbm": "dBm",
"kw": "kW",
"time": {
"days": "d.",
"hours": "h.",
"min": "min.",
"sec": "sec.",
"dbm": "dBm",
"mhz": "MHz",
"kw": "kW",
"rpm": "RPM",
"ppm": "ppm",
"byte": "byte",
"mbyte": "MB"
"sec": "sec."
},
"button": {
"upgrade": "Upgrade",
"restart": "Restart",
@@ -35,25 +31,26 @@
"success": "Success",
"error": "Error"
},
"index": {
"title": "OpenTherm Gateway",
"section": {
"network": "Network",
"system": "System"
},
"system": {
"build": {
"title": "Build",
"version": "Version",
"commit": "Commit",
"date": "Date",
"core": "Core",
"sdk": "SDK"
},
"uptime": "Uptime",
"memory": {
"heap": "Memory (heap)",
"psram": "Memory (PSRAM)",
"title": "Free memory",
"maxFreeBlock": "max free block",
"min": "min"
},
@@ -70,22 +67,26 @@
"lastResetReason": "Last reset reason"
}
},
"dashboard": {
"name": "Dashboard",
"title": "Dashboard - OpenTherm Gateway",
"section": {
"control": "Control",
"states": "States",
"sensors": "Sensors",
"diag": "OpenTherm diagnostic"
},
"thermostat": {
"heating": "Heating",
"dhw": "DHW",
"currentTemp": "Current",
"temp.current": "Current",
"enable": "Enable",
"turbo": "Turbo mode"
},
"notify": {
"fault": {
"title": "Boiler Fault state is active!",
@@ -97,6 +98,7 @@
},
"reset": "Try reset"
},
"states": {
"mNetworkConnected": "Network connection",
"mMqttConnected": "MQTT connection",
@@ -104,6 +106,7 @@
"mExtPumpState": "External pump",
"mCascadeControlInput": "Cascade control (input)",
"mCascadeControlOutput": "Cascade control (output)",
"sConnected": "OpenTherm connection",
"sFlame": "Flame",
"sCoolingActive": "Cooling",
@@ -112,10 +115,10 @@
"sFaultCode": "Fault code",
"sDiagActive": "Diagnostic",
"sDiagCode": "Diagnostic code",
"mHeatEnabled": "Heating enabled",
"mHeatBlocking": "Heating blocked",
"mHeatOverheat": "Heating overheat",
"mHeatFreezing": "Heating freezing",
"sHeatActive": "Heating active",
"mHeatSetpointTemp": "Heating setpoint temp",
"mHeatTargetTemp": "Heating target temp",
@@ -123,6 +126,7 @@
"mHeatRetTemp": "Heating return temp",
"mHeatIndoorTemp": "Heating, indoor temp",
"mHeatOutdoorTemp": "Heating, outdoor temp",
"mDhwEnabled": "DHW enabled",
"mDhwOverheat": "DHW overheat",
"sDhwActive": "DHW active",
@@ -130,6 +134,7 @@
"mDhwCurrTemp": "DHW current temp",
"mDhwRetTemp": "DHW return temp"
},
"sensors": {
"values": {
"temp": "Temperature",
@@ -139,19 +144,23 @@
}
}
},
"network": {
"title": "Network - OpenTherm Gateway",
"name": "Network settings",
"section": {
"static": "Static settings",
"availableNetworks": "Available networks",
"staSettings": "WiFi settings",
"apSettings": "AP settings"
},
"scan": {
"pos": "#",
"info": "Info"
},
"wifi": {
"ssid": "SSID",
"password": "Password",
@@ -159,6 +168,7 @@
"signal": "Signal",
"connected": "Connected"
},
"params": {
"hostname": "Hostname",
"dhcp": "Use DHCP",
@@ -168,15 +178,16 @@
"gateway": "Gateway",
"dns": "DNS"
},
"sta": {
"channel": {
"note": "set 0 for auto select"
}
"channel.note": "set 0 for auto select"
}
},
"sensors": {
"title": "Sensors settings - OpenTherm Gateway",
"name": "Sensors settings",
"enabled": "Enabled",
"sensorName": {
"title": "Sensor name",
@@ -233,11 +244,10 @@
"otHeatingPumpHours": "OpenTherm, number of pump operating hours (heating)",
"otDhwPumpHours": "OpenTherm, number of pump operating hours (DHW)",
"otCoolingHours": "OpenTherm, number of cooling hours",
"ntcTemp": "NTC sensor",
"dallasTemp": "DALLAS sensor",
"bluetooth": "BLE sensor",
"dht11": "DHT11 sensor",
"dht22": "DHT22 sensor",
"heatSetpointTemp": "Heating, setpoint temp",
"manual": "Manual via MQTT/API",
"notConfigured": "Not configured"
@@ -264,9 +274,11 @@
}
}
},
"settings": {
"title": "Settings - OpenTherm Gateway",
"name": "Settings",
"section": {
"portal": "Portal settings",
"system": "System settings",
@@ -281,21 +293,18 @@
"extPump": "External pump settings",
"cascadeControl": "Cascade control settings"
},
"enable": "Enable",
"note": {
"restart": "After changing these settings, the device must be restarted for the changes to take effect.",
"blankNotUse": "blank - not use",
"bleDevice": "BLE device can be used <u>only</u> with some ESP32 boards with BLE support!"
},
"temp": {
"min": "Minimum temperature",
"max": "Maximum temperature"
},
"avgType": {
"mean": "Mean temperature",
"min": "Minimum temperature",
"max": "Maximum temperature"
},
"maxModulation": "Max modulation level",
"ohProtection": {
"title": "Overheating protection",
@@ -311,22 +320,18 @@
},
"freezeProtection": {
"title": "Freeze protection",
"desc": "Heating will be forced to turn on if the heat carrier or indoor temperature drops below <b>Low temperature</b>.",
"highTemp": {
"title": "High temperature threshold",
"note": "Threshold when the system returns to normal mode after freeze protection activation"
},
"lowTemp": {
"title": "Low temperature threshold",
"note": "Threshold when heating is forced to turn on"
}
"desc": "Heating will be forced to turn on if the heat carrier or indoor temperature drops below <b>Low temperature</b> during <b>Waiting time</b>.",
"lowTemp": "Low temperature threshold",
"thresholdTime": "Waiting time <small>(sec)</small>"
},
"portal": {
"login": "Login",
"password": "Password",
"auth": "Require authentication",
"mdns": "Use mDNS"
},
"system": {
"unit": "Unit system",
"metric": "Metric <small>(celsius, liters, bar)</small>",
@@ -346,6 +351,7 @@
"timezonePresets": "Select preset..."
}
},
"heating": {
"hyst": {
"title": "Hysteresis",
@@ -357,24 +363,19 @@
"set0target": "Set null target"
}
},
"turboFactor": "Turbo mode coeff.",
"indoorTempAvgType": {
"title": "Indoor temp. averaging type",
"desc": "May be useful when using two or more indoor temp. sensors (when using «Equitherm» and/or «PID»)."
},
"outdoorTempAvgType": {
"title": "Outdoor temp. averaging type",
"desc": "May be useful when using two or more outdoor temp. sensors (when using «Equitherm»)."
}
"turboFactor": "Turbo mode coeff."
},
"emergency": {
"desc": "Emergency mode is activated automatically when «PID» or «Equitherm» cannot calculate the heat carrier setpoint:<br />- if «Equitherm» is enabled and the outdoor temperature sensor is disconnected;<br />- if «PID» or OT option <i>«Native heating control»</i> is enabled and the indoor temperature sensor is disconnected.<br /><b>Note:</b> On network fault or MQTT fault, sensors with <i>«Manual via MQTT/API»</i> type will be in DISCONNECTED state.",
"target": {
"title": "Target temperature",
"note": "<b>Important:</b> <u>Target indoor temperature</u> if OT option <i>«Native heating control»</i> is enabled.<br />In all other cases, the <u>target heat carrier temperature</u>."
},
"treshold": "Treshold time <small>(sec)</small>"
},
"equitherm": {
"slope": {
"title": "Slope",
@@ -398,6 +399,7 @@
"outdoorTemp": "Outdoor temperature"
}
},
"pid": {
"p": "P factor",
"i": "I factor",
@@ -417,6 +419,7 @@
"thresholdLow": "Threshold low"
}
},
"ot": {
"advanced": "Advanced Settings",
"inGpio": "In GPIO",
@@ -432,6 +435,7 @@
"title": "Max boiler power <small>(kW)</small>",
"note": "<b>0</b> - try detect automatically. Typically found in the boiler specification as \"maximum useful heat output\"."
},
"options": {
"title": "Options (additional settings)",
"desc": "Options can change the logic of the boiler. Not all options are documented in the protocol, so the same option can have different effects on different boilers.<br /><b>Note:</b> There is no need to change anything if everything works well.",
@@ -453,11 +457,13 @@
"immergasFix": "Fix for Immergas boilers",
"alwaysSendIndoorTemp": "Send current indoor temp to boiler"
},
"nativeOTC": {
"title": "Native OTC mode",
"note": "Works <u>ONLY</u> if the boiler is in OTC mode: requires and accepts the target indoor temperature and self-regulates the heat carrier temperature based on the built-in curves mode. Incompatible with PID and Equitherm."
}
},
"mqtt": {
"homeAssistantDiscovery": "Home Assistant Discovery",
"server": "Server",
@@ -467,6 +473,7 @@
"prefix": "Prefix",
"interval": "Publish interval <small>(sec)</small>"
},
"extPump": {
"use": "Use external pump",
"gpio": "Relay GPIO",
@@ -475,6 +482,7 @@
"antiStuckInterval": "Anti stuck interval <small>(days)</small>",
"antiStuckTime": "Anti stuck time <small>(min)</small>"
},
"cascadeControl": {
"input": {
"desc": "Can be used to turn on the heating only if another boiler is faulty. The other boiler controller must change the state of the GPIO input in the event of a fault.",
@@ -498,26 +506,26 @@
}
}
},
"upgrade": {
"title": "Upgrade - OpenTherm Gateway",
"name": "Upgrade",
"section": {
"backupAndRestore": {
"title": "Backup & restore",
"desc": "In this section you can save and restore a backup of ALL settings."
},
"upgrade": {
"title": "Upgrade",
"desc": "In this section you can upgrade the firmware and filesystem of your device.<br />Latest releases can be downloaded from the <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Releases page</a> of the project repository."
}
"backupAndRestore": "Backup & restore",
"backupAndRestore.desc": "In this section you can save and restore a backup of ALL settings.",
"upgrade": "Upgrade",
"upgrade.desc": "In this section you can upgrade the firmware and filesystem of your device.<br />Latest releases can be downloaded from the <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Releases page</a> of the project repository."
},
"note": {
"disclaimer1": "After a successful upgrade the filesystem, ALL settings will be reset to default values! Save backup before upgrading.",
"disclaimer2": "After a successful upgrade, the device will automatically reboot after 15 seconds."
},
"settingsFile": "Settings file",
"fw": "Firmware",
"fs": "Filesystem"
}
}
}
}
+59 -51
View File
@@ -8,19 +8,15 @@
"issues": "Problemi e domande",
"releases": "Versione"
},
"units": {
"dbm": "dBm",
"kw": "kW",
"time": {
"days": "d.",
"hours": "h.",
"min": "min.",
"sec": "sec.",
"dbm": "dBm",
"mhz": "MHz",
"kw": "kW",
"rpm": "RPM",
"ppm": "ppm",
"byte": "byte",
"mbyte": "MB"
"sec": "sec."
},
"button": {
"upgrade": "Aggiorna",
"restart": "Riavvia",
@@ -35,25 +31,26 @@
"success": "Riuscito",
"error": "Errore"
},
"index": {
"title": "OpenTherm Gateway",
"section": {
"network": "Rete",
"system": "Sistema"
},
"system": {
"build": {
"title": "Build",
"version": "Versione",
"commit": "Commit",
"date": "Data",
"core": "Core",
"sdk": "SDK"
},
"uptime": "Tempo di attività",
"memory": {
"heap": "Memoria (heap)",
"psram": "Memoria (PSRAM)",
"title": "Memoria libera",
"maxFreeBlock": "max free block",
"min": "min"
},
@@ -70,22 +67,26 @@
"lastResetReason": "Motivo ultimo Reset"
}
},
"dashboard": {
"name": "Pannello",
"title": "Pannello - OpenTherm Gateway",
"section": {
"control": "Controlli",
"states": "Stato",
"sensors": "Sensori",
"diag": "Diagnostica OpenTherm"
},
"thermostat": {
"heating": "Riscaldamento",
"dhw": "ACS",
"currentTemp": "Attuale",
"temp.current": "Attuale",
"enable": "Attiva",
"turbo": "Turbo"
},
"notify": {
"fault": {
"title": "Rilevamento guasti caldiaia attivo!",
@@ -97,6 +98,7 @@
},
"reset": "Prova a resettare"
},
"states": {
"mNetworkConnected": "Connessione Rete",
"mMqttConnected": "Connessione MQTT",
@@ -104,6 +106,7 @@
"mExtPumpState": "Pompa esterna",
"mCascadeControlInput": "Controllo a cascata (input)",
"mCascadeControlOutput": "Controllo a cascata (output)",
"sConnected": "Connessione OpenTherm",
"sFlame": "Fiamma",
"sCoolingActive": "Raffrescamento",
@@ -112,10 +115,10 @@
"sFaultCode": "Codice anomalia",
"sDiagActive": "Diagnostica",
"sDiagCode": "Codice Diagnostica",
"mHeatEnabled": "Riscaldamento attivato",
"mHeatBlocking": "Riscaldamento bloccato",
"mHeatOverheat": "Riscaldamento surriscaldamento",
"mHeatFreezing": "Protezione antigelo",
"sHeatActive": "Riscaldamento attivo",
"mHeatSetpointTemp": "Temp riscaldamento impostato",
"mHeatTargetTemp": "Target Temp caldaia",
@@ -123,6 +126,7 @@
"mHeatRetTemp": "Temp ritorno riscaldamento",
"mHeatIndoorTemp": "Riscaldamento, temp interna",
"mHeatOutdoorTemp": "Riscaldamento, temp esterna",
"mDhwEnabled": "ACS attivata",
"mDhwOverheat": "ACS surriscaldamento",
"sDhwActive": "ACS attiva",
@@ -130,6 +134,7 @@
"mDhwCurrTemp": "ACS temp attuale",
"mDhwRetTemp": "ACS temp ricircolo"
},
"sensors": {
"values": {
"temp": "Temperatura",
@@ -139,19 +144,23 @@
}
}
},
"network": {
"title": "Rete - OpenTherm Gateway",
"name": "Impostazioni rete",
"section": {
"static": "Impostazioni statico",
"availableNetworks": "Reti disponibili",
"staSettings": "Impostazioni WiFi",
"apSettings": "Impostazioni AP"
},
"scan": {
"pos": "#",
"info": "Info"
},
"wifi": {
"ssid": "SSID",
"password": "Password",
@@ -159,6 +168,7 @@
"signal": "Segnale",
"connected": "Connesso"
},
"params": {
"hostname": "Hostname",
"dhcp": "Usa DHCP",
@@ -168,15 +178,16 @@
"gateway": "Gateway",
"dns": "DNS"
},
"sta": {
"channel": {
"note": "Metti 0 per auto selezione"
}
"channel.note": "Metti 0 per auto selezione"
}
},
"sensors": {
"title": "Impostazione sensori - OpenTherm Gateway",
"name": "Impostazione sensori",
"enabled": "Attivato",
"sensorName": {
"title": "Nome sensore",
@@ -233,11 +244,10 @@
"otHeatingPumpHours": "OpenTherm, numero di ore di funzionamento della pompa (riscaldamento)",
"otDhwPumpHours": "OpenTherm, numero di ore di funzionamento della pompa (ACS)",
"otCoolingHours": "OpenTherm, numero di ore di funzionamento della cooling",
"ntcTemp": "Sensore NTC",
"dallasTemp": "Sensore DALLAS",
"bluetooth": "Sensore BLE",
"dht11": "Sensore DHT11",
"dht22": "Sensore DHT22",
"heatSetpointTemp": "Riscaldamento, temp impostata",
"manual": "Manuale via MQTT/API",
"notConfigured": "Non configurato"
@@ -264,9 +274,11 @@
}
}
},
"settings": {
"title": "Impostazioni - OpenTherm Gateway",
"name": "Impostazioni",
"section": {
"portal": "Impostazioni Accesso",
"system": "Impostazioni sistema",
@@ -281,21 +293,18 @@
"extPump": "Impostazioni pompa esterna",
"cascadeControl": "Impostazioni controllo a cascata"
},
"enable": "Attiva",
"note": {
"restart": "Dopo aver cambiato queste impostazioni, il sistema sarà riavviato perchè i cambiamenti abbiano effetto.",
"blankNotUse": "vuoto - non usare",
"bleDevice": "Dispositivi BLE possono essere usati <u>solo</u> con alcune schede ESP32 che supportano il bluetooth!"
},
"temp": {
"min": "Temperatura minima",
"max": "Temperatura massima"
},
"avgType": {
"mean": "Temperatura media",
"min": "Temperatura minima",
"max": "Temperatura massima"
},
"maxModulation": "Max livello modulazione",
"ohProtection": {
"title": "Protezione contro il surriscaldamento",
@@ -311,22 +320,18 @@
},
"freezeProtection": {
"title": "Protezione antigelo",
"desc": "Il riscaldamento verrà forzatamente attivato se la temperatura del vettore termico o la temperatura interna scende al di sotto della <b>Soglia di temperatura bassa</b>.",
"highTemp": {
"title": "Soglia di temperatura alta",
"note": "Soglia quando il sistema ritorna alla modalità normale dopo l'attivazione della protezione antigelo"
},
"lowTemp": {
"title": "Soglia di temperatura bassa",
"note": "Soglia quando il riscaldamento viene forzatamente attivato"
}
"desc": "Il riscaldamento verrà attivato forzatamente se la temperatura del vettore di calore o interna scende al di sotto della <b>temperatura minima</b> durante il <b>tempo di attesa</b>.",
"lowTemp": "Soglia di temperatura minima",
"thresholdTime": "Tempo di attesa <small>(sec)</small>"
},
"portal": {
"login": "Login",
"password": "Password",
"auth": "Richiede autenticazione",
"mdns": "Usa mDNS"
},
"system": {
"unit": "Unità di misura",
"metric": "Metrico <small>(celsius, litri, bar)</small>",
@@ -346,6 +351,7 @@
"timezonePresets": "Seleziona preimpostato..."
}
},
"heating": {
"hyst": {
"title": "Isteresi",
@@ -357,24 +363,19 @@
"set0target": "Imposta target nullo"
}
},
"turboFactor": "Turbo mode coeff.",
"indoorTempAvgType": {
"title": "Tipo di media temperatura interna",
"desc": "Utile con due o più sensori di temperatura interna (quando si usa «Equitherm» e/o «PID»)."
},
"outdoorTempAvgType": {
"title": "Tipo di media temperatura esterna",
"desc": "Utile con due o più sensori di temperatura esterna (quando si usa «Equitherm»)."
}
"turboFactor": "Turbo mode coeff."
},
"emergency": {
"desc": "Il modo emergenza è attivato automaticamente quando «PID» o «Equitherm» non possono calcolare il setpoint:<br />- se «Equitherm» è attivato e il sensore della temperatura esternare è disconnesso;<br />- se «PID» o l'opzione OT <i>«Impostazioni riscaldamento native»</i> è attiva e il sensore di temperatura interno è disconnesso.<br /><b>Nota:</b> In mancanza di rete o MQTT, sensore di tipo <i>«Manuale via MQTT/API»</i> è in stato Disconnesso.",
"target": {
"title": "Temperatura impostata",
"note": "<b>Importante:</b> <u>Temperatura interna impostata</u> se l'opzione OT <i>«Controllo riscaldamento interno»</i> è attivato.<br />In tutti gli altri casi, la <u>target heat carrier temperature</u>."
},
"treshold": "Tempo di soglia <small>(sec)</small>"
},
"equitherm": {
"slope": {
"title": "Pendenza",
@@ -398,6 +399,7 @@
"outdoorTemp": "Temperatura esterna"
}
},
"pid": {
"p": "Fattore P",
"i": "Fattore I",
@@ -417,6 +419,7 @@
"thresholdLow": "Soglia inferiore"
}
},
"ot": {
"advanced": "Impostazioni avanzate",
"inGpio": "In GPIO",
@@ -432,6 +435,7 @@
"title": "Potenza massima caldaia <small>(kW)</small>",
"note": "<b>0</b> - prova a rilevarla automaticamente. Di solito si trova nelle specifiche delle caldaia come \"potenza massima disponibile\"."
},
"options": {
"title": "Opzioni (impostazioni aggiuntive)",
"desc": "Le opzioni possono modificare la logica della caldaia. Non tutte le opzioni sono documentate nel protocollo, quindi la stessa opzione può avere effetti diversi su caldaie diverse.<br /><b>Nota:</b> Non è necessario modificare nulla se tutto funziona correttamente.",
@@ -453,11 +457,13 @@
"immergasFix": "Fix per caldiaie Immergas",
"alwaysSendIndoorTemp": "Invia la temp attuale interna alla caldaia"
},
"nativeOTC": {
"title": "Modalità nativa di calcolo della temperatura del vettore termico",
"note": "Funziona <u>SOLO</u> se la caldaia è in modalità OTC: richiede e accetta la temperatura interna target e regola autonomamente la temperatura del vettore termico basata sulla modalità curve integrata. Incompatibile con PID e Equitherm."
}
},
"mqtt": {
"homeAssistantDiscovery": "Home Assistant Discovery",
"server": "Server",
@@ -467,6 +473,7 @@
"prefix": "Prefisso",
"interval": "Intervallo invio <small>(sec)</small>"
},
"extPump": {
"use": "Usa pompa/circolatore esterno",
"gpio": "GPIO relè",
@@ -475,6 +482,7 @@
"antiStuckInterval": "Intervallo antiblocco <small>(days)</small>",
"antiStuckTime": "Tempo antiblocco <small>(min)</small>"
},
"cascadeControl": {
"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.",
@@ -498,26 +506,26 @@
}
}
},
"upgrade": {
"title": "Aggiornamenti - OpenTherm Gateway",
"name": "Aggiornamenti",
"section": {
"backupAndRestore": {
"title": "Backup & restore",
"desc": "In questa sezione puoi salvare e recuperare un backup di tutte le impostazioni."
},
"upgrade": {
"title": "Aggiorna",
"desc": "In questa sezione puoi aggiornare il firmware il filesystem del tuo dispositivo.<br />L'ultimo aggiornamento può essere scaricato da <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Releases page</a> del progetto."
}
"backupAndRestore": "Backup & restore",
"backupAndRestore.desc": "In questa sezione puoi salvare e recuperare un backup di tutte le impostazioni.",
"upgrade": "Aggiorna",
"upgrade.desc": "In questa sezione puoi aggiornare il firmware il filesystem del tuo dispositivo.<br />L'ultimo aggiornamento può essere scaricato da <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Releases page</a> del progetto."
},
"note": {
"disclaimer1": "Dopo un aggiornamento riuscito del filesystem, tutte le impostazioni sono impostate di default! Salva un backup prima di aggiornare.",
"disclaimer2": "Dopo un aggiornamento riuscito, il sistema viene automaticamente riavviato dopo 15 secondi."
},
"settingsFile": "Settings file",
"fw": "Firmware",
"fs": "Filesystem"
}
}
}
}
+18 -51
View File
@@ -8,18 +8,13 @@
"issues": "Problemen & vragen",
"releases": "Releases"
},
"units": {
"dbm": "dBm",
"kw": "kW",
"time": {
"days": "d.",
"hours": "u.",
"min": "min.",
"sec": "sec.",
"dbm": "dBm",
"mhz": "MHz",
"kw": "kW",
"rpm": "RPM",
"ppm": "ppm",
"byte": "byte",
"mbyte": "MB"
"sec": "sec."
},
"button": {
"upgrade": "Upgraden",
@@ -45,15 +40,13 @@
"build": {
"title": "Build",
"version": "Versie",
"commit": "Commit",
"date": "Datum",
"core": "Core",
"sdk": "SDK"
},
"uptime": "Uptime",
"memory": {
"heap": "Geheugen (heap)",
"psram": "Geheugen (PSRAM)",
"title": "Vrij geheugen",
"maxFreeBlock": "max. vrij blok",
"min": "min"
},
@@ -82,7 +75,7 @@
"thermostat": {
"heating": "Verwarming",
"dhw": "Warm water",
"currentTemp": "Huidig",
"temp.current": "Huidig",
"enable": "Inschakelen",
"turbo": "Turbomodus"
},
@@ -115,7 +108,6 @@
"mHeatEnabled": "Verwarming ingeschakeld",
"mHeatBlocking": "Verwarming geblokkeerd",
"mHeatOverheat": "Verwarming oververhit",
"mHeatFreezing": "Verwarming vorstbescherming",
"sHeatActive": "Verwarming actief",
"mHeatSetpointTemp": "Insteltemperatuur verwarming",
"mHeatTargetTemp": "Doeltemperatuur verwarming",
@@ -169,9 +161,7 @@
"dns": "DNS"
},
"sta": {
"channel": {
"note": "zet op 0 voor automatische selectie"
}
"channel.note": "zet op 0 voor automatische selectie"
}
},
"sensors": {
@@ -233,11 +223,10 @@
"otHeatingPumpHours": "OpenTherm, aantal pompuren (verwarming)",
"otDhwPumpHours": "OpenTherm, aantal pompuren (warm water)",
"otCoolingHours": "OpenTherm, aantal cooling",
"ntcTemp": "NTC-sensor",
"dallasTemp": "DALLAS-sensor",
"bluetooth": "BLE-sensor",
"dht11": "DHT11-sensor",
"dht22": "DHT22-sensor",
"heatSetpointTemp": "Verwarming, insteltemperatuur",
"manual": "Handmatig via MQTT/API",
"notConfigured": "Niet geconfigureerd"
@@ -291,11 +280,6 @@
"min": "Minimumtemperatuur",
"max": "Maximumtemperatuur"
},
"avgType": {
"mean": "Gemiddelde temperatuur",
"min": "Minimum temperatuur",
"max": "Maximum temperatuur"
},
"maxModulation": "Max. modulatieniveau",
"ohProtection": {
"title": "Oververhittingsbeveiliging",
@@ -310,16 +294,10 @@
}
},
"freezeProtection": {
"title": "Vorbeveiliging",
"desc": "Verwarming zal geforceerd worden ingeschakeld als de temperatuur van de warmtedrager of de binnentemperatuur daalt onder de <b>Lage temperatuurdrempel</b>.",
"highTemp": {
"title": "Hoge temperatuurdrempel",
"note": "Drempel waarna het systeem terugkeert naar de normale modus na activering van de vorbeveiliging"
},
"lowTemp": {
"title": "Lage temperatuurdrempel",
"note": "Drempel wanneer de verwarming geforceerd wordt ingeschakeld"
}
"title": "Vorstbeveiliging",
"desc": "De verwarming wordt geforceerd ingeschakeld als de temperatuur van de warmtedrager of de binnentemperatuur onder de <b>Lage temperatuur</b> daalt gedurende de <b>Wachttijd</b>.",
"lowTemp": "Drempelwaarde lage temperatuur",
"thresholdTime": "Wachttijd <small>(sec)</small>"
},
"portal": {
"login": "Gebruikersnaam",
@@ -357,15 +335,7 @@
"set0target": "Stel null target in"
}
},
"turboFactor": "Turbomodus coëff.",
"indoorTempAvgType": {
"title": "Binnentemperatuur gemiddelde type",
"desc": "Nuttig bij twee of meer binnentemperatuursensoren (bij gebruik van «Equitherm» en/of «PID»)."
},
"outdoorTempAvgType": {
"title": "Buitentemperatuur gemiddelde type",
"desc": "Nuttig bij twee of meer buitensensoren (bij gebruik van «Equitherm»)."
}
"turboFactor": "Turbomodus coëff."
},
"emergency": {
"desc": "Noodmodus wordt automatisch geactiveerd wanneer «PID» of «Equitherm» het instelpunt van de warmtedrager niet kan berekenen:<br />- als «Equitherm» is ingeschakeld en de buitentemperatuursensor is losgekoppeld;<br />- als «PID» of OT-optie <i>«Natuurlijke verwarmingsregeling»</i> is ingeschakeld en de binnentemperatuursensor is losgekoppeld.<br /><b>Let op:</b> Bij een netwerk- of MQTT-storing krijgen sensoren van het type <i>«Handmatig via MQTT/API»</i> de status ONVERBONDEN.",
@@ -453,6 +423,7 @@
"immergasFix": "Fix voor Immergas-ketels",
"alwaysSendIndoorTemp": "Stuur huidige binnentemp naar ketel"
},
"nativeOTC": {
"title": "Native warmtedrager temperatuur berekeningsmodus",
"note": "Werkt <u>ALLEEN</u> als de ketel in OTC-modus is: vereist en accepteert de doel binnentemperatuur en regelt zelf de warmtedrager temperatuur op basis van de ingebouwde curves modus. Incompatibel met PID en Equitherm."
@@ -502,14 +473,10 @@
"title": "Upgrade - OpenTherm Gateway",
"name": "Upgrade",
"section": {
"backupAndRestore": {
"title": "Back-up & herstel",
"desc": "In deze sectie kunt u een back-up van ALLE instellingen opslaan en herstellen."
},
"upgrade": {
"title": "Upgrade",
"desc": "In deze sectie kunt u de firmware en het bestandssysteem van uw apparaat upgraden.<br />De nieuwste releases kunnen worden gedownload van de <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Releases-pagina</a> van de projectrepository."
}
"backupAndRestore": "Back-up & herstel",
"backupAndRestore.desc": "In deze sectie kunt u een back-up van ALLE instellingen opslaan en herstellen.",
"upgrade": "Upgrade",
"upgrade.desc": "In deze sectie kunt u de firmware en het bestandssysteem van uw apparaat upgraden.<br />De nieuwste releases kunnen worden gedownload van de <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Releases-pagina</a> van de projectrepository."
},
"note": {
"disclaimer1": "Na een succesvolle upgrade van het bestandssysteem worden ALLE instellingen teruggezet naar de standaardwaarden! Sla een back-up op voordat u gaat upgraden.",
+59 -51
View File
@@ -8,19 +8,15 @@
"issues": "Проблемы и вопросы",
"releases": "Релизы"
},
"units": {
"dbm": "дБм",
"kw": "кВт",
"time": {
"days": "д.",
"hours": "ч.",
"min": "мин.",
"sec": "сек.",
"dbm": "дБм",
"mhz": "МГц",
"kw": "кВт",
"rpm": "RPM",
"ppm": "ppm",
"byte": "байт",
"mbyte": "мбайт"
"sec": "сек."
},
"button": {
"upgrade": "Обновить",
"restart": "Перезагрузка",
@@ -35,25 +31,26 @@
"success": "Успешно",
"error": "Ошибка"
},
"index": {
"title": "OpenTherm Gateway",
"section": {
"network": "Сеть",
"system": "Система"
},
"system": {
"build": {
"title": "Билд",
"version": "Версия",
"commit": "Коммит",
"date": "Дата",
"core": "Ядро",
"sdk": "SDK"
},
"uptime": "Аптайм",
"memory": {
"heap": "Память (heap)",
"psram": "Память (PSRAM)",
"title": "ОЗУ",
"maxFreeBlock": "макс. блок",
"min": "мин."
},
@@ -70,22 +67,26 @@
"lastResetReason": "Причина перезагрузки"
}
},
"dashboard": {
"name": "Дашборд",
"title": "Дашборд - OpenTherm Gateway",
"section": {
"control": "Управление",
"states": "Состояние",
"sensors": "Сенсоры",
"diag": "Диагностика OpenTherm"
},
"thermostat": {
"heating": "Отопление",
"dhw": "ГВС",
"currentTemp": "Текущая",
"temp.current": "Текущая",
"enable": "Вкл",
"turbo": "Турбо"
},
"notify": {
"fault": {
"title": "Состояние неисправности котла активно!",
@@ -97,6 +98,7 @@
},
"reset": "Сбросить"
},
"states": {
"mNetworkConnected": "Подключение к сети",
"mMqttConnected": "Подключение к MQTT",
@@ -104,6 +106,7 @@
"mExtPumpState": "Внешний насос",
"mCascadeControlInput": "Каскадное управление (вход)",
"mCascadeControlOutput": "Каскадное управление (выход)",
"sConnected": "Подключение к OpenTherm",
"sFlame": "Пламя",
"sCoolingActive": "Охлаждение",
@@ -112,10 +115,10 @@
"sFaultCode": "Код ошибки",
"sDiagActive": "Диагностика",
"sDiagCode": "Диагностический код",
"mHeatEnabled": "Отопление",
"mHeatBlocking": "Блокировка отопления",
"mHeatOverheat": "Отопление, перегрев",
"mHeatFreezing": "Отопление, защита от замерзания",
"sHeatActive": "Активность отопления",
"mHeatSetpointTemp": "Отопление, уставка",
"mHeatTargetTemp": "Отопление, целевая температура",
@@ -123,6 +126,7 @@
"mHeatRetTemp": "Отопление, температура обратки",
"mHeatIndoorTemp": "Отопление, внутренняя темп.",
"mHeatOutdoorTemp": "Отопление, наружная темп.",
"mDhwEnabled": "ГВС",
"mDhwOverheat": "ГВС, перегрев",
"sDhwActive": "Активность ГВС",
@@ -130,6 +134,7 @@
"mDhwCurrTemp": "ГВС, текущая температура",
"mDhwRetTemp": "ГВС, температура обратки"
},
"sensors": {
"values": {
"temp": "Температура",
@@ -139,19 +144,23 @@
}
}
},
"network": {
"title": "Сеть - OpenTherm Gateway",
"name": "Настройки сети",
"section": {
"static": "Статические параметры",
"availableNetworks": "Доступные сети",
"staSettings": "Настройки подключения",
"apSettings": "Настройки точки доступа"
},
"scan": {
"pos": "#",
"info": "Инфо"
},
"wifi": {
"ssid": "Имя сети",
"password": "Пароль",
@@ -159,6 +168,7 @@
"signal": "Сигнал",
"connected": "Подключено"
},
"params": {
"hostname": "Имя хоста",
"dhcp": "Использовать DHCP",
@@ -168,15 +178,16 @@
"gateway": "Адрес шлюза",
"dns": "DNS адрес"
},
"sta": {
"channel": {
"note": "установите 0 для автоматического выбора"
}
"channel.note": "установите 0 для автоматического выбора"
}
},
"sensors": {
"title": "Настройки сенсоров - OpenTherm Gateway",
"name": "Настройки сенсоров",
"enabled": "Включить и использовать",
"sensorName": {
"title": "Имя сенсора",
@@ -233,11 +244,10 @@
"otHeatingPumpHours": "OpenTherm, кол-во часов работы насоса (отопление)",
"otDhwPumpHours": "OpenTherm, кол-во часов работы насоса (ГВС)",
"otCoolingHours": "OpenTherm, кол-во часов работы охлаждения",
"ntcTemp": "NTC датчик",
"dallasTemp": "DALLAS датчик",
"bluetooth": "BLE датчик",
"dht11": "DHT11 датчик",
"dht22": "DHT22 датчик",
"heatSetpointTemp": "Отопление, температура уставки",
"manual": "Вручную через MQTT/API",
"notConfigured": "Не сконфигурировано"
@@ -264,9 +274,11 @@
}
}
},
"settings": {
"title": "Настройки - OpenTherm Gateway",
"name": "Настройки",
"section": {
"portal": "Настройки портала",
"system": "Системные настройки",
@@ -281,21 +293,18 @@
"extPump": "Настройки дополнительного насоса",
"cascadeControl": "Настройки каскадного управления"
},
"enable": "Вкл",
"note": {
"restart": "После изменения этих настроек устройство необходимо перезагрузить, чтобы изменения вступили в силу.",
"blankNotUse": "пусто - не использовать",
"bleDevice": "BLE устройство можно использовать <u>только</u> с некоторыми платами ESP32, которые поддерживают BLE!"
},
"temp": {
"min": "Мин. температура",
"max": "Макс. температура"
},
"avgType": {
"mean": "Средняя температура",
"min": "Минимальная температура",
"max": "Максимальная температура"
},
"maxModulation": "Макс. уровень модуляции",
"ohProtection": {
"title": "Защита от перегрева",
@@ -311,22 +320,18 @@
},
"freezeProtection": {
"title": "Защита от замерзания",
"desc": "Отопление будет принудительно включено, если темп. теплоносителя или внутренняя темп. опустится ниже <b>нижнего порога</b>.",
"highTemp": {
"title": "Верхний порог температуры",
"note": "Порог, при котором система вернется в нормальное состояние после активации защиты от замерзания"
},
"lowTemp": {
"title": "Нижний порог температуры",
"note": "Порог, при котором отопление будет принудительно включено"
}
"desc": "Отопление будет принудительно включено, если темп. теплоносителя или внутренняя темп. опустится ниже <b>нижнего порога</b> в течение <b>времени ожидания</b>.",
"lowTemp": "Нижний порог температуры",
"thresholdTime": "Время ожидания <small>(сек)</small>"
},
"portal": {
"login": "Логин",
"password": "Пароль",
"auth": "Требовать аутентификацию",
"mdns": "Использовать mDNS"
},
"system": {
"unit": "Система единиц",
"metric": "Метрическая <small>(цельсии, литры, бары)</small>",
@@ -346,6 +351,7 @@
"timezonePresets": "Выберите пресет..."
}
},
"heating": {
"hyst": {
"title": "Гистерезис",
@@ -357,24 +363,19 @@
"set0target": "Установить 0 в качестве целевой темп."
}
},
"turboFactor": "Коэфф. турбо режима",
"indoorTempAvgType": {
"title": "Тип усреднения внутренней темп.",
"desc": "Полезно при использовании двух и более датчиков внутренней температуры (при использовании «Equitherm» и/или «PID»)."
},
"outdoorTempAvgType": {
"title": "Тип усреднения наружнной темп.",
"desc": "Полезно при использовании двух и более датчиков наружной температуры (при использовании «Equitherm»)."
}
"turboFactor": "Коэфф. турбо режима"
},
"emergency": {
"desc": "Аварийный режим активируется автоматически, если «ПИД» или «ПЗА» не могут рассчитать уставку теплоносителя:<br />- если «ПЗА» включен и датчик наружной температуры отключен;<br />- если включен «ПИД» или OT опция <i>«Передать управление отоплением котлу»</i> и датчик внутренней температуры отключен.<br /><b>Примечание:</b> При сбое сети или MQTT датчики с типом <i>«Вручную через MQTT/API»</i> будут находиться в состоянии ОТКЛЮЧЕН.",
"target": {
"title": "Целевая температура",
"note": "<b>Важно:</b> <u>Целевая температура в помещении</u>, если включена ОТ опция <i>«Передать управление отоплением котлу»</i>.<br />Во всех остальных случаях <u>целевая температура теплоносителя</u>."
},
"treshold": "Пороговое время включения <small>(сек)</small>"
},
"equitherm": {
"slope": {
"title": "Наклон",
@@ -398,6 +399,7 @@
"outdoorTemp": "Наружная температура"
}
},
"pid": {
"p": "Коэффициент P",
"i": "Коэффициент I",
@@ -417,6 +419,7 @@
"thresholdLow": "Нижний порог"
}
},
"ot": {
"advanced": "Дополнительные настройки",
"inGpio": "Вход GPIO",
@@ -432,6 +435,7 @@
"title": "Макс. мощность котла <small>(кВт)</small>",
"note": "<b>0</b> - попробовать определить автоматически. Обычно можно найти в спецификации котла как \"максимальная полезная тепловая мощность\"."
},
"options": {
"title": "Опции (дополнительные настройки)",
"desc": "Опции могут менять логику работы котла. Не все опции задокументированы в протоколе, поэтому одна и та же опция может иметь разный эффект на разных котлах.<br /><b>Примечание:</b> Нет необходимости что-то менять, если всё работает хорошо.",
@@ -453,11 +457,13 @@
"immergasFix": "Фикс для котлов Immergas",
"alwaysSendIndoorTemp": "Передавать текущую темп. в помещении котлу"
},
"nativeOTC": {
"title": "Нативный режим OTC (расчёт температуры теплоносителя)",
"note": "Работает <u>ТОЛЬКО</u> если котел в режиме OTC: требует и принимает целевую температуру в помещении и сам регулирует температуру теплоносителя на основе встроенного режима кривых. Несовместимо с ПИД и ПЗА."
}
},
"mqtt": {
"homeAssistantDiscovery": "Home Assistant Discovery",
"server": "Адрес сервера",
@@ -467,6 +473,7 @@
"prefix": "Префикс",
"interval": "Интервал публикации <small>(сек)</small>"
},
"extPump": {
"use": "Использовать доп. насос",
"gpio": "GPIO реле",
@@ -475,6 +482,7 @@
"antiStuckInterval": "Интервал защиты от блокировки <small>(в днях)</small>",
"antiStuckTime": "Время работы насоса <small>(в минутах)</small>"
},
"cascadeControl": {
"input": {
"desc": "Может использоваться для включения отопления только при неисправности другого котла. Контроллер другого котла должен изменить состояние входа GPIO в случае неисправности.",
@@ -498,26 +506,26 @@
}
}
},
"upgrade": {
"title": "Обновление - OpenTherm Gateway",
"name": "Обновление",
"section": {
"backupAndRestore": {
"title": "Резервное копирование и восстановление",
"desc": "В этом разделе вы можете сохранить и восстановить резервную копию ВСЕХ настроек."
},
"upgrade": {
"title": "Обновление",
"desc": "В этом разделе вы можете обновить прошивку и файловую систему вашего устройства.<br />Последнюю версию можно загрузить со страницы <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Релизы</a> в репозитории проекта."
}
"backupAndRestore": "Резервное копирование и восстановление",
"backupAndRestore.desc": "В этом разделе вы можете сохранить и восстановить резервную копию ВСЕХ настроек.",
"upgrade": "Обновление",
"upgrade.desc": "В этом разделе вы можете обновить прошивку и файловую систему вашего устройства.<br />Последнюю версию можно загрузить со страницы <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Релизы</a> в репозитории проекта."
},
"note": {
"disclaimer1": "После успешного обновления файловой системы ВСЕ настройки будут сброшены на стандартные! Создайте резервную копию ПЕРЕД обновлением.",
"disclaimer2": "После успешного обновления устройство автоматически перезагрузится через 15 секунд."
},
"settingsFile": "Файл настроек",
"fw": "Прошивка",
"fs": "Файловая система"
}
}
}
}
+4 -13
View File
@@ -47,7 +47,7 @@
<div class="thermostat-header" data-i18n>dashboard.thermostat.heating</div>
<div class="thermostat-temp">
<div class="thermostat-temp-target"><span class="targetTemp"></span> <span class="tempUnit"></span></div>
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.currentTemp</span>: <span id="tHeatCurrentTemp"></span> <span class="tempUnit"></span></div>
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.temp.current</span>: <span id="tHeatCurrentTemp"></span> <span class="tempUnit"></span></div>
</div>
<div class="thermostat-minus">
<button class="tAction outline" data-action="decrement"><i class="icons-down"></i></button>
@@ -68,7 +68,7 @@
<div class="thermostat-header" data-i18n>dashboard.thermostat.dhw</div>
<div class="thermostat-temp">
<div class="thermostat-temp-target"><span class="targetTemp"></span> <span class="tempUnit"></span></div>
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.currentTemp</span>: <span id="tDhwCurrentTemp"></span> <span class="tempUnit"></span></div>
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.temp.current</span>: <span id="tDhwCurrentTemp"></span> <span class="tempUnit"></span></div>
</div>
<div class="thermostat-minus">
<button class="tAction outline" data-action="decrement"><i class="icons-down"></i></button>
@@ -195,10 +195,6 @@
<th scope="row" data-i18n>dashboard.states.mHeatOverheat</th>
<td><i class="mHeatOverheat"></i></td>
</tr>
<tr>
<th scope="row" data-i18n>dashboard.states.mHeatFreezing</th>
<td><i class="mHeatFreezing"></i></td>
</tr>
<tr>
<th scope="row" data-i18n>dashboard.states.sHeatActive</th>
<td><i class="sHeatActive"></i></td>
@@ -324,7 +320,7 @@
document.addEventListener('DOMContentLoaded', async () => {
const lang = new Lang(document.getElementById('lang'));
await lang.build();
lang.build();
let actionTimer = null;
let actionLongPress = false;
@@ -640,11 +636,6 @@
result.master.heating.overheat ? "success" : "error",
result.master.heating.overheat ? "red" : "green"
);
setStatus(
'.mHeatFreezing',
result.master.heating.freezing ? "success" : "error",
result.master.heating.freezing ? "red" : "green"
);
setValue('.mHeatSetpointTemp', result.master.heating.setpointTemp);
setValue('.mHeatTargetTemp', result.master.heating.targetTemp);
setValue('.mHeatCurrTemp', result.master.heating.currentTemp);
@@ -769,7 +760,7 @@
}
if (sData.rssi !== undefined) {
appendValue(".sValue", `${i18n('dashboard.sensors.values.rssi')}: <b>${sData.rssi.toFixed(0)}</b> ${i18n('units.dbm')}`, `<br />`, sensorNode);
appendValue(".sValue", `${i18n('dashboard.sensors.values.rssi')}: <b>${sData.rssi.toFixed(0)}</b> ${i18n('dbm')}`, `<br />`, sensorNode);
}
}
+10 -24
View File
@@ -104,7 +104,6 @@
<th scope="row" data-i18n>index.system.build.title</th>
<td>
Env: <b id="build-env"></b><br />
<span data-i18n>index.system.build.commit</span>: <b id="build-commit"></b><br />
<span data-i18n>index.system.build.date</span>: <b id="build-date"></b><br />
<span data-i18n>index.system.build.core</span>: <b id="build-core"></b><br />
<span data-i18n>index.system.build.sdk</span>: <b id="build-sdk"></b>
@@ -113,32 +112,25 @@
<tr>
<th scope="row" data-i18n>index.system.uptime</th>
<td>
<b id="uptime-days"></b> <span data-i18n>units.days</span>,
<b id="uptime-hours"></b> <span data-i18n>units.hours</span>,
<b id="uptime-min"></b> <span data-i18n>units.min</span>,
<b id="uptime-sec"></b> <span data-i18n>units.sec</span>
<b id="uptime-days"></b> <span data-i18n>time.days</span>,
<b id="uptime-hours"></b> <span data-i18n>time.hours</span>,
<b id="uptime-min"></b> <span data-i18n>time.min</span>,
<b id="uptime-sec"></b> <span data-i18n>time.sec</span>
</td>
</tr>
<tr>
<th scope="row" data-i18n>index.system.memory.heap</th>
<th scope="row" data-i18n>index.system.memory.title</th>
<td>
<b id="heap-free"></b> of <b id="heap-total"></b> <span data-i18n>units.byte</span> (<span data-i18n>index.system.memory.min</span>: <b id="heap-min-free"></b> <span data-i18n>units.byte</span>)<br />
<span data-i18n>index.system.memory.maxFreeBlock</span>: <b id="heap-max-free-block"></b> <span data-i18n>units.byte</span> (<span data-i18n>index.system.memory.min</span>: <b id="heap-min-max-free-block"></b> <span data-i18n>units.byte</span>)
</td>
</tr>
<tr>
<th scope="row" data-i18n>index.system.memory.psram</th>
<td>
<b id="psram-free"></b> of <b id="psram-total"></b> <span data-i18n>units.byte</span> (<span data-i18n>index.system.memory.min</span>: <b id="psram-min-free"></b> <span data-i18n>units.byte</span>)<br />
<span data-i18n>index.system.memory.maxFreeBlock</span>: <b id="psram-max-free-block"></b> <span data-i18n>units.byte</span>
<b id="heap-free"></b> of <b id="heap-total"></b> bytes (<span data-i18n>index.system.memory.min</span>: <b id="heap-min-free"></b> bytes)<br />
<span data-i18n>index.system.memory.maxFreeBlock</span>: <b id="heap-max-free-block"></b> bytes (<span data-i18n>index.system.memory.min</span>: <b id="heap-min-max-free-block"></b> bytes)
</td>
</tr>
<tr>
<th scope="row" data-i18n>index.system.board</th>
<td>
<span data-i18n>index.system.chip.model</span>: <b id="chip-model"></b> (rev. <span id="chip-rev"></span>)<br />
<span data-i18n>index.system.chip.cores</span>: <b id="chip-cores"></b>, <span data-i18n>index.system.chip.freq</span>: <b id="chip-freq"></b> <span data-i18n>units.mhz</span><br />
<span data-i18n>index.system.flash.size</span>: <b id="flash-size"></b> <span data-i18n>units.mbyte</span> (<span data-i18n>index.system.flash.realSize</span>: <b id="flash-real-size"></b> <span data-i18n>units.mbyte</span>)
<span data-i18n>index.system.chip.cores</span>: <b id="chip-cores"></b>, <span data-i18n>index.system.chip.freq</span>: <b id="chip-freq"></b> mHz<br />
<span data-i18n>index.system.flash.size</span>: <b id="flash-size"></b> MB (<span data-i18n>index.system.flash.realSize</span>: <b id="flash-real-size"></b> MB)
</td>
</tr>
<tr>
@@ -177,7 +169,7 @@
<script>
document.addEventListener('DOMContentLoaded', async () => {
const lang = new Lang(document.getElementById('lang'));
await lang.build();
lang.build();
setTimeout(async function onLoadPage() {
try {
@@ -214,7 +206,6 @@
setBusy('#main-busy', '#main-table', false);
setValue('#build-version', result.build.version);
setValue('#build-commit', result.build.commit);
setValue('#build-date', result.build.date);
setValue('#build-env', result.build.env);
setValue('#build-core', result.build.core);
@@ -226,11 +217,6 @@
setValue('#heap-max-free-block', result.heap.maxFreeBlock);
setValue('#heap-min-max-free-block', result.heap.minMaxFreeBlock);
setValue('#psram-total', result.psram.total);
setValue('#psram-free', result.psram.free);
setValue('#psram-min-free', result.psram.minFree);
setValue('#psram-max-free-block', result.psram.maxFreeBlock);
setValue('#chip-model', result.chip.model);
setValue('#chip-rev', result.chip.rev);
setValue('#chip-cores', result.chip.cores);
+1 -1
View File
@@ -179,7 +179,7 @@
<script>
document.addEventListener('DOMContentLoaded', async () => {
const lang = new Lang(document.getElementById('lang'));
await lang.build();
lang.build();
const fillData = (data) => {
setInputValue("[name='hostname']", data.hostname);
+4 -14
View File
@@ -118,8 +118,6 @@
<option value="50" data-i18n>sensors.types.ntcTemp</option>
<option value="51" data-i18n>sensors.types.dallasTemp</option>
<option value="52" data-i18n>sensors.types.bluetooth</option>
<option value="53" data-i18n>sensors.types.dht11</option>
<option value="54" data-i18n>sensors.types.dht22</option>
<option value="253" data-i18n>sensors.types.heatSetpointTemp</option>
<option value="254" data-i18n>sensors.types.manual</option>
<option value="255" data-i18n>sensors.types.notConfigured</option>
@@ -203,7 +201,7 @@
<script>
document.addEventListener("DOMContentLoaded", async () => {
const lang = new Lang(document.getElementById("lang"));
await lang.build();
lang.build();
const container = document.querySelector("article");
const templateNode = container.querySelector("#template");
@@ -273,35 +271,27 @@
}
switch(parseInt(event.target.value)) {
// NTC10K
// ntc
case 50:
parentGpio.classList.remove("hidden");
parentAddress.classList.add("hidden");
address.removeAttribute("pattern");
break;
// OneWire
// dallas
case 51:
parentGpio.classList.remove("hidden");
parentAddress.classList.remove("hidden");
address.setAttribute("pattern", "([A-Fa-f0-9]{2}:){7}[A-Fa-f0-9]{2}");
break;
// Bluetooth
// ble
case 52:
parentGpio.classList.add("hidden");
parentAddress.classList.remove("hidden");
address.setAttribute("pattern", "([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}");
break;
// DHT
case 53:
case 54:
parentGpio.classList.remove("hidden");
parentAddress.classList.add("hidden");
address.removeAttribute("pattern");
break;
// other
default:
parentGpio.classList.add("hidden");
+6 -35
View File
@@ -198,28 +198,6 @@
</label>
</div>
<div class="grid">
<label>
<span data-i18n>settings.heating.indoorTempAvgType.title</span>
<select name="heating[indoorTempAvgType]">
<option value="0" data-i18n>settings.avgType.mean</option>
<option value="1" data-i18n>settings.avgType.min</option>
<option value="2" data-i18n>settings.avgType.max</option>
</select>
<small data-i18n>settings.heating.indoorTempAvgType.desc</small>
</label>
<label>
<span data-i18n>settings.heating.outdoorTempAvgType.title</span>
<select name="heating[outdoorTempAvgType]">
<option value="0" data-i18n>settings.avgType.mean</option>
<option value="1" data-i18n>settings.avgType.min</option>
<option value="2" data-i18n>settings.avgType.max</option>
</select>
<small data-i18n>settings.heating.outdoorTempAvgType.desc</small>
</label>
</div>
<hr />
<details>
@@ -281,15 +259,13 @@
<div class="grid">
<label>
<span data-i18n>settings.freezeProtection.highTemp.title</span>
<input type="number" inputmode="numeric" name="heating[freezeProtection][highTemp]" min="0" max="0" step="1" required>
<small data-i18n>settings.freezeProtection.highTemp.note</small>
<span data-i18n>settings.freezeProtection.lowTemp</span>
<input type="number" inputmode="numeric" name="heating[freezeProtection][lowTemp]" min="0" max="0" step="1" required>
</label>
<label>
<span data-i18n>settings.freezeProtection.lowTemp.title</span>
<input type="number" inputmode="numeric" name="heating[freezeProtection][lowTemp]" min="0" max="0" step="1" required>
<small data-i18n>settings.freezeProtection.lowTemp.note</small>
<span data-i18n>settings.freezeProtection.thresholdTime</span>
<input type="number" inputmode="numeric" name="heating[freezeProtection][thresholdTime]" min="30" max="1800" step="1" required>
</label>
</div>
@@ -943,7 +919,7 @@
<script>
document.addEventListener('DOMContentLoaded', async () => {
const lang = new Lang(document.getElementById('lang'));
await lang.build();
lang.build();
let etChart = null;
let etChartConfig = {
@@ -1193,8 +1169,6 @@
setSelectValue("[name='heating[hysteresis][action]']", data.heating.hysteresis.action);
setInputValue("[name='heating[turboFactor]']", data.heating.turboFactor);
setInputValue("[name='heating[maxModulation]']", data.heating.maxModulation);
setSelectValue("[name='heating[indoorTempAvgType]']", data.heating.indoorTempAvgType);
setSelectValue("[name='heating[outdoorTempAvgType]']", data.heating.outdoorTempAvgType);
setInputValue("[name='heating[overheatProtection][highTemp]']", data.heating.overheatProtection.highTemp, {
"min": 0,
"max": data.system.unitSystem == 0 ? 100 : 212
@@ -1203,14 +1177,11 @@
"min": 0,
"max": data.system.unitSystem == 0 ? 99 : 211
});
setInputValue("[name='heating[freezeProtection][highTemp]']", data.heating.freezeProtection.highTemp, {
"min": data.system.unitSystem == 0 ? 1 : 34,
"max": data.system.unitSystem == 0 ? 50 : 122
});
setInputValue("[name='heating[freezeProtection][lowTemp]']", data.heating.freezeProtection.lowTemp, {
"min": data.system.unitSystem == 0 ? 1 : 34,
"max": data.system.unitSystem == 0 ? 30 : 86
});
setInputValue("[name='heating[freezeProtection][thresholdTime]']", data.heating.freezeProtection.thresholdTime);
setBusy('#heating-settings-busy', '#heating-settings', false);
// DHW
+3 -3
View File
@@ -35,7 +35,7 @@
<article>
<div>
<hgroup>
<h2 data-i18n>upgrade.section.backupAndRestore.title</h2>
<h2 data-i18n>upgrade.section.backupAndRestore</h2>
<p data-i18n>upgrade.section.backupAndRestore.desc</p>
</hgroup>
@@ -56,7 +56,7 @@
<article>
<div>
<hgroup>
<h2 data-i18n>upgrade.section.upgrade.title</h2>
<h2 data-i18n>upgrade.section.upgrade</h2>
<p data-i18n>upgrade.section.upgrade.desc</p>
</hgroup>
@@ -105,7 +105,7 @@
<script>
document.addEventListener('DOMContentLoaded', async () => {
const lang = new Lang(document.getElementById('lang'));
await lang.build();
lang.build();
setupRestoreBackupForm('#restore');
+3 -3
View File
@@ -784,9 +784,9 @@ const purposeUnit = (purpose, unitSystem) => {
7: tUnit,
8: "%",
248: "%",
249: i18n('units.kw'),
250: i18n('units.rpm'),
251: i18n('units.ppm'),
249: i18n('kw'),
250: "RPM",
251: "ppm",
252: pressureUnit(unitSystem),
253: "%",
254: tUnit
-16
View File
@@ -1,16 +0,0 @@
import subprocess
Import("env")
try:
commit_hash = "undefined"
result = subprocess.check_output(
["git", "rev-parse", "--short", "HEAD"]
)
commit_hash = result.decode("utf-8").strip()
env.Append(
CPPDEFINES=[
("BUILD_COMMIT", '\\"{}\\"'.format(commit_hash))
]
)
except Exception as error:
print("Failed to get commit hash: {}".format(error))