mirror of
https://github.com/Laxilef/OTGateway.git
synced 2026-06-18 22:39:31 +05:00
Compare commits
21 Commits
2bd3360880
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 54217fbbc1 | |||
| 69116aa3d2 | |||
| bb6b3f1854 | |||
| a4ca20f9a9 | |||
| f5e08f20a2 | |||
| 07650b4878 | |||
| ffcacb3d48 | |||
| bdfa793c49 | |||
| 25280bf9b1 | |||
| 9c2e420ec7 | |||
| af2d4624b3 | |||
| 14d2262d2f | |||
| db99746ee9 | |||
| bfc1cc1118 | |||
| 01a70b3288 | |||
| 5d053690c6 | |||
| ea95b5fa7d | |||
| dd9cb0b88f | |||
| ec7a24ce0c | |||
| 44fb0afffa | |||
| ef1d6bf195 |
@@ -0,0 +1,169 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "assets/**"
|
||||
- "tools/**"
|
||||
- "**/*.md"
|
||||
- "LICENSE"
|
||||
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "assets/**"
|
||||
- "tools/**"
|
||||
- "**/*.md"
|
||||
- "LICENSE"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
name: Prepare (get envs)
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
envs: ${{ steps.envs.outputs.envs }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Install PlatformIO Core
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
pip install --upgrade intelhex
|
||||
|
||||
- name: Get environments
|
||||
id: envs
|
||||
shell: bash
|
||||
run: |
|
||||
ENVS=$(
|
||||
pio project config --json-output \
|
||||
| jq -c '
|
||||
.[]
|
||||
| select(type == "array")
|
||||
| .[0]
|
||||
| select(startswith("env:"))
|
||||
| sub("^env:"; "")
|
||||
' | jq -s -c '.'
|
||||
)
|
||||
|
||||
echo "envs=$ENVS" >> "$GITHUB_OUTPUT"
|
||||
echo "$ENVS"
|
||||
|
||||
build:
|
||||
name: Build ${{ matrix.env }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: prepare
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
env: ${{ fromJson(needs.prepare.outputs.envs) }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
- name: Install PlatformIO Core
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
pip install --upgrade intelhex
|
||||
|
||||
- name: Full clean
|
||||
run: |
|
||||
pio run -e ${{ matrix.env }} -t fullclean
|
||||
|
||||
- name: Build firmware & filesystem
|
||||
env:
|
||||
PIOENV: ${{ matrix.env }}
|
||||
run: |
|
||||
pio run -e ${{ matrix.env }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ matrix.env }}
|
||||
if-no-files-found: error
|
||||
path: |
|
||||
build/*.bin
|
||||
build/*.elf
|
||||
|
||||
release:
|
||||
name: Release Dev
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
permissions:
|
||||
contents: write
|
||||
if: ${{ github.repository_owner == 'Laxilef' && github.ref == 'refs/heads/async' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Move dev tag
|
||||
run: |
|
||||
git fetch --tags
|
||||
git tag -f dev
|
||||
git push origin refs/tags/dev --force
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: artifacts
|
||||
merge-multiple: true
|
||||
|
||||
- name: Delete old release assets
|
||||
uses: mknejp/delete-release-assets@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: dev
|
||||
fail-if-no-assets: false
|
||||
fail-if-no-release: false
|
||||
assets: |
|
||||
*.bin
|
||||
*.elf
|
||||
|
||||
- name: Clear release body
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh release edit dev --notes ""
|
||||
|
||||
- name: Publish Dev release
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
tag_name: dev
|
||||
target_commitish: async
|
||||
name: Dev (unstable)
|
||||
prerelease: true
|
||||
make_latest: false
|
||||
generate_release_notes: true
|
||||
files: |
|
||||
artifacts/*.bin
|
||||
artifacts/*.elf
|
||||
@@ -0,0 +1,110 @@
|
||||
name: CI
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
validate-json:
|
||||
name: Validate JSON
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install jq
|
||||
run: sudo apt-get update && sudo apt-get install -y jq
|
||||
|
||||
- name: Validate
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
echo "Searching JSON files in src_data..."
|
||||
|
||||
files=$(find src_data -type f -iname "*.json")
|
||||
|
||||
if [ -z "$files" ]; then
|
||||
echo "No JSON files found."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
failed=0
|
||||
|
||||
for file in $files; do
|
||||
echo "Validating: $file"
|
||||
|
||||
if ! jq empty "$file" >/dev/null 2>&1; then
|
||||
echo "❌ Invalid JSON: $file"
|
||||
failed=1
|
||||
else
|
||||
echo "✅ Valid JSON: $file"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$failed" -ne 0 ]; then
|
||||
echo ""
|
||||
echo "JSON validation failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "All JSON files are valid."
|
||||
|
||||
cpplint:
|
||||
name: cpplint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
key: ${{ runner.os }}-cpplint
|
||||
path: ~/.cache/pip
|
||||
|
||||
- name: Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Install cpplint
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade cpplint
|
||||
|
||||
- name: cpplint
|
||||
run: |
|
||||
FILTERS="-legal/copyright,\
|
||||
-runtime/int,\
|
||||
-runtime/references,\
|
||||
-runtime/indentation_namespace,\
|
||||
-runtime/arrays,\
|
||||
-runtime/printf,\
|
||||
-whitespace/line_length,\
|
||||
-whitespace/braces,\
|
||||
-whitespace/comments,\
|
||||
-whitespace/indent,\
|
||||
-whitespace/newline,\
|
||||
-whitespace/parens,\
|
||||
-whitespace/blank_line,\
|
||||
-readability/braces,\
|
||||
-readability/todo,\
|
||||
-readability/namespace,\
|
||||
-build/header_guard,\
|
||||
-build/include_subdir,\
|
||||
-build/include_what_you_use,\
|
||||
-build/namespaces,\
|
||||
-build/c++11"
|
||||
|
||||
cpplint \
|
||||
--repository=. \
|
||||
--recursive \
|
||||
--quiet \
|
||||
--filter="$FILTERS" \
|
||||
include lib src
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
[](https://github.com/Laxilef/OTGateway/releases)
|
||||
[](https://github.com/Laxilef/OTGateway/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/otgateway/)
|
||||
[](LICENSE.txt)
|
||||
[](https://t.me/otgateway)
|
||||
|
||||
@@ -71,10 +72,18 @@ 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!
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
class BufferedWebServer {
|
||||
public:
|
||||
BufferedWebServer(WebServer* webServer, size_t bufferSize = 64) {
|
||||
explicit BufferedWebServer(WebServer* webServer, size_t bufferSize = 64) {
|
||||
this->webServer = webServer;
|
||||
this->bufferSize = bufferSize;
|
||||
this->buffer = (uint8_t*)malloc(bufferSize * sizeof(*this->buffer));
|
||||
this->buffer = static_cast<uint8_t*>(malloc(bufferSize * sizeof(*this->buffer)));
|
||||
}
|
||||
|
||||
~BufferedWebServer() {
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
|
||||
if (pretty) {
|
||||
serializeJsonPretty(content, *this);
|
||||
|
||||
|
||||
} else {
|
||||
serializeJson(content, *this);
|
||||
}
|
||||
@@ -99,4 +99,4 @@ protected:
|
||||
uint8_t* buffer;
|
||||
size_t bufferSize = 64;
|
||||
size_t bufferPos = 0;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ public:
|
||||
typedef std::function<void(unsigned long, uint8_t)> BeforeSendRequestCallback;
|
||||
typedef std::function<void(unsigned long, unsigned long, OpenThermResponseStatus, uint8_t)> AfterSendRequestCallback;
|
||||
|
||||
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false, bool alwaysReceive = false) : OpenTherm(inPin, outPin, isSlave, alwaysReceive) {}
|
||||
explicit CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false, bool alwaysReceive = false) : OpenTherm(inPin, outPin, isSlave, alwaysReceive) {}
|
||||
~CustomOpenTherm() {}
|
||||
|
||||
CustomOpenTherm* setDelayCallback(DelayCallback callback = nullptr) {
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
if (this->publishEventCallback) {
|
||||
this->publishEventCallback(topic, false);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
return topic;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class T>
|
||||
String getDeviceTopic(T value, char dpvSeparator = '/') {
|
||||
String topic = "";
|
||||
topic.concat(this->devicePrefix);
|
||||
@@ -147,7 +147,7 @@ public:
|
||||
return topic;
|
||||
}
|
||||
|
||||
template <class DT, class VT>
|
||||
template <class DT, class VT>
|
||||
String getEntityIdWithPrefix(DT domain, VT value, char separator = '_') {
|
||||
String topic = "";
|
||||
topic.concat(domain);
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
return topic;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class T>
|
||||
String getUniqueIdWithPrefix(T value, char separator = '_') {
|
||||
String topic = "";
|
||||
topic.concat(this->devicePrefix);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM
|
||||
#define PROGMEM // NOLINT
|
||||
#endif
|
||||
|
||||
const char HA_ENTITY_BINARY_SENSOR[] PROGMEM = "binary_sensor";
|
||||
|
||||
@@ -21,4 +21,4 @@ public:
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
@@ -12,10 +12,10 @@ public:
|
||||
typedef std::function<void(const char*, size_t, size_t, bool)> PublishEventCallback;
|
||||
typedef std::function<void(size_t, size_t)> FlushEventCallback;
|
||||
|
||||
MqttWriter(MqttClient* client, size_t bufferSize = 64) {
|
||||
explicit MqttWriter(MqttClient* client, size_t bufferSize = 64) {
|
||||
this->client = client;
|
||||
this->bufferSize = bufferSize;
|
||||
this->buffer = (uint8_t*) malloc(bufferSize * sizeof(*this->buffer));
|
||||
this->buffer = static_cast<uint8_t*>(malloc(bufferSize * sizeof(*this->buffer)));
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
this->mutex = new std::mutex();
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
serializeJson(doc, *this);
|
||||
this->flush();
|
||||
this->client->endMessage();
|
||||
|
||||
|
||||
written = this->writeAfterLock;
|
||||
}
|
||||
this->unlock();
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
this->write(buffer, length);
|
||||
this->flush();
|
||||
this->client->endMessage();
|
||||
|
||||
|
||||
written = this->writeAfterLock;
|
||||
result = written == length;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ void NetworkConnection::onEvent(System_Event_t *event) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -106,7 +106,7 @@ void NetworkConnection::onEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
rawDisconnectReason = info.wifi_sta_disconnected.reason;
|
||||
disconnectReason = convertDisconnectReason(info.wifi_sta_disconnected.reason);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ NetworkConnection::DisconnectReason NetworkConnection::convertDisconnectReason(u
|
||||
case WIFI_REASON_HANDSHAKE_TIMEOUT:
|
||||
return DisconnectReason::HANDSHAKE_TIMEOUT;
|
||||
#endif
|
||||
|
||||
|
||||
default:
|
||||
return DisconnectReason::OTHER;
|
||||
}
|
||||
@@ -155,4 +155,4 @@ NetworkConnection::DisconnectReason NetworkConnection::convertDisconnectReason(u
|
||||
bool NetworkConnection::useDhcp = false;
|
||||
NetworkConnection::Status NetworkConnection::status = Status::NONE;
|
||||
NetworkConnection::DisconnectReason NetworkConnection::disconnectReason = DisconnectReason::NONE;
|
||||
uint8_t NetworkConnection::rawDisconnectReason = 0;
|
||||
uint8_t NetworkConnection::rawDisconnectReason = 0;
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace NetworkUtils {
|
||||
static Status status;
|
||||
static DisconnectReason disconnectReason;
|
||||
static uint8_t rawDisconnectReason;
|
||||
|
||||
|
||||
static void setup(bool useDhcp);
|
||||
static void setUseDhcp(bool value);
|
||||
static void reset();
|
||||
@@ -44,4 +44,4 @@ namespace NetworkUtils {
|
||||
static DisconnectReason convertDisconnectReason(uint8_t reason);
|
||||
static bool useDhcp;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace NetworkUtils {
|
||||
|
||||
wifi_station_dhcpc_set_maxtry(5);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && ESP_ARDUINO_VERSION_MAJOR < 3
|
||||
// Nothing. Because memory leaks when turn off WiFi on ESP32 SDK < 3.0.0
|
||||
return true;
|
||||
@@ -473,4 +473,4 @@ namespace NetworkUtils {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
#include <FS.h>
|
||||
|
||||
|
||||
class DynamicPage : public RequestHandler {
|
||||
public:
|
||||
typedef std::function<bool(HTTPMethod, const String&)> CanHandleCallback;
|
||||
typedef std::function<bool()> BeforeSendCallback;
|
||||
typedef std::function<String(const char*)> TemplateCallback;
|
||||
|
||||
DynamicPage(const char* uri, FS* fs, const char* path, const char* cacheHeader = nullptr) {
|
||||
this->uri = uri;
|
||||
this->fs = fs;
|
||||
this->path = path;
|
||||
this->cacheHeader = cacheHeader;
|
||||
}
|
||||
|
||||
DynamicPage* setCanHandleCallback(CanHandleCallback callback = nullptr) {
|
||||
this->canHandleCallback = callback;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DynamicPage* setBeforeSendCallback(BeforeSendCallback callback = nullptr) {
|
||||
this->beforeSendCallback = callback;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DynamicPage* setTemplateCallback(TemplateCallback callback = nullptr) {
|
||||
this->templateCallback = callback;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
bool canHandle(WebServer &server, HTTPMethod method, const String &uri) override {
|
||||
return this->canHandle(method, uri);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool canHandle(HTTPMethod method, const String& uri) override {
|
||||
return uri.equals(this->uri) && (!this->canHandleCallback || this->canHandleCallback(method, uri));
|
||||
}
|
||||
|
||||
bool handle(WebServer& server, HTTPMethod method, const String& uri) override {
|
||||
if (!this->canHandle(method, uri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->beforeSendCallback && !this->beforeSendCallback()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
File file = this->fs->open(this->path, "r");
|
||||
if (!file) {
|
||||
return false;
|
||||
|
||||
} else if (file.isDirectory()) {
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->cacheHeader != nullptr) {
|
||||
server.sendHeader(F("Cache-Control"), this->cacheHeader);
|
||||
}
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
if (!server.chunkedResponseModeStart(200, F("text/html"))) {
|
||||
server.send(505, F("text/html"), F("HTTP1.1 required"));
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
|
||||
server.send(200, "text/html", emptyString);
|
||||
#endif
|
||||
|
||||
uint8_t* argStartPos = nullptr;
|
||||
uint8_t* argEndPos = nullptr;
|
||||
uint8_t argName[16];
|
||||
size_t sizeArgName = 0;
|
||||
bool argNameProcess = false;
|
||||
while (file.available()) {
|
||||
uint8_t buf[64];
|
||||
size_t length = file.read(buf, sizeof(buf));
|
||||
size_t offset = 0;
|
||||
|
||||
if (argNameProcess) {
|
||||
argEndPos = (uint8_t*) memchr(buf, '}', length);
|
||||
|
||||
if (argEndPos != nullptr) {
|
||||
size_t fullSizeArgName = sizeArgName + (argEndPos - buf);
|
||||
if (fullSizeArgName < sizeof(argName)) {
|
||||
// copy full arg name
|
||||
if (argEndPos - buf > 0) {
|
||||
memcpy(argName + sizeArgName, buf, argEndPos - buf);
|
||||
}
|
||||
argName[fullSizeArgName] = '\0';
|
||||
|
||||
// send arg value
|
||||
String argValue = this->templateCallback((const char*) argName);
|
||||
if (argValue.length()) {
|
||||
server.sendContent(argValue.c_str());
|
||||
|
||||
} else if (fullSizeArgName > 0) {
|
||||
server.sendContent("{");
|
||||
server.sendContent((const char*) argName);
|
||||
server.sendContent("}");
|
||||
}
|
||||
|
||||
offset = size_t(argEndPos - buf + 1);
|
||||
sizeArgName = 0;
|
||||
argNameProcess = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (argNameProcess) {
|
||||
server.sendContent("{");
|
||||
|
||||
if (sizeArgName > 0) {
|
||||
argName[sizeArgName] = '\0';
|
||||
server.sendContent((const char*) argName);
|
||||
}
|
||||
|
||||
argNameProcess = false;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
uint8_t* currentBuf = buf + offset;
|
||||
size_t currentLength = length - offset;
|
||||
|
||||
argStartPos = (uint8_t*) memchr(currentBuf, '{', currentLength);
|
||||
|
||||
// send all content
|
||||
if (argStartPos == nullptr) {
|
||||
if (currentLength > 0) {
|
||||
server.sendContent((const char*) currentBuf, currentLength);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
argEndPos = (uint8_t*) memchr(argStartPos, '}', length - (argStartPos - buf));
|
||||
if (argEndPos != nullptr) {
|
||||
sizeArgName = argEndPos - argStartPos - 1;
|
||||
|
||||
// send all content if arg len > space
|
||||
if (sizeArgName >= sizeof(argName)) {
|
||||
if (currentLength > 0) {
|
||||
server.sendContent((const char*) currentBuf, currentLength);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// arg name
|
||||
memcpy(argName, argStartPos + 1, sizeArgName);
|
||||
argName[sizeArgName] = '\0';
|
||||
|
||||
// send arg value
|
||||
String argValue = this->templateCallback((const char*) argName);
|
||||
if (argValue.length()) {
|
||||
// send content before var
|
||||
if (argStartPos - buf > 0) {
|
||||
server.sendContent((const char*) currentBuf, argStartPos - buf);
|
||||
}
|
||||
|
||||
server.sendContent(argValue.c_str());
|
||||
|
||||
} else {
|
||||
server.sendContent((const char*) currentBuf, argEndPos - currentBuf + 1);
|
||||
}
|
||||
|
||||
offset = size_t(argEndPos - currentBuf + 1);
|
||||
|
||||
} else {
|
||||
sizeArgName = length - size_t(argStartPos - currentBuf) - 1;
|
||||
|
||||
// send all content if arg len > space
|
||||
if (sizeArgName >= sizeof(argName)) {
|
||||
if (currentLength) {
|
||||
server.sendContent((const char*) currentBuf, currentLength);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// send content before var
|
||||
if (argStartPos - buf > 0) {
|
||||
server.sendContent((const char*) currentBuf, argStartPos - buf);
|
||||
}
|
||||
|
||||
// copy arg name chunk
|
||||
if (sizeArgName > 0) {
|
||||
memcpy(argName, argStartPos + 1, sizeArgName);
|
||||
}
|
||||
|
||||
argNameProcess = true;
|
||||
|
||||
break;
|
||||
}
|
||||
} while(true);
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
server.chunkedResponseFinalize();
|
||||
#else
|
||||
server.sendContent(emptyString);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
FS* fs = nullptr;
|
||||
CanHandleCallback canHandleCallback;
|
||||
BeforeSendCallback beforeSendCallback;
|
||||
TemplateCallback templateCallback;
|
||||
const char* uri = nullptr;
|
||||
const char* path = nullptr;
|
||||
const char* cacheHeader = nullptr;
|
||||
};
|
||||
@@ -7,7 +7,7 @@ class StaticPage : public RequestHandler {
|
||||
public:
|
||||
typedef std::function<bool(HTTPMethod, const String&)> CanHandleCallback;
|
||||
typedef std::function<bool()> BeforeSendCallback;
|
||||
|
||||
|
||||
template <class T>
|
||||
StaticPage(const char* uri, FS* fs, T path, const char* cacheHeader = nullptr) {
|
||||
this->uri = uri;
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
if (server._eTagEnabled && !this->eTag.isEmpty()) {
|
||||
server.sendHeader(F("ETag"), this->eTag);
|
||||
}
|
||||
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
server.streamFile(file, F("text/html"), method);
|
||||
#else
|
||||
@@ -102,4 +102,4 @@ protected:
|
||||
const char* uri = nullptr;
|
||||
String path;
|
||||
const char* cacheHeader = nullptr;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -28,14 +28,14 @@ public:
|
||||
|
||||
typedef std::function<bool(AsyncWebServerRequest *request, UpgradeType)> BeforeUpgradeCallback;
|
||||
typedef std::function<void(AsyncWebServerRequest *request, const UpgradeResult&, const UpgradeResult&)> AfterUpgradeCallback;
|
||||
|
||||
UpgradeHandler(AsyncURIMatcher uri) : uri(uri) {}
|
||||
|
||||
bool canHandle(AsyncWebServerRequest *request) const override final {
|
||||
explicit UpgradeHandler(AsyncURIMatcher uri) : uri(uri) {}
|
||||
|
||||
bool canHandle(AsyncWebServerRequest *request) const final {
|
||||
if (!request->isHTTP()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return this->uri.matches(request);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
return this;
|
||||
}
|
||||
|
||||
void handleRequest(AsyncWebServerRequest *request) override final {
|
||||
void handleRequest(AsyncWebServerRequest *request) final {
|
||||
if (this->afterUpgradeCallback) {
|
||||
this->afterUpgradeCallback(request, this->firmwareResult, this->filesystemResult);
|
||||
}
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
this->filesystemResult.error.clear();
|
||||
}
|
||||
|
||||
void handleUpload(AsyncWebServerRequest *request, const String &fileName, size_t index, uint8_t *data, size_t dataLength, bool isFinal) override final {
|
||||
void handleUpload(AsyncWebServerRequest *request, const String &fileName, size_t index, uint8_t *data, size_t dataLength, bool isFinal) final {
|
||||
UpgradeResult* result = nullptr;
|
||||
|
||||
if (!request->hasParam(asyncsrv::T_name, true, true)) {
|
||||
@@ -123,7 +123,7 @@ public:
|
||||
bool begin = false;
|
||||
if (result->type == UpgradeType::FIRMWARE) {
|
||||
begin = Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH);
|
||||
|
||||
|
||||
} else if (result->type == UpgradeType::FILESYSTEM) {
|
||||
begin = Update.begin(UPDATE_SIZE_UNKNOWN, U_SPIFFS);
|
||||
}
|
||||
@@ -135,10 +135,10 @@ public:
|
||||
Log.serrorln(FPSTR(L_PORTAL_OTA), "File '%s', on start: %s", fileName.c_str(), result->error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Log.sinfoln(FPSTR(L_PORTAL_OTA), "File '%s', started", fileName.c_str());
|
||||
}
|
||||
|
||||
|
||||
if (dataLength) {
|
||||
if (Update.write(data, dataLength) != dataLength) {
|
||||
Update.end(false);
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
result->progress += dataLength;
|
||||
Log.sinfoln(
|
||||
FPSTR(L_PORTAL_OTA), "File '%s', write %d bytes, %d of %d bytes",
|
||||
@@ -179,7 +179,7 @@ public:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isFinal) {
|
||||
if (!Update.end(true)) {
|
||||
result->status = UpgradeStatus::ERROR_ON_FINISH;
|
||||
@@ -194,7 +194,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool isRequestHandlerTrivial() const override final {
|
||||
bool isRequestHandlerTrivial() const final {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -205,4 +205,4 @@ protected:
|
||||
|
||||
UpgradeResult firmwareResult{UpgradeType::FIRMWARE, UpgradeStatus::NONE};
|
||||
UpgradeResult filesystemResult{UpgradeType::FILESYSTEM, UpgradeStatus::NONE};
|
||||
};
|
||||
};
|
||||
|
||||
+6
-6
@@ -35,9 +35,9 @@ namespace CrashRecorder {
|
||||
} ext_t;
|
||||
|
||||
|
||||
__NOINIT_ATTR volatile static backtrace_t backtrace;
|
||||
__NOINIT_ATTR volatile static epc_t epc;
|
||||
__NOINIT_ATTR volatile static ext_t ext;
|
||||
__NOINIT_ATTR volatile static backtrace_t backtrace; // NOLINT
|
||||
__NOINIT_ATTR volatile static epc_t epc; // NOLINT
|
||||
__NOINIT_ATTR volatile static ext_t ext; // NOLINT
|
||||
|
||||
uint8_t backtraceMaxLength = sizeof(backtrace.data) / sizeof(*backtrace.data);
|
||||
uint8_t epcMaxLength = sizeof(epc.data) / sizeof(*epc.data);
|
||||
@@ -70,7 +70,7 @@ namespace CrashRecorder {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void init() {
|
||||
if (backtrace.length > backtraceMaxLength) {
|
||||
backtrace.length = 0;
|
||||
@@ -98,7 +98,7 @@ extern "C" void custom_crash_callback(struct rst_info *info, uint32_t stack, uin
|
||||
CrashRecorder::backtrace.continues = false;
|
||||
uint32_t value;
|
||||
for (uint32_t i = stack; i < stack_end; i += 4) {
|
||||
value = *((uint32_t*) i);
|
||||
value = *((uint32_t*) i); // NOLINT
|
||||
|
||||
// keep only addresses in code area
|
||||
if ((value >= 0x40000000) && (value < 0x40300000)) {
|
||||
@@ -129,4 +129,4 @@ extern "C" void custom_crash_callback(struct rst_info *info, uint32_t stack, uin
|
||||
|
||||
CrashRecorder::epc.length = _length;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+25
-25
@@ -45,7 +45,7 @@ public:
|
||||
doc[FPSTR(HA_MIN)] = -99;
|
||||
doc[FPSTR(HA_MAX)] = 99;
|
||||
}
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("volume_flow_rate");
|
||||
if (unit == UnitSystem::METRIC) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_L_MIN);
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_GAL_MIN);
|
||||
}
|
||||
@@ -110,19 +110,19 @@ public:
|
||||
case Sensors::Purpose::OUTDOOR_TEMP:
|
||||
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer-outline");
|
||||
break;
|
||||
|
||||
|
||||
case Sensors::Purpose::INDOOR_TEMP:
|
||||
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer");
|
||||
break;
|
||||
|
||||
|
||||
case Sensors::Purpose::HEATING_TEMP:
|
||||
doc[FPSTR(HA_ICON)] = F("mdi:radiator");
|
||||
break;
|
||||
|
||||
|
||||
case Sensors::Purpose::HEATING_RETURN_TEMP:
|
||||
doc[FPSTR(HA_ICON)] = F("mdi:heating-coil");
|
||||
break;
|
||||
|
||||
|
||||
case Sensors::Purpose::DHW_TEMP:
|
||||
doc[FPSTR(HA_ICON)] = F("mdi:faucet");
|
||||
break;
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
case Sensors::Purpose::DHW_RETURN_TEMP:
|
||||
doc[FPSTR(HA_ICON)] = F("mdi:heating-coil");
|
||||
break;
|
||||
|
||||
|
||||
case Sensors::Purpose::EXHAUST_TEMP:
|
||||
doc[FPSTR(HA_ICON)] = F("mdi:smoke");
|
||||
break;
|
||||
@@ -193,7 +193,7 @@ public:
|
||||
doc[FPSTR(HA_DEVICE_CLASS)] = FPSTR(S_TEMPERATURE);
|
||||
if (unit == UnitSystem::METRIC) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||
}
|
||||
@@ -214,7 +214,7 @@ public:
|
||||
case Sensors::ValueType::BATTERY:
|
||||
Sensors::makeObjectIdWithSuffix(objId, sSensor.name, FPSTR(S_BATTERY));
|
||||
sName += F(" battery");
|
||||
|
||||
|
||||
doc[FPSTR(HA_DEVICE_CLASS)] = FPSTR(S_BATTERY);
|
||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC);
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_PERCENT);
|
||||
@@ -225,7 +225,7 @@ public:
|
||||
case Sensors::ValueType::RSSI:
|
||||
Sensors::makeObjectIdWithSuffix(objId, sSensor.name, FPSTR(S_RSSI));
|
||||
sName += F(" RSSI");
|
||||
|
||||
|
||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("signal_strength");
|
||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC);
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("dBm");
|
||||
@@ -264,8 +264,8 @@ public:
|
||||
// object id's
|
||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getUniqueIdWithPrefix(objId.c_str());
|
||||
doc[FPSTR(HA_DEFAULT_ENTITY_ID)] = this->getEntityIdWithPrefix(
|
||||
sSensor.type == Sensors::Type::MANUAL
|
||||
? FPSTR(HA_ENTITY_NUMBER)
|
||||
sSensor.type == Sensors::Type::MANUAL
|
||||
? FPSTR(HA_ENTITY_NUMBER)
|
||||
: FPSTR(HA_ENTITY_SENSOR),
|
||||
objId.c_str()
|
||||
);
|
||||
@@ -346,7 +346,7 @@ public:
|
||||
|
||||
doc[FPSTR(HA_NAME)] = sName;
|
||||
}
|
||||
|
||||
|
||||
const String& configTopic = this->makeConfigTopic(FPSTR(HA_ENTITY_BINARY_SENSOR), objId.c_str());
|
||||
objId.clear();
|
||||
|
||||
@@ -393,7 +393,7 @@ public:
|
||||
|
||||
doc[FPSTR(HA_NAME)] = sName;
|
||||
}
|
||||
|
||||
|
||||
const String& configTopic = this->makeConfigTopic(FPSTR(HA_ENTITY_SENSOR), objId.c_str());
|
||||
objId.clear();
|
||||
|
||||
@@ -477,7 +477,7 @@ public:
|
||||
|
||||
if (unit == UnitSystem::METRIC) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||
}
|
||||
@@ -535,7 +535,7 @@ public:
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||
doc[FPSTR(HA_MIN)] = 0;
|
||||
doc[FPSTR(HA_MAX)] = 99;
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||
doc[FPSTR(HA_MIN)] = 32;
|
||||
@@ -569,7 +569,7 @@ public:
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||
doc[FPSTR(HA_MIN)] = 1;
|
||||
doc[FPSTR(HA_MAX)] = 100;
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||
doc[FPSTR(HA_MIN)] = 33;
|
||||
@@ -604,7 +604,7 @@ public:
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||
doc[FPSTR(HA_MIN)] = 0;
|
||||
doc[FPSTR(HA_MAX)] = 99;
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||
doc[FPSTR(HA_MIN)] = 32;
|
||||
@@ -638,7 +638,7 @@ public:
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||
doc[FPSTR(HA_MIN)] = 1;
|
||||
doc[FPSTR(HA_MAX)] = 100;
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||
doc[FPSTR(HA_MIN)] = 33;
|
||||
@@ -789,7 +789,7 @@ public:
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||
doc[FPSTR(HA_MIN)] = -99;
|
||||
doc[FPSTR(HA_MAX)] = 99;
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||
doc[FPSTR(HA_MIN)] = -146;
|
||||
@@ -823,7 +823,7 @@ public:
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||
doc[FPSTR(HA_MIN)] = 1;
|
||||
doc[FPSTR(HA_MAX)] = 100;
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||
doc[FPSTR(HA_MIN)] = 1;
|
||||
@@ -1238,7 +1238,7 @@ public:
|
||||
|
||||
if (unit == UnitSystem::METRIC) {
|
||||
doc[FPSTR(HA_TEMPERATURE_UNIT)] = "C";
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_TEMPERATURE_UNIT)] = "F";
|
||||
}
|
||||
@@ -1290,7 +1290,7 @@ public:
|
||||
|
||||
if (unit == UnitSystem::METRIC) {
|
||||
doc[FPSTR(HA_TEMPERATURE_UNIT)] = "C";
|
||||
|
||||
|
||||
} else if (unit == UnitSystem::IMPERIAL) {
|
||||
doc[FPSTR(HA_TEMPERATURE_UNIT)] = "F";
|
||||
}
|
||||
@@ -1393,7 +1393,7 @@ public:
|
||||
bool deleteDhwState() {
|
||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_BINARY_SENSOR), F("dhw")).c_str());
|
||||
}
|
||||
|
||||
|
||||
bool deleteInputDhwTarget() {
|
||||
return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_NUMBER), F("dhw_target")).c_str());
|
||||
}
|
||||
@@ -1408,4 +1408,4 @@ public:
|
||||
};
|
||||
|
||||
const char HaHelper::AVAILABILITY_OT_CONN[] = "{{ iif(value_json.slave.connected, 'online', 'offline') }}";
|
||||
const char HaHelper::AVAILABILITY_SENSOR_CONN[] = "{{ iif(value_json.connected, 'online', 'offline') }}";
|
||||
const char HaHelper::AVAILABILITY_SENSOR_CONN[] = "{{ iif(value_json.connected, 'online', 'offline') }}";
|
||||
|
||||
+24
-24
@@ -10,7 +10,7 @@ extern FileData fsNetworkSettings, fsSettings, fsSensorsSettings;
|
||||
|
||||
class MainTask : public Task {
|
||||
public:
|
||||
MainTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {
|
||||
explicit MainTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {
|
||||
this->blinker = new Blinker();
|
||||
|
||||
network->setDelayCallback([this](unsigned int time) {
|
||||
@@ -175,7 +175,7 @@ protected:
|
||||
this->cascadeControl();
|
||||
this->externalPump();
|
||||
this->miscRunned = millis();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ protected:
|
||||
minFreeHeapDiff = this->minFreeHeap - minFreeHeap;
|
||||
this->minFreeHeap = minFreeHeap;
|
||||
}
|
||||
|
||||
|
||||
size_t minMaxFreeBlockHeap = getMaxFreeBlockHeap(true);
|
||||
size_t minMaxFreeBlockHeapDiff = 0;
|
||||
if (minMaxFreeBlockHeap < this->minMaxFreeBlockHeap || this->minMaxFreeBlockHeap == 0) {
|
||||
@@ -225,11 +225,11 @@ protected:
|
||||
uint8_t availableSensors = 0;
|
||||
|
||||
if (Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::INDOOR_TEMP)) {
|
||||
auto value = Sensors::getMeanValueByPurpose(Sensors::Purpose::INDOOR_TEMP, Sensors::ValueType::PRIMARY);
|
||||
auto value = Sensors::getMeanValueByPurpose(Sensors::Purpose::INDOOR_TEMP, Sensors::ValueType::PRIMARY, settings.heating.indoorTempAvgType);
|
||||
if (value < lowTemp) {
|
||||
lowTemp = value;
|
||||
}
|
||||
|
||||
|
||||
availableSensors++;
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ protected:
|
||||
if (value < lowTemp) {
|
||||
lowTemp = value;
|
||||
}
|
||||
|
||||
|
||||
availableSensors++;
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ protected:
|
||||
|
||||
if (availableSensors) {
|
||||
if (vars.master.heating.freezing) {
|
||||
if (lowTemp - (float) settings.heating.freezeProtection.highTemp + 0.0001f >= 0.0f) {
|
||||
if (lowTemp - static_cast<float>(settings.heating.freezeProtection.highTemp) + 0.0001f >= 0.0f) {
|
||||
vars.master.heating.freezing = false;
|
||||
|
||||
Log.sinfoln(
|
||||
@@ -264,7 +264,7 @@ protected:
|
||||
}
|
||||
|
||||
} else {
|
||||
if ((float) settings.heating.freezeProtection.lowTemp - lowTemp + 0.0001f >= 0.0f) {
|
||||
if (static_cast<float>(settings.heating.freezeProtection.lowTemp) - lowTemp + 0.0001f >= 0.0f) {
|
||||
vars.master.heating.freezing = true;
|
||||
|
||||
if (!settings.heating.enabled) {
|
||||
@@ -304,7 +304,7 @@ protected:
|
||||
if (!settings.equitherm.enabled && settings.pid.enabled) {
|
||||
emergencyFlags |= 0b00000010;
|
||||
}
|
||||
|
||||
|
||||
if (settings.opentherm.options.nativeOTC) {
|
||||
emergencyFlags |= 0b00000100;
|
||||
}
|
||||
@@ -353,7 +353,7 @@ protected:
|
||||
if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||
digitalWrite(configuredGpio, LOW);
|
||||
}
|
||||
|
||||
|
||||
if (GPIO_IS_VALID(settings.system.statusLedGpio)) {
|
||||
configuredGpio = settings.system.statusLedGpio;
|
||||
pinMode(configuredGpio, OUTPUT);
|
||||
@@ -437,7 +437,7 @@ protected:
|
||||
|
||||
Log.sinfoln(FPSTR(L_CASCADE_INPUT), F("Deinitialized on GPIO %hhu"), configuredInputGpio);
|
||||
}
|
||||
|
||||
|
||||
if (GPIO_IS_VALID(settings.cascadeControl.input.gpio)) {
|
||||
configuredInputGpio = settings.cascadeControl.input.gpio;
|
||||
pinMode(configuredInputGpio, INPUT);
|
||||
@@ -479,7 +479,7 @@ protected:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!settings.cascadeControl.input.enabled || configuredInputGpio == GPIO_IS_NOT_CONFIGURED) {
|
||||
if (!vars.cascadeControl.input) {
|
||||
vars.cascadeControl.input = true;
|
||||
@@ -502,14 +502,14 @@ protected:
|
||||
|
||||
Log.sinfoln(FPSTR(L_CASCADE_OUTPUT), F("Deinitialized on GPIO %hhu"), configuredOutputGpio);
|
||||
}
|
||||
|
||||
|
||||
if (GPIO_IS_VALID(settings.cascadeControl.output.gpio)) {
|
||||
configuredOutputGpio = settings.cascadeControl.output.gpio;
|
||||
pinMode(configuredOutputGpio, OUTPUT);
|
||||
digitalWrite(
|
||||
configuredOutputGpio,
|
||||
settings.cascadeControl.output.invertState
|
||||
? HIGH
|
||||
? HIGH
|
||||
: LOW
|
||||
);
|
||||
|
||||
@@ -538,7 +538,7 @@ protected:
|
||||
if (value != outputTempValue) {
|
||||
outputTempValue = value;
|
||||
outputChangedTs = millis();
|
||||
|
||||
|
||||
} else if (millis() - outputChangedTs >= settings.cascadeControl.output.thresholdTime * 1000u) {
|
||||
vars.cascadeControl.output = value;
|
||||
|
||||
@@ -591,14 +591,14 @@ protected:
|
||||
if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||
digitalWrite(configuredGpio, LOW);
|
||||
}
|
||||
|
||||
|
||||
if (GPIO_IS_VALID(settings.externalPump.gpio)) {
|
||||
configuredGpio = settings.externalPump.gpio;
|
||||
pinMode(configuredGpio, OUTPUT);
|
||||
digitalWrite(
|
||||
configuredGpio,
|
||||
settings.externalPump.invertState
|
||||
? HIGH
|
||||
? HIGH
|
||||
: LOW
|
||||
);
|
||||
|
||||
@@ -625,13 +625,13 @@ protected:
|
||||
} else if (vars.master.heating.enabled && !this->heatingEnabled) {
|
||||
this->heatingEnabled = true;
|
||||
}
|
||||
|
||||
|
||||
if (!settings.externalPump.use) {
|
||||
if (vars.externalPump.state) {
|
||||
digitalWrite(
|
||||
configuredGpio,
|
||||
settings.externalPump.invertState
|
||||
? HIGH
|
||||
? HIGH
|
||||
: LOW
|
||||
);
|
||||
|
||||
@@ -649,7 +649,7 @@ protected:
|
||||
digitalWrite(
|
||||
configuredGpio,
|
||||
settings.externalPump.invertState
|
||||
? HIGH
|
||||
? HIGH
|
||||
: LOW
|
||||
);
|
||||
|
||||
@@ -662,7 +662,7 @@ protected:
|
||||
digitalWrite(
|
||||
configuredGpio,
|
||||
settings.externalPump.invertState
|
||||
? HIGH
|
||||
? HIGH
|
||||
: LOW
|
||||
);
|
||||
|
||||
@@ -683,7 +683,7 @@ protected:
|
||||
digitalWrite(
|
||||
configuredGpio,
|
||||
settings.externalPump.invertState
|
||||
? LOW
|
||||
? LOW
|
||||
: HIGH
|
||||
);
|
||||
|
||||
@@ -697,11 +697,11 @@ protected:
|
||||
digitalWrite(
|
||||
configuredGpio,
|
||||
settings.externalPump.invertState
|
||||
? LOW
|
||||
? LOW
|
||||
: HIGH
|
||||
);
|
||||
|
||||
Log.sinfoln(FPSTR(L_EXTPUMP), F("Enabled: anti stuck"));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
+8
-8
@@ -8,7 +8,7 @@ extern FileData fsSettings;
|
||||
|
||||
class MqttTask : public Task {
|
||||
public:
|
||||
MqttTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {
|
||||
explicit MqttTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {
|
||||
this->wifiClient = new MqttWiFiClient();
|
||||
this->client = new MqttClient(this->wifiClient);
|
||||
this->writer = new MqttWriter(this->client, 256);
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
this->onDisconnect();
|
||||
this->connected = false;
|
||||
}
|
||||
|
||||
|
||||
Task::disable();
|
||||
|
||||
Log.sinfoln(FPSTR(L_MQTT), F("Disabled"));
|
||||
@@ -96,7 +96,7 @@ protected:
|
||||
const char* getTaskName() override {
|
||||
return "Mqtt";
|
||||
}
|
||||
|
||||
|
||||
/*BaseType_t getTaskCore() override {
|
||||
return 1;
|
||||
}*/
|
||||
@@ -137,7 +137,7 @@ protected:
|
||||
for (size_t i = 0; i < length && this->client->available(); i++) {
|
||||
payload[i] = this->client->read();
|
||||
}
|
||||
|
||||
|
||||
this->onMessage(topic, payload, length);
|
||||
});
|
||||
|
||||
@@ -340,7 +340,7 @@ protected:
|
||||
this->haHelper->publishSignalQualityDynamicSensor(sSettings, false);
|
||||
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::TEMPERATURE, settings.system.unitSystem);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::PRIMARY, settings.system.unitSystem);
|
||||
}
|
||||
@@ -443,7 +443,7 @@ protected:
|
||||
} else if (payload[i] == 10) {
|
||||
Log.print(F("\r\n> "));
|
||||
} else {
|
||||
Log.print((char) payload[i]);
|
||||
Log.print(static_cast<char>(payload[i]));
|
||||
}
|
||||
}
|
||||
Log.print(F("\r\n\n"));
|
||||
@@ -567,7 +567,7 @@ protected:
|
||||
this->haHelper->publishSignalQualityDynamicSensor(sSettings, false);
|
||||
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::TEMPERATURE, settings.system.unitSystem);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::PRIMARY, settings.system.unitSystem);
|
||||
}
|
||||
@@ -664,4 +664,4 @@ protected:
|
||||
|
||||
return this->writer->publish(topic, doc, true);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
+38
-38
@@ -3,7 +3,7 @@ extern FileData fsSettings;
|
||||
|
||||
class OpenThermTask : public Task {
|
||||
public:
|
||||
OpenThermTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {}
|
||||
explicit OpenThermTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {}
|
||||
|
||||
~OpenThermTask() {
|
||||
delete this->instance;
|
||||
@@ -41,7 +41,7 @@ protected:
|
||||
uint32_t getTaskStackSize() override {
|
||||
return 7500;
|
||||
}
|
||||
|
||||
|
||||
BaseType_t getTaskCore() override {
|
||||
return 0;
|
||||
}
|
||||
@@ -160,7 +160,7 @@ protected:
|
||||
if (this->configuredRxLedGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||
digitalWrite(this->configuredRxLedGpio, LOW);
|
||||
}
|
||||
|
||||
|
||||
if (GPIO_IS_VALID(settings.opentherm.rxLedGpio)) {
|
||||
this->configuredRxLedGpio = settings.opentherm.rxLedGpio;
|
||||
pinMode(this->configuredRxLedGpio, OUTPUT);
|
||||
@@ -178,8 +178,8 @@ protected:
|
||||
&& !vars.master.heating.overheat;
|
||||
|
||||
// DHW settings
|
||||
vars.master.dhw.enabled = settings.opentherm.options.dhwSupport
|
||||
&& settings.dhw.enabled
|
||||
vars.master.dhw.enabled = settings.opentherm.options.dhwSupport
|
||||
&& settings.dhw.enabled
|
||||
&& !vars.master.dhw.overheat;
|
||||
vars.master.dhw.targetTemp = settings.dhw.target;
|
||||
|
||||
@@ -236,7 +236,7 @@ protected:
|
||||
F("Failed receive boiler status: %s"),
|
||||
CustomOpenTherm::statusToString(this->instance->getLastResponseStatus())
|
||||
);
|
||||
|
||||
|
||||
} else {
|
||||
vars.slave.heating.active = CustomOpenTherm::isCentralHeatingActive(response);
|
||||
vars.slave.dhw.active = settings.opentherm.options.dhwSupport ? CustomOpenTherm::isHotWaterActive(response) : false;
|
||||
@@ -251,7 +251,7 @@ protected:
|
||||
} else if (vars.slave.diag.active) {
|
||||
vars.slave.diag.active = false;
|
||||
}
|
||||
|
||||
|
||||
Log.snoticeln(
|
||||
FPSTR(L_OT), F("Received boiler status. Heating: %hhu; DHW: %hhu; flame: %hhu; cooling: %hhu; channel 2: %hhu; fault: %hhu; diag: %hhu"),
|
||||
vars.slave.heating.active, vars.slave.dhw.active,
|
||||
@@ -270,15 +270,15 @@ protected:
|
||||
F("Connected, downtime: %lu s."),
|
||||
(millis() - this->disconnectedTime) / 1000
|
||||
);
|
||||
|
||||
|
||||
this->connectedTime = millis();
|
||||
vars.slave.connected = true;
|
||||
|
||||
|
||||
} else if (vars.slave.connected && millis() - this->lastSuccessResponse > 6325) {
|
||||
Log.swarningln(
|
||||
FPSTR(L_OT),
|
||||
F("Disconnected, uptime: %lu s."),
|
||||
(millis() - this->connectedTime) / 1000
|
||||
(millis() - this->connectedTime) / 1000
|
||||
);
|
||||
|
||||
// Mark sensors as disconnected
|
||||
@@ -403,7 +403,7 @@ protected:
|
||||
FPSTR(L_OT), F("Received min modulation: %hhu%%, max power: %.2f kW"),
|
||||
vars.slave.modulation.min, vars.slave.power.max
|
||||
);
|
||||
|
||||
|
||||
if (settings.heating.maxModulation < vars.slave.modulation.min) {
|
||||
settings.heating.maxModulation = vars.slave.modulation.min;
|
||||
fsSettings.update();
|
||||
@@ -519,7 +519,7 @@ protected:
|
||||
|
||||
Log.swarningln(FPSTR(L_SETTINGS_HEATING), F("Updated max temp: %hhu"), settings.heating.maxTemp);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed receive min/max temp"));
|
||||
}
|
||||
@@ -542,7 +542,7 @@ protected:
|
||||
} else {
|
||||
Log.swarningln(FPSTR(L_OT), F("Failed receive fault code"));
|
||||
}
|
||||
|
||||
|
||||
} else if (vars.slave.fault.code != 0) {
|
||||
vars.slave.fault.code = 0;
|
||||
}
|
||||
@@ -558,7 +558,7 @@ protected:
|
||||
} else {
|
||||
Log.swarningln(FPSTR(L_OT), F("Failed receive diag code"));
|
||||
}
|
||||
|
||||
|
||||
} else if (vars.slave.diag.code != 0) {
|
||||
vars.slave.diag.code = 0;
|
||||
}
|
||||
@@ -767,7 +767,7 @@ protected:
|
||||
}
|
||||
}
|
||||
vars.slave.power.current = power;
|
||||
|
||||
|
||||
Log.snoticeln(
|
||||
FPSTR(L_OT), F("Received modulation level: %hhu%%, power: %.2f of %.2f kW (min: %.2f kW)"),
|
||||
vars.slave.modulation.current, vars.slave.power.current,
|
||||
@@ -1027,7 +1027,7 @@ protected:
|
||||
Log.swarningln(FPSTR(L_OT), F("Failed receive outdoor temp"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update solar storage temp
|
||||
if (Sensors::getAmountByType(Sensors::Type::OT_SOLAR_STORAGE_TEMP, true)) {
|
||||
if (this->updateSolarStorageTemp()) {
|
||||
@@ -1195,7 +1195,7 @@ protected:
|
||||
if (vars.slave.diag.active) {
|
||||
if (this->instance->sendServiceReset()) {
|
||||
Log.sinfoln(FPSTR(L_OT), F("Boiler diagnostic reset successfully"));
|
||||
|
||||
|
||||
} else {
|
||||
Log.serrorln(FPSTR(L_OT), F("Boiler diagnostic reset failed"));
|
||||
}
|
||||
@@ -1247,7 +1247,7 @@ protected:
|
||||
FPSTR(L_OT_HEATING), F("Set current indoor temp: %.2f (converted: %.2f, response: %.2f)"),
|
||||
indoorTemp, convertedTemp, vars.slave.heating.indoorTemp
|
||||
);
|
||||
|
||||
|
||||
} else {
|
||||
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set current indoor temp"));
|
||||
}
|
||||
@@ -1401,7 +1401,7 @@ protected:
|
||||
);
|
||||
|
||||
if (vars.master.heating.overheat) {
|
||||
if ((float) settings.heating.overheatProtection.lowTemp - highTemp + 0.0001f >= 0.0f) {
|
||||
if (static_cast<float>(settings.heating.overheatProtection.lowTemp) - highTemp + 0.0001f >= 0.0f) {
|
||||
vars.master.heating.overheat = false;
|
||||
|
||||
Log.sinfoln(
|
||||
@@ -1411,7 +1411,7 @@ protected:
|
||||
}
|
||||
|
||||
} else if (vars.slave.heating.active) {
|
||||
if (highTemp - (float) settings.heating.overheatProtection.highTemp + 0.0001f >= 0.0f) {
|
||||
if (highTemp - static_cast<float>(settings.heating.overheatProtection.highTemp) + 0.0001f >= 0.0f) {
|
||||
vars.master.heating.overheat = true;
|
||||
|
||||
Log.swarningln(
|
||||
@@ -1441,7 +1441,7 @@ protected:
|
||||
);
|
||||
|
||||
if (vars.master.dhw.overheat) {
|
||||
if ((float) settings.dhw.overheatProtection.lowTemp - highTemp + 0.0001f >= 0.0f) {
|
||||
if (static_cast<float>(settings.dhw.overheatProtection.lowTemp) - highTemp + 0.0001f >= 0.0f) {
|
||||
vars.master.dhw.overheat = false;
|
||||
|
||||
Log.sinfoln(
|
||||
@@ -1451,7 +1451,7 @@ protected:
|
||||
}
|
||||
|
||||
} else if (vars.slave.dhw.active) {
|
||||
if (highTemp - (float) settings.dhw.overheatProtection.highTemp + 0.0001f >= 0.0f) {
|
||||
if (highTemp - static_cast<float>(settings.dhw.overheatProtection.highTemp) + 0.0001f >= 0.0f) {
|
||||
vars.master.dhw.overheat = true;
|
||||
|
||||
Log.swarningln(
|
||||
@@ -1480,10 +1480,10 @@ protected:
|
||||
|
||||
if (this->setMasterVersion(vars.master.appVersion, vars.master.type)) {
|
||||
Log.snoticeln(
|
||||
FPSTR(L_OT), F("Set master version: %u, type: %u"),
|
||||
FPSTR(L_OT), F("Set master version: %u, type: %u"),
|
||||
vars.master.appVersion, vars.master.type
|
||||
);
|
||||
|
||||
|
||||
} else {
|
||||
Log.swarningln(FPSTR(L_OT), F("Failed set master version"));
|
||||
}
|
||||
@@ -1517,7 +1517,7 @@ protected:
|
||||
FPSTR(L_OT), F("Set master member id: %u, flags: %u"),
|
||||
vars.master.memberId, vars.master.flags
|
||||
);
|
||||
|
||||
|
||||
} else {
|
||||
Log.swarningln(FPSTR(L_OT), F("Failed set master config"));
|
||||
}
|
||||
@@ -1561,7 +1561,7 @@ protected:
|
||||
OpenThermMessageID::SConfigSMemberIDcode,
|
||||
0
|
||||
));
|
||||
|
||||
|
||||
if (!CustomOpenTherm::isValidResponse(response)) {
|
||||
return false;
|
||||
|
||||
@@ -1633,7 +1633,7 @@ protected:
|
||||
const unsigned int request = ((dayOfWeek & 0x07) << 13)
|
||||
| ((ptm->tm_hour & 0x1F) << 8)
|
||||
| (ptm->tm_min & 0x3F);
|
||||
|
||||
|
||||
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
|
||||
OpenThermRequestType::WRITE_DATA,
|
||||
OpenThermMessageID::DayTime,
|
||||
@@ -1892,11 +1892,11 @@ protected:
|
||||
* From slave member id code:
|
||||
* id: slave.memberIdCode & 0xFF,
|
||||
* flags: (slave.memberIdCode & 0xFFFF) >> 8
|
||||
* @param id
|
||||
* @param flags
|
||||
* @param force
|
||||
* @return true
|
||||
* @return false
|
||||
* @param id
|
||||
* @param flags
|
||||
* @param force
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool setMasterConfig(const uint8_t id, const uint8_t flags, const bool force = false) {
|
||||
const uint8_t rMemberId = (force || id > 0) ? id : vars.slave.memberId;
|
||||
@@ -2350,7 +2350,7 @@ protected:
|
||||
}
|
||||
|
||||
vars.slave.dhw.flowRate = value;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2393,7 +2393,7 @@ protected:
|
||||
}
|
||||
|
||||
vars.slave.heating.returnTemp = CustomOpenTherm::getFloat(response);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2432,7 +2432,7 @@ protected:
|
||||
return false;
|
||||
}
|
||||
|
||||
const float value = (float) CustomOpenTherm::getInt(response);
|
||||
const float value = CustomOpenTherm::getInt(response);
|
||||
if (!isValidTemp(value, settings.opentherm.unitSystem, -40, 500)) {
|
||||
return false;
|
||||
}
|
||||
@@ -2456,7 +2456,7 @@ protected:
|
||||
return false;
|
||||
}
|
||||
|
||||
const float value = (float) CustomOpenTherm::getInt(response);
|
||||
const float value = CustomOpenTherm::getInt(response);
|
||||
if (value <= 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -2500,7 +2500,7 @@ protected:
|
||||
}
|
||||
|
||||
vars.slave.solar.storage = CustomOpenTherm::getFloat(response);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2519,7 +2519,7 @@ protected:
|
||||
}
|
||||
|
||||
vars.slave.solar.collector = CustomOpenTherm::getFloat(response);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+17
-13
@@ -18,7 +18,7 @@ extern WebSerial* webSerial;
|
||||
|
||||
class PortalTask : public LeanTask {
|
||||
public:
|
||||
PortalTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {
|
||||
explicit PortalTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {
|
||||
this->webServer = new AsyncWebServer(80);
|
||||
this->dnsServer = new DNSServer();
|
||||
}
|
||||
@@ -73,7 +73,7 @@ protected:
|
||||
if (request->authenticate(settings.portal.login, settings.portal.password, PROJECT_NAME)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
|
||||
return request->requestAuthentication(AsyncAuthType::AUTH_BASIC, PROJECT_NAME, "Authentication failed");
|
||||
});
|
||||
|
||||
@@ -235,7 +235,7 @@ protected:
|
||||
if (sensorId < 0 || sensorId > 255 || !Sensors::isValidSensorId(sensorId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (jsonToSensorSettings(sensorId, sensor.value(), Sensors::settings[sensorId])) {
|
||||
fsSensorsSettings.update();
|
||||
changed = true;
|
||||
@@ -407,7 +407,7 @@ protected:
|
||||
responseDoc[sensorId] = Sensors::settings[sensorId].name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// send response
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
@@ -436,7 +436,7 @@ protected:
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}).addMiddleware(&authMiddleware);
|
||||
|
||||
|
||||
auto& ssHandler = this->webServer->on("/api/sensor", HTTP_POST, [](AsyncWebServerRequest *request, JsonVariant &requestDoc) {
|
||||
if (vars.states.restarting) {
|
||||
return request->send(503);
|
||||
@@ -459,7 +459,7 @@ protected:
|
||||
if (!Sensors::isValidSensorId(sensorId)) {
|
||||
return request->send(404);
|
||||
}
|
||||
|
||||
|
||||
// prepare request
|
||||
auto prevSettings = Sensors::settings[sensorId];
|
||||
bool changed = jsonToSensorSettings(sensorId, requestDoc, Sensors::settings[sensorId]);
|
||||
@@ -471,7 +471,7 @@ protected:
|
||||
|
||||
auto& sSettings = Sensors::settings[sensorId];
|
||||
sensorSettingsToJson(sensorId, sSettings, responseDoc);
|
||||
|
||||
|
||||
// send response
|
||||
response->setLength();
|
||||
response->setCode(changed ? 201 : 200);
|
||||
@@ -515,7 +515,7 @@ protected:
|
||||
auto *response = new AsyncJsonResponse();
|
||||
auto& responseDoc = response->getRoot();
|
||||
varsToJson(vars, responseDoc);
|
||||
|
||||
|
||||
// send response
|
||||
response->setLength();
|
||||
response->setCode(changed ? 201 : 200);
|
||||
@@ -570,7 +570,7 @@ protected:
|
||||
docPsram[FPSTR(S_FREE)] = ESP.getFreePsram();
|
||||
docPsram[FPSTR(S_MIN_FREE)] = ESP.getMinFreePsram();
|
||||
docPsram[FPSTR(S_MAX_FREE_BLOCK)] = ESP.getMaxAllocPsram();
|
||||
|
||||
|
||||
auto docChip = doc[FPSTR(S_CHIP)].to<JsonObject>();
|
||||
docChip[FPSTR(S_MODEL)] = ESP.getChipModel();
|
||||
docChip[FPSTR(S_REV)] = ESP.getChipRevision();
|
||||
@@ -605,7 +605,7 @@ protected:
|
||||
docHeap[FPSTR(S_MIN_FREE)] = getFreeHeap(true);
|
||||
docHeap[FPSTR(S_MAX_FREE_BLOCK)] = getMaxFreeBlockHeap();
|
||||
docHeap[FPSTR(S_MIN_MAX_FREE_BLOCK)] = getMaxFreeBlockHeap(true);
|
||||
|
||||
|
||||
auto docChip = doc[FPSTR(S_CHIP)].to<JsonObject>();
|
||||
docChip[FPSTR(S_MODEL)] = ESP.getChipModel();
|
||||
docChip[FPSTR(S_REV)] = ESP.getChipRevision();
|
||||
@@ -810,9 +810,13 @@ protected:
|
||||
|
||||
static void getFilename(char* filename, size_t maxSizeFilename, const char* type) {
|
||||
const time_t now = time(nullptr);
|
||||
const tm* localNow = localtime(&now);
|
||||
|
||||
tm localNow {};
|
||||
localtime_r(&now, &localNow);
|
||||
|
||||
char localNowValue[20];
|
||||
strftime(localNowValue, sizeof(localNowValue), PSTR("%Y-%m-%d-%H-%M-%S"), localNow);
|
||||
strftime(localNowValue, sizeof(localNowValue), PSTR("%Y-%m-%d-%H-%M-%S"), &localNow);
|
||||
|
||||
snprintf_P(filename, maxSizeFilename, PSTR("%s_%s_%s.json"), networkSettings.hostname, localNowValue, type);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ GyverPID pidRegulator(0, 0, 0);
|
||||
|
||||
class RegulatorTask : public LeanTask {
|
||||
public:
|
||||
RegulatorTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {}
|
||||
explicit RegulatorTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {}
|
||||
|
||||
protected:
|
||||
float prevHeatingTarget = 0.0f;
|
||||
@@ -23,7 +23,7 @@ protected:
|
||||
uint32_t getTaskStackSize() override {
|
||||
return 5000;
|
||||
}
|
||||
|
||||
|
||||
/*BaseType_t getTaskCore() override {
|
||||
return 1;
|
||||
}*/
|
||||
@@ -158,7 +158,7 @@ protected:
|
||||
1.0f / settings.equitherm.exponent
|
||||
);
|
||||
float etResult = settings.heating.target + settings.equitherm.shift + sf * (
|
||||
tempDelta >= 0
|
||||
tempDelta >= 0
|
||||
? pow(tempDelta, 1.0f / settings.equitherm.exponent)
|
||||
: -(pow(-(tempDelta), 1.0f / settings.equitherm.exponent))
|
||||
);
|
||||
|
||||
+64
-35
@@ -35,7 +35,7 @@ public:
|
||||
OT_HEATING_PUMP_HOURS = 25,
|
||||
OT_DHW_PUMP_HOURS = 26,
|
||||
OT_COOLING_HOURS = 27,
|
||||
|
||||
|
||||
NTC_10K_TEMP = 50,
|
||||
DALLAS_TEMP = 51,
|
||||
BLUETOOTH = 52,
|
||||
@@ -77,6 +77,12 @@ public:
|
||||
RSSI = 3
|
||||
};
|
||||
|
||||
enum class AverageType : uint8_t {
|
||||
MEAN = 0,
|
||||
MINIMUM = 1,
|
||||
MAXIMUM = 2
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool enabled = false;
|
||||
char name[33];
|
||||
@@ -192,7 +198,7 @@ public:
|
||||
|
||||
auto& sSensor = settings[sensorId];
|
||||
auto& rSensor = results[sensorId];
|
||||
|
||||
|
||||
float compensatedValue = value;
|
||||
if (sSensor.type == Type::HEATING_SETPOINT_TEMP || sSensor.type == Type::MANUAL) {
|
||||
rSensor.values[valueId] = compensatedValue;
|
||||
@@ -215,7 +221,7 @@ public:
|
||||
|
||||
if (sSensor.filtering && fabsf(rSensor.values[valueId]) >= 0.1f) {
|
||||
rSensor.values[valueId] += (compensatedValue - rSensor.values[valueId]) * sSensor.filteringFactor;
|
||||
|
||||
|
||||
} else {
|
||||
rSensor.values[valueId] = compensatedValue;
|
||||
}
|
||||
@@ -248,11 +254,11 @@ public:
|
||||
}
|
||||
|
||||
uint8_t updated = 0;
|
||||
|
||||
|
||||
// read sensors data for current instance
|
||||
for (uint8_t sensorId = 0; sensorId <= getMaxSensorId(); sensorId++) {
|
||||
auto& sSensor = settings[sensorId];
|
||||
|
||||
|
||||
// only target & valid sensors
|
||||
if (!sSensor.enabled || sSensor.type != type) {
|
||||
continue;
|
||||
@@ -295,7 +301,7 @@ public:
|
||||
FPSTR(L_SENSORS), F("#%hhu '%s' new status: %s"),
|
||||
sensorId, sSensor.name, status ? F("CONNECTED") : F("DISCONNECTED")
|
||||
);
|
||||
|
||||
|
||||
rSensor.connected = status;
|
||||
}
|
||||
|
||||
@@ -312,11 +318,11 @@ public:
|
||||
}
|
||||
|
||||
uint8_t updated = 0;
|
||||
|
||||
|
||||
// read sensors data for current instance
|
||||
for (uint8_t sensorId = 0; sensorId <= getMaxSensorId(); sensorId++) {
|
||||
auto& sSensor = settings[sensorId];
|
||||
|
||||
|
||||
// only target & valid sensors
|
||||
if (!sSensor.enabled || sSensor.type != type) {
|
||||
continue;
|
||||
@@ -330,38 +336,61 @@ public:
|
||||
return updated;
|
||||
}
|
||||
|
||||
static float getMeanValueByPurpose(Purpose purpose, const ValueType valueType, bool onlyConnected = true) {
|
||||
static float getMeanValueByPurpose(Purpose purpose, const ValueType valueType, const AverageType avgType = AverageType::MEAN, const bool onlyConnected = true, const float defaultValue = NAN) {
|
||||
if (settings == nullptr || results == nullptr) {
|
||||
return 0.0f;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
uint8_t valueId = (uint8_t) valueType;
|
||||
if (!isValidValueId(valueId)) {
|
||||
return 0.0f;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
float value = 0.0f;
|
||||
uint8_t amount = 0;
|
||||
|
||||
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
|
||||
auto& sSensor = settings[id];
|
||||
auto& rSensor = results[id];
|
||||
if (avgType == AverageType::MEAN) {
|
||||
float sum = 0.0f;
|
||||
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
|
||||
auto& sSensor = settings[id];
|
||||
auto& rSensor = results[id];
|
||||
|
||||
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
|
||||
value += rSensor.values[valueId];
|
||||
amount++;
|
||||
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 (!amount) {
|
||||
return 0.0f;
|
||||
|
||||
} else if (amount == 1) {
|
||||
return value;
|
||||
|
||||
} else {
|
||||
return value / amount;
|
||||
}
|
||||
return amount > 0 ? value : defaultValue;
|
||||
}
|
||||
|
||||
static bool existsConnectedSensorsByPurpose(Purpose purpose) {
|
||||
@@ -411,13 +440,13 @@ public:
|
||||
return value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class T>
|
||||
static String cleanName(T value, char space = ' ') {
|
||||
String res = value;
|
||||
return cleanName(res, space);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class T>
|
||||
static String& makeObjectId(String& res, T value, char separator = '_') {
|
||||
res = value;
|
||||
cleanName(res);
|
||||
@@ -427,7 +456,7 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class T>
|
||||
static String makeObjectId(T value, char separator = '_') {
|
||||
String res;
|
||||
makeObjectId(res, value, separator);
|
||||
@@ -435,7 +464,7 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class TV, class TS>
|
||||
template <class TV, class TS>
|
||||
static String& makeObjectIdWithSuffix(String& res, TV value, TS suffix, char separator = '_') {
|
||||
res.clear();
|
||||
makeObjectId(res, value, separator);
|
||||
@@ -445,14 +474,14 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class TV, class TS>
|
||||
template <class TV, class TS>
|
||||
static String makeObjectIdWithSuffix(TV value, TS suffix, char separator = '_') {
|
||||
String res;
|
||||
makeObjectIdWithSuffix(res, value, suffix, separator);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class TV, class TP>
|
||||
template <class TV, class TP>
|
||||
static String& makeObjectIdWithPrefix(String& res, TV value, TP prefix, char separator = '_') {
|
||||
res = prefix;
|
||||
res += separator;
|
||||
@@ -461,7 +490,7 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class TV, class TP>
|
||||
template <class TV, class TP>
|
||||
static String makeObjectIdWithPrefix(TV value, TP prefix, char separator = '_') {
|
||||
String res;
|
||||
return makeObjectIdWithPrefix(res, value, prefix, separator);
|
||||
@@ -474,4 +503,4 @@ public:
|
||||
|
||||
uint8_t Sensors::maxSensors = 0;
|
||||
Sensors::Settings* Sensors::settings = nullptr;
|
||||
Sensors::Result* Sensors::results = nullptr;
|
||||
Sensors::Result* Sensors::results = nullptr;
|
||||
|
||||
+61
-25
@@ -74,7 +74,7 @@ public:
|
||||
}
|
||||
|
||||
static bool parseAtcData(const NimBLEAdvertisedDevice* device, uint8_t sensorId) {
|
||||
NimBLEUUID serviceUuid((uint16_t) 0x181A);
|
||||
NimBLEUUID serviceUuid(static_cast<uint16_t>(0x181A));
|
||||
|
||||
auto serviceData = device->getServiceData(serviceUuid);
|
||||
if (!serviceData.size()) {
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Log.snoticeln(
|
||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu, service %s: found ATC1441 format"),
|
||||
sensorId, serviceUuid.toString().c_str()
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
}
|
||||
|
||||
static bool parsePvvxData(const NimBLEAdvertisedDevice* device, uint8_t sensorId) {
|
||||
NimBLEUUID serviceUuid((uint16_t) 0x181A);
|
||||
NimBLEUUID serviceUuid(static_cast<uint16_t>(0x181A));
|
||||
|
||||
auto serviceData = device->getServiceData(serviceUuid);
|
||||
if (!serviceData.size()) {
|
||||
@@ -142,7 +142,7 @@ public:
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Log.snoticeln(
|
||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu, service %s: found PVVX format"),
|
||||
sensorId, serviceUuid.toString().c_str()
|
||||
@@ -178,7 +178,7 @@ public:
|
||||
}
|
||||
|
||||
static bool parseBTHomeData(const NimBLEAdvertisedDevice* device, uint8_t sensorId) {
|
||||
NimBLEUUID serviceUuid((uint16_t) 0xFCD2);
|
||||
NimBLEUUID serviceUuid(static_cast<uint16_t>(0xFCD2));
|
||||
|
||||
auto serviceData = device->getServiceData(serviceUuid);
|
||||
if (!serviceData.size()) {
|
||||
@@ -202,7 +202,7 @@ public:
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Log.snoticeln(
|
||||
FPSTR(L_SENSORS_BLE), F("Sensor #%hhu, service %s: found BTHome format"),
|
||||
sensorId, serviceUuid.toString().c_str()
|
||||
@@ -263,7 +263,7 @@ public:
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t rawHumidity = (static_cast<uint16_t>(serviceData[serviceDataPos + 1]) << 8)
|
||||
uint16_t rawHumidity = (static_cast<uint16_t>(serviceData[serviceDataPos + 1]) << 8)
|
||||
| static_cast<uint8_t>(serviceData[serviceDataPos]);
|
||||
float humidity = static_cast<float>(rawHumidity) * 0.01f;
|
||||
Sensors::setValueById(sensorId, humidity, Sensors::ValueType::HUMIDITY, true, true);
|
||||
@@ -283,7 +283,7 @@ public:
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t batteryMv = (static_cast<uint16_t>(serviceData[serviceDataPos + 1]) << 8)
|
||||
uint16_t batteryMv = (static_cast<uint16_t>(serviceData[serviceDataPos + 1]) << 8)
|
||||
| static_cast<uint8_t>(serviceData[serviceDataPos]);
|
||||
serviceDataPos += 2;
|
||||
foundData = true;
|
||||
@@ -304,7 +304,7 @@ public:
|
||||
|
||||
class SensorsTask : public LeanTask {
|
||||
public:
|
||||
SensorsTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {
|
||||
explicit SensorsTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {
|
||||
this->gpioLastPollingTime.reserve(2);
|
||||
|
||||
// OneWire
|
||||
@@ -423,14 +423,50 @@ protected:
|
||||
}
|
||||
|
||||
void updateMasterValues() {
|
||||
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.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.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.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.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);
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
void makeDallasInstances() {
|
||||
@@ -470,7 +506,7 @@ protected:
|
||||
|
||||
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
|
||||
auto& sSensor = Sensors::settings[sensorId];
|
||||
|
||||
|
||||
if (!sSensor.enabled || sSensor.type != Sensors::Type::DALLAS_TEMP || sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
||||
continue;
|
||||
}
|
||||
@@ -524,7 +560,7 @@ protected:
|
||||
// check & filling sensors address
|
||||
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
|
||||
auto& sSensor = Sensors::settings[sensorId];
|
||||
|
||||
|
||||
if (!sSensor.enabled || sSensor.type != Sensors::Type::DALLAS_TEMP || sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
||||
continue;
|
||||
|
||||
@@ -557,7 +593,7 @@ protected:
|
||||
if (sCheckingSensor.type != Sensors::Type::DALLAS_TEMP || checkingSensorId == sensorId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (sCheckingSensor.gpio != sSensor.gpio || isEmptyAddress(sCheckingSensor.address)) {
|
||||
continue;
|
||||
}
|
||||
@@ -618,7 +654,7 @@ protected:
|
||||
// read sensors data for current instance
|
||||
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
|
||||
auto& sSensor = Sensors::settings[sensorId];
|
||||
|
||||
|
||||
// only target & valid sensors
|
||||
if (!sSensor.enabled || sSensor.type != Sensors::Type::DALLAS_TEMP || sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
||||
continue;
|
||||
@@ -626,7 +662,7 @@ protected:
|
||||
} else if (sSensor.gpio != gpio || isEmptyAddress(sSensor.address)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
auto& rSensor = Sensors::results[sensorId];
|
||||
float value = instance.getTempC(sSensor.address);
|
||||
if (value == DEVICE_DISCONNECTED_C) {
|
||||
@@ -685,7 +721,7 @@ protected:
|
||||
|
||||
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
|
||||
auto& sSensor = Sensors::settings[sensorId];
|
||||
|
||||
|
||||
if (!sSensor.enabled || sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
||||
continue;
|
||||
}
|
||||
@@ -736,7 +772,7 @@ protected:
|
||||
if (rSensor.signalQuality > 0) {
|
||||
rSensor.signalQuality--;
|
||||
}
|
||||
|
||||
|
||||
this->gpioLastPollingTime[sSensor.gpio] = millis();
|
||||
this->dhtIsPolling = false;
|
||||
});
|
||||
@@ -769,7 +805,7 @@ protected:
|
||||
void pollingNtcSensors() {
|
||||
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
|
||||
auto& sSensor = Sensors::settings[sensorId];
|
||||
|
||||
|
||||
if (!sSensor.enabled || sSensor.type != Sensors::Type::NTC_10K_TEMP || sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
||||
continue;
|
||||
}
|
||||
@@ -794,7 +830,7 @@ protected:
|
||||
}
|
||||
|
||||
const float sensorResistance = value > 1
|
||||
? DEFAULT_NTC_REF_RESISTANCE / (DEFAULT_NTC_VREF / (float) value - 1.0f)
|
||||
? DEFAULT_NTC_REF_RESISTANCE / (DEFAULT_NTC_VREF / static_cast<float>(value) - 1.0f)
|
||||
: 0.0f;
|
||||
const float rawTemp = 1.0f / (
|
||||
1.0f / (DEFAULT_NTC_NOMINAL_TEMP + 273.15f) +
|
||||
@@ -933,4 +969,4 @@ protected:
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
+4
-2
@@ -107,6 +107,8 @@ 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;
|
||||
@@ -131,7 +133,7 @@ struct Settings {
|
||||
uint8_t minTemp = DEFAULT_DHW_MIN_TEMP;
|
||||
uint8_t maxTemp = DEFAULT_DHW_MAX_TEMP;
|
||||
uint8_t maxModulation = 100;
|
||||
|
||||
|
||||
struct {
|
||||
uint8_t highTemp = 95;
|
||||
uint8_t lowTemp = 90;
|
||||
@@ -439,4 +441,4 @@ struct Variables {
|
||||
bool restarting = false;
|
||||
bool upgrading = false;
|
||||
} states;
|
||||
} vars;
|
||||
} vars;
|
||||
|
||||
+2
-2
@@ -147,7 +147,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM
|
||||
#define PROGMEM // NOLINT
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
@@ -168,4 +168,4 @@ enum class HysteresisAction : uint8_t {
|
||||
SET_ZERO_TARGET = 1
|
||||
};
|
||||
|
||||
char buffer[255];
|
||||
char buffer[255];
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ void setup() {
|
||||
|
||||
return tm{sec, min, hour};
|
||||
});
|
||||
|
||||
|
||||
Serial.begin(115200);
|
||||
#if ARDUINO_USB_MODE
|
||||
Serial.setTxBufferSize(512);
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM
|
||||
#define PROGMEM // NOLINT
|
||||
#endif
|
||||
|
||||
const char L_SETTINGS[] PROGMEM = "SETTINGS";
|
||||
@@ -115,6 +115,7 @@ 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";
|
||||
@@ -155,6 +156,7 @@ 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";
|
||||
@@ -222,4 +224,4 @@ const char S_USE_DHCP[] PROGMEM = "useDhcp";
|
||||
const char S_USER[] PROGMEM = "user";
|
||||
const char S_VALUE[] PROGMEM = "value";
|
||||
const char S_VERSION[] PROGMEM = "version";
|
||||
const char S_WEBSERIAL[] PROGMEM = "webSerial";
|
||||
const char S_WEBSERIAL[] PROGMEM = "webSerial";
|
||||
|
||||
+49
-11
@@ -7,7 +7,7 @@ String getChipId(const char* prefix = nullptr, const char* suffix = nullptr) {
|
||||
+ (prefix != nullptr ? strlen(prefix) : 0)
|
||||
+ (suffix != nullptr ? strlen(suffix) : 0)
|
||||
);
|
||||
|
||||
|
||||
if (prefix != nullptr) {
|
||||
chipId.concat(prefix);
|
||||
}
|
||||
@@ -139,7 +139,7 @@ inline bool isValidTemp(const float value, UnitSystem unit, const float min = 0.
|
||||
|
||||
float roundf(float value, uint8_t decimals = 2) {
|
||||
if (decimals == 0) {
|
||||
return (int)(value + 0.5f);
|
||||
return static_cast<int>(value + 0.5f);
|
||||
|
||||
} else if (abs(value) < 0.00000001f) {
|
||||
return 0.0f;
|
||||
@@ -147,7 +147,7 @@ float roundf(float value, uint8_t decimals = 2) {
|
||||
|
||||
float multiplier = pow10(decimals);
|
||||
value += 0.5f / multiplier * (value < 0.0f ? -1.0f : 1.0f);
|
||||
return (int)(value * multiplier) / multiplier;
|
||||
return static_cast<int>(value * multiplier) / multiplier;
|
||||
}
|
||||
|
||||
inline size_t getTotalHeap() {
|
||||
@@ -470,7 +470,7 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
|
||||
otOptions[FPSTR(S_ALWAYS_SEND_INDOOR_TEMP)] = src.opentherm.options.alwaysSendIndoorTemp;
|
||||
otOptions[FPSTR(S_NATIVE_OTC)] = src.opentherm.options.nativeOTC;
|
||||
otOptions[FPSTR(S_IMMERGAS_FIX)] = src.opentherm.options.immergasFix;
|
||||
|
||||
|
||||
|
||||
auto mqtt = dst[FPSTR(S_MQTT)].to<JsonObject>();
|
||||
mqtt[FPSTR(S_ENABLED)] = src.mqtt.enabled;
|
||||
@@ -486,7 +486,7 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
|
||||
emergency[FPSTR(S_TARGET)] = roundf(src.emergency.target, 2);
|
||||
emergency[FPSTR(S_TRESHOLD_TIME)] = src.emergency.tresholdTime;
|
||||
}
|
||||
|
||||
|
||||
auto heating = dst[FPSTR(S_HEATING)].to<JsonObject>();
|
||||
heating[FPSTR(S_ENABLED)] = src.heating.enabled;
|
||||
heating[FPSTR(S_TURBO)] = src.heating.turbo;
|
||||
@@ -498,6 +498,8 @@ 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;
|
||||
@@ -1393,6 +1395,42 @@ 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>();
|
||||
|
||||
@@ -1736,8 +1774,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
||||
float minTemp = indoorTempControl ? THERMOSTAT_INDOOR_MIN_TEMP : dst.heating.minTemp;
|
||||
float maxTemp = indoorTempControl ? THERMOSTAT_INDOOR_MAX_TEMP : dst.heating.maxTemp;
|
||||
|
||||
float value = !src[FPSTR(S_HEATING)][FPSTR(S_TARGET)].isNull()
|
||||
? src[FPSTR(S_HEATING)][FPSTR(S_TARGET)].as<float>()
|
||||
float value = !src[FPSTR(S_HEATING)][FPSTR(S_TARGET)].isNull()
|
||||
? src[FPSTR(S_HEATING)][FPSTR(S_TARGET)].as<float>()
|
||||
: dst.heating.target;
|
||||
bool valid = isValidTemp(
|
||||
value,
|
||||
@@ -1763,8 +1801,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
||||
|
||||
// force check dhw target
|
||||
{
|
||||
float value = !src[FPSTR(S_DHW)][FPSTR(S_TARGET)].isNull()
|
||||
? src[FPSTR(S_DHW)][FPSTR(S_TARGET)].as<float>()
|
||||
float value = !src[FPSTR(S_DHW)][FPSTR(S_TARGET)].isNull()
|
||||
? src[FPSTR(S_DHW)][FPSTR(S_TARGET)].as<float>()
|
||||
: dst.dhw.target;
|
||||
bool valid = isValidTemp(
|
||||
value,
|
||||
@@ -2023,7 +2061,7 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se
|
||||
for (uint8_t i = 0; i < sizeof(dst.address); i++) {
|
||||
dst.address[i] = 0x00;
|
||||
}
|
||||
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -2219,4 +2257,4 @@ bool jsonToVars(const JsonVariantConst src, Variables& dst) {
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
+42
-57
@@ -8,15 +8,21 @@
|
||||
"issues": "问题与反馈",
|
||||
"releases": "发行版"
|
||||
},
|
||||
"dbm": "dBm",
|
||||
"kw": "kW",
|
||||
"time": {
|
||||
"units": {
|
||||
"days": "天",
|
||||
"hours": "小时",
|
||||
"min": "分",
|
||||
"sec": "秒"
|
||||
"sec": "秒",
|
||||
"dbm": "dBm",
|
||||
"mhz": "MHz",
|
||||
"kw": "kW",
|
||||
"rpm": "RPM",
|
||||
"ppm": "ppm",
|
||||
"byte": "byte",
|
||||
"mbyte": "MB",
|
||||
"liter": "升",
|
||||
"gallon": "加仑"
|
||||
},
|
||||
|
||||
"button": {
|
||||
"upgrade": "固件升级",
|
||||
"restart": "重启",
|
||||
@@ -31,15 +37,12 @@
|
||||
"success": "成功",
|
||||
"error": "错误"
|
||||
},
|
||||
|
||||
"index": {
|
||||
"title": "OpenTherm Gateway",
|
||||
|
||||
"section": {
|
||||
"network": "网络",
|
||||
"system": "系统"
|
||||
},
|
||||
|
||||
"system": {
|
||||
"build": {
|
||||
"title": "Build",
|
||||
@@ -51,7 +54,8 @@
|
||||
},
|
||||
"uptime": "运行时间",
|
||||
"memory": {
|
||||
"title": "可用内存",
|
||||
"heap": "内存 (heap)",
|
||||
"psram": "内存 (PSRAM)",
|
||||
"maxFreeBlock": "max free block",
|
||||
"min": "min"
|
||||
},
|
||||
@@ -68,26 +72,22 @@
|
||||
"lastResetReason": "上次重置原因"
|
||||
}
|
||||
},
|
||||
|
||||
"dashboard": {
|
||||
"name": "仪表盘",
|
||||
"title": "仪表盘 - OpenTherm Gateway",
|
||||
|
||||
"section": {
|
||||
"control": "调节",
|
||||
"states": "状态",
|
||||
"sensors": "传感器",
|
||||
"diag": "OpenTherm 诊断"
|
||||
},
|
||||
|
||||
"thermostat": {
|
||||
"heating": "供暖",
|
||||
"dhw": "生活热水",
|
||||
"temp.current": "当前温度",
|
||||
"currentTemp": "当前温度",
|
||||
"enable": "启用",
|
||||
"turbo": "Turbo 模式"
|
||||
},
|
||||
|
||||
"notify": {
|
||||
"fault": {
|
||||
"title": "锅炉报警状态已激活!",
|
||||
@@ -99,7 +99,6 @@
|
||||
},
|
||||
"reset": "点击复位"
|
||||
},
|
||||
|
||||
"states": {
|
||||
"mNetworkConnected": "网络连接状态",
|
||||
"mMqttConnected": "MQTT服务器连接状态",
|
||||
@@ -107,7 +106,6 @@
|
||||
"mExtPumpState": "外置循环泵",
|
||||
"mCascadeControlInput": "Cascade 控制 (input)",
|
||||
"mCascadeControlOutput": "Cascade 控制 (output)",
|
||||
|
||||
"sConnected": "OpenTherm 通讯状态",
|
||||
"sFlame": "火焰",
|
||||
"sCoolingActive": "制冷",
|
||||
@@ -116,10 +114,10 @@
|
||||
"sFaultCode": "报警代码",
|
||||
"sDiagActive": "诊断状态",
|
||||
"sDiagCode": "诊断代码",
|
||||
|
||||
"mHeatEnabled": "供暖功能已启用",
|
||||
"mHeatBlocking": "供暖",
|
||||
"mHeatOverheat": "供暖超热保护",
|
||||
"mHeatFreezing": "防冻保护",
|
||||
"sHeatActive": "供暖激活状态",
|
||||
"mHeatSetpointTemp": "供暖供水设定温度",
|
||||
"mHeatTargetTemp": "供暖供水目标温度",
|
||||
@@ -127,7 +125,6 @@
|
||||
"mHeatRetTemp": "供暖回水温度",
|
||||
"mHeatIndoorTemp": "供暖,室内温度",
|
||||
"mHeatOutdoorTemp": "供暖,室外温度",
|
||||
|
||||
"mDhwEnabled": "生活热水功能已启用",
|
||||
"mDhwOverheat": "生活热水超热保护",
|
||||
"sDhwActive": "生活热水激活",
|
||||
@@ -135,7 +132,6 @@
|
||||
"mDhwCurrTemp": "生活热水当前出水温度",
|
||||
"mDhwRetTemp": "生活热水回水温度"
|
||||
},
|
||||
|
||||
"sensors": {
|
||||
"values": {
|
||||
"temp": "温度",
|
||||
@@ -145,23 +141,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"network": {
|
||||
"title": "网络 - OpenTherm Gateway",
|
||||
"name": "网络设置",
|
||||
|
||||
"section": {
|
||||
"static": "静态设置",
|
||||
"availableNetworks": "可用网络",
|
||||
"staSettings": "WiFi 设置",
|
||||
"apSettings": "AP 设置"
|
||||
},
|
||||
|
||||
"scan": {
|
||||
"pos": "#",
|
||||
"info": "Info"
|
||||
},
|
||||
|
||||
"wifi": {
|
||||
"ssid": "SSID",
|
||||
"password": "密码",
|
||||
@@ -169,7 +161,6 @@
|
||||
"signal": "信号强度",
|
||||
"connected": "已连接"
|
||||
},
|
||||
|
||||
"params": {
|
||||
"hostname": "Hostname",
|
||||
"dhcp": "自动 (DHCP)",
|
||||
@@ -179,16 +170,15 @@
|
||||
"gateway": "网关",
|
||||
"dns": "DNS 服务器"
|
||||
},
|
||||
|
||||
"sta": {
|
||||
"channel.note": "自动选择设置为0"
|
||||
"channel": {
|
||||
"note": "自动选择设置为0"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"sensors": {
|
||||
"title": "传感器设置 - OpenTherm Gateway",
|
||||
"name": "传感器设置",
|
||||
|
||||
"enabled": "启用",
|
||||
"sensorName": {
|
||||
"title": "传感器名称",
|
||||
@@ -245,7 +235,6 @@
|
||||
"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 传感器",
|
||||
@@ -277,11 +266,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"settings": {
|
||||
"title": "设置 - OpenTherm Gateway",
|
||||
"name": "设置",
|
||||
|
||||
"section": {
|
||||
"portal": "Portal 设置",
|
||||
"system": "系统设置",
|
||||
@@ -296,18 +283,21 @@
|
||||
"extPump": "外置循环泵设置",
|
||||
"cascadeControl": "Cascade 级联控制设置"
|
||||
},
|
||||
|
||||
"enable": "启用",
|
||||
"note": {
|
||||
"restart": "更改这些设置后,必须重启设备以使变更生效",
|
||||
"blankNotUse": "空白 - 未使用",
|
||||
"bleDevice": "BLE设备仅支持搭载BLE功能的特定ESP32开发板使用!"
|
||||
},
|
||||
|
||||
"temp": {
|
||||
"min": "最低温度",
|
||||
"max": "最高温度"
|
||||
},
|
||||
"avgType": {
|
||||
"mean": "平均温度",
|
||||
"min": "最低温度",
|
||||
"max": "最高温度"
|
||||
},
|
||||
"maxModulation": "最大调制范围",
|
||||
"ohProtection": {
|
||||
"title": "超温保护",
|
||||
@@ -333,14 +323,12 @@
|
||||
"note": "强制开启加热的阈值"
|
||||
}
|
||||
},
|
||||
|
||||
"portal": {
|
||||
"login": "登录",
|
||||
"password": "密码",
|
||||
"auth": "需身份验证",
|
||||
"mdns": "使用 mDNS"
|
||||
},
|
||||
|
||||
"system": {
|
||||
"unit": "单位",
|
||||
"metric": "公制 <small>(摄氏度、升、巴)</small>",
|
||||
@@ -360,7 +348,6 @@
|
||||
"timezonePresets": "选择预设配置..."
|
||||
}
|
||||
},
|
||||
|
||||
"heating": {
|
||||
"hyst": {
|
||||
"title": "滞回",
|
||||
@@ -372,19 +359,24 @@
|
||||
"set0target": "设置空目标"
|
||||
}
|
||||
},
|
||||
"turboFactor": "Turbo 模式系数"
|
||||
"turboFactor": "Turbo 模式系数",
|
||||
"indoorTempAvgType": {
|
||||
"title": "室内温度平均类型",
|
||||
"desc": "使用两个或更多室内温度传感器时可能有用(使用 «Equitherm» 和/或 «PID» 时)。"
|
||||
},
|
||||
"outdoorTempAvgType": {
|
||||
"title": "室外温度平均类型",
|
||||
"desc": "使用两个或更多室外温度传感器时可能有用(使用 «Equitherm» 时)。"
|
||||
}
|
||||
},
|
||||
|
||||
"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": "斜率",
|
||||
@@ -408,7 +400,6 @@
|
||||
"outdoorTemp": "室外温度"
|
||||
}
|
||||
},
|
||||
|
||||
"pid": {
|
||||
"p": "P 系数",
|
||||
"i": "I 系数",
|
||||
@@ -428,7 +419,6 @@
|
||||
"thresholdLow": "Threshold low"
|
||||
}
|
||||
},
|
||||
|
||||
"ot": {
|
||||
"advanced": "高级设置",
|
||||
"inGpio": "In GPIO",
|
||||
@@ -442,9 +432,8 @@
|
||||
},
|
||||
"maxPower": {
|
||||
"title": "最大锅炉功率 <small>(kW)</small>",
|
||||
"note": "<b>0</b> - 自动检测,通常在锅炉参数设置中的\"最大有效热输出\"。 "
|
||||
"note": "<b>0</b> - 自动检测,通常在锅炉参数设置中的\"最大有效热输出\"。"
|
||||
},
|
||||
|
||||
"options": {
|
||||
"title": "选项(附加设置)",
|
||||
"desc": "附加设置选项可调整锅炉的运行逻辑。由于协议未完整记录所有选项,同一选项在不同锅炉上可能产生不同效果。<br /><b>注意:</b>若系统运行正常,无需修改设置。",
|
||||
@@ -466,13 +455,11 @@
|
||||
"immergasFix": "针对Immergas锅炉的兼容性修复",
|
||||
"alwaysSendIndoorTemp": "向锅炉发送当前室内温度"
|
||||
},
|
||||
|
||||
"nativeOTC": {
|
||||
"title": "原生热载体温度计算模式",
|
||||
"note": "仅在锅炉处于 OTC 模式时<u>才</u>工作:需要并接受目标室内温度,并基于内置曲线模式自行调节热载体温度。与 PID 和 Equitherm 不兼容。"
|
||||
}
|
||||
},
|
||||
|
||||
"mqtt": {
|
||||
"homeAssistantDiscovery": "Home Assistant 自动发现",
|
||||
"server": "服务器地址",
|
||||
@@ -482,7 +469,6 @@
|
||||
"prefix": "Prefix 前缀",
|
||||
"interval": "发布间隔 <small>(秒)</small>"
|
||||
},
|
||||
|
||||
"extPump": {
|
||||
"use": "使用外置循环泵",
|
||||
"gpio": "继电器 GPIO引脚",
|
||||
@@ -491,7 +477,6 @@
|
||||
"antiStuckInterval": "防卡死间隔时间<small>(天)</small>",
|
||||
"antiStuckTime": "防卡死运行时长<small>(分钟)</small>"
|
||||
},
|
||||
|
||||
"cascadeControl": {
|
||||
"input": {
|
||||
"desc": "仅当另一台锅炉发生故障时启用本锅炉加热。另一台锅炉的控制器需在故障发生时切换GPIO输入状态以触发本功能。",
|
||||
@@ -515,23 +500,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"upgrade": {
|
||||
"title": "固件升级 - OpenTherm Gateway",
|
||||
"name": "固件升级",
|
||||
|
||||
"section": {
|
||||
"backupAndRestore": "备份与恢复",
|
||||
"backupAndRestore.desc": "本功能支持备份和恢复全部设置",
|
||||
"upgrade": "升级",
|
||||
"upgrade.desc": "本模块支持升级设备的固件与系统文件。<br />可从以下地址下载最新版本 <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Releases page</a> 。"
|
||||
"backupAndRestore": {
|
||||
"title": "备份与恢复",
|
||||
"desc": "本功能支持备份和恢复全部设置"
|
||||
},
|
||||
"upgrade": {
|
||||
"title": "升级",
|
||||
"desc": "本模块支持升级设备的固件与系统文件。<br />可从以下地址下载最新版本 <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Releases page</a> 。"
|
||||
}
|
||||
},
|
||||
|
||||
"note": {
|
||||
"disclaimer1": "升级系统文件成功后,所有设置将恢复为默认值!升级前请务必备份配置。",
|
||||
"disclaimer2": "升级成功后,设备将在15秒后自动重启。"
|
||||
},
|
||||
|
||||
"settingsFile": "设置文件",
|
||||
"fw": "Firmware",
|
||||
"fs": "Filesystem"
|
||||
|
||||
+40
-56
@@ -8,15 +8,21 @@
|
||||
"issues": "Issues & questions",
|
||||
"releases": "Releases"
|
||||
},
|
||||
"dbm": "dBm",
|
||||
"kw": "kW",
|
||||
"time": {
|
||||
"units": {
|
||||
"days": "d.",
|
||||
"hours": "h.",
|
||||
"min": "min.",
|
||||
"sec": "sec."
|
||||
"sec": "sec.",
|
||||
"dbm": "dBm",
|
||||
"mhz": "MHz",
|
||||
"kw": "kW",
|
||||
"rpm": "RPM",
|
||||
"ppm": "ppm",
|
||||
"byte": "byte",
|
||||
"mbyte": "MB",
|
||||
"liter": "L",
|
||||
"gallon": "gal"
|
||||
},
|
||||
|
||||
"button": {
|
||||
"upgrade": "Upgrade",
|
||||
"restart": "Restart",
|
||||
@@ -31,15 +37,12 @@
|
||||
"success": "Success",
|
||||
"error": "Error"
|
||||
},
|
||||
|
||||
"index": {
|
||||
"title": "OpenTherm Gateway",
|
||||
|
||||
"section": {
|
||||
"network": "Network",
|
||||
"system": "System"
|
||||
},
|
||||
|
||||
"system": {
|
||||
"build": {
|
||||
"title": "Build",
|
||||
@@ -51,7 +54,8 @@
|
||||
},
|
||||
"uptime": "Uptime",
|
||||
"memory": {
|
||||
"title": "Free memory",
|
||||
"heap": "Memory (heap)",
|
||||
"psram": "Memory (PSRAM)",
|
||||
"maxFreeBlock": "max free block",
|
||||
"min": "min"
|
||||
},
|
||||
@@ -68,26 +72,22 @@
|
||||
"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",
|
||||
"temp.current": "Current",
|
||||
"currentTemp": "Current",
|
||||
"enable": "Enable",
|
||||
"turbo": "Turbo mode"
|
||||
},
|
||||
|
||||
"notify": {
|
||||
"fault": {
|
||||
"title": "Boiler Fault state is active!",
|
||||
@@ -99,7 +99,6 @@
|
||||
},
|
||||
"reset": "Try reset"
|
||||
},
|
||||
|
||||
"states": {
|
||||
"mNetworkConnected": "Network connection",
|
||||
"mMqttConnected": "MQTT connection",
|
||||
@@ -107,7 +106,6 @@
|
||||
"mExtPumpState": "External pump",
|
||||
"mCascadeControlInput": "Cascade control (input)",
|
||||
"mCascadeControlOutput": "Cascade control (output)",
|
||||
|
||||
"sConnected": "OpenTherm connection",
|
||||
"sFlame": "Flame",
|
||||
"sCoolingActive": "Cooling",
|
||||
@@ -116,7 +114,6 @@
|
||||
"sFaultCode": "Fault code",
|
||||
"sDiagActive": "Diagnostic",
|
||||
"sDiagCode": "Diagnostic code",
|
||||
|
||||
"mHeatEnabled": "Heating enabled",
|
||||
"mHeatBlocking": "Heating blocked",
|
||||
"mHeatOverheat": "Heating overheat",
|
||||
@@ -128,7 +125,6 @@
|
||||
"mHeatRetTemp": "Heating return temp",
|
||||
"mHeatIndoorTemp": "Heating, indoor temp",
|
||||
"mHeatOutdoorTemp": "Heating, outdoor temp",
|
||||
|
||||
"mDhwEnabled": "DHW enabled",
|
||||
"mDhwOverheat": "DHW overheat",
|
||||
"sDhwActive": "DHW active",
|
||||
@@ -136,7 +132,6 @@
|
||||
"mDhwCurrTemp": "DHW current temp",
|
||||
"mDhwRetTemp": "DHW return temp"
|
||||
},
|
||||
|
||||
"sensors": {
|
||||
"values": {
|
||||
"temp": "Temperature",
|
||||
@@ -146,23 +141,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"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",
|
||||
@@ -170,7 +161,6 @@
|
||||
"signal": "Signal",
|
||||
"connected": "Connected"
|
||||
},
|
||||
|
||||
"params": {
|
||||
"hostname": "Hostname",
|
||||
"dhcp": "Use DHCP",
|
||||
@@ -180,16 +170,15 @@
|
||||
"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",
|
||||
@@ -246,7 +235,6 @@
|
||||
"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",
|
||||
@@ -278,11 +266,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"settings": {
|
||||
"title": "Settings - OpenTherm Gateway",
|
||||
"name": "Settings",
|
||||
|
||||
"section": {
|
||||
"portal": "Portal settings",
|
||||
"system": "System settings",
|
||||
@@ -297,18 +283,21 @@
|
||||
"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",
|
||||
@@ -334,14 +323,12 @@
|
||||
"note": "Threshold when heating is forced to turn on"
|
||||
}
|
||||
},
|
||||
|
||||
"portal": {
|
||||
"login": "Login",
|
||||
"password": "Password",
|
||||
"auth": "Require authentication",
|
||||
"mdns": "Use mDNS"
|
||||
},
|
||||
|
||||
"system": {
|
||||
"unit": "Unit system",
|
||||
"metric": "Metric <small>(celsius, liters, bar)</small>",
|
||||
@@ -361,7 +348,6 @@
|
||||
"timezonePresets": "Select preset..."
|
||||
}
|
||||
},
|
||||
|
||||
"heating": {
|
||||
"hyst": {
|
||||
"title": "Hysteresis",
|
||||
@@ -373,19 +359,24 @@
|
||||
"set0target": "Set null target"
|
||||
}
|
||||
},
|
||||
"turboFactor": "Turbo mode coeff."
|
||||
"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»)."
|
||||
}
|
||||
},
|
||||
|
||||
"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",
|
||||
@@ -409,7 +400,6 @@
|
||||
"outdoorTemp": "Outdoor temperature"
|
||||
}
|
||||
},
|
||||
|
||||
"pid": {
|
||||
"p": "P factor",
|
||||
"i": "I factor",
|
||||
@@ -429,7 +419,6 @@
|
||||
"thresholdLow": "Threshold low"
|
||||
}
|
||||
},
|
||||
|
||||
"ot": {
|
||||
"advanced": "Advanced Settings",
|
||||
"inGpio": "In GPIO",
|
||||
@@ -445,7 +434,6 @@
|
||||
"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.",
|
||||
@@ -467,13 +455,11 @@
|
||||
"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",
|
||||
@@ -483,7 +469,6 @@
|
||||
"prefix": "Prefix",
|
||||
"interval": "Publish interval <small>(sec)</small>"
|
||||
},
|
||||
|
||||
"extPump": {
|
||||
"use": "Use external pump",
|
||||
"gpio": "Relay GPIO",
|
||||
@@ -492,7 +477,6 @@
|
||||
"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.",
|
||||
@@ -516,26 +500,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"upgrade": {
|
||||
"title": "Upgrade - OpenTherm Gateway",
|
||||
"name": "Upgrade",
|
||||
|
||||
"section": {
|
||||
"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."
|
||||
"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."
|
||||
}
|
||||
},
|
||||
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,523 @@
|
||||
{
|
||||
"values": {
|
||||
"logo": "",
|
||||
"nav": {
|
||||
"license": "",
|
||||
"source": "",
|
||||
"help": "",
|
||||
"issues": "",
|
||||
"releases": ""
|
||||
},
|
||||
"units": {
|
||||
"days": "",
|
||||
"hours": "",
|
||||
"min": "",
|
||||
"sec": "",
|
||||
"dbm": "",
|
||||
"mhz": "",
|
||||
"kw": "",
|
||||
"rpm": "",
|
||||
"ppm": "",
|
||||
"byte": "",
|
||||
"mbyte": ""
|
||||
},
|
||||
"button": {
|
||||
"upgrade": "",
|
||||
"restart": "",
|
||||
"save": "",
|
||||
"saved": "",
|
||||
"refresh": "",
|
||||
"restore": "",
|
||||
"restored": "",
|
||||
"backup": "",
|
||||
"wait": "",
|
||||
"uploading": "",
|
||||
"success": "",
|
||||
"error": ""
|
||||
},
|
||||
"index": {
|
||||
"title": "",
|
||||
"section": {
|
||||
"network": "",
|
||||
"system": ""
|
||||
},
|
||||
"system": {
|
||||
"build": {
|
||||
"title": "",
|
||||
"version": "",
|
||||
"commit": "",
|
||||
"date": "",
|
||||
"core": "",
|
||||
"sdk": ""
|
||||
},
|
||||
"uptime": "",
|
||||
"memory": {
|
||||
"heap": "",
|
||||
"psram": "",
|
||||
"maxFreeBlock": "",
|
||||
"min": ""
|
||||
},
|
||||
"board": "",
|
||||
"chip": {
|
||||
"model": "",
|
||||
"cores": "",
|
||||
"freq": ""
|
||||
},
|
||||
"flash": {
|
||||
"size": "",
|
||||
"realSize": ""
|
||||
},
|
||||
"lastResetReason": ""
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"name": "",
|
||||
"title": "",
|
||||
"section": {
|
||||
"control": "",
|
||||
"states": "",
|
||||
"sensors": "",
|
||||
"diag": ""
|
||||
},
|
||||
"thermostat": {
|
||||
"heating": "",
|
||||
"dhw": "",
|
||||
"currentTemp": "",
|
||||
"enable": "",
|
||||
"turbo": ""
|
||||
},
|
||||
"notify": {
|
||||
"fault": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"diag": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"reset": ""
|
||||
},
|
||||
"states": {
|
||||
"mNetworkConnected": "",
|
||||
"mMqttConnected": "",
|
||||
"mEmergencyState": "",
|
||||
"mExtPumpState": "",
|
||||
"mCascadeControlInput": "",
|
||||
"mCascadeControlOutput": "",
|
||||
"sConnected": "",
|
||||
"sFlame": "",
|
||||
"sCoolingActive": "",
|
||||
"sCoolingSetpoint": "",
|
||||
"sFaultActive": "",
|
||||
"sFaultCode": "",
|
||||
"sDiagActive": "",
|
||||
"sDiagCode": "",
|
||||
"mHeatEnabled": "",
|
||||
"mHeatBlocking": "",
|
||||
"mHeatOverheat": "",
|
||||
"mHeatFreezing": "",
|
||||
"sHeatActive": "",
|
||||
"mHeatSetpointTemp": "",
|
||||
"mHeatTargetTemp": "",
|
||||
"mHeatCurrTemp": "",
|
||||
"mHeatRetTemp": "",
|
||||
"mHeatIndoorTemp": "",
|
||||
"mHeatOutdoorTemp": "",
|
||||
"mDhwEnabled": "",
|
||||
"mDhwOverheat": "",
|
||||
"sDhwActive": "",
|
||||
"mDhwTargetTemp": "",
|
||||
"mDhwCurrTemp": "",
|
||||
"mDhwRetTemp": ""
|
||||
},
|
||||
"sensors": {
|
||||
"values": {
|
||||
"temp": "",
|
||||
"humidity": "",
|
||||
"battery": "",
|
||||
"rssi": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"title": "",
|
||||
"name": "",
|
||||
"section": {
|
||||
"static": "",
|
||||
"availableNetworks": "",
|
||||
"staSettings": "",
|
||||
"apSettings": ""
|
||||
},
|
||||
"scan": {
|
||||
"pos": "",
|
||||
"info": ""
|
||||
},
|
||||
"wifi": {
|
||||
"ssid": "",
|
||||
"password": "",
|
||||
"channel": "",
|
||||
"signal": "",
|
||||
"connected": ""
|
||||
},
|
||||
"params": {
|
||||
"hostname": "",
|
||||
"dhcp": "",
|
||||
"mac": "",
|
||||
"ip": "",
|
||||
"subnet": "",
|
||||
"gateway": "",
|
||||
"dns": ""
|
||||
},
|
||||
"sta": {
|
||||
"channel": {
|
||||
"note": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensors": {
|
||||
"title": "",
|
||||
"name": "",
|
||||
"enabled": "",
|
||||
"sensorName": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"purpose": "",
|
||||
"purposes": {
|
||||
"outdoorTemp": "",
|
||||
"indoorTemp": "",
|
||||
"heatTemp": "",
|
||||
"heatRetTemp": "",
|
||||
"dhwTemp": "",
|
||||
"dhwRetTemp": "",
|
||||
"dhwFlowRate": "",
|
||||
"exhaustTemp": "",
|
||||
"modLevel": "",
|
||||
"number": "",
|
||||
"powerFactor": "",
|
||||
"power": "",
|
||||
"fanSpeed": "",
|
||||
"co2": "",
|
||||
"pressure": "",
|
||||
"humidity": "",
|
||||
"temperature": "",
|
||||
"notConfigured": ""
|
||||
},
|
||||
"type": "",
|
||||
"types": {
|
||||
"otOutdoorTemp": "",
|
||||
"otHeatTemp": "",
|
||||
"otHeatRetTemp": "",
|
||||
"otDhwTemp": "",
|
||||
"otDhwTemp2": "",
|
||||
"otDhwFlowRate": "",
|
||||
"otCh2Temp": "",
|
||||
"otExhaustTemp": "",
|
||||
"otHeatExchangerTemp": "",
|
||||
"otPressure": "",
|
||||
"otModLevel": "",
|
||||
"otCurrentPower": "",
|
||||
"otExhaustCo2": "",
|
||||
"otExhaustFanSpeed": "",
|
||||
"otSupplyFanSpeed": "",
|
||||
"otSolarStorageTemp": "",
|
||||
"otSolarCollectorTemp": "",
|
||||
"otFanSpeedSetpoint": "",
|
||||
"otFanSpeedCurrent": "",
|
||||
"otBurnerStarts": "",
|
||||
"otDhwBurnerStarts": "",
|
||||
"otHeatingPumpStarts": "",
|
||||
"otDhwPumpStarts": "",
|
||||
"otBurnerHours": "",
|
||||
"otDhwBurnerHours": "",
|
||||
"otHeatingPumpHours": "",
|
||||
"otDhwPumpHours": "",
|
||||
"otCoolingHours": "",
|
||||
"ntcTemp": "",
|
||||
"dallasTemp": "",
|
||||
"bluetooth": "",
|
||||
"dht11": "",
|
||||
"dht22": "",
|
||||
"heatSetpointTemp": "",
|
||||
"manual": "",
|
||||
"notConfigured": ""
|
||||
},
|
||||
"gpio": "",
|
||||
"address": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"correction": {
|
||||
"desc": "",
|
||||
"offset": "",
|
||||
"factor": ""
|
||||
},
|
||||
"filtering": {
|
||||
"desc": "",
|
||||
"enabled": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"factor": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "",
|
||||
"name": "",
|
||||
"section": {
|
||||
"portal": "",
|
||||
"system": "",
|
||||
"diag": "",
|
||||
"heating": "",
|
||||
"dhw": "",
|
||||
"emergency": "",
|
||||
"equitherm": "",
|
||||
"pid": "",
|
||||
"ot": "",
|
||||
"mqtt": "",
|
||||
"extPump": "",
|
||||
"cascadeControl": ""
|
||||
},
|
||||
"enable": "",
|
||||
"note": {
|
||||
"restart": "",
|
||||
"blankNotUse": "",
|
||||
"bleDevice": ""
|
||||
},
|
||||
"temp": {
|
||||
"min": "",
|
||||
"max": ""
|
||||
},
|
||||
"avgType": {
|
||||
"mean": "",
|
||||
"min": "",
|
||||
"max": ""
|
||||
},
|
||||
"maxModulation": "",
|
||||
"ohProtection": {
|
||||
"title": "",
|
||||
"desc": "",
|
||||
"highTemp": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"lowTemp": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
}
|
||||
},
|
||||
"freezeProtection": {
|
||||
"title": "",
|
||||
"desc": "",
|
||||
"highTemp": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"lowTemp": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
}
|
||||
},
|
||||
"portal": {
|
||||
"login": "",
|
||||
"password": "",
|
||||
"auth": "",
|
||||
"mdns": ""
|
||||
},
|
||||
"system": {
|
||||
"unit": "",
|
||||
"metric": "",
|
||||
"imperial": "",
|
||||
"statusLedGpio": "",
|
||||
"logLevel": "",
|
||||
"serial": {
|
||||
"enable": "",
|
||||
"baud": ""
|
||||
},
|
||||
"webSerial": {
|
||||
"enable": ""
|
||||
},
|
||||
"ntp": {
|
||||
"server": "",
|
||||
"timezone": "",
|
||||
"timezonePresets": ""
|
||||
}
|
||||
},
|
||||
"heating": {
|
||||
"hyst": {
|
||||
"title": "",
|
||||
"desc": "",
|
||||
"value": "",
|
||||
"action": {
|
||||
"title": "",
|
||||
"disableHeating": "",
|
||||
"set0target": ""
|
||||
}
|
||||
},
|
||||
"turboFactor": "",
|
||||
"indoorTempAvgType": {
|
||||
"title": "",
|
||||
"desc": ""
|
||||
},
|
||||
"outdoorTempAvgType": {
|
||||
"title": "",
|
||||
"desc": ""
|
||||
}
|
||||
},
|
||||
"emergency": {
|
||||
"desc": "",
|
||||
"target": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"treshold": ""
|
||||
},
|
||||
"equitherm": {
|
||||
"slope": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"exponent": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"shift": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"targetDiffFactor": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"chart": {
|
||||
"targetTemp": "",
|
||||
"setpointTemp": "",
|
||||
"outdoorTemp": ""
|
||||
}
|
||||
},
|
||||
"pid": {
|
||||
"p": "",
|
||||
"i": "",
|
||||
"d": "",
|
||||
"dt": "",
|
||||
"limits": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"deadband": {
|
||||
"title": "",
|
||||
"note": "",
|
||||
"p_multiplier": "",
|
||||
"i_multiplier": "",
|
||||
"d_multiplier": "",
|
||||
"thresholdHigh": "",
|
||||
"thresholdLow": ""
|
||||
}
|
||||
},
|
||||
"ot": {
|
||||
"advanced": "",
|
||||
"inGpio": "",
|
||||
"outGpio": "",
|
||||
"ledGpio": "",
|
||||
"memberId": "",
|
||||
"flags": "",
|
||||
"minPower": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"maxPower": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
},
|
||||
"options": {
|
||||
"title": "",
|
||||
"desc": "",
|
||||
"dhwSupport": "",
|
||||
"coolingSupport": "",
|
||||
"summerWinterMode": "",
|
||||
"heatingStateToSummerWinterMode": "",
|
||||
"ch2AlwaysEnabled": "",
|
||||
"heatingToCh2": "",
|
||||
"dhwToCh2": "",
|
||||
"dhwBlocking": "",
|
||||
"dhwStateAsDhwBlocking": "",
|
||||
"maxTempSyncWithTargetTemp": "",
|
||||
"getMinMaxTemp": "",
|
||||
"ignoreDiagState": "",
|
||||
"autoFaultReset": "",
|
||||
"autoDiagReset": "",
|
||||
"setDateAndTime": "",
|
||||
"immergasFix": "",
|
||||
"alwaysSendIndoorTemp": ""
|
||||
},
|
||||
"nativeOTC": {
|
||||
"title": "",
|
||||
"note": ""
|
||||
}
|
||||
},
|
||||
"mqtt": {
|
||||
"homeAssistantDiscovery": "",
|
||||
"server": "",
|
||||
"port": "",
|
||||
"user": "",
|
||||
"password": "",
|
||||
"prefix": "",
|
||||
"interval": ""
|
||||
},
|
||||
"extPump": {
|
||||
"use": "",
|
||||
"gpio": "",
|
||||
"invertState": "",
|
||||
"postCirculationTime": "",
|
||||
"antiStuckInterval": "",
|
||||
"antiStuckTime": ""
|
||||
},
|
||||
"cascadeControl": {
|
||||
"input": {
|
||||
"desc": "",
|
||||
"enable": "",
|
||||
"gpio": "",
|
||||
"invertState": "",
|
||||
"thresholdTime": ""
|
||||
},
|
||||
"output": {
|
||||
"desc": "",
|
||||
"enable": "",
|
||||
"gpio": "",
|
||||
"invertState": "",
|
||||
"thresholdTime": "",
|
||||
"events": {
|
||||
"desc": "",
|
||||
"onFault": "",
|
||||
"onLossConnection": "",
|
||||
"onEnabledHeating": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"upgrade": {
|
||||
"title": "",
|
||||
"name": "",
|
||||
"section": {
|
||||
"backupAndRestore": {
|
||||
"title": "",
|
||||
"desc": ""
|
||||
},
|
||||
"upgrade": {
|
||||
"title": "",
|
||||
"desc": ""
|
||||
}
|
||||
},
|
||||
"note": {
|
||||
"disclaimer1": "",
|
||||
"disclaimer2": ""
|
||||
},
|
||||
"settingsFile": "",
|
||||
"fw": "",
|
||||
"fs": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
-56
@@ -8,15 +8,21 @@
|
||||
"issues": "Problemi e domande",
|
||||
"releases": "Versione"
|
||||
},
|
||||
"dbm": "dBm",
|
||||
"kw": "kW",
|
||||
"time": {
|
||||
"units": {
|
||||
"days": "d.",
|
||||
"hours": "h.",
|
||||
"min": "min.",
|
||||
"sec": "sec."
|
||||
"sec": "sec.",
|
||||
"dbm": "dBm",
|
||||
"mhz": "MHz",
|
||||
"kw": "kW",
|
||||
"rpm": "RPM",
|
||||
"ppm": "ppm",
|
||||
"byte": "byte",
|
||||
"mbyte": "MB",
|
||||
"liter": "litro",
|
||||
"gallon": "gal"
|
||||
},
|
||||
|
||||
"button": {
|
||||
"upgrade": "Aggiorna",
|
||||
"restart": "Riavvia",
|
||||
@@ -31,15 +37,12 @@
|
||||
"success": "Riuscito",
|
||||
"error": "Errore"
|
||||
},
|
||||
|
||||
"index": {
|
||||
"title": "OpenTherm Gateway",
|
||||
|
||||
"section": {
|
||||
"network": "Rete",
|
||||
"system": "Sistema"
|
||||
},
|
||||
|
||||
"system": {
|
||||
"build": {
|
||||
"title": "Build",
|
||||
@@ -51,7 +54,8 @@
|
||||
},
|
||||
"uptime": "Tempo di attività",
|
||||
"memory": {
|
||||
"title": "Memoria libera",
|
||||
"heap": "Memoria (heap)",
|
||||
"psram": "Memoria (PSRAM)",
|
||||
"maxFreeBlock": "max free block",
|
||||
"min": "min"
|
||||
},
|
||||
@@ -68,26 +72,22 @@
|
||||
"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",
|
||||
"temp.current": "Attuale",
|
||||
"currentTemp": "Attuale",
|
||||
"enable": "Attiva",
|
||||
"turbo": "Turbo"
|
||||
},
|
||||
|
||||
"notify": {
|
||||
"fault": {
|
||||
"title": "Rilevamento guasti caldiaia attivo!",
|
||||
@@ -99,7 +99,6 @@
|
||||
},
|
||||
"reset": "Prova a resettare"
|
||||
},
|
||||
|
||||
"states": {
|
||||
"mNetworkConnected": "Connessione Rete",
|
||||
"mMqttConnected": "Connessione MQTT",
|
||||
@@ -107,7 +106,6 @@
|
||||
"mExtPumpState": "Pompa esterna",
|
||||
"mCascadeControlInput": "Controllo a cascata (input)",
|
||||
"mCascadeControlOutput": "Controllo a cascata (output)",
|
||||
|
||||
"sConnected": "Connessione OpenTherm",
|
||||
"sFlame": "Fiamma",
|
||||
"sCoolingActive": "Raffrescamento",
|
||||
@@ -116,10 +114,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",
|
||||
@@ -127,7 +125,6 @@
|
||||
"mHeatRetTemp": "Temp ritorno riscaldamento",
|
||||
"mHeatIndoorTemp": "Riscaldamento, temp interna",
|
||||
"mHeatOutdoorTemp": "Riscaldamento, temp esterna",
|
||||
|
||||
"mDhwEnabled": "ACS attivata",
|
||||
"mDhwOverheat": "ACS surriscaldamento",
|
||||
"sDhwActive": "ACS attiva",
|
||||
@@ -135,7 +132,6 @@
|
||||
"mDhwCurrTemp": "ACS temp attuale",
|
||||
"mDhwRetTemp": "ACS temp ricircolo"
|
||||
},
|
||||
|
||||
"sensors": {
|
||||
"values": {
|
||||
"temp": "Temperatura",
|
||||
@@ -145,23 +141,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"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",
|
||||
@@ -169,7 +161,6 @@
|
||||
"signal": "Segnale",
|
||||
"connected": "Connesso"
|
||||
},
|
||||
|
||||
"params": {
|
||||
"hostname": "Hostname",
|
||||
"dhcp": "Usa DHCP",
|
||||
@@ -179,16 +170,15 @@
|
||||
"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",
|
||||
@@ -245,7 +235,6 @@
|
||||
"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",
|
||||
@@ -277,11 +266,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"settings": {
|
||||
"title": "Impostazioni - OpenTherm Gateway",
|
||||
"name": "Impostazioni",
|
||||
|
||||
"section": {
|
||||
"portal": "Impostazioni Accesso",
|
||||
"system": "Impostazioni sistema",
|
||||
@@ -296,18 +283,21 @@
|
||||
"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",
|
||||
@@ -333,14 +323,12 @@
|
||||
"note": "Soglia quando il riscaldamento viene forzatamente attivato"
|
||||
}
|
||||
},
|
||||
|
||||
"portal": {
|
||||
"login": "Login",
|
||||
"password": "Password",
|
||||
"auth": "Richiede autenticazione",
|
||||
"mdns": "Usa mDNS"
|
||||
},
|
||||
|
||||
"system": {
|
||||
"unit": "Unità di misura",
|
||||
"metric": "Metrico <small>(celsius, litri, bar)</small>",
|
||||
@@ -360,7 +348,6 @@
|
||||
"timezonePresets": "Seleziona preimpostato..."
|
||||
}
|
||||
},
|
||||
|
||||
"heating": {
|
||||
"hyst": {
|
||||
"title": "Isteresi",
|
||||
@@ -372,19 +359,24 @@
|
||||
"set0target": "Imposta target nullo"
|
||||
}
|
||||
},
|
||||
"turboFactor": "Turbo mode coeff."
|
||||
"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»)."
|
||||
}
|
||||
},
|
||||
|
||||
"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",
|
||||
@@ -408,7 +400,6 @@
|
||||
"outdoorTemp": "Temperatura esterna"
|
||||
}
|
||||
},
|
||||
|
||||
"pid": {
|
||||
"p": "Fattore P",
|
||||
"i": "Fattore I",
|
||||
@@ -428,7 +419,6 @@
|
||||
"thresholdLow": "Soglia inferiore"
|
||||
}
|
||||
},
|
||||
|
||||
"ot": {
|
||||
"advanced": "Impostazioni avanzate",
|
||||
"inGpio": "In GPIO",
|
||||
@@ -444,7 +434,6 @@
|
||||
"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.",
|
||||
@@ -466,13 +455,11 @@
|
||||
"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",
|
||||
@@ -482,7 +469,6 @@
|
||||
"prefix": "Prefisso",
|
||||
"interval": "Intervallo invio <small>(sec)</small>"
|
||||
},
|
||||
|
||||
"extPump": {
|
||||
"use": "Usa pompa/circolatore esterno",
|
||||
"gpio": "GPIO relè",
|
||||
@@ -491,7 +477,6 @@
|
||||
"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.",
|
||||
@@ -515,26 +500,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"upgrade": {
|
||||
"title": "Aggiornamenti - OpenTherm Gateway",
|
||||
"name": "Aggiornamenti",
|
||||
|
||||
"section": {
|
||||
"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."
|
||||
"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."
|
||||
}
|
||||
},
|
||||
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+40
-15
@@ -8,13 +8,20 @@
|
||||
"issues": "Problemen & vragen",
|
||||
"releases": "Releases"
|
||||
},
|
||||
"dbm": "dBm",
|
||||
"kw": "kW",
|
||||
"time": {
|
||||
"units": {
|
||||
"days": "d.",
|
||||
"hours": "u.",
|
||||
"min": "min.",
|
||||
"sec": "sec."
|
||||
"sec": "sec.",
|
||||
"dbm": "dBm",
|
||||
"mhz": "MHz",
|
||||
"kw": "kW",
|
||||
"rpm": "RPM",
|
||||
"ppm": "ppm",
|
||||
"byte": "byte",
|
||||
"mbyte": "MB",
|
||||
"liter": "L",
|
||||
"gallon": "gal"
|
||||
},
|
||||
"button": {
|
||||
"upgrade": "Upgraden",
|
||||
@@ -47,7 +54,8 @@
|
||||
},
|
||||
"uptime": "Uptime",
|
||||
"memory": {
|
||||
"title": "Vrij geheugen",
|
||||
"heap": "Geheugen (heap)",
|
||||
"psram": "Geheugen (PSRAM)",
|
||||
"maxFreeBlock": "max. vrij blok",
|
||||
"min": "min"
|
||||
},
|
||||
@@ -76,7 +84,7 @@
|
||||
"thermostat": {
|
||||
"heating": "Verwarming",
|
||||
"dhw": "Warm water",
|
||||
"temp.current": "Huidig",
|
||||
"currentTemp": "Huidig",
|
||||
"enable": "Inschakelen",
|
||||
"turbo": "Turbomodus"
|
||||
},
|
||||
@@ -109,6 +117,7 @@
|
||||
"mHeatEnabled": "Verwarming ingeschakeld",
|
||||
"mHeatBlocking": "Verwarming geblokkeerd",
|
||||
"mHeatOverheat": "Verwarming oververhit",
|
||||
"mHeatFreezing": "Verwarming vorstbescherming",
|
||||
"sHeatActive": "Verwarming actief",
|
||||
"mHeatSetpointTemp": "Insteltemperatuur verwarming",
|
||||
"mHeatTargetTemp": "Doeltemperatuur verwarming",
|
||||
@@ -162,7 +171,9 @@
|
||||
"dns": "DNS"
|
||||
},
|
||||
"sta": {
|
||||
"channel.note": "zet op 0 voor automatische selectie"
|
||||
"channel": {
|
||||
"note": "zet op 0 voor automatische selectie"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensors": {
|
||||
@@ -224,7 +235,6 @@
|
||||
"otHeatingPumpHours": "OpenTherm, aantal pompuren (verwarming)",
|
||||
"otDhwPumpHours": "OpenTherm, aantal pompuren (warm water)",
|
||||
"otCoolingHours": "OpenTherm, aantal cooling",
|
||||
|
||||
"ntcTemp": "NTC-sensor",
|
||||
"dallasTemp": "DALLAS-sensor",
|
||||
"bluetooth": "BLE-sensor",
|
||||
@@ -283,6 +293,11 @@
|
||||
"min": "Minimumtemperatuur",
|
||||
"max": "Maximumtemperatuur"
|
||||
},
|
||||
"avgType": {
|
||||
"mean": "Gemiddelde temperatuur",
|
||||
"min": "Minimum temperatuur",
|
||||
"max": "Maximum temperatuur"
|
||||
},
|
||||
"maxModulation": "Max. modulatieniveau",
|
||||
"ohProtection": {
|
||||
"title": "Oververhittingsbeveiliging",
|
||||
@@ -308,7 +323,6 @@
|
||||
"note": "Drempel wanneer de verwarming geforceerd wordt ingeschakeld"
|
||||
}
|
||||
},
|
||||
|
||||
"portal": {
|
||||
"login": "Gebruikersnaam",
|
||||
"password": "Wachtwoord",
|
||||
@@ -345,7 +359,15 @@
|
||||
"set0target": "Stel null target in"
|
||||
}
|
||||
},
|
||||
"turboFactor": "Turbomodus coëff."
|
||||
"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»)."
|
||||
}
|
||||
},
|
||||
"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.",
|
||||
@@ -433,7 +455,6 @@
|
||||
"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."
|
||||
@@ -483,10 +504,14 @@
|
||||
"title": "Upgrade - OpenTherm Gateway",
|
||||
"name": "Upgrade",
|
||||
"section": {
|
||||
"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."
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"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.",
|
||||
|
||||
+41
-56
@@ -8,15 +8,21 @@
|
||||
"issues": "Проблемы и вопросы",
|
||||
"releases": "Релизы"
|
||||
},
|
||||
"dbm": "дБм",
|
||||
"kw": "кВт",
|
||||
"time": {
|
||||
"units": {
|
||||
"days": "д.",
|
||||
"hours": "ч.",
|
||||
"min": "мин.",
|
||||
"sec": "сек."
|
||||
"sec": "сек.",
|
||||
"dbm": "дБм",
|
||||
"mhz": "МГц",
|
||||
"kw": "кВт",
|
||||
"rpm": "RPM",
|
||||
"ppm": "ppm",
|
||||
"byte": "байт",
|
||||
"mbyte": "мбайт",
|
||||
"liter": "Л.",
|
||||
"gallon": "гал."
|
||||
},
|
||||
|
||||
"button": {
|
||||
"upgrade": "Обновить",
|
||||
"restart": "Перезагрузка",
|
||||
@@ -31,15 +37,12 @@
|
||||
"success": "Успешно",
|
||||
"error": "Ошибка"
|
||||
},
|
||||
|
||||
"index": {
|
||||
"title": "OpenTherm Gateway",
|
||||
|
||||
"section": {
|
||||
"network": "Сеть",
|
||||
"system": "Система"
|
||||
},
|
||||
|
||||
"system": {
|
||||
"build": {
|
||||
"title": "Билд",
|
||||
@@ -51,7 +54,8 @@
|
||||
},
|
||||
"uptime": "Аптайм",
|
||||
"memory": {
|
||||
"title": "ОЗУ",
|
||||
"heap": "Память (heap)",
|
||||
"psram": "Память (PSRAM)",
|
||||
"maxFreeBlock": "макс. блок",
|
||||
"min": "мин."
|
||||
},
|
||||
@@ -68,26 +72,22 @@
|
||||
"lastResetReason": "Причина перезагрузки"
|
||||
}
|
||||
},
|
||||
|
||||
"dashboard": {
|
||||
"name": "Дашборд",
|
||||
"title": "Дашборд - OpenTherm Gateway",
|
||||
|
||||
"section": {
|
||||
"control": "Управление",
|
||||
"states": "Состояние",
|
||||
"sensors": "Сенсоры",
|
||||
"diag": "Диагностика OpenTherm"
|
||||
},
|
||||
|
||||
"thermostat": {
|
||||
"heating": "Отопление",
|
||||
"dhw": "ГВС",
|
||||
"temp.current": "Текущая",
|
||||
"currentTemp": "Текущая",
|
||||
"enable": "Вкл",
|
||||
"turbo": "Турбо"
|
||||
},
|
||||
|
||||
"notify": {
|
||||
"fault": {
|
||||
"title": "Состояние неисправности котла активно!",
|
||||
@@ -99,7 +99,6 @@
|
||||
},
|
||||
"reset": "Сбросить"
|
||||
},
|
||||
|
||||
"states": {
|
||||
"mNetworkConnected": "Подключение к сети",
|
||||
"mMqttConnected": "Подключение к MQTT",
|
||||
@@ -107,7 +106,6 @@
|
||||
"mExtPumpState": "Внешний насос",
|
||||
"mCascadeControlInput": "Каскадное управление (вход)",
|
||||
"mCascadeControlOutput": "Каскадное управление (выход)",
|
||||
|
||||
"sConnected": "Подключение к OpenTherm",
|
||||
"sFlame": "Пламя",
|
||||
"sCoolingActive": "Охлаждение",
|
||||
@@ -116,10 +114,10 @@
|
||||
"sFaultCode": "Код ошибки",
|
||||
"sDiagActive": "Диагностика",
|
||||
"sDiagCode": "Диагностический код",
|
||||
|
||||
"mHeatEnabled": "Отопление",
|
||||
"mHeatBlocking": "Блокировка отопления",
|
||||
"mHeatOverheat": "Отопление, перегрев",
|
||||
"mHeatFreezing": "Отопление, защита от замерзания",
|
||||
"sHeatActive": "Активность отопления",
|
||||
"mHeatSetpointTemp": "Отопление, уставка",
|
||||
"mHeatTargetTemp": "Отопление, целевая температура",
|
||||
@@ -127,7 +125,6 @@
|
||||
"mHeatRetTemp": "Отопление, температура обратки",
|
||||
"mHeatIndoorTemp": "Отопление, внутренняя темп.",
|
||||
"mHeatOutdoorTemp": "Отопление, наружная темп.",
|
||||
|
||||
"mDhwEnabled": "ГВС",
|
||||
"mDhwOverheat": "ГВС, перегрев",
|
||||
"sDhwActive": "Активность ГВС",
|
||||
@@ -135,7 +132,6 @@
|
||||
"mDhwCurrTemp": "ГВС, текущая температура",
|
||||
"mDhwRetTemp": "ГВС, температура обратки"
|
||||
},
|
||||
|
||||
"sensors": {
|
||||
"values": {
|
||||
"temp": "Температура",
|
||||
@@ -145,23 +141,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"network": {
|
||||
"title": "Сеть - OpenTherm Gateway",
|
||||
"name": "Настройки сети",
|
||||
|
||||
"section": {
|
||||
"static": "Статические параметры",
|
||||
"availableNetworks": "Доступные сети",
|
||||
"staSettings": "Настройки подключения",
|
||||
"apSettings": "Настройки точки доступа"
|
||||
},
|
||||
|
||||
"scan": {
|
||||
"pos": "#",
|
||||
"info": "Инфо"
|
||||
},
|
||||
|
||||
"wifi": {
|
||||
"ssid": "Имя сети",
|
||||
"password": "Пароль",
|
||||
@@ -169,7 +161,6 @@
|
||||
"signal": "Сигнал",
|
||||
"connected": "Подключено"
|
||||
},
|
||||
|
||||
"params": {
|
||||
"hostname": "Имя хоста",
|
||||
"dhcp": "Использовать DHCP",
|
||||
@@ -179,16 +170,15 @@
|
||||
"gateway": "Адрес шлюза",
|
||||
"dns": "DNS адрес"
|
||||
},
|
||||
|
||||
"sta": {
|
||||
"channel.note": "установите 0 для автоматического выбора"
|
||||
"channel": {
|
||||
"note": "установите 0 для автоматического выбора"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"sensors": {
|
||||
"title": "Настройки сенсоров - OpenTherm Gateway",
|
||||
"name": "Настройки сенсоров",
|
||||
|
||||
"enabled": "Включить и использовать",
|
||||
"sensorName": {
|
||||
"title": "Имя сенсора",
|
||||
@@ -245,7 +235,6 @@
|
||||
"otHeatingPumpHours": "OpenTherm, кол-во часов работы насоса (отопление)",
|
||||
"otDhwPumpHours": "OpenTherm, кол-во часов работы насоса (ГВС)",
|
||||
"otCoolingHours": "OpenTherm, кол-во часов работы охлаждения",
|
||||
|
||||
"ntcTemp": "NTC датчик",
|
||||
"dallasTemp": "DALLAS датчик",
|
||||
"bluetooth": "BLE датчик",
|
||||
@@ -277,11 +266,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"settings": {
|
||||
"title": "Настройки - OpenTherm Gateway",
|
||||
"name": "Настройки",
|
||||
|
||||
"section": {
|
||||
"portal": "Настройки портала",
|
||||
"system": "Системные настройки",
|
||||
@@ -296,18 +283,21 @@
|
||||
"extPump": "Настройки дополнительного насоса",
|
||||
"cascadeControl": "Настройки каскадного управления"
|
||||
},
|
||||
|
||||
"enable": "Вкл",
|
||||
"note": {
|
||||
"restart": "После изменения этих настроек устройство необходимо перезагрузить, чтобы изменения вступили в силу.",
|
||||
"blankNotUse": "пусто - не использовать",
|
||||
"bleDevice": "BLE устройство можно использовать <u>только</u> с некоторыми платами ESP32, которые поддерживают BLE!"
|
||||
},
|
||||
|
||||
"temp": {
|
||||
"min": "Мин. температура",
|
||||
"max": "Макс. температура"
|
||||
},
|
||||
"avgType": {
|
||||
"mean": "Средняя температура",
|
||||
"min": "Минимальная температура",
|
||||
"max": "Максимальная температура"
|
||||
},
|
||||
"maxModulation": "Макс. уровень модуляции",
|
||||
"ohProtection": {
|
||||
"title": "Защита от перегрева",
|
||||
@@ -333,14 +323,12 @@
|
||||
"note": "Порог, при котором отопление будет принудительно включено"
|
||||
}
|
||||
},
|
||||
|
||||
"portal": {
|
||||
"login": "Логин",
|
||||
"password": "Пароль",
|
||||
"auth": "Требовать аутентификацию",
|
||||
"mdns": "Использовать mDNS"
|
||||
},
|
||||
|
||||
"system": {
|
||||
"unit": "Система единиц",
|
||||
"metric": "Метрическая <small>(цельсии, литры, бары)</small>",
|
||||
@@ -360,7 +348,6 @@
|
||||
"timezonePresets": "Выберите пресет..."
|
||||
}
|
||||
},
|
||||
|
||||
"heating": {
|
||||
"hyst": {
|
||||
"title": "Гистерезис",
|
||||
@@ -372,19 +359,24 @@
|
||||
"set0target": "Установить 0 в качестве целевой темп."
|
||||
}
|
||||
},
|
||||
"turboFactor": "Коэфф. турбо режима"
|
||||
"turboFactor": "Коэфф. турбо режима",
|
||||
"indoorTempAvgType": {
|
||||
"title": "Тип усреднения внутренней темп.",
|
||||
"desc": "Полезно при использовании двух и более датчиков внутренней температуры (при использовании «Equitherm» и/или «PID»)."
|
||||
},
|
||||
"outdoorTempAvgType": {
|
||||
"title": "Тип усреднения наружнной темп.",
|
||||
"desc": "Полезно при использовании двух и более датчиков наружной температуры (при использовании «Equitherm»)."
|
||||
}
|
||||
},
|
||||
|
||||
"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": "Наклон",
|
||||
@@ -408,7 +400,6 @@
|
||||
"outdoorTemp": "Наружная температура"
|
||||
}
|
||||
},
|
||||
|
||||
"pid": {
|
||||
"p": "Коэффициент P",
|
||||
"i": "Коэффициент I",
|
||||
@@ -428,7 +419,6 @@
|
||||
"thresholdLow": "Нижний порог"
|
||||
}
|
||||
},
|
||||
|
||||
"ot": {
|
||||
"advanced": "Дополнительные настройки",
|
||||
"inGpio": "Вход GPIO",
|
||||
@@ -444,7 +434,6 @@
|
||||
"title": "Макс. мощность котла <small>(кВт)</small>",
|
||||
"note": "<b>0</b> - попробовать определить автоматически. Обычно можно найти в спецификации котла как \"максимальная полезная тепловая мощность\"."
|
||||
},
|
||||
|
||||
"options": {
|
||||
"title": "Опции (дополнительные настройки)",
|
||||
"desc": "Опции могут менять логику работы котла. Не все опции задокументированы в протоколе, поэтому одна и та же опция может иметь разный эффект на разных котлах.<br /><b>Примечание:</b> Нет необходимости что-то менять, если всё работает хорошо.",
|
||||
@@ -466,13 +455,11 @@
|
||||
"immergasFix": "Фикс для котлов Immergas",
|
||||
"alwaysSendIndoorTemp": "Передавать текущую темп. в помещении котлу"
|
||||
},
|
||||
|
||||
"nativeOTC": {
|
||||
"title": "Нативный режим OTC (расчёт температуры теплоносителя)",
|
||||
"note": "Работает <u>ТОЛЬКО</u> если котел в режиме OTC: требует и принимает целевую температуру в помещении и сам регулирует температуру теплоносителя на основе встроенного режима кривых. Несовместимо с ПИД и ПЗА."
|
||||
}
|
||||
},
|
||||
|
||||
"mqtt": {
|
||||
"homeAssistantDiscovery": "Home Assistant Discovery",
|
||||
"server": "Адрес сервера",
|
||||
@@ -482,7 +469,6 @@
|
||||
"prefix": "Префикс",
|
||||
"interval": "Интервал публикации <small>(сек)</small>"
|
||||
},
|
||||
|
||||
"extPump": {
|
||||
"use": "Использовать доп. насос",
|
||||
"gpio": "GPIO реле",
|
||||
@@ -491,7 +477,6 @@
|
||||
"antiStuckInterval": "Интервал защиты от блокировки <small>(в днях)</small>",
|
||||
"antiStuckTime": "Время работы насоса <small>(в минутах)</small>"
|
||||
},
|
||||
|
||||
"cascadeControl": {
|
||||
"input": {
|
||||
"desc": "Может использоваться для включения отопления только при неисправности другого котла. Контроллер другого котла должен изменить состояние входа GPIO в случае неисправности.",
|
||||
@@ -515,26 +500,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"upgrade": {
|
||||
"title": "Обновление - OpenTherm Gateway",
|
||||
"name": "Обновление",
|
||||
|
||||
"section": {
|
||||
"backupAndRestore": "Резервное копирование и восстановление",
|
||||
"backupAndRestore.desc": "В этом разделе вы можете сохранить и восстановить резервную копию ВСЕХ настроек.",
|
||||
"upgrade": "Обновление",
|
||||
"upgrade.desc": "В этом разделе вы можете обновить прошивку и файловую систему вашего устройства.<br />Последнюю версию можно загрузить со страницы <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Релизы</a> в репозитории проекта."
|
||||
"backupAndRestore": {
|
||||
"title": "Резервное копирование и восстановление",
|
||||
"desc": "В этом разделе вы можете сохранить и восстановить резервную копию ВСЕХ настроек."
|
||||
},
|
||||
"upgrade": {
|
||||
"title": "Обновление",
|
||||
"desc": "В этом разделе вы можете обновить прошивку и файловую систему вашего устройства.<br />Последнюю версию можно загрузить со страницы <a href=\"https://github.com/Laxilef/OTGateway/releases\" target=\"_blank\">Релизы</a> в репозитории проекта."
|
||||
}
|
||||
},
|
||||
|
||||
"note": {
|
||||
"disclaimer1": "После успешного обновления файловой системы ВСЕ настройки будут сброшены на стандартные! Создайте резервную копию ПЕРЕД обновлением.",
|
||||
"disclaimer2": "После успешного обновления устройство автоматически перезагрузится через 15 секунд."
|
||||
},
|
||||
|
||||
"settingsFile": "Файл настроек",
|
||||
"fw": "Прошивка",
|
||||
"fs": "Файловая система"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.temp.current</span>: <span id="tHeatCurrentTemp"></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>
|
||||
<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.temp.current</span>: <span id="tDhwCurrentTemp"></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>
|
||||
<div class="thermostat-minus">
|
||||
<button class="tAction outline" data-action="decrement"><i class="icons-down"></i></button>
|
||||
@@ -351,9 +351,14 @@
|
||||
value = -(step);
|
||||
}
|
||||
|
||||
newSettings[purpose].target = parseFloat(constrain(newSettings[purpose].target + value, minTemp, maxTemp).toFixed(2));
|
||||
modifiedTime = Date.now();
|
||||
setValue('.targetTemp', newSettings[purpose].target, tContainer);
|
||||
const newValue = parseFloat(constrain(newSettings[purpose].target + value, minTemp, maxTemp).toFixed(2));
|
||||
if (newSettings[purpose].target != newValue) {
|
||||
newSettings[purpose].target = newValue;
|
||||
modifiedTime = Date.now();
|
||||
|
||||
setValue('.targetTemp', newValue, tContainer);
|
||||
tContainer.querySelector('.thermostat-header').setAttribute("aria-busy", "true");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -383,27 +388,46 @@
|
||||
value = -(bigStep);
|
||||
}
|
||||
|
||||
newSettings[purpose].target = parseFloat(constrain(newSettings[purpose].target + value, minTemp, maxTemp).toFixed(2));
|
||||
modifiedTime = Date.now();
|
||||
const newValue = parseFloat(constrain(newSettings[purpose].target + value, minTemp, maxTemp).toFixed(2));
|
||||
if (newSettings[purpose].target != newValue) {
|
||||
newSettings[purpose].target = newValue;
|
||||
modifiedTime = Date.now();
|
||||
|
||||
setValue('.targetTemp', newSettings[purpose].target, tContainer);
|
||||
setValue('.targetTemp', newSettings[purpose].target, tContainer);
|
||||
tContainer.querySelector('.thermostat-header').setAttribute("aria-busy", "true");
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector('#tHeatEnabled').addEventListener('change', (event) => {
|
||||
if (newSettings.heating.enabled == event.currentTarget.checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
modifiedTime = Date.now();
|
||||
newSettings.heating.enabled = event.currentTarget.checked;
|
||||
document.querySelector('.tHeat .thermostat-header').setAttribute("aria-busy", "true");
|
||||
});
|
||||
|
||||
document.querySelector('#tHeatTurbo').addEventListener('change', (event) => {
|
||||
if (newSettings.heating.turbo == event.currentTarget.checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
modifiedTime = Date.now();
|
||||
newSettings.heating.turbo = event.currentTarget.checked;
|
||||
document.querySelector('.tHeat .thermostat-header').setAttribute("aria-busy", "true");
|
||||
});
|
||||
|
||||
document.querySelector('#tDhwEnabled').addEventListener('change', (event) => {
|
||||
if (newSettings.dhw.enabled == event.currentTarget.checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
modifiedTime = Date.now();
|
||||
newSettings.dhw.enabled = event.currentTarget.checked;
|
||||
document.querySelector('.tDhw .thermostat-header').setAttribute("aria-busy", "true");
|
||||
});
|
||||
|
||||
document.querySelector('.notify-fault .reset').addEventListener('click', async (event) => {
|
||||
@@ -531,6 +555,10 @@
|
||||
setValue('.pressureUnit', pressureUnit(unitSystem));
|
||||
setValue('.volumeUnit', volumeUnit(unitSystem));
|
||||
|
||||
document.querySelectorAll('.thermostat-header').forEach((item) => {
|
||||
item.setAttribute("aria-busy", "false");
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
@@ -769,7 +797,7 @@
|
||||
}
|
||||
|
||||
if (sData.rssi !== undefined) {
|
||||
appendValue(".sValue", `${i18n('dashboard.sensors.values.rssi')}: <b>${sData.rssi.toFixed(0)}</b> ${i18n('dbm')}`, `<br />`, sensorNode);
|
||||
appendValue(".sValue", `${i18n('dashboard.sensors.values.rssi')}: <b>${sData.rssi.toFixed(0)}</b> ${i18n('units.dbm')}`, `<br />`, sensorNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,25 +113,32 @@
|
||||
<tr>
|
||||
<th scope="row" data-i18n>index.system.uptime</th>
|
||||
<td>
|
||||
<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>
|
||||
<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>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row" data-i18n>index.system.memory.title</th>
|
||||
<th scope="row" data-i18n>index.system.memory.heap</th>
|
||||
<td>
|
||||
<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)
|
||||
<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>
|
||||
</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> 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)
|
||||
<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>)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -219,6 +226,11 @@
|
||||
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);
|
||||
|
||||
@@ -198,6 +198,28 @@
|
||||
</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>
|
||||
@@ -785,7 +807,7 @@
|
||||
|
||||
<label>
|
||||
<input type="checkbox" name="externalPump[invertState]" value="true">
|
||||
<span data-i18n>settings.externalPump.invertState</span>
|
||||
<span data-i18n>settings.extPump.invertState</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
@@ -1171,6 +1193,8 @@
|
||||
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
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<article>
|
||||
<div>
|
||||
<hgroup>
|
||||
<h2 data-i18n>upgrade.section.backupAndRestore</h2>
|
||||
<h2 data-i18n>upgrade.section.backupAndRestore.title</h2>
|
||||
<p data-i18n>upgrade.section.backupAndRestore.desc</p>
|
||||
</hgroup>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<article>
|
||||
<div>
|
||||
<hgroup>
|
||||
<h2 data-i18n>upgrade.section.upgrade</h2>
|
||||
<h2 data-i18n>upgrade.section.upgrade.title</h2>
|
||||
<p data-i18n>upgrade.section.upgrade.desc</p>
|
||||
</hgroup>
|
||||
|
||||
|
||||
@@ -318,7 +318,7 @@ const setupRestoreBackupForm = (formSelector) => {
|
||||
console.log("Backup: ", data);
|
||||
|
||||
if (data.settings != undefined) {
|
||||
for (var key in data.settings) {
|
||||
for (const key in data.settings) {
|
||||
let response = await fetch(url, {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
@@ -338,6 +338,41 @@ const setupRestoreBackupForm = (formSelector) => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let finalPayload = {};
|
||||
if (data.settings.emergency?.target !== undefined) {
|
||||
finalPayload.emergency ??= {};
|
||||
finalPayload.emergency.target = data.settings.emergency.target;
|
||||
}
|
||||
|
||||
if (data.settings.heating?.target !== undefined) {
|
||||
finalPayload.heating ??= {};
|
||||
finalPayload.heating.target = data.settings.heating.target;
|
||||
}
|
||||
|
||||
if (data.settings.dhw?.target !== undefined) {
|
||||
finalPayload.dhw ??= {};
|
||||
finalPayload.dhw.target = data.settings.dhw.target;
|
||||
}
|
||||
|
||||
if (Object.keys(finalPayload).length) {
|
||||
let response = await fetch(url, {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"settings": finalPayload
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
onFailed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.sensors != undefined) {
|
||||
@@ -765,8 +800,8 @@ const pressureUnit = (unitSystem) => {
|
||||
|
||||
const volumeUnit = (unitSystem) => {
|
||||
return unit2str(unitSystem, {
|
||||
0: "L",
|
||||
1: "gal"
|
||||
0: i18n('units.liter'),
|
||||
1: i18n('units.gallon')
|
||||
});
|
||||
}
|
||||
|
||||
@@ -780,13 +815,13 @@ const purposeUnit = (purpose, unitSystem) => {
|
||||
3: tUnit,
|
||||
4: tUnit,
|
||||
5: tUnit,
|
||||
6: `${volumeUnit(unitSystem)}/${i18n('time.min')}`,
|
||||
6: `${volumeUnit(unitSystem)}/${i18n('units.min')}`,
|
||||
7: tUnit,
|
||||
8: "%",
|
||||
248: "%",
|
||||
249: i18n('kw'),
|
||||
250: "RPM",
|
||||
251: "ppm",
|
||||
249: i18n('units.kw'),
|
||||
250: i18n('units.rpm'),
|
||||
251: i18n('units.ppm'),
|
||||
252: pressureUnit(unitSystem),
|
||||
253: "%",
|
||||
254: tUnit
|
||||
|
||||
Reference in New Issue
Block a user